| author | Ian Bull | 2010-12-03 01:21:14 (EST) |
|---|---|---|
| committer | Fabian Steeg | 2010-12-03 01:21:14 (EST) |
| commit | a0a02493b0af245b6ae73f7c5903fc9f297063ec (patch) (side-by-side diff) | |
| tree | a23b0ded1e95730677abd6d54f78c57f40206d24 | |
| parent | eea63f32345a97afce2c6b8b9bf1a924f2836ce7 (diff) | |
| download | org.eclipse.gef4-a0a02493b0af245b6ae73f7c5903fc9f297063ec.zip org.eclipse.gef4-a0a02493b0af245b6ae73f7c5903fc9f297063ec.tar.gz org.eclipse.gef4-a0a02493b0af245b6ae73f7c5903fc9f297063ec.tar.bz2 | |
Added the jface bundle
31 files changed, 4417 insertions, 0 deletions
diff --git a/org.eclipse.zest.jface/.classpath b/org.eclipse.zest.jface/.classpath new file mode 100644 index 0000000..ad32c83 --- a/dev/null +++ b/org.eclipse.zest.jface/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/org.eclipse.zest.jface/.project b/org.eclipse.zest.jface/.project new file mode 100644 index 0000000..9bf8980 --- a/dev/null +++ b/org.eclipse.zest.jface/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.zest.jface</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/org.eclipse.zest.jface/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.zest.jface/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..beedbd2 --- a/dev/null +++ b/org.eclipse.zest.jface/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Thu Dec 02 22:03:22 PST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.eclipse.zest.jface/META-INF/MANIFEST.MF b/org.eclipse.zest.jface/META-INF/MANIFEST.MF new file mode 100644 index 0000000..f371173 --- a/dev/null +++ b/org.eclipse.zest.jface/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Jface +Bundle-SymbolicName: org.eclipse.zest.jface +Bundle-Version: 2.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Require-Bundle: org.eclipse.ui;bundle-version="3.7.0", + org.eclipse.zest.core;bundle-version="2.0.0", + org.eclipse.zest.layouts;bundle-version="2.0.0", + org.eclipse.draw2d;bundle-version="3.7.0" +Export-Package: org.eclipse.zest.core.viewers, + org.eclipse.zest.core.viewers.internal;x-internal:=true diff --git a/org.eclipse.zest.jface/build.properties b/org.eclipse.zest.jface/build.properties new file mode 100644 index 0000000..34d2e4d --- a/dev/null +++ b/org.eclipse.zest.jface/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/AbstractStructuredGraphViewer.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/AbstractStructuredGraphViewer.java new file mode 100644 index 0000000..6add9e2 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/AbstractStructuredGraphViewer.java @@ -0,0 +1,801 @@ +/******************************************************************************* + * Copyright 2005-2010, 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 + * <mateusz.matela@gmail.com> - Adapt Zest to changes in layout - + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=283179 + ******************************************************************************/ +package org.eclipse.zest.core.viewers; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; + +import org.eclipse.draw2d.IFigure; +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTError; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.widgets.Widget; +import org.eclipse.zest.core.viewers.internal.IStylingGraphModelFactory; +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.ZestStyles; +import org.eclipse.zest.core.widgets.custom.CGraphNode; +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. + * + * @author Del Myers + * @since 2.0 + */ +public abstract class AbstractStructuredGraphViewer extends + AbstractZoomableViewer { + /** + * Contains top-level styles for the entire graph. Set in the constructor. * + */ + private int graphStyle; + + /** + * Contains node-level styles for the graph. Set in setNodeStyle(). Defaults + * are used in the constructor. + */ + private int nodeStyle; + + /** + * Contains arc-level styles for the graph. Set in setConnectionStyle(). + * Defaults are used in the constructor. + */ + private int connectionStyle; + + private HashMap nodesMap = new HashMap(); + private HashMap connectionsMap = new HashMap(); + + /** + * A simple graph comparator that orders graph elements based on thier type + * (connection or node), and their unique object identification. + */ + private class SimpleGraphComparator implements Comparator { + TreeSet storedStrings; + + /** + * + */ + public SimpleGraphComparator() { + this.storedStrings = new TreeSet(); + } + + /* + * (non-Javadoc) + * + * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) + */ + public int compare(Object arg0, Object arg1) { + if (arg0 instanceof GraphNode && arg1 instanceof GraphConnection) { + return 1; + } else if (arg0 instanceof GraphConnection + && arg1 instanceof GraphNode) { + return -1; + } + if (arg0.equals(arg1)) { + return 0; + } + return getObjectString(arg0).compareTo(getObjectString(arg1)); + } + + private String getObjectString(Object o) { + String s = o.getClass().getName() + "@" + + Integer.toHexString(o.hashCode()); + while (storedStrings.contains(s)) { + s = s + 'X'; + } + return s; + } + } + + protected AbstractStructuredGraphViewer(int graphStyle) { + this.graphStyle = graphStyle; + this.connectionStyle = SWT.NONE; + this.nodeStyle = SWT.NONE; + + } + + /** + * Sets the default style for nodes in this graph. Note: if an input is set + * on the viewer, a ZestException will be thrown. + * + * @param nodeStyle + * the style for the nodes. + * @see #ZestStyles + */ + public void setNodeStyle(int nodeStyle) { + if (getInput() != null) { + throw new SWTError(SWT.ERROR_UNSPECIFIED); + } + this.nodeStyle = nodeStyle; + } + + /** + * Sets the default style for connections in this graph. Note: if an input + * is set on the viewer, a ZestException will be thrown. + * + * @param connectionStyle + * the style for the connections. + * @see #ZestStyles + */ + public void setConnectionStyle(int connectionStyle) { + if (getInput() != null) { + throw new SWTError(SWT.ERROR_UNSPECIFIED); + } + if (!ZestStyles.validateConnectionStyle(connectionStyle)) { + throw new SWTError(SWT.ERROR_INVALID_ARGUMENT); + } + this.connectionStyle = connectionStyle; + } + + /** + * Returns the style set for the graph + * + * @return The style set of the graph + */ + public int getGraphStyle() { + return graphStyle; + } + + /** + * Returns the style set for the nodes. + * + * @return the style set for the nodes. + */ + public int getNodeStyle() { + return nodeStyle; + } + + public Graph getGraphControl() { + return (Graph) getControl(); + } + + /** + * @return the connection style. + */ + public int getConnectionStyle() { + return connectionStyle; + } + + /** + * Sets the layout algorithm for this viewer. Subclasses may place + * restrictions on the algorithms that it accepts. + * + * @param algorithm + * the layout algorithm + * @param run + * true if the layout algorithm should be run immediately. This + * is a hint. + */ + public abstract void setLayoutAlgorithm(LayoutAlgorithm algorithm, + boolean run); + + /** + * Gets the current layout algorithm. + * + * @return the current layout algorithm. + */ + protected abstract LayoutAlgorithm getLayoutAlgorithm(); + + /** + * Equivalent to setLayoutAlgorithm(algorithm, false). + * + * @param algorithm + */ + public void setLayoutAlgorithm(LayoutAlgorithm algorithm) { + setLayoutAlgorithm(algorithm, false); + } + + public Object[] getNodeElements() { + return this.nodesMap.keySet().toArray(); + } + + public Object[] getConnectionElements() { + return this.connectionsMap.keySet().toArray(); + } + + /** + * @noreference This method is not intended to be referenced by clients. + * @return + */ + public HashMap getNodesMap() { + return this.nodesMap; + } + + /** + * + * @param element + * @return + * @noreference This method is not intended to be referenced by clients. + */ + public GraphNode addGraphModelContainer(Object element) { + GraphNode node = this.getGraphModelNode(element); + if (node == null) { + node = new GraphContainer((Graph) getControl(), SWT.NONE); + this.nodesMap.put(element, node); + node.setData(element); + } + return node; + } + + /** + * + * @param container + * @param element + * @return + * @noreference This method is not intended to be referenced by clients. + */ + public GraphNode addGraphModelNode(GraphContainer container, Object element) { + GraphNode node = this.getGraphModelNode(element); + if (node == null) { + node = new GraphNode(container, SWT.NONE); + this.nodesMap.put(element, node); + node.setData(element); + } + return node; + } + + /** + * + * @param element + * @param figure + * @return + * @noreference This method is not intended to be referenced by clients. + */ + public GraphNode addGraphModelNode(Object element, IFigure figure) { + GraphNode node = this.getGraphModelNode(element); + if (node == null) { + if (figure != null) { + node = new CGraphNode((Graph) getControl(), SWT.NONE, figure); + this.nodesMap.put(element, node); + node.setData(element); + } else { + node = new GraphNode((Graph) getControl(), SWT.NONE); + this.nodesMap.put(element, node); + node.setData(element); + } + } + return node; + } + + /** + * + * @param element + * @param source + * @param target + * @return + * @noreference This method is not intended to be referenced by clients. + */ + public GraphConnection addGraphModelConnection(Object element, + GraphNode source, GraphNode target) { + GraphConnection connection = this.getGraphModelConnection(element); + if (connection == null) { + connection = new GraphConnection((Graph) getControl(), SWT.NONE, + source, target); + this.connectionsMap.put(element, connection); + connection.setData(element); + } + return connection; + + } + + /** + * + * @param obj + * @return + * @noreference This method is not intended to be referenced by clients. + */ + public GraphConnection getGraphModelConnection(Object obj) { + return (GraphConnection) this.connectionsMap.get(obj); + } + + /** + * + * @param obj + * @return + * @noreference This method is not intended to be referenced by clients. + */ + public GraphNode getGraphModelNode(Object obj) { + return (GraphNode) this.nodesMap.get(obj); + } + + /** + * @param obj + * @noreference This method is not intended to be referenced by clients. + */ + public void removeGraphModelConnection(Object obj) { + GraphConnection connection = (GraphConnection) connectionsMap.get(obj); + if (connection != null) { + connectionsMap.remove(obj); + if (!connection.isDisposed()) { + connection.dispose(); + } + } + } + + /** + * @noreference This method is not intended to be referenced by clients. + */ + public void removeGraphModelNode(Object obj) { + GraphNode node = (GraphNode) nodesMap.get(obj); + if (node != null) { + nodesMap.remove(obj); + if (!node.isDisposed()) { + node.dispose(); + } + } + } + + protected void handleDispose(DisposeEvent event) { + + if (getControl() != null && !getControl().isDisposed()) { + getControl().dispose(); + } + super.handleDispose(event); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.StructuredViewer#internalRefresh(java.lang. + * Object) + */ + protected void internalRefresh(Object element) { + if (getInput() == null) { + return; + } + if (element == getInput()) { + getFactory().refreshGraph(getGraphControl()); + } else { + getFactory().refresh(getGraphControl(), element); + } + // After all the items are loaded, we call update to ensure drawing. + // This way the damaged area does not get too big if we start + // adding and removing more nodes + getGraphControl().getLightweightSystem().getUpdateManager() + .performUpdate(); + } + + protected void doUpdateItem(Widget item, Object element, boolean fullMap) { + if (item == getGraphControl()) { + getFactory().update(getNodesArray(getGraphControl())); + getFactory().update(getConnectionsArray(getGraphControl())); + } else if (item instanceof GraphItem) { + getFactory().update((GraphItem) item); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.StructuredViewer#doFindInputItem(java.lang. + * Object) + */ + protected Widget doFindInputItem(Object element) { + + if (element == getInput() && element instanceof Widget) { + return (Widget) element; + } + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.StructuredViewer#doFindItem(java.lang.Object) + */ + protected Widget doFindItem(Object element) { + Widget node = (Widget) nodesMap.get(element); + Widget connection = (Widget) connectionsMap.get(element); + return (node != null) ? node : connection; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.StructuredViewer#getSelectionFromWidget() + */ + protected List getSelectionFromWidget() { + List internalSelection = getWidgetSelection(); + LinkedList externalSelection = new LinkedList(); + for (Iterator i = internalSelection.iterator(); i.hasNext();) { + // @tag zest.todo : should there be a method on IGraphItem to get + // the external data? + GraphItem item = (GraphItem) i.next(); + if (item instanceof GraphNode) { + externalSelection.add(((GraphNode) item).getData()); + } else if (item instanceof GraphConnection) { + externalSelection.add(((GraphConnection) item) + .getExternalConnection()); + } else if (item instanceof Widget) { + externalSelection.add(((Widget) item).getData()); + } + } + return externalSelection; + } + + protected GraphItem[] /* GraphItem */findItems(List l) { + if (l == null) { + return new GraphItem[0]; + } + + ArrayList list = new ArrayList(); + Iterator iterator = l.iterator(); + + while (iterator.hasNext()) { + GraphItem w = (GraphItem) findItem(iterator.next()); + list.add(w); + } + return (GraphItem[]) list.toArray(new GraphItem[list.size()]); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.StructuredViewer#setSelectionToWidget(java. + * util.List, boolean) + */ + protected void setSelectionToWidget(List l, boolean reveal) { + Graph control = (Graph) getControl(); + List selection = new LinkedList(); + for (Iterator i = l.iterator(); i.hasNext();) { + Object obj = i.next(); + GraphNode node = (GraphNode) nodesMap.get(obj); + GraphConnection conn = (GraphConnection) connectionsMap.get(obj); + if (node != null) { + selection.add(node); + } + if (conn != null) { + selection.add(conn); + } + } + control.setSelection((GraphNode[]) selection + .toArray(new GraphNode[selection.size()])); + } + + /** + * Gets the internal model elements that are selected. + * + * @return + */ + protected List getWidgetSelection() { + Graph control = (Graph) getControl(); + return control.getSelection(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.Viewer#inputChanged(java.lang.Object, + * java.lang.Object) + */ + protected void inputChanged(Object input, Object oldInput) { + IStylingGraphModelFactory factory = getFactory(); + factory.setConnectionStyle(getConnectionStyle()); + factory.setNodeStyle(getNodeStyle()); + + // Save the old map so we can set the size and position of any nodes + // that are the same + Map oldNodesMap = nodesMap; + Graph graph = (Graph) getControl(); + graph.setSelection(new GraphNode[0]); + + Iterator iterator = nodesMap.values().iterator(); + while (iterator.hasNext()) { + GraphNode node = (GraphNode) iterator.next(); + if (!node.isDisposed()) { + node.dispose(); + } + } + + iterator = connectionsMap.values().iterator(); + while (iterator.hasNext()) { + GraphConnection connection = (GraphConnection) iterator.next(); + if (!connection.isDisposed()) { + connection.dispose(); + } + } + + nodesMap = new HashMap(); + connectionsMap = new HashMap(); + + graph = factory.createGraphModel(graph); + + ((Graph) getControl()).setNodeStyle(getNodeStyle()); + ((Graph) getControl()).setConnectionStyle(getConnectionStyle()); + + // check if any of the pre-existing nodes are still present + // in this case we want them to keep the same location & size + for (Iterator iter = oldNodesMap.keySet().iterator(); iter.hasNext();) { + Object data = iter.next(); + GraphNode newNode = (GraphNode) nodesMap.get(data); + if (newNode != null) { + GraphNode oldNode = (GraphNode) oldNodesMap.get(data); + newNode.setLocation(oldNode.getLocation().x, oldNode + .getLocation().y); + if (oldNode.isSizeFixed()) { + newNode.setSize(oldNode.getSize().width, + oldNode.getSize().height); + } + } + } + } + + /** + * Returns the factory used to create the model. This must not be called + * before the content provider is set. + * + * @return + * @noreference This method is not intended to be referenced by clients. + * @nooverride This method is not intended to be re-implemented or extended + * by clients. + */ + protected abstract IStylingGraphModelFactory getFactory(); + + protected void filterVisuals() { + if (getGraphControl() == null) { + return; + } + Object[] filtered = getFilteredChildren(getInput()); + SimpleGraphComparator comparator = new SimpleGraphComparator(); + TreeSet filteredElements = new TreeSet(comparator); + TreeSet unfilteredElements = new TreeSet(comparator); + List connections = getGraphControl().getConnections(); + List nodes = getGraphControl().getNodes(); + if (filtered.length == 0) { + // set everything to invisible. + // @tag zest.bug.156528-Filters.check : should we only filter out + // the nodes? + for (Iterator i = connections.iterator(); i.hasNext();) { + GraphConnection c = (GraphConnection) i.next(); + c.setVisible(false); + } + for (Iterator i = nodes.iterator(); i.hasNext();) { + GraphNode n = (GraphNode) i.next(); + n.setVisible(false); + } + return; + } + for (Iterator i = connections.iterator(); i.hasNext();) { + GraphConnection c = (GraphConnection) i.next(); + if (c.getExternalConnection() != null) { + unfilteredElements.add(c); + } + } + for (Iterator i = nodes.iterator(); i.hasNext();) { + GraphNode n = (GraphNode) i.next(); + if (n.getData() != null) { + unfilteredElements.add(n); + } + } + for (int i = 0; i < filtered.length; i++) { + Object modelElement = connectionsMap.get(filtered[i]); + if (modelElement == null) { + modelElement = nodesMap.get(filtered[i]); + } + if (modelElement != null) { + filteredElements.add(modelElement); + } + } + unfilteredElements.removeAll(filteredElements); + // set all the elements that did not pass the filters to invisible, and + // all the elements that passed to visible. + while (unfilteredElements.size() > 0) { + GraphItem i = (GraphItem) unfilteredElements.first(); + i.setVisible(false); + unfilteredElements.remove(i); + } + while (filteredElements.size() > 0) { + GraphItem i = (GraphItem) filteredElements.first(); + i.setVisible(true); + filteredElements.remove(i); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.viewers.StructuredViewer#getRawChildren(java.lang.Object + * ) + */ + protected Object[] getRawChildren(Object parent) { + if (parent == getInput()) { + // get the children from the model. + LinkedList children = new LinkedList(); + if (getGraphControl() != null) { + List connections = getGraphControl().getConnections(); + List nodes = getGraphControl().getNodes(); + for (Iterator i = connections.iterator(); i.hasNext();) { + GraphConnection c = (GraphConnection) i.next(); + if (c.getExternalConnection() != null) { + children.add(c.getExternalConnection()); + } + } + for (Iterator i = nodes.iterator(); i.hasNext();) { + GraphNode n = (GraphNode) i.next(); + if (n.getData() != null) { + children.add(n.getData()); + } + } + return children.toArray(); + } + } + return super.getRawChildren(parent); + } + + /** + * + */ + public void reveal(Object element) { + Widget[] items = this.findItems(element); + for (int i = 0; i < items.length; i++) { + Widget item = items[i]; + if (item instanceof GraphNode) { + GraphNode graphModelNode = (GraphNode) item; + graphModelNode.highlight(); + } else if (item instanceof GraphConnection) { + GraphConnection graphModelConnection = (GraphConnection) item; + graphModelConnection.highlight(); + } + } + } + + public void unReveal(Object element) { + Widget[] items = this.findItems(element); + for (int i = 0; i < items.length; i++) { + Widget item = items[i]; + if (item instanceof GraphNode) { + GraphNode graphModelNode = (GraphNode) item; + graphModelNode.unhighlight(); + } else if (item instanceof GraphConnection) { + GraphConnection graphModelConnection = (GraphConnection) item; + graphModelConnection.unhighlight(); + } + } + } + + /** + * Applies the viewers layouts. + * + */ + public abstract void applyLayout(); + + /** + * Removes the given connection object from the layout algorithm and the + * model. + * + * @param connection + */ + public void removeRelationship(Object connection) { + GraphConnection relationship = (GraphConnection) connectionsMap + .get(connection); + + if (relationship != null) { + // remove the relationship from the model + relationship.dispose(); + } + } + + /** + * Creates a new node and adds it to the graph. If it already exists nothing + * happens. + * + * @param newNode + */ + public void addNode(Object element) { + if (nodesMap.get(element) == null) { + // create the new node + getFactory().createNode(getGraphControl(), element); + + } + } + + /** + * Removes the given element from the layout algorithm and the model. + * + * @param element + * The node element to remove. + */ + public void removeNode(Object element) { + GraphNode node = (GraphNode) nodesMap.get(element); + + if (node != null) { + // remove the node and it's connections from the model + node.dispose(); + } + } + + /** + * Creates a new relationship between the source node and the destination + * node. If either node doesn't exist then it will be created. + * + * @param connection + * The connection data object. + * @param srcNode + * The source node data object. + * @param destNode + * The destination node data object. + */ + public void addRelationship(Object connection, Object srcNode, + Object destNode) { + // create the new relationship + IStylingGraphModelFactory modelFactory = getFactory(); + modelFactory.createConnection(getGraphControl(), connection, srcNode, + destNode); + + } + + /** + * Adds a new relationship given the connection. It will use the content + * provider to determine the source and destination nodes. + * + * @param connection + * The connection data object. + */ + public void addRelationship(Object connection) { + IStylingGraphModelFactory modelFactory = getFactory(); + if (connectionsMap.get(connection) == null) { + if (modelFactory.getContentProvider() instanceof IGraphContentProvider) { + IGraphContentProvider content = ((IGraphContentProvider) modelFactory + .getContentProvider()); + Object source = content.getSource(connection); + Object dest = content.getDestination(connection); + // create the new relationship + modelFactory.createConnection(getGraphControl(), connection, + source, dest); + } else { + throw new UnsupportedOperationException(); + } + } + } + + /** + * Converts the list of GraphModelConnection objects into an array and + * returns it. + * + * @return GraphModelConnection[] + */ + protected GraphConnection[] getConnectionsArray(Graph graph) { + GraphConnection[] connsArray = new GraphConnection[graph + .getConnections().size()]; + connsArray = (GraphConnection[]) graph.getConnections().toArray( + connsArray); + return connsArray; + } + + /** + * Converts the list of GraphModelNode objects into an array an returns it. + * + * @return GraphModelNode[] + */ + protected GraphNode[] getNodesArray(Graph graph) { + GraphNode[] nodesArray = new GraphNode[graph.getNodes().size()]; + nodesArray = (GraphNode[]) graph.getNodes().toArray(nodesArray); + return nodesArray; + } + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/AbstractZoomableViewer.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/AbstractZoomableViewer.java new file mode 100644 index 0000000..a9b4e02 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/AbstractZoomableViewer.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +import org.eclipse.draw2d.geometry.Rectangle; +import org.eclipse.jface.viewers.StructuredViewer; + +/** + * A simple interface that provides zooming capabilites. Not intended to be + * subclassed by clients. + * + * @author Del Myers + * + * @noextend This class is not intended to be subclassed by clients. + * + */ +// @tag bug.156286-Zooming.fix +public abstract class AbstractZoomableViewer extends StructuredViewer { + /** + * Returns a ZoomManager that zooming can be done on. May return null if + * none is available. + * + * @return a ZoomManager that zooming can be done on. + * @since 2.0 + */ + protected abstract ZoomManager getZoomManager(); + + public void zoomTo(int x, int y, int width, int height) { + Rectangle r = new Rectangle(x, y, width, height); + if (r.isEmpty()) { + getZoomManager().setZoomAsText("100%"); + } else { + getZoomManager().zoomTo(r); + } + } +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/EntityConnectionData.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/EntityConnectionData.java new file mode 100644 index 0000000..ae1dc65 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/EntityConnectionData.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +/** + * A simple object that is used as the "external connection" in content + * providers that don't ask the user to create their own external connection. + * + * This is used whenever users don't specify a connection + * + * @author Del Myers + */ +public final class EntityConnectionData { + public final Object source; + public final Object dest; + + /** + * Creates a new entity connection data. The source and dest are users + * nodes. + */ + public EntityConnectionData(Object source, Object dest) { + /* + * if (source == null) { throw new + * RuntimeException("Creating relationship with null source object"); } + * if (dest == null) { throw new + * RuntimeException("Creating relationship with null dest object"); } + */ + this.source = source; + this.dest = dest; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (!(obj instanceof EntityConnectionData)) { + return false; + } + EntityConnectionData that = (EntityConnectionData) obj; + return (this.source.equals(that.source) && this.dest.equals(that.dest)); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return this.source.hashCode() + this.dest.hashCode(); + } +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/GraphViewer.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/GraphViewer.java new file mode 100644 index 0000000..ed8f6cd --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/GraphViewer.java @@ -0,0 +1,380 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IContentProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Widget; +import org.eclipse.zest.core.viewers.internal.GraphModelEntityFactory; +import org.eclipse.zest.core.viewers.internal.GraphModelEntityRelationshipFactory; +import org.eclipse.zest.core.viewers.internal.GraphModelFactory; +import org.eclipse.zest.core.viewers.internal.IStylingGraphModelFactory; +import org.eclipse.zest.core.widgets.Graph; +import org.eclipse.zest.core.widgets.GraphItem; +import org.eclipse.zest.core.widgets.ZestStyles; +import org.eclipse.zest.layouts.LayoutAlgorithm; + +/** + * This view is used to represent a static graph. Static graphs can be layed + * out, but do not continually update their layout locations. + * + * @author Ian Bull + * + * @author Chris Callendar + * + * @noextend This class is not intended to be subclassed by clients. + */ +public class GraphViewer extends AbstractStructuredGraphViewer implements + ISelectionProvider { + + protected Graph graph = null; + private IStylingGraphModelFactory modelFactory = null; + private List selectionChangedListeners = null; + ZoomManager zoomManager = null; + + /** + * Initializes the viewer. + * + * @param composite + * @param style + * the style for the viewer and for the layout algorithm + * @see ZestStyles#LAYOUT_GRID + * @see ZestStyles#LAYOUT_TREE + * @see ZestStyles#LAYOUT_RADIAL + * @see ZestStyles#LAYOUT_SPRING + * @see ZestStyles#NO_OVERLAPPING_NODES + * @see ZestStyles#NODES_HIGHLIGHT_ADJACENT + * @see SWT#V_SCROLL + * @see SWT#H_SCROLL + */ + public GraphViewer(Composite composite, int style) { + super(style); + this.graph = new Graph(composite, style); + hookControl(this.graph); + } + + public void setControl(Graph graphModel) { + this.graph = graphModel; + hookControl(this.graph); + } + + protected void hookControl(Control control) { + super.hookControl(control); + + selectionChangedListeners = new ArrayList(); + getGraphControl().addSelectionListener(new SelectionAdapter() { + + public void widgetSelected(SelectionEvent e) { + Iterator iterator = selectionChangedListeners.iterator(); + + ISelection structuredSelection = getSelection(); + SelectionChangedEvent event = new SelectionChangedEvent( + GraphViewer.this, structuredSelection); + + while (iterator.hasNext()) { + ISelectionChangedListener listener = (ISelectionChangedListener) iterator + .next(); + listener.selectionChanged(event); + } + + } + + }); + + control.addMouseListener(new MouseListener() { + + public void mouseDoubleClick(MouseEvent e) { + DoubleClickEvent doubleClickEvent = new DoubleClickEvent( + GraphViewer.this, getSelection()); + fireDoubleClick(doubleClickEvent); + } + + public void mouseDown(MouseEvent e) { + + } + + public void mouseUp(MouseEvent e) { + + } + + }); + } + + protected void inputChanged(Object input, Object oldInput) { + graph.setDynamicLayout(false); + super.inputChanged(input, oldInput); + graph.setDynamicLayout(true); + graph.applyLayout(); + } + + /** + * Gets the styles for this structuredViewer + * + * @return + */ + public int getStyle() { + return this.graph.getStyle(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer# + * getGraphControl() + */ + public Graph getGraphControl() { + return super.getGraphControl(); + }; + + /** + * Sets the layout algorithm to use for this viewer. + * + * @param algorithm + * the algorithm to layout the nodes + * @param runLayout + * if the layout should be run + */ + public void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean runLayout) { + graph.setLayoutAlgorithm(algorithm, runLayout); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer# + * setLayoutAlgorithm(org.eclipse.zest.layouts.LayoutAlgorithm) + */ + public void setLayoutAlgorithm(LayoutAlgorithm algorithm) { + super.setLayoutAlgorithm(algorithm); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer#setNodeStyle + * (int) + */ + public void setNodeStyle(int nodeStyle) { + super.setNodeStyle(nodeStyle); + this.graph.setNodeStyle(nodeStyle); + } + + public void setContentProvider(IContentProvider contentProvider) { + if (contentProvider instanceof IGraphContentProvider) { + super.setContentProvider(contentProvider); + } else if (contentProvider instanceof IGraphEntityContentProvider) { + super.setContentProvider(contentProvider); + } else if (contentProvider instanceof IGraphEntityRelationshipContentProvider) { + super.setContentProvider(contentProvider); + } else { + throw new IllegalArgumentException( + "Invalid content provider, only IGraphContentProvider, IGraphEntityContentProvider, or IGraphEntityRelationshipContentProvider are supported."); + } + } + + /** + * Finds the graph widget item for a given user model item. + * + * Note: This method returns an internal interface (GraphItem). You should + * be able to cast this to either a IGraphModelNode or IGraphModelConnection + * (which are also internal). These are internal because this API is not + * stable. If use this method (to access internal nodes and edges), your + * code may not compile between versions. + * + * @param The + * user model node. + * @return An IGraphItem. This should be either a IGraphModelNode or + * IGraphModelConnection + */ + public GraphItem findGraphItem(Object element) { + Widget[] result = findItems(element); + return (result.length == 0 || !(result[0] instanceof GraphItem)) ? null + : (GraphItem) result[0]; + } + + /** + * Applys the current layout to the viewer + */ + public void applyLayout() { + graph.applyLayout(); + } + + protected void setSelectionToWidget(List l, boolean reveal) { + GraphItem[] listOfItems = findItems(l); + graph.setSelection(listOfItems); + } + + public Control getControl() { + return graph; + } + + public Object[] getNodeElements() { + return super.getNodeElements(); + } + + public Object[] getConnectionElements() { + return super.getConnectionElements(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#reveal + * (java.lang.Object) + */ + public void reveal(Object element) { + super.reveal(element); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer# + * setConnectionStyle(int) + */ + public void setConnectionStyle(int connectionStyle) { + super.setConnectionStyle(connectionStyle); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#unReveal + * (java.lang.Object) + */ + public void unReveal(Object element) { + super.unReveal(element); + } + + public void addSelectionChangedListener(ISelectionChangedListener listener) { + if (!selectionChangedListeners.contains(listener)) { + selectionChangedListeners.add(listener); + } + } + + public void removeSelectionChangedListener( + ISelectionChangedListener listener) { + if (selectionChangedListeners.contains(listener)) { + selectionChangedListeners.remove(listener); + } + } + + /** + * {@inheritDoc} + * + * NOTE: If a layout algorithm is set in the receiver, layout is performed + * after the refresh. + */ + public void refresh(Object element) { + boolean dynamicLayoutEnabled = graph.isDynamicLayoutEnabled(); + graph.setDynamicLayout(false); + super.refresh(element); + graph.setDynamicLayout(dynamicLayoutEnabled); + } + + /** + * {@inheritDoc} + * + * NOTE: If a layout algorithm is set in the receiver, layout is performed + * after the refresh. + */ + public void refresh(Object element, boolean updateLabels) { + boolean dynamicLayoutEnabled = graph.isDynamicLayoutEnabled(); + graph.setDynamicLayout(false); + super.refresh(element, updateLabels); + graph.setDynamicLayout(dynamicLayoutEnabled); + } + + /** + * {@inheritDoc} + * + * NOTE: If a layout algorithm is set in the receiver, layout is performed + * after the update. + */ + public void update(Object element, String[] properties) { + boolean dynamicLayoutEnabled = graph.isDynamicLayoutEnabled(); + graph.setDynamicLayout(false); + super.update(element, properties); + graph.setDynamicLayout(dynamicLayoutEnabled); + } + + /** + * {@inheritDoc} + * + * NOTE: If a layout algorithm is set in the receiver, layout is performed + * after the update. + */ + public void update(Object[] elements, String[] properties) { + boolean dynamicLayoutEnabled = graph.isDynamicLayoutEnabled(); + graph.setDynamicLayout(false); + super.update(elements, properties); + graph.setDynamicLayout(dynamicLayoutEnabled); + } + + // @tag zest.bug.156286-Zooming.fix.experimental : expose the zoom manager + // for new actions. + protected ZoomManager getZoomManager() { + if (zoomManager == null) { + zoomManager = new ZoomManager(getGraphControl().getRootLayer(), + getGraphControl().getViewport()); + } + return zoomManager; + } + + /** + * (non-Javadoc) + * + * @see org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer#getFactory() + * @noreference This method is not intended to be referenced by clients. + * @nooverride This method is not intended to be re-implemented or extended + * by clients. + */ + protected IStylingGraphModelFactory getFactory() { + if (modelFactory == null) { + if (getContentProvider() instanceof IGraphContentProvider) { + modelFactory = new GraphModelFactory(this); + } else if (getContentProvider() instanceof IGraphEntityContentProvider) { + modelFactory = new GraphModelEntityFactory(this); + } else if (getContentProvider() instanceof IGraphEntityRelationshipContentProvider) { + modelFactory = new GraphModelEntityRelationshipFactory(this); + } + } + return modelFactory; + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.zest.core.viewers.AbstractStructuredGraphViewer# + * getLayoutAlgorithm() + */ + protected LayoutAlgorithm getLayoutAlgorithm() { + return graph.getLayoutAlgorithm(); + } + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IConnectionStyleBezierExtension.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IConnectionStyleBezierExtension.java new file mode 100644 index 0000000..41ed0ca --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IConnectionStyleBezierExtension.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +/** + * An extension to the IConnectinStyleProvider that allows styling specific to + * bezier curves. + * + * Bezier curves are defined by a set of four points: two point in the layout + * (start and end), and two related control points (also start and end). The + * control points are defined relative to their corresponding layout point. This + * definition includes an angle between the layout point and the line between + * the two layout points, as well as a ratio distance from the corresponding + * layout point. The ratio distance is defined as a fraction between 0 and 1 of + * the distance between the two layout points. Using this definition allows + * bezier curves to have a consistant look regardless of the actual positions of + * the nodes in the layouts. + * + * @author Del Myers + * + */ +// @tag bug(152530-Bezier(fix)) : users can style bezier curves. +public interface IConnectionStyleBezierExtension { + + /** + * Gets the angle between the start point, and the line between the start + * and end, which will define the position of the start control point. If + * the start angle, and the end angle are the same sign, the two control + * points are guaranteed to be on the same side of the line. + * + * @param rel + * the relationship to base on. + * @return the start angle or <code>Double.NaN</code> for defaults. + */ + double getStartAngle(Object rel); + + /** + * Gets the angle between the end point, and the line between the start and + * end, which will define the position of the end control point. If the + * start angle, and the end angle are the same sign, the two control points + * are guaranteed to be on the same side of the line. + * + * @param rel + * the relationship to base on. + * @return the end angle or <code>Double.NaN</code> for defaults. + */ + double getEndAngle(Object rel); + + /** + * Gets the distance between the start point and the start control point, as + * a fraction of the distance between the start point and end point. + * + * @param rel + * the relationship to base on. + * @return the start distance or <code>Double.NaN</code> for defaults. + */ + double getStartDistance(Object rel); + + /** + * Gets the distance between the end point and the end control point, as a + * fraction of the distance between the start point and end point. + * + * @param rel + * the relationship to base on. + * @return the end distance or <code>Double.NaN</code> for defaults. + */ + double getEndDistance(Object rel); +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IConnectionStyleProvider.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IConnectionStyleProvider.java new file mode 100644 index 0000000..92d5c72 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IConnectionStyleProvider.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +import org.eclipse.draw2d.IFigure; +import org.eclipse.swt.graphics.Color; +import org.eclipse.ui.services.IDisposable; + +/** + * An extension to label providers, to supply styles for connections based upon + * relationships, rather than on connected nodes. + * + * @author Del Myers + * @see #IGraphContentProvider + * @see #IEntityStyleProvider + * + */ +// @tag bug(151327-Styles) : created to solve this bug +public interface IConnectionStyleProvider extends IDisposable { + /** + * Returns the style flags for this connection. Valid flags are those that + * begin with CONNECTION in @see org.eclipse.zest.core.ZestStyles. Check + * ZestStyles for legal combinations. + * + * @param rel + * the relationship represented by this connection. + * @return the style flags for this connection. + * @see org.eclipse.zest.core.widgets.ZestStyles + */ + public int getConnectionStyle(Object rel); + + /** + * Returns the color for the connection. Null for default. Any resources + * created by this class must be disposed by this class. + * + * @param rel + * the relationship represented by this connection. + * @return the color. + * @see #dispose() + */ + public Color getColor(Object rel); + + /** + * Returns the highlighted color for this connection. Null for default. Any + * resources created by this class must be disposed by this class. + * + * @param rel + * the relationship represented by this connection. + * @return the highlighted color. Null for default. + * @see #dispose() + */ + public Color getHighlightColor(Object rel); + + /** + * Returns the line width of the connection. -1 for default. + * + * @param rel + * the relationship represented by this connection. + * @return the line width for the connection. -1 for default. + */ + public int getLineWidth(Object rel); + + /** + * Returns the tooltop for this node. If null is returned Zest will simply + * use the default tooltip. + * + * @param entity + * @return + */ + public IFigure getTooltip(Object entity); +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IEntityConnectionStyleBezierExtension.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IEntityConnectionStyleBezierExtension.java new file mode 100644 index 0000000..16aa721 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IEntityConnectionStyleBezierExtension.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +/** + * An extension to the IEntityConnectinStyleProvider that allows styling + * specific to bezier curves. + * + * Bezier curves are defined by a set of four points: two point in the layout + * (start and end), and two related control points (also start and end). The + * control points are defined relative to their corresponding layout point. This + * definition includes an angle between the layout point and the line between + * the two layout points, as well as a ratio distance from the corresponding + * layout point. The ratio distance is defined as a fraction between 0 and 1 of + * the distance between the two layout points. Using this definition allows + * bezier curves to have a consistant look regardless of the actual positions of + * the nodes in the layouts. + * + * @author Del Myers + * + */ +// @tag zest(bug(152530-Bezier(fix))) : users can style bezier curves. +interface IEntityConnectionStyleBezierExtension { + + /** + * Gets the angle between the start point, and the line between the start + * and end, which will define the position of the start control point. If + * the start angle, and the end angle are the same sign, the two control + * points are guaranteed to be on the same side of the line. + * + * @param source + * the source node to base on. + * @param dest + * the destination node to base on. + * @return the start angle or <code>Double.NaN</code> for defaults. + */ + double getStartAngle(Object source, Object dest); + + /** + * Gets the angle between the end point, and the line between the start and + * end, which will define the position of the end control point. If the + * start angle, and the end angle are the same sign, the two control points + * are guaranteed to be on the same side of the line. + * + * @param source + * the source node to base on. + * @param dest + * the destination node to base on. + * @return the end angle or <code>Double.NaN</code> for defaults. + */ + double getEndAngle(Object source, Object dest); + + /** + * Gets the distance between the start point and the start control point, as + * a fraction of the distance between the start point and end point. + * + * @param source + * the source node to base on. + * @param dest + * the destination node to base on. + * @return the start distance or <code>Double.NaN</code> for defaults. + */ + double getStartDistance(Object source, Object dest); + + /** + * Gets the distance between the end point and the end control point, as a + * fraction of the distance between the start point and end point. + * + * @param source + * the source node to base on. + * @param dest + * the destination node to base on. + * @return the end distance or <code>Double.NaN</code> for defaults. + */ + double getEndDistance(Object source, Object dest); +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IEntityConnectionStyleProvider.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IEntityConnectionStyleProvider.java new file mode 100644 index 0000000..a418930 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IEntityConnectionStyleProvider.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +import org.eclipse.draw2d.IFigure; +import org.eclipse.swt.graphics.Color; +import org.eclipse.ui.services.IDisposable; + +/** + * An extension for label providers which allows users to set styles for + * connections that are based on entity end points. + * + * @author Del Myers + * + */ +// @tag bug(151327-Styles) : fix +public interface IEntityConnectionStyleProvider extends IDisposable { + + /** + * Returns the style flags for this connection. Valid flags are those that + * begin with CONNECTION in @see org.eclipse.zest.core.ZestStyles. Check + * ZestStyles for legal combinations. + * + * @param src + * the source entity. + * @param dest + * the destination entity. + * @return the style flags for this connection. + * @see org.eclipse.zest.core.widgets.ZestStyles + */ + public int getConnectionStyle(Object src, Object dest); + + /** + * Returns the color for the connection. Null for default. + * + * @param src + * the source entity. Any resources created by this class must be + * disposed by this class. + * @param dest + * the destination entity. + * @return the color. + * @see #dispose() + */ + public Color getColor(Object src, Object dest); + + /** + * Returns the highlighted color for this connection. Null for default. + * + * @param src + * the source entity. Any resources created by this class must be + * disposed by this class. + * @param dest + * the destination entity. + * @return the highlighted color. Null for default. + * @see #dispose() + */ + public Color getHighlightColor(Object src, Object dest); + + /** + * Returns the line width of the connection. -1 for default. + * + * @param src + * the source entity. + * @param dest + * the destination entity. + * @return the line width for the connection. -1 for default. + */ + public int getLineWidth(Object src, Object dest); + + /** + * Returns the tooltop for this node. If null is returned Zest will simply + * use the default tooltip. + * + * @param entity + * @return + */ + public IFigure getTooltip(Object entity); +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IEntityStyleProvider.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IEntityStyleProvider.java new file mode 100644 index 0000000..a222b7a --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IEntityStyleProvider.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +import org.eclipse.draw2d.IFigure; +import org.eclipse.swt.graphics.Color; +import org.eclipse.ui.services.IDisposable; + +/** + * An extension to Label providers for graphs. Gets specific details about the + * style of an entity before it is created. This style provider offers: + * + * -Background and forground colours -Hilighted and unhighlighted colours + * (colours defined by selections). -Border color. -Highlighted and + * unhighlighted colours for borders. -Border width -Font for text inside the + * entity. + * + * Any method may return null if the Zest defaults are preferred. + * + * NOTE: It is up to the implementors of this interface to dispose of any Colors + * or Fonts that are created by this class. The dispose() method will be called + * at the end of the entity's life-cycle so that this class may dispose of its + * resources. + * + * @author Del Myers + * @see org.eclipse.jface.viewers.IColorProvider + * @tag bug(151327-Styles) : created to solve this bug + */ +public interface IEntityStyleProvider extends IDisposable { + + /** + * Returns the forground colour of this entity. May return null for + * defaults. Any resources created by this class must be disposed by this + * class. + * + * @param entity + * the entity to be styled. + * @return the forground colour of this entity. + * @see #dispose() + */ + public Color getNodeHighlightColor(Object entity); + + /** + * Returns the background colour for this entity. May return null for + * defaults. Any resources created by this class must be disposed by this + * class. + * + * @param entity + * the entity to be styled. + * @return the background colour for this entity. + * @see #dispose() + */ + public Color getBorderColor(Object entity); + + /** + * Returns the border highlight colour for this entity. May return null for + * defaults. Any resources created by this class must be disposed by this + * class. + * + * @param entity + * the entity to be styled. + * @return the border highlight colour for this entity. + * @see #dispose() + */ + public Color getBorderHighlightColor(Object entity); + + /** + * Returns the border width for this entity. May return -1 for defaults. + * + * @param entity + * the entity to be styled. + * @return the border width, or -1 for defaults. + */ + public int getBorderWidth(Object entity); + + /** + * Returns true iff the adjacent entities should be highlighted when this + * node is selected. Zest's default action is true. + * + * @return true iff the adjacent entities should be highlighted when this + * node is selected. + */ + // @tag ADJACENT : Removed highlight adjacent + // public boolean highlightAdjacentEntities(Object entity); + /** + * Returns the color that adjacent entities will be drawn when this entity + * is selected. Will be ignored if HighlightAdjacentEntities() returns + * false. May return null for defaults. Any resources created by this class + * must be disposed by this class. + * + * @param entity + * the entity to be styled. + * @return the color for adjacent entities. + * @see #highlightAdjacentEntities(Object entity) + * @see #dispose() + */ + // @tag ADJACENT : Removed highlight adjacent + // public Color getAdjacentEntityHighlightColor(Object entity); + /** + * Returns the colour that this node should be coloured. This will be + * ignored if getNodeColour returns null. Any resources created by this + * class must be diposed by this class. + * + * @param entity + * The entity to be styled + * @return The colour for the node + * @see #dispose() + */ + public Color getBackgroundColour(Object entity); + + public Color getForegroundColour(Object entity); + + /** + * Returns the tooltop for this node. If null is returned Zest will simply + * use the default tooltip. + * + * @param entity + * @return + */ + public IFigure getTooltip(Object entity); + + public boolean fisheyeNode(Object entity); + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IFigureProvider.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IFigureProvider.java new file mode 100644 index 0000000..49af9c9 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IFigureProvider.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2009-2010 EclipseSource 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: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package org.eclipse.zest.core.viewers; + +import org.eclipse.draw2d.IFigure; + +/** + * Allows a user to create a figure for an element in graph model. To use this + * interface, it should be implemented and passed to + * {@link GraphViewer#setLabelProvider()} + */ +public interface IFigureProvider { + + /** + * Creates a custom figure for a graph model element + */ + public IFigure getFigure(Object element); +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IGraphContentProvider.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IGraphContentProvider.java new file mode 100644 index 0000000..7fda779 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IGraphContentProvider.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +import org.eclipse.jface.viewers.IStructuredContentProvider; + +/** + * A graph content provider. + * + * @author Ian Bull + */ +public interface IGraphContentProvider extends IStructuredContentProvider { + + /** + * Gets the source Object for the given relationship. Note, at least one of + * the source or destination must not be null. If both are null, then + * nothing can be displayed in the graph (a relationship cannot exist + * without nodes to be connected to). However, if one of getSource() or + * getDestination() returns null, then the resulting graph will contain an + * unconnected node for the non-null object returned from the other method. + * + * @param rel + * the relationship. + * @return the source, or null for an unconnected destination. + */ + public Object getSource(Object rel); + + /** + * Gets the target Object for the given relationship. Note, at least one of + * the source or destination must not be null. If both are null, then + * nothing can be displayed in the graph (a relationship cannot exist + * without nodes to be connected to). However, if one of getSource() or + * getDestination() returns null, then the resulting graph will contain an + * unconnected node for the non-null object returned from the other method. + * + * @param rel + * the relationship. + * @return the destination, or null for an unconnected source. + */ + public Object getDestination(Object rel); + + /** + * Returns all the relationships in the graph for the given input. + * + * @input the input model object. + * @return all the relationships in the graph for the given input. + */ + public Object[] getElements(Object input); + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IGraphEntityContentProvider.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IGraphEntityContentProvider.java new file mode 100644 index 0000000..5d5e57b --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IGraphEntityContentProvider.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +import org.eclipse.jface.viewers.IStructuredContentProvider; + +/** + * + * @author Ian Bull + * + */ +public interface IGraphEntityContentProvider extends IStructuredContentProvider { + + public Object[] getElements(Object inputElement); + + /** + * Gets the elements this object is connected to + * + * @param entity + * @return + */ + public Object[] getConnectedTo(Object entity); + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IGraphEntityRelationshipContentProvider.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IGraphEntityRelationshipContentProvider.java new file mode 100644 index 0000000..5ed24a3 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IGraphEntityRelationshipContentProvider.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +import org.eclipse.jface.viewers.IStructuredContentProvider; + +/** + * A content provider that is node-relationship centric. Call-backs return model + * nodes to the user, and ask for relationships. Both nodes and relationships + * are represented by the user's model. + * + * @author Del Myers + * + */ +// @tag bug.154580-Content.fix : new content provider that returns relationships +// for the given source and destination. +public interface IGraphEntityRelationshipContentProvider extends + IStructuredContentProvider { + /** + * Gets the relationships between the given source and destination nodes. + * + * @param source + * the source node. + * @param dest + * the destination node. + * @return objects represtenting the different relationships between the + * nodes. + */ + public Object[] getRelationships(Object source, Object dest); + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/INestedContentProvider.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/INestedContentProvider.java new file mode 100644 index 0000000..a6a82cc --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/INestedContentProvider.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2009-2010 EclipseSource 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: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package org.eclipse.zest.core.viewers; + +/** + * A content provider for nested graphs. Any entity based content provider + * (IGraphEntityContentProvider or IGraphEntityRelationshipContentProvider) can + * also implement this interface. Any node that "hasChildren" will be rendered + * as a container. + * + * Note: Containers cannot contain other containers. + * + * @author irbull + */ +public interface INestedContentProvider { + + /** + * Does the current node have children? If so, it will be rendered as a + * container. + * + * @param element + * The current node + * @return True if it has children, false otherwise + */ + public boolean hasChildren(Object element); + + /** + * Gets the children of this node. This method will not be called if + * hasChildren returns false. + * + * @param element + * The current node + * @return The list of children for this node. + */ + public Object[] getChildren(Object element); +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ISelfStyleProvider.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ISelfStyleProvider.java new file mode 100644 index 0000000..4039023 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ISelfStyleProvider.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2009-2010 EclipseSource 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: EclipseSource - initial API and implementation + ******************************************************************************/ +package org.eclipse.zest.core.viewers; + +import org.eclipse.zest.core.widgets.GraphConnection; +import org.eclipse.zest.core.widgets.GraphNode; + +/** + * Provides a mechanism to style nodes and edges when they are created. + * + * After each node or edge is created, the self styling method will be called + * with both the element and the widget. + */ +public interface ISelfStyleProvider { + + /** + * Styles a connection + */ + public void selfStyleConnection(Object element, GraphConnection connection); + + /** + * Styles a node + */ + public void selfStyleNode(Object element, GraphNode node); + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IZoomableWorkbenchPart.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IZoomableWorkbenchPart.java new file mode 100644 index 0000000..f977988 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IZoomableWorkbenchPart.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +/** + * An interface that can be added to IWorkbenchParts based on ZEST views so that + * zooming is supported. + * + * @author Del Myers + * + */ +// @tag bug.156286-Zooming.fix : experimental +public interface IZoomableWorkbenchPart { + /** + * Returns the viewer that is zoomable. + * + * @return the viewer that is zoomable. + */ + AbstractZoomableViewer getZoomableViewer(); +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ZoomContributionViewItem.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ZoomContributionViewItem.java new file mode 100644 index 0000000..31223a2 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ZoomContributionViewItem.java @@ -0,0 +1,247 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers; + +import org.eclipse.jface.action.ContributionItem; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MenuAdapter; +import org.eclipse.swt.events.MenuEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.CoolBar; +import org.eclipse.swt.widgets.CoolItem; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +/** + * A contribution item that adds a combo to a toolbar or coolbar, or a list of + * zooms to a menu. Can only be used for one toolbar, coolbar, or menu. + * + * In order to use this item, let your workbench part implement + * IZoomableWorkbenchPart. If the workbench part then supplies a viewer that is + * zoomable, the combo or menu created by this item will be enabled. + * + * @author Del Myers + * + */ +// @tag zest.bug.156286-Zooming.fix : create a contribution item that can set +// zooming on Zest views. +public class ZoomContributionViewItem extends ContributionItem implements + ZoomListener { + /** + * Zooms to fit the width. + */ + public static final String FIT_WIDTH = ZoomManager.FIT_WIDTH; + /** + * Zooms to fit the height. + */ + public static final String FIT_HEIGHT = ZoomManager.FIT_HEIGHT; + /** + * Zooms to fit entirely within the viewport. + */ + public static final String FIT_ALL = ZoomManager.FIT_ALL; + + private String[] zoomLevels; + private ZoomManager zoomManager; + private Combo combo; + private Menu fMenu; + private MenuAdapter menuAdapter = new MenuAdapter() { + public void menuShown(MenuEvent e) { + refresh(true); + } + }; + + /** + * Creates a new contribution item that will work on the given part + * service.initialZooms will be used to populate the combo or the menu. + * Valid values for initialZooms are percentage numbers (e.g., "100%"), or + * FIT_WIDTH, FIT_HEIGHT, FIT_ALL. + * + * @param partService + * service used to see whether the view is zoomable. + */ + public ZoomContributionViewItem(IZoomableWorkbenchPart part) { + zoomManager = part.getZoomableViewer().getZoomManager(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets + * .Menu, int) + */ + public void fill(Menu menu, int index) { + if (this.fMenu == null || this.fMenu != menu) { + if (this.fMenu != null) { + this.fMenu.removeMenuListener(menuAdapter); + this.fMenu = null; + } + this.fMenu = menu; + menu.addMenuListener(menuAdapter); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets + * .CoolBar, int) + */ + public void fill(CoolBar parent, int index) { + CoolItem item = new CoolItem(parent, SWT.DROP_DOWN); + Combo combo = createCombo(parent); + item.setControl(combo); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets + * .ToolBar, int) + */ + public void fill(ToolBar parent, int index) { + ToolItem item = new ToolItem(parent, SWT.DROP_DOWN); + Combo combo = createCombo(parent); + item.setControl(combo); + } + + private Combo createCombo(Composite parent) { + this.combo = new Combo(parent, SWT.DROP_DOWN); + this.combo.setItems(zoomLevels); + this.combo.addSelectionListener(new SelectionAdapter() { + /* + * (non-Javadoc) + * + * @see + * org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse + * .swt.events.SelectionEvent) + */ + public void widgetSelected(SelectionEvent e) { + int selection = combo.getSelectionIndex(); + if (selection > 0) { + doZoom(combo.getItem(selection)); + } else { + doZoom(combo.getItem(0)); + } + } + }); + return this.combo; + } + + private void doZoom(String zoom) { + if (zoomManager != null) { + zoomManager.setZoomAsText(zoom); + } + } + + private void refresh(boolean rebuild) { + // + if (combo != null && !combo.isDisposed()) { + refreshCombo(rebuild); + } else if (fMenu != null && !fMenu.isDisposed()) { + refreshMenu(rebuild); + } + } + + /** + * @param rebuild + */ + private void refreshMenu(boolean rebuild) { + fMenu.setEnabled(false); + if (zoomManager == null) { + return; + } + if (rebuild) { + zoomLevels = zoomManager.getZoomLevelsAsText(); + MenuItem[] oldItems = fMenu.getItems(); + for (int i = 0; i < oldItems.length; i++) { + if (oldItems[i].getData() == this) { + oldItems[i].dispose(); + } + } + for (int i = 0; i < zoomLevels.length; i++) { + MenuItem item = new MenuItem(fMenu, SWT.RADIO); + item.setText(zoomLevels[i]); + item.setData(this); + item.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + MenuItem source = (MenuItem) e.getSource(); + doZoom(source.getText()); + } + }); + } + } + String zoom = zoomManager.getZoomAsText(); + MenuItem[] items = fMenu.getItems(); + for (int i = 0; i < items.length; i++) { + MenuItem item = items[i]; + if (item.getData() == this) { + item.setSelection(false); + if (zoom.equalsIgnoreCase(item.getText())) { + item.setSelection(true); + } + } + } + fMenu.setEnabled(true); + } + + /** + * @param rebuild + */ + private void refreshCombo(boolean rebuild) { + combo.setEnabled(false); + if (zoomManager == null) { + return; + } + if (rebuild) { + combo.setItems(zoomManager.getZoomLevelsAsText()); + } + String zoom = zoomManager.getZoomAsText(); + int index = combo.indexOf(zoom); + if (index > 0) { + combo.select(index); + } + combo.setEnabled(true); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.gef.editparts.ZoomListener#zoomChanged(double) + */ + public void zoomChanged(double z) { + refresh(false); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.action.ContributionItem#dispose() + */ + + public void dispose() { + if (combo != null) { + combo = null; + } + if (fMenu != null) { + fMenu = null; + } + // @tag zest.bug.159667-ZoomDispose : make sure that we no longer listen + // to the part service. + super.dispose(); + } +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ZoomListener.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ZoomListener.java new file mode 100644 index 0000000..ea86ef5 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ZoomListener.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 IBM Corporation 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: IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.zest.core.viewers; + +/** + * Listens to zoom level changes. + * + * @author Eric Bordeau + * @since 2.0 + */ +public interface ZoomListener { + + /** + * Called whenever the ZoomManager's zoom level changes. + * + * @param zoom + * the new zoom level. + */ + void zoomChanged(double zoom); + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ZoomManager.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ZoomManager.java new file mode 100644 index 0000000..cf97e90 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ZoomManager.java @@ -0,0 +1,611 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 IBM Corporation 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: IBM Corporation - initial API and implementation + ******************************************************************************/ +package org.eclipse.zest.core.viewers; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.draw2d.FreeformFigure; +import org.eclipse.draw2d.IFigure; +import org.eclipse.draw2d.ScalableFigure; +import org.eclipse.draw2d.ScalableFreeformLayeredPane; +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.widgets.Display; +import org.eclipse.zest.core.viewers.internal.SharedMessages; + +/** + * Manage the primary zoom function in a graphical viewer. This class is used by + * the zoom contribution items, including: + * <UL> + * <LI>{@link org.eclipse.gef.ui.actions.ZoomInAction} + * <LI>{@link org.eclipse.gef.ui.actions.ZoomOutAction} + * <LI>and {@link org.eclipse.gef.ui.actions.ZoomComboContributionItem} + * </UL> + * <P> + * A ZoomManager controls how zoom in and zoom out are performed. It also + * determines the list of choices the user sees in the drop-down Combo on the + * toolbar. The zoom manager controls a <code>ScalableFigure</code>, which + * performs the actual zoom, and also a <code>Viewport</code>. The viewport is + * needed so that the scrolled location is preserved as the zoom level changes. + * <p> + * <b>NOTE:</b> For the settings of {@link #FIT_ALL Page}, {@link #FIT_WIDTH + * Width} and {@link #FIT_HEIGHT Height} to work properly, the given + * <code>Viewport</code> should have its scrollbars always visible or never + * visible. Otherwise, these settings may cause undesired effects. + * + * @author Dan Lee + * @author Eric Bordeau + * @since 2.0 + */ +public class ZoomManager { + + /** Style bit meaning don't animate any zooms */ + public static final int ANIMATE_NEVER = 0; + /** Style bit meaning animate during {@link #zoomIn()} and {@link #zoomOut()} */ + public static final int ANIMATE_ZOOM_IN_OUT = 1; + + private List listeners = new ArrayList(); + + private double multiplier = 1.0; + private ScalableFigure pane; + private Viewport viewport; + private double zoom = 1.0; + // private int zoomAnimationStyle = ANIMATE_NEVER; + private String currentZoomContant = null; + private double[] zoomLevels = { .5, .75, 1.0, 1.5, 2.0, 2.5, 3, 4 }; + + /** + * String constant for the "Height" zoom level. At this zoom level, the zoom + * manager will adopt a zoom setting such that the entire height of the + * diagram will be visible on the screen. + */ + public static final String FIT_HEIGHT = SharedMessages.FitHeightAction_Label; + /** + * String constant for the "Width" zoom level. At this zoom level, the zoom + * manager will adopt a zoom setting such that the entire width of the + * diagram will be visible on the screen. + */ + public static final String FIT_WIDTH = SharedMessages.FitWidthAction_Label; + /** + * String constant for the "Page" zoom level. At this zoom level, the zoom + * manager will adopt a zoom setting such that the entire diagram will be + * visible on the screen. + */ + public static final String FIT_ALL = SharedMessages.FitAllAction_Label; + private List zoomLevelContributions = Collections.EMPTY_LIST; + + //DecimalFormat format = new DecimalFormat("####%"); //$NON-NLS-1$ + + /** + * Creates a new ZoomManager. + * + * @param pane + * The ScalableFigure associated with this ZoomManager + * @param viewport + * The Viewport assoicated with this ZoomManager + */ + public ZoomManager(ScalableFigure pane, Viewport viewport) { + this.pane = pane; + this.viewport = viewport; + zoomLevelContributions = new ArrayList(); + zoomLevelContributions.add(FIT_ALL); + } + + /** + * @deprecated Use {@link #ZoomManager(ScalableFigure, Viewport)} instead. + * Creates a new ZoomManager + * @param pane + * The ScalableFreeformLayeredPane associated with this + * ZoomManager + * @param viewport + * The Viewport assoicated with this viewport + */ + public ZoomManager(ScalableFreeformLayeredPane pane, Viewport viewport) { + this.pane = pane; + this.viewport = viewport; + } + + /** + * Adds the given ZoomListener to this ZoomManager's list of listeners. + * + * @param listener + * the ZoomListener to be added + */ + public void addZoomListener(ZoomListener listener) { + listeners.add(listener); + } + + /** + * returns <code>true</code> if the zoommanager can perform + * <code>zoomIn()</code>. + * + * @return boolean true if zoomIn can be called + */ + public boolean canZoomIn() { + return getZoom() < getMaxZoom(); + } + + /** + * returns <code>true</code> if the zoommanager can perform + * <code>zoomOut()</code>. + * + * @return boolean true if zoomOut can be called + */ + public boolean canZoomOut() { + return getZoom() > getMinZoom(); + } + + /** + * Notifies listeners that the zoom level has changed. + */ + protected void fireZoomChanged() { + Iterator iter = listeners.iterator(); + while (iter.hasNext()) { + ((ZoomListener) iter.next()).zoomChanged(zoom); + } + } + + private double getFitXZoomLevel(int which) { + IFigure fig = getScalableFigure(); + + Dimension available = getViewport().getClientArea().getSize(); + Dimension desired; + if (fig instanceof FreeformFigure) { + desired = ((FreeformFigure) fig).getFreeformExtent().getCopy() + .union(0, 0).getSize(); + } else { + desired = fig.getPreferredSize().getCopy(); + } + + desired.width -= fig.getInsets().getWidth(); + desired.height -= fig.getInsets().getHeight(); + + while (fig != getViewport()) { + available.width -= fig.getInsets().getWidth(); + available.height -= fig.getInsets().getHeight(); + fig = fig.getParent(); + } + + double scaleX = Math.min(available.width * zoom / desired.width, + getMaxZoom()); + double scaleY = Math.min(available.height * zoom / desired.height, + getMaxZoom()); + if (which == 0) { + return scaleX; + } + if (which == 1) { + return scaleY; + } + return Math.min(scaleX, scaleY); + } + + /** + * Calculates and returns the zoom percent required so that the entire + * height of the {@link #getScalableFigure() scalable figure} is visible on + * the screen. This is the zoom level associated with {@link #FIT_HEIGHT}. + * + * @return zoom setting required to fit the scalable figure vertically on + * the screen + */ + protected double getFitHeightZoomLevel() { + return getFitXZoomLevel(1); + } + + /** + * Calculates and returns the zoom percentage required to fit the entire + * {@link #getScalableFigure() scalable figure} on the screen. This is the + * zoom setting associated with {@link #FIT_ALL}. It is the minimum of + * {@link #getFitHeightZoomLevel()} and {@link #getFitWidthZoomLevel()}. + * + * @return zoom setting required to fit the entire scalable figure on the + * screen + */ + protected double getFitPageZoomLevel() { + return getFitXZoomLevel(2); + } + + /** + * Calculates and returns the zoom percentage required so that the entire + * width of the {@link #getScalableFigure() scalable figure} is visible on + * the screen. This is the zoom setting associated with {@link #FIT_WIDTH}. + * + * @return zoom setting required to fit the scalable figure horizontally on + * the screen + */ + protected double getFitWidthZoomLevel() { + return getFitXZoomLevel(0); + } + + /** + * Returns the maxZoom. + * + * @return double + */ + public double getMaxZoom() { + return getZoomLevels()[getZoomLevels().length - 1]; + } + + /** + * Returns the minZoom. + * + * @return double + */ + public double getMinZoom() { + return getZoomLevels()[0]; + } + + /** + * Returns the mutltiplier. This value is used to use zoom levels internally + * that are proportionally different than those displayed to the user. e.g. + * with a multiplier value of 2.0, the zoom level 1.0 will be displayed as + * "200%". + * + * @return double The multiplier + */ + public double getUIMultiplier() { + return multiplier; + } + + /** + * Returns the zoom level that is one level higher than the current level. + * If zoom level is at maximum, returns the maximum. + * + * @return double The next zoom level + */ + public double getNextZoomLevel() { + for (int i = 0; i < zoomLevels.length; i++) { + if (zoomLevels[i] > zoom) { + return zoomLevels[i]; + } + } + return getMaxZoom(); + } + + /** + * Returns the zoom level that is one level higher than the current level. + * If zoom level is at maximum, returns the maximum. + * + * @return double The previous zoom level + */ + public double getPreviousZoomLevel() { + for (int i = 1; i < zoomLevels.length; i++) { + if (zoomLevels[i] >= zoom) { + return zoomLevels[i - 1]; + } + } + return getMinZoom(); + } + + /** + * Returns the figure which performs the actual zooming. + * + * @return the scalable figure + */ + public ScalableFigure getScalableFigure() { + return pane; + } + + /** + * Returns the viewport. + * + * @return Viewport + */ + public Viewport getViewport() { + return viewport; + } + + /** + * Returns the current zoom level. + * + * @return double the zoom level + */ + public double getZoom() { + return zoom; + } + + private String format(double d) { + return "" + ((int) (d * 100)) + "%"; + } + + /** + * Returns the current zoom level as a percentage formatted String + * + * @return String The current zoom level as a String + */ + public String getZoomAsText() { + if (currentZoomContant != null) { + return currentZoomContant; + } + + // String newItem = format.format(zoom * multiplier); + String newItem = format(zoom * multiplier); + return newItem; + } + + /** + * Returns the list of strings that should be appended to the list of + * numerical zoom levels. These could be things such as Fit Width, Fit Page, + * etc. May return <code>null</code>. + * + * @return the list of contributed zoom levels + */ + public List getZoomLevelContributions() { + return zoomLevelContributions; + } + + /** + * Returns the zoomLevels. + * + * @return double[] + */ + public double[] getZoomLevels() { + return zoomLevels; + } + + /** + * Returns the list of zoom levels as Strings in percent notation, plus any + * additional zoom levels that were contributed using + * {@link #setZoomLevelContributions(List)}. + * + * @return List The list of zoom levels + */ + public String[] getZoomLevelsAsText() { + String[] zoomLevelStrings = new String[zoomLevels.length + + zoomLevelContributions.size()]; + + if (zoomLevelContributions != null) { + for (int i = 0; i < zoomLevelContributions.size(); i++) { + zoomLevelStrings[i] = (String) zoomLevelContributions.get(i); + } + } + for (int i = 0; i < zoomLevels.length; i++) { + // zoomLevelStrings[i + zoomLevelContributions.size()] = + // format.format(zoomLevels[i] * multiplier); + zoomLevelStrings[i + zoomLevelContributions.size()] = format(zoomLevels[i] + * multiplier); + } + + return zoomLevelStrings; + } + + /** + * Sets the zoom level to the given value. Min-max range check is not done. + * + * @param zoom + * the new zoom level + */ + protected void primSetZoom(double zoom) { + Point p1 = getViewport().getClientArea().getCenter(); + Point p2 = p1.getCopy(); + Point p = getViewport().getViewLocation(); + double prevZoom = this.zoom; + this.zoom = zoom; + pane.setScale(zoom); + fireZoomChanged(); + getViewport().validate(); + + p2.scale(zoom / prevZoom); + Dimension dif = p2.getDifference(p1); + p.x += dif.width; + p.y += dif.height; + setViewLocation(p); + } + + /** + * Removes the given ZoomListener from this ZoomManager's list of listeners. + * + * @param listener + * the ZoomListener to be removed + */ + public void removeZoomListener(ZoomListener listener) { + listeners.remove(listener); + } + + /** + * Sets the UI multiplier. The UI multiplier is applied to all zoom settings + * when they are presented to the user ({@link #getZoomAsText()}). + * Similarly, the multiplier is inversely applied when the user specifies a + * zoom level ({@link #setZoomAsText(String)}). + * <P> + * When the UI multiplier is <code>1.0</code>, the User will see the exact + * zoom level that is being applied. If the value is <code>2.0</code>, then + * a scale of <code>0.5</code> will be labeled "100%" to the User. + * + * @param multiplier + * The mutltiplier to set + */ + public void setUIMultiplier(double multiplier) { + this.multiplier = multiplier; + } + + /** + * Sets the Viewport's view associated with this ZoomManager to the passed + * Point + * + * @param p + * The new location for the Viewport's view. + */ + public void setViewLocation(Point p) { + viewport.setViewLocation(p.x, p.y); + + } + + /** + * Sets the zoom level to the given value. If the zoom is out of the min-max + * range, it will be ignored. + * + * @param zoom + * the new zoom level + */ + public void setZoom(double zoom) { + currentZoomContant = null; + zoom = Math.min(getMaxZoom(), zoom); + zoom = Math.max(getMinZoom(), zoom); + if (this.zoom != zoom) { + primSetZoom(zoom); + } + } + + /** + * Sets which zoom methods get animated. + * + * @param style + * the style bits determining the zoom methods to be animated. + */ + public void setZoomAnimationStyle(int style) { + // zoomAnimationStyle = style; + } + + /** + * Sets zoom to the passed string. The string must be composed of numeric + * characters only with the exception of a decimal point and a '%' as the + * last character. If the zoom level contribution list has been set, this + * method should be overridden to provide the appropriate zoom + * implementation for the new zoom levels. + * + * @param zoomString + * The new zoom level + */ + public void setZoomAsText(String zoomString) { + currentZoomContant = null; + if (zoomString.equalsIgnoreCase(FIT_HEIGHT)) { + currentZoomContant = FIT_HEIGHT; + primSetZoom(getFitHeightZoomLevel()); + viewport.getUpdateManager().performUpdate(); + viewport.setViewLocation(viewport.getHorizontalRangeModel() + .getValue(), viewport.getVerticalRangeModel().getMinimum()); + } else if (zoomString.equalsIgnoreCase(FIT_ALL)) { + currentZoomContant = FIT_ALL; + primSetZoom(getFitPageZoomLevel()); + viewport.getUpdateManager().performUpdate(); + viewport.setViewLocation(viewport.getHorizontalRangeModel() + .getMinimum(), viewport.getVerticalRangeModel() + .getMinimum()); + } else if (zoomString.equalsIgnoreCase(FIT_WIDTH)) { + currentZoomContant = FIT_WIDTH; + primSetZoom(getFitWidthZoomLevel()); + viewport.getUpdateManager().performUpdate(); + viewport.setViewLocation(viewport.getHorizontalRangeModel() + .getMinimum(), viewport.getVerticalRangeModel().getValue()); + } else { + try { + // Trim off the '%' + if (zoomString.charAt(zoomString.length() - 1) == '%') { + zoomString = zoomString.substring(0, + zoomString.length() - 1); + } + double newZoom = Double.parseDouble(zoomString) / 100; + setZoom(newZoom / multiplier); + } catch (Exception e) { + Display.getCurrent().beep(); + } + } + } + + /** + * Sets the list of zoom level contributions (as strings). If you contribute + * something <b>other than</b> {@link #FIT_HEIGHT}, {@link #FIT_WIDTH} and + * {@link #FIT_ALL} you must subclass this class and override this method to + * implement your contributed zoom function. + * + * @param contributions + * the list of contributed zoom levels + */ + public void setZoomLevelContributions(List contributions) { + zoomLevelContributions = contributions; + } + + /** + * Sets the zoomLevels. + * + * @param zoomLevels + * The zoomLevels to set + */ + public void setZoomLevels(double[] zoomLevels) { + this.zoomLevels = zoomLevels; + } + + /** + * Sets the zoom level to be one level higher + */ + public void zoomIn() { + setZoom(getNextZoomLevel()); + } + + /** + * Currently does nothing. + * + * @param rect + * a rectangle + */ + public void zoomTo(Rectangle rect) { + } + + // private void performAnimatedZoom(Rectangle rect, boolean zoomIn, int + // iterationCount) { + // double finalRatio; + // double zoomIncrement; + // + // if (zoomIn) { + // finalRatio = zoom / getNextZoomLevel(); + // zoomIncrement = (getNextZoomLevel() - zoom) / iterationCount; + // } else { + // finalRatio = zoom / getPreviousZoomLevel(); + // zoomIncrement = (getPreviousZoomLevel() - zoom) / iterationCount; + // } + // + // getScalableFigure().translateToRelative(rect); + // Point originalViewLocation = getViewport().getViewLocation(); + // Point finalViewLocation = calculateViewLocation(rect, finalRatio); + // + // double xIncrement = + // (double) (finalViewLocation.x - originalViewLocation.x) / iterationCount; + // double yIncrement = + // (double) (finalViewLocation.y - originalViewLocation.y) / iterationCount; + // + // double originalZoom = zoom; + // Point currentViewLocation = new Point(); + // for (int i = 1; i < iterationCount; i++) { + // currentViewLocation.x = (int)(originalViewLocation.x + (xIncrement * i)); + // currentViewLocation.y = (int)(originalViewLocation.y + (yIncrement * i)); + // setZoom(originalZoom + zoomIncrement * i); + // getViewport().validate(); + // setViewLocation(currentViewLocation); + // getViewport().getUpdateManager().performUpdate(); + // } + // + // if (zoomIn) + // setZoom(getNextZoomLevel()); + // else + // setZoom(getPreviousZoomLevel()); + // + // getViewport().validate(); + // setViewLocation(finalViewLocation); + // } + // + // private Point calculateViewLocation(Rectangle zoomRect, double ratio) { + // Point viewLocation = new Point(); + // viewLocation.x = (int)(zoomRect.x / ratio); + // viewLocation.y = (int)(zoomRect.y / ratio); + // return viewLocation; + // } + + /** + * Sets the zoom level to be one level lower + */ + public void zoomOut() { + setZoom(getPreviousZoomLevel()); + } + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java new file mode 100644 index 0000000..a7e2d3c --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java @@ -0,0 +1,430 @@ +/******************************************************************************* + * Copyright 2005, 2010, 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 <mateusz.matela@gmail.com> - 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.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.eclipse.draw2d.IFigure; +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.StructuredViewer; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.swt.SWT; +import org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer; +import org.eclipse.zest.core.viewers.IFigureProvider; +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; + +/** + * Base class that can be used for model factories. Offers facilities to style + * the items that have been created by the factory. + * + * @author Del Myers + */ +// @tag zest.bug.160367-Refreshing.fix : update the factory to use the +// IStylingGraphModelFactory +public abstract class AbstractStylingModelFactory implements + IStylingGraphModelFactory { + private AbstractStructuredGraphViewer viewer; + private int connectionStyle; + private int nodeStyle; + + /** + * + */ + public AbstractStylingModelFactory(AbstractStructuredGraphViewer viewer) { + this.viewer = viewer; + this.connectionStyle = SWT.NONE; + this.nodeStyle = SWT.NONE; + } + + public void styleConnection(GraphConnection conn) { + // recount the source and target connections on the node. + // this isn't a great way to do it, because it results in + // an n^2 algorithm. But, if anyone can figure out a better way + // go ahead and try it. + GraphNode source = conn.getSource(); + GraphNode dest = conn.getDestination(); + LinkedList rightList = getConnectionList(source, dest); + + LinkedList leftList = null; + + if (dest != source) { + leftList = getConnectionList(dest, source); + } + + // adjust the arcs going from source to destination + adjustCurves(rightList); + // adjust the arcs going from destination to source + if (leftList != null) { + adjustCurves(leftList); + } + } + + /** + * Takes a list of IGraphModelConnections and adjusts the curve depths and + * the bezier curves based on the number of curves in the list. + * + * @param rightList + */ + protected void adjustCurves(List connections) { + // @tag TODO curves : add back this code to adjust the curves + // int scale = 3; + // for (int i = 0; i < connections.size(); i++) { + // GraphConnection conn = (GraphConnection) connections.get(i); + // if (conn.getSource() == conn.getDestination()) { + // scale = 5; + // } + // // even if the connection isn't curved in the style, the edit part + // // may decide that it should be curved if source and dest are equal. + // // @tag drawing(arcs) : check here if arcs are too close when being + // // drawn. Adjust the constant. + // int lineWidth = conn.getLineWidth(); + // conn.setCurveDepth((i + 1) * (scale + lineWidth)); + // + // // @tag zest(bug(152530-Bezier(fix))) : set the angles, etc based on + // // the count. + // // limit the angle to 90 degrees. + // conn.setStartAngle(90.0 - 85.0 / Math.pow(i, 1.0 / 9.0)); + // conn.setEndAngle(85.0 / Math.pow(i, 1.0 / 9.0) - 90.0); + // // limit the length to 1 + // conn.setStartLength(.75 - .25 / (Math.sqrt(i))); + // conn.setEndLength(.75 - .25 / (Math.sqrt(i))); + // } + } + + /** + * @param source + * @param dest + * @return + */ + private LinkedList getConnectionList(GraphNode source, GraphNode dest) { + LinkedList list = new LinkedList(); + Iterator i = source.getSourceConnections().iterator(); + while (i.hasNext()) { + GraphConnection c = (GraphConnection) i.next(); + if (c.getDestination() == dest) { + list.add(c); + } + } + return list; + } + + public void styleItem(GraphItem item) { + GraphItemStyler.styleItem(item, getLabelProvider()); + if (item instanceof GraphConnection) { + styleConnection((GraphConnection) item); + } + } + + public StructuredViewer getViewer() { + return viewer; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory# + * getLabelProvider() + */ + public IBaseLabelProvider getLabelProvider() { + return viewer.getLabelProvider(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory# + * getContentProvider() + */ + public IStructuredContentProvider getContentProvider() { + return (IStructuredContentProvider) viewer.getContentProvider(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory# + * createConnection(org.eclipse.zest.core.internal.graphmodel.GraphModel, + * java.lang.Object, java.lang.Object, java.lang.Object) + */ + public GraphConnection createConnection(Graph graph, Object element, + Object source, Object dest) { + if (source == null || dest == null) { + return null; + } + GraphConnection oldConnection = viewer.getGraphModelConnection(element); + GraphNode sn = viewer.getGraphModelNode(source); + GraphNode dn = viewer.getGraphModelNode(dest); + if (oldConnection != null) { + if (sn != oldConnection.getSource() + || dn != oldConnection.getDestination()) { + viewer.removeGraphModelConnection(oldConnection); + } else { + styleItem(oldConnection); + return oldConnection; + } + } + if (sn == null) { + sn = createNode(graph, source); + } + if (dn == null) { + dn = createNode(graph, dest); + } + GraphConnection c = viewer.addGraphModelConnection(element, sn, dn); + styleItem(c); + return c; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory# + * createNode(org.eclipse.zest.core.internal.graphmodel.GraphModel, + * java.lang.Object) + */ + public GraphNode createNode(Graph graph, Object element, IFigure figure) { + GraphNode node = null; + if (getContentProvider() instanceof INestedContentProvider) { + boolean isContainer = ((INestedContentProvider) getContentProvider()) + .hasChildren(element); + if (isContainer) { + node = viewer.addGraphModelContainer(element); + styleItem(node); + Object[] childNodes = ((INestedContentProvider) getContentProvider()) + .getChildren(element); + childNodes = filter(getViewer().getInput(), childNodes); + if (childNodes == null) { + return node; + } + for (int i = 0; i < childNodes.length; i++) { + GraphNode childNode = viewer.addGraphModelNode( + (GraphContainer) node, childNodes[i]); + styleItem(childNode); + } + ((GraphContainer) node).applyLayout(); + return node; + } + } + node = viewer.addGraphModelNode(element, figure); + styleItem(node); + return node; + } + + public GraphNode createNode(Graph graph, Object element) { + IFigure nodeFigure = null; + if (getLabelProvider() instanceof IFigureProvider) { + nodeFigure = ((IFigureProvider) getLabelProvider()) + .getFigure(element); + } + return this.createNode(graph, element, nodeFigure); + } + + public void setConnectionStyle(int style) { + this.connectionStyle = style; + } + + /** + * @return the connectionStyle + */ + public int getConnectionStyle() { + return connectionStyle; + } + + public void setNodeStyle(int style) { + this.nodeStyle = style; + } + + /** + * @return the nodeStyle + */ + public int getNodeStyle() { + return nodeStyle; + } + + /** + * Default implementation simply restyles the item, regardless of the + * properties. + */ + public void update(GraphItem item) { + styleItem(item); + } + + /** + * Default implementation simply restyles the items, regardless of the + * properties. + */ + public void update(GraphItem[] items) { + for (int i = 0; i < items.length; i++) { + styleItem(items[i]); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory# + * refreshGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel) + */ + public void refreshGraph(Graph graph) { + // with this kind of graph, it is just as easy and cost-effective to + // rebuild the whole thing. + + Map oldMap = viewer.getNodesMap(); + HashMap nodesMap = new HashMap(); + // have to copy the Map data accross so that it doesn't get overwritten + for (Iterator keys = oldMap.keySet().iterator(); keys.hasNext();) { + Object key = keys.next(); + nodesMap.put(key, oldMap.get(key)); + } + clearGraph(graph); + doBuildGraph(graph); + // update the positions on the new nodes to match the old ones. + GraphNode[] nodes = getNodesArray(graph); + // save a little time, go with the smallest list as the primary list + if (nodes.length < nodesMap.keySet().size()) { + for (int i = 0; i < nodes.length; i++) { + GraphNode oldNode = (GraphNode) nodesMap + .get(nodes[i].getData()); + if (oldNode != null) { + nodes[i].setLocation(oldNode.getLocation().x, oldNode + .getLocation().y); + if (oldNode.isSizeFixed()) { + nodes[i].setSize(oldNode.getSize().width, oldNode + .getSize().height); + } + } + } + } else { + for (Iterator i = nodesMap.keySet().iterator(); i.hasNext();) { + Object key = i.next(); + GraphNode node = viewer.getGraphModelNode(key); + if (node != null) { + GraphNode oldNode = (GraphNode) nodesMap.get(key); + node.setLocation(oldNode.getLocation().x, oldNode + .getLocation().y); + if (oldNode.isSizeFixed()) { + node.setSize(oldNode.getSize().width, + oldNode.getSize().height); + } + } + } + } + } + + /** + * Convenience method for clearing all the elements in the graph. + * + * @param graph + */ + public void clearGraph(Graph graph) { + graph.setSelection(null); + Object[] nodeElements = viewer.getNodeElements(); + for (int i = 0; i < nodeElements.length; i++) { + viewer.removeGraphModelNode(nodeElements[i]); + } + Object[] connectionElements = viewer.getConnectionElements(); + for (int i = 0; i < connectionElements.length; i++) { + viewer.removeGraphModelConnection(connectionElements[i]); + } + } + + /** + * Builds the graph model from the viewer's content provider. There is no + * guarantee that the model will be cleared before this method is called. + * + * @param graph + */ + protected void doBuildGraph(Graph model) { + clearGraph(model); + model.setConnectionStyle(getConnectionStyle()); + model.setNodeStyle(getNodeStyle()); + } + + /** + * Determines if this element should be filtered or not. + * + * @param parent + * @param element + * @return + */ + protected boolean filterElement(Object parent, Object element) { + ViewerFilter[] filters = getViewer().getFilters(); + for (int i = 0; i < filters.length; i++) { + boolean selected = filters[i].select(viewer, parent, element); + if (!selected) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory# + * isFiltered(java.lang.Object) + */ + protected Object[] filter(Object parent, Object[] elements) { + Object[] result = elements; + ViewerFilter[] filters = getViewer().getFilters(); + for (int i = 0; i < filters.length; i++) { + result = filters[i].filter(viewer, parent, result); + } + return result; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh + * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object) + */ + public void refresh(Graph graph, Object element) { + refresh(graph, element, false); + } + + /** + * Converts the list of GraphNode objects into an array and return it. + * + * @return GraphModelNode[] + */ + protected GraphNode[] getNodesArray(Graph graph) { + GraphNode[] nodesArray = new GraphNode[graph.getNodes().size()]; + nodesArray = (GraphNode[]) graph.getNodes().toArray(nodesArray); + return nodesArray; + } + + /** + * Converts the list of GraphConnections objects into an array and return + * it. + * + * @param graph + * @return + */ + protected GraphConnection[] getConnectionArray(Graph graph) { + GraphConnection[] connectionArray = new GraphConnection[graph + .getConnections().size()]; + connectionArray = (GraphConnection[]) graph.getConnections().toArray( + connectionArray); + return connectionArray; + } +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphItemStyler.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphItemStyler.java new file mode 100644 index 0000000..1926f2b --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphItemStyler.java @@ -0,0 +1,279 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers.internal; + +import org.eclipse.draw2d.IFigure; +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.IColorProvider; +import org.eclipse.jface.viewers.IFontProvider; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTError; +import org.eclipse.swt.graphics.Color; +import org.eclipse.zest.core.viewers.IConnectionStyleProvider; +import org.eclipse.zest.core.viewers.IEntityConnectionStyleProvider; +import org.eclipse.zest.core.viewers.IEntityStyleProvider; +import org.eclipse.zest.core.viewers.ISelfStyleProvider; +import org.eclipse.zest.core.widgets.GraphConnection; +import org.eclipse.zest.core.widgets.GraphItem; +import org.eclipse.zest.core.widgets.GraphNode; +import org.eclipse.zest.core.widgets.ZestStyles; + +/* + * Helper class used to style graph elements based on graph element stylers. + * + * @author Del Myers + */ +// @tag bug(151327-Styles) : created to help resolve this bug +public class GraphItemStyler { + public static void styleItem(GraphItem item, + final IBaseLabelProvider labelProvider) { + + if (item instanceof GraphNode) { + GraphNode node = (GraphNode) item; + // set defaults. + if (node.getGraphModel().getNodeStyle() != ZestStyles.NONE) { + node.setNodeStyle(node.getGraphModel().getNodeStyle()); + } else { + node.setNodeStyle(SWT.NONE); + } + Object entity = node.getData(); + if (labelProvider instanceof IEntityStyleProvider) { + styleNode(node, (IEntityStyleProvider) labelProvider); + } + if (labelProvider instanceof IColorProvider) { + IColorProvider colorProvider = (IColorProvider) labelProvider; + node.setForegroundColor(colorProvider.getForeground(entity)); + node.setBackgroundColor(colorProvider.getBackground(entity)); + } + if (labelProvider instanceof IFontProvider) { + IFontProvider fontProvider = (IFontProvider) labelProvider; + node.setFont(fontProvider.getFont(entity)); + } + if (labelProvider instanceof ILabelProvider) { + String text = ((ILabelProvider) labelProvider).getText(node + .getData()); + node.setText((text != null) ? text : ""); + node.setImage(((ILabelProvider) labelProvider).getImage(node + .getData())); + } + if (labelProvider instanceof ISelfStyleProvider) { + ((ISelfStyleProvider) labelProvider) + .selfStyleNode(entity, node); + } + } else if (item instanceof GraphConnection) { + GraphConnection conn = (GraphConnection) item; + + // set defaults + if (conn.getGraphModel().getConnectionStyle() != ZestStyles.NONE) { + int s = conn.getGraphModel().getConnectionStyle(); + conn.setConnectionStyle(s); + } else { + conn.setConnectionStyle(SWT.NONE); + } + if (labelProvider instanceof ILabelProvider) { + String text = ((ILabelProvider) labelProvider).getText(conn + .getExternalConnection()); + conn.setText((text != null) ? text : ""); + conn.setImage(((ILabelProvider) labelProvider).getImage(conn + .getExternalConnection())); + } + if (labelProvider instanceof IEntityConnectionStyleProvider) { + styleEntityConnection(conn, + (IEntityConnectionStyleProvider) labelProvider); + } else if (labelProvider instanceof IConnectionStyleProvider) { + styleConnection(conn, (IConnectionStyleProvider) labelProvider); + } + int swt = getLineStyleForZestStyle(conn.getConnectionStyle()); + conn.setLineStyle(swt); + if (labelProvider instanceof ISelfStyleProvider) { + ((ISelfStyleProvider) labelProvider).selfStyleConnection(conn + .getData(), conn); + } + } + } + + /** + * @param conn + * @param provider + */ + private static void styleConnection(GraphConnection conn, + IConnectionStyleProvider provider) { + Object rel = conn.getExternalConnection(); + Color c; + int style = provider.getConnectionStyle(rel); + if (!ZestStyles.validateConnectionStyle(style)) { + throw new SWTError(SWT.ERROR_INVALID_ARGUMENT); + } + if (style != ZestStyles.NONE) { + conn.setConnectionStyle(style); + } + // @tag bug(152530-Bezier(fix)) + // @tat TODO curves bezier: Add back the bezier connection stuff + // if (ZestStyles.checkStyle(conn.getConnectionStyle(), + // ZestStyles.CONNECTIONS_BEZIER) + // && provider instanceof IConnectionStyleBezierExtension) { + // IConnectionStyleBezierExtension bezier = + // (IConnectionStyleBezierExtension) provider; + // double d; + // if (!Double.isNaN((d = bezier.getStartAngle(rel)))) { + // conn.setStartAngle(d); + // } + // if (!Double.isNaN((d = bezier.getEndAngle(rel)))) { + // conn.setEndAngle(d); + // } + // if (!Double.isNaN((d = bezier.getStartDistance(rel)))) { + // conn.setStartLength(d); + // } + // if (!Double.isNaN((d = bezier.getEndDistance(rel)))) { + // conn.setEndLength(d); + // } + // } + if ((c = provider.getHighlightColor(rel)) != null) { + conn.setHighlightColor(c); + } + if ((c = provider.getColor(rel)) != null) { + conn.setLineColor(c); + } + IFigure tooltip; + if ((tooltip = provider.getTooltip(rel)) != null) { + conn.setTooltip(tooltip); + } + int w = -1; + if ((w = provider.getLineWidth(rel)) >= 0) { + conn.setLineWidth(w); + } + } + + /** + * @param conn + * @param provider + */ + private static void styleEntityConnection(GraphConnection conn, + IEntityConnectionStyleProvider provider) { + Object src = conn.getSource().getData(); + Object dest = conn.getDestination().getData(); + Color c; + int style = provider.getConnectionStyle(src, dest); + if (!ZestStyles.validateConnectionStyle(style)) { + throw new SWTError(SWT.ERROR_INVALID_ARGUMENT); + } + if (style != ZestStyles.NONE) { + conn.setConnectionStyle(style); + } + // @tag bug(152530-Bezier(fisx)) + // @tag TODO curved connections bezier : add back the bezier connection + // stuff + // if (ZestStyles.checkStyle(conn.getConnectionStyle(), + // ZestStyles.CONNECTIONS_BEZIER) + // && provider instanceof IEntityConnectionStyleBezierExtension) { + // IEntityConnectionStyleBezierExtension bezier = + // (IEntityConnectionStyleBezierExtension) provider; + // double d; + // if (!Double.isNaN((d = bezier.getStartAngle(src, dest)))) { + // conn.setStartAngle(d); + // } + // if (!Double.isNaN((d = bezier.getEndAngle(src, dest)))) { + // conn.setEndAngle(d); + // } + // if (!Double.isNaN((d = bezier.getStartDistance(src, dest)))) { + // conn.setStartLength(d); + // } + // if (!Double.isNaN((d = bezier.getEndDistance(src, dest)))) { + // conn.setEndLength(d); + // } + // } + if ((c = provider.getColor(src, dest)) != null) { + conn.setLineColor(c); + } + if ((c = provider.getHighlightColor(src, dest)) != null) { + conn.setHighlightColor(c); + } + int w = -1; + if ((w = provider.getLineWidth(src, dest)) >= 0) { + conn.setLineWidth(w); + } + } + + /** + * Styles the given node according to the properties in the style provider. + * + * @param node + * the graph element to style. + * @param data + * the element that is being styled. + * @param provider + * the style provier. + */ + // @tag bug(151327-Styles) : resolution + private static void styleNode(GraphNode node, IEntityStyleProvider provider) { + Object entity = node.getData(); + // @tag ADJACENT : Removed highlight adjacent + // node.setHighlightAdjacentNodes(provider.highlightAdjacentEntities(entity)); + + // @tag ADJACENT : Removed highlight adjacent + /* + * if (provider.highlightAdjacentEntities(entity)) { Color c = + * provider.getAdjacentEntityHighlightColor(entity); if (c != null) { + * node.setHighlightAdjacentColor(c); } } + */ + Color c; + IFigure figure; + int width = -1; + if (provider.fisheyeNode(entity) == true) { + node.setNodeStyle(node.getNodeStyle() | ZestStyles.NODES_FISHEYE); + } + if ((c = provider.getBorderColor(entity)) != null) { + node.setBorderColor(c); + } + if ((c = provider.getBorderHighlightColor(entity)) != null) { + node.setBorderHighlightColor(c); + } + if ((c = provider.getNodeHighlightColor(entity)) != null) { + node.setHighlightColor(c); + } + if ((c = provider.getBackgroundColour(entity)) != null) { + node.setBackgroundColor(c); + } + if ((c = provider.getForegroundColour(entity)) != null) { + node.setForegroundColor(c); + } + if ((width = provider.getBorderWidth(entity)) >= 0) { + node.setBorderWidth(width); + } + if ((figure = provider.getTooltip(entity)) != null) { + node.setTooltip(figure); + } + + } + + /** + * Returns the SWT line style for the given zest connection style. + * + */ + public static int getLineStyleForZestStyle(int style) { + int lineStyles = ZestStyles.CONNECTIONS_DASH_DOT + | ZestStyles.CONNECTIONS_DASH | ZestStyles.CONNECTIONS_DOT + | ZestStyles.CONNECTIONS_SOLID; + style = style & lineStyles; + if (style == 0) { + style = ZestStyles.CONNECTIONS_SOLID; + } + switch (style) { + case ZestStyles.CONNECTIONS_DASH_DOT: + return SWT.LINE_DASHDOT; + case ZestStyles.CONNECTIONS_DASH: + return SWT.LINE_DASH; + case ZestStyles.CONNECTIONS_DOT: + return SWT.LINE_DOT; + } + return SWT.LINE_SOLID; + } +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphModelEntityFactory.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphModelEntityFactory.java new file mode 100644 index 0000000..d71471b --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphModelEntityFactory.java @@ -0,0 +1,229 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers.internal; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer; +import org.eclipse.zest.core.viewers.EntityConnectionData; +import org.eclipse.zest.core.viewers.IFigureProvider; +import org.eclipse.zest.core.viewers.IGraphEntityContentProvider; +import org.eclipse.zest.core.widgets.Graph; +import org.eclipse.zest.core.widgets.GraphConnection; +import org.eclipse.zest.core.widgets.GraphItem; +import org.eclipse.zest.core.widgets.GraphNode; + +/* + * + * @author Ian Bull + */ +public class GraphModelEntityFactory extends AbstractStylingModelFactory { + + AbstractStructuredGraphViewer viewer = null; + + public GraphModelEntityFactory(AbstractStructuredGraphViewer viewer) { + super(viewer); + this.viewer = viewer; + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory# + * createGraphModel() + */ + public Graph createGraphModel(Graph model) { + doBuildGraph(model); + return model; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory + * #doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel) + */ + protected void doBuildGraph(Graph model) { + super.doBuildGraph(model); + Object inputElement = getViewer().getInput(); + Object entities[] = getContentProvider().getElements(inputElement); + if (entities == null) { + return; + } + for (int i = 0; i < entities.length; i++) { + Object data = entities[i]; + IFigureProvider figureProvider = null; + if (getLabelProvider() instanceof IFigureProvider) { + figureProvider = (IFigureProvider) getLabelProvider(); + } + if (!filterElement(inputElement, data)) { + if (figureProvider != null) { + createNode(model, data, figureProvider.getFigure(data)); + } else { + createNode(model, data); + } + } + } + + // We may have other entities (such as children of containers) + Set keySet = ((AbstractStructuredGraphViewer) getViewer()) + .getNodesMap().keySet(); + entities = keySet.toArray(); + + for (int i = 0; i < entities.length; i++) { + Object data = entities[i]; + + // If this element is filtered, continue to the next one. + if (filterElement(inputElement, data)) { + continue; + } + Object[] related = ((IGraphEntityContentProvider) getContentProvider()) + .getConnectedTo(data); + + if (related != null) { + for (int j = 0; j < related.length; j++) { + // if the node this node is connected to is filtered, + // don't display this edge + if (filterElement(inputElement, related[j])) { + continue; + } + EntityConnectionData connectionData = new EntityConnectionData( + data, related[j]); + if (filterElement(inputElement, connectionData)) { + continue; + } + createConnection(model, connectionData, data, related[j]); + } + } + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh + * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object) + */ + public void refresh(Graph graph, Object element, boolean refreshLabels) { + if (element == null) { + return; + } + GraphNode node = viewer.getGraphModelNode(element); + if (node == null) { + // check to make sure that the user didn't send us an edge. + GraphConnection conn = viewer.getGraphModelConnection(element); + if (conn != null) { + // refresh on the connected nodes. + refresh(graph, conn.getSource().getData(), refreshLabels); + refresh(graph, conn.getDestination().getData(), refreshLabels); + return; + } + } + // can only refresh on nodes in this kind of factory. + if (node == null) { + // do nothing + return; + } + reconnect(graph, element, refreshLabels); + + if (refreshLabels) { + update(node); + for (Iterator it = node.getSourceConnections().iterator(); it + .hasNext();) { + update((GraphItem) it.next()); + } + for (Iterator it = node.getTargetConnections().iterator(); it + .hasNext();) { + update((GraphItem) it.next()); + } + } + } + + /** + * @param graph + * @param element + * @param refreshLabels + */ + private void reconnect(Graph graph, Object element, boolean refreshLabels) { + GraphNode node = viewer.getGraphModelNode(element); + Object[] related = ((IGraphEntityContentProvider) getContentProvider()) + .getConnectedTo(element); + List connections = node.getSourceConnections(); + LinkedList toAdd = new LinkedList(); + LinkedList toDelete = new LinkedList(); + LinkedList toKeep = new LinkedList(); + HashSet oldExternalConnections = new HashSet(); + HashSet newExternalConnections = new HashSet(); + for (Iterator it = connections.iterator(); it.hasNext();) { + oldExternalConnections.add(((GraphConnection) it.next()) + .getExternalConnection()); + } + for (int i = 0; i < related.length; i++) { + newExternalConnections.add(new EntityConnectionData(element, + related[i])); + } + for (Iterator it = oldExternalConnections.iterator(); it.hasNext();) { + Object next = it.next(); + if (!newExternalConnections.contains(next)) { + toDelete.add(next); + } else { + toKeep.add(next); + } + } + for (Iterator it = newExternalConnections.iterator(); it.hasNext();) { + Object next = it.next(); + if (!oldExternalConnections.contains(next)) { + toAdd.add(next); + } + } + for (Iterator it = toDelete.iterator(); it.hasNext();) { + viewer.removeGraphModelConnection(it.next()); + } + toDelete.clear(); + LinkedList newNodeList = new LinkedList(); + for (Iterator it = toAdd.iterator(); it.hasNext();) { + EntityConnectionData data = (EntityConnectionData) it.next(); + GraphNode dest = viewer.getGraphModelNode(data.dest); + if (dest == null) { + newNodeList.add(data.dest); + } + createConnection(graph, data, data.source, data.dest); + } + toAdd.clear(); + if (refreshLabels) { + for (Iterator i = toKeep.iterator(); i.hasNext();) { + styleItem(viewer.getGraphModelConnection(i.next())); + } + } + for (Iterator it = newNodeList.iterator(); it.hasNext();) { + // refresh the new nodes so that we get a fully-up-to-date graph. + refresh(graph, it.next()); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh + * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object, + * boolean) + */ + public void refresh(Graph graph, Object element) { + refresh(graph, element, false); + } + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphModelEntityRelationshipFactory.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphModelEntityRelationshipFactory.java new file mode 100644 index 0000000..39786dc --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphModelEntityRelationshipFactory.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers.internal; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer; +import org.eclipse.zest.core.viewers.IGraphEntityRelationshipContentProvider; +import org.eclipse.zest.core.widgets.Graph; +import org.eclipse.zest.core.widgets.GraphContainer; +import org.eclipse.zest.core.widgets.GraphNode; + +/* + * A factory for the IGraphEntityRelationshipContentProvider. + * + * @author Del Myers + */ +// @tag bug.154580-Content.fix +// @tag bug.160367-Refreshing.fix : updated to use new +// AbstractStylingModelFactory +public class GraphModelEntityRelationshipFactory extends + AbstractStylingModelFactory { + + public GraphModelEntityRelationshipFactory( + AbstractStructuredGraphViewer viewer) { + super(viewer); + if (!(viewer.getContentProvider() instanceof IGraphEntityRelationshipContentProvider)) { + throw new IllegalArgumentException( + "Expected IGraphEntityRelationshipContentProvider"); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory + * #createGraphModel() + */ + public Graph createGraphModel(Graph model) { + doBuildGraph(model); + return model; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory + * #doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel) + */ + protected void doBuildGraph(Graph model) { + super.doBuildGraph(model); + Object[] nodes = getContentProvider().getElements( + getViewer().getInput()); + nodes = filter(getViewer().getInput(), nodes); + createModelNodes(model, nodes); + createModelRelationships(model); + } + + /** + * Creates all the model relationships. Assumes that all of the model nodes + * have been created in the graph model already. Runtime O(n^2) + O(r). + * + * @param model + * the model to create the relationship on. + */ + private void createModelRelationships(Graph model) { + GraphNode[] modelNodes = getNodesArray(model); + List listOfNodes = new ArrayList(); + for (int i = 0; i < modelNodes.length; i++) { + listOfNodes.add(modelNodes[i]); + } + + for (int i = 0; i < listOfNodes.size(); i++) { + GraphNode node = (GraphNode) listOfNodes.get(i); + if (node instanceof GraphContainer) { + List childNodes = ((GraphContainer) node).getNodes(); + listOfNodes.addAll(childNodes); + } + } + modelNodes = (GraphNode[]) listOfNodes + .toArray(new GraphNode[listOfNodes.size()]); + + IGraphEntityRelationshipContentProvider content = getCastedContent(); + for (int i = 0; i < modelNodes.length; i++) { + for (int j = 0; j < modelNodes.length; j++) { + Object[] rels = content.getRelationships(modelNodes[i] + .getData(), modelNodes[j].getData()); + if (rels != null) { + rels = filter(getViewer().getInput(), rels); + for (int r = 0; r < rels.length; r++) { + createConnection(model, rels[r], modelNodes[i] + .getData(), modelNodes[j].getData()); + } + } + } + } + } + + /** + * Creates the model nodes for the given external nodes. + * + * @param model + * the graph model. + * @param nodes + * the external nodes. + */ + private void createModelNodes(Graph model, Object[] nodes) { + for (int i = 0; i < nodes.length; i++) { + createNode(model, nodes[i]); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh + * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object) + */ + public void refresh(Graph graph, Object element) { + refresh(graph, element, false); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh + * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object, + * boolean) + */ + public void refresh(Graph graph, Object element, boolean updateLabels) { + // with this kind of graph, it is just as easy and cost-effective to + // rebuild the whole thing. + refreshGraph(graph); + } + + private IGraphEntityRelationshipContentProvider getCastedContent() { + return (IGraphEntityRelationshipContentProvider) getContentProvider(); + } + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphModelFactory.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphModelFactory.java new file mode 100644 index 0000000..a44c678 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphModelFactory.java @@ -0,0 +1,181 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers.internal; + +import java.util.Iterator; +import java.util.List; + +import org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer; +import org.eclipse.zest.core.viewers.IFigureProvider; +import org.eclipse.zest.core.viewers.IGraphContentProvider; +import org.eclipse.zest.core.widgets.Graph; +import org.eclipse.zest.core.widgets.GraphConnection; +import org.eclipse.zest.core.widgets.GraphNode; + +/** + * This factory helps make models (nodes & connections). + * + * @author Ian Bull + * @author Chris Callendar + */ +public class GraphModelFactory extends AbstractStylingModelFactory { + + AbstractStructuredGraphViewer viewer = null; + + public GraphModelFactory(AbstractStructuredGraphViewer viewer) { + super(viewer); + this.viewer = viewer; + } + + /* + * (non-Javadoc) + * + * @see ca.uvic.cs.zest.internal.graphmodel.IGraphModelFactory#createModel() + */ + public Graph createGraphModel(Graph model) { + doBuildGraph(model); + return model; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory + * #doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel) + */ + protected void doBuildGraph(Graph model) { + super.doBuildGraph(model); + // make the model have the same styles as the viewer + Object rels[] = getContentProvider() + .getElements(getViewer().getInput()); + if (rels != null) { + IFigureProvider figureProvider = null; + if (getLabelProvider() instanceof IFigureProvider) { + figureProvider = (IFigureProvider) getLabelProvider(); + } + + // If rels returns null then just continue + // @tag zest(bug(134928(fix))) : An empty graph causes an NPE + for (int i = 0; i < rels.length; i++) { + // Check the filter on the source + Object source = getCastedContent().getSource(rels[i]); + source = filterElement(getViewer().getInput(), source) ? null + : source; + + // Check hte filter on the dest + Object dest = getCastedContent().getDestination(rels[i]); + dest = filterElement(getViewer().getInput(), dest) ? null + : dest; + + if (source == null) { + // just create the node for the destination + if (dest != null) { + if (figureProvider != null) { + createNode(model, dest, figureProvider + .getFigure(dest)); + } else { + createNode(model, dest); + } + } + continue; + } else if (dest == null) { + // just create the node for the source + if (source != null) { + if (figureProvider != null) { + createNode(model, source, figureProvider + .getFigure(dest)); + } else { + createNode(model, source); + } + } + continue; + } + // If any of the source, dest is null or the edge is filtered, + // don't create the graph. + if (source != null && dest != null + && !filterElement(getViewer().getInput(), rels[i])) { + createConnection(model, rels[i], getCastedContent() + .getSource(rels[i]), getCastedContent() + .getDestination(rels[i])); + } + } + } + + } + + private IGraphContentProvider getCastedContent() { + return (IGraphContentProvider) getContentProvider(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh + * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object) + */ + public void refresh(Graph graph, Object element) { + refresh(graph, element, false); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh + * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object, + * boolean) + */ + public void refresh(Graph graph, Object element, boolean updateLabels) { + GraphConnection conn = viewer.getGraphModelConnection(element); + if (conn == null) { + // did the user send us a node? Check all of the connections on the + // node. + GraphNode node = viewer.getGraphModelNode(element); + if (node != null) { + List connections = node.getSourceConnections(); + for (Iterator it = connections.iterator(); it.hasNext();) { + GraphConnection c = (GraphConnection) it.next(); + refresh(graph, c.getExternalConnection(), updateLabels); + } + connections = node.getTargetConnections(); + for (Iterator it = connections.iterator(); it.hasNext();) { + GraphConnection c = (GraphConnection) it.next(); + refresh(graph, c.getExternalConnection(), updateLabels); + } + } + return; + } + Object oldSource = conn.getSource().getData(); + Object oldDest = conn.getDestination().getData(); + Object newSource = getCastedContent().getSource(element); + Object newDest = getCastedContent().getDestination(element); + if (!(oldSource.equals(newSource) && oldDest.equals(newDest))) { + GraphNode internalSource = viewer.getGraphModelNode(newSource); + GraphNode internalDest = viewer.getGraphModelNode(newDest); + if (internalSource == null) { + internalSource = createNode(graph, newSource); + } else if (updateLabels) { + styleItem(internalSource); + } + if (internalDest == null) { + internalDest = createNode(graph, newDest); + } else if (updateLabels) { + styleItem(internalDest); + } + if (updateLabels) { + styleItem(conn); + } + } + + } + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/IStylingGraphModelFactory.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/IStylingGraphModelFactory.java new file mode 100644 index 0000000..cafb8bb --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/IStylingGraphModelFactory.java @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright 2005-2010, 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.viewers.internal; + +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.StructuredViewer; +import org.eclipse.zest.core.widgets.Graph; +import org.eclipse.zest.core.widgets.GraphConnection; +import org.eclipse.zest.core.widgets.GraphItem; +import org.eclipse.zest.core.widgets.GraphNode; + +/** + * A Graph model factory that supports the structural and visual refreshing of + * graph elements based on the content provider and label provider in the viewer + * that this factory is associated with. Model elements are created using the + * content provider supplied by getContentProvider(), and styled using the label + * provider supplied by getLabelProvider(). By the end of creation and + * refreshing, the graph model elements are expected to be styled according to + * the given label provider, however, default styles are dependant on the + * particular implementation of IStylingGraphModelFactory. Unless otherwise + * documented, clients should expect that the implementation of + * IStylingGraphModelFactory adheres to the general defaults found in + * {@link IZestGraphDefaults}. + * + * @author Del Myers + */ + +public interface IStylingGraphModelFactory { + /** + * Returns the label provider used in this factory. + * + * @return the label provider used in this factory. + */ + public IBaseLabelProvider getLabelProvider(); + + /** + * Returns the content provider used in this factory. + * + * @return the content provider used in this factory. + */ + public IStructuredContentProvider getContentProvider(); + + /** + * Creates and returns the graph model from this factory based on the label + * provider and the label provider returned in getContentProvider() and + * getLabelProvider(). + * + * @return the created graph model. + */ + public Graph createGraphModel(Graph model); + + /** + * Creates and returns a node on the given graph based on the user model + * data, "data", using the content provider returned by + * getContentProvider(). They node will also be styled according to the + * information given by the label provider. If the node already exists in + * the graph, it is restyled and returned; no new node is created. + * + * @param graph + * the graph to create or retrieve the node on. + * @param element + * the user model data to use in the node. + * @return the node created or retrieved for the given graph. + */ + public GraphNode createNode(Graph graph, Object element); + + /** + * Creates and returns a connection with the given source and destination + * objects from the user model. If the source and destination nodes don't + * exist for the given user model objects, they are created using + * createNode(GraphModel, Object). If a connection already exists for the + * given user data, but with different source or destinations, it is + * disconnected and reconnected to the given source and destination. It is + * always styled according to the label provider provided by + * getLabelProvider(). + * + * @param graph + * the graph to create or retrieve the connection on. + * @param element + * the user model data to use in this connection. + * @param source + * the user model data used for the source node. + * @param dest + * the user model data used for the destination node. + * @return the created or retrieved connection for the given graph. + */ + public GraphConnection createConnection(Graph graph, Object element, + Object source, Object dest); + + /** + * Restyles the given graph items according to the label provider supplied + * by getLabelProvider(). + * + * @param items + * the items to update. + */ + public void update(GraphItem[] items); + + /** + * Restyles the given graph item according to the label provider supplied by + * getLabelProvider(). + * + * @param item + * the item to update. + */ + public void update(GraphItem item); + + /** + * Structurally refreshes the graph model nodes and connections associated + * with the given user model element. Does nothing if the element does not + * currently exist in the view. No restyling is done by default. + * + * @param graph + * @param element + * the element to restructure. + */ + public void refresh(Graph graph, Object element); + + /** + * Structurally refreshes the graph model nodes and connections associated + * with the given user model element. If updateLabels is true, then the + * labels are updated as well. Does nothing if the element does not + * currently exist in the view. + * + * @param graph + * the graph to find the element on. + * @param element + * the user model element. + * @param updateLabels + * true if the labels should be updated as well. + */ + public void refresh(Graph graph, Object element, boolean updateLabels); + + /** + * Structurally refreshes the entire graph. + * + * @param graph + * the graph to refresh; + */ + public void refreshGraph(Graph graph); + + /** + * Returns the viewer that this factory is building the model for. + * + * @return the viewer that this factory is building the model for. + */ + public StructuredViewer getViewer(); + + public void setConnectionStyle(int style); + + /** + * @return the connectionStyle + */ + public int getConnectionStyle(); + + public void setNodeStyle(int style); + + /** + * @return the nodeStyle + */ + public int getNodeStyle(); + +} diff --git a/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/SharedMessages.java b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/SharedMessages.java new file mode 100644 index 0000000..9d4f2e5 --- a/dev/null +++ b/org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/SharedMessages.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2003, 2005-2010 IBM Corporation 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: IBM Corporation - initial API and implementation + ******************************************************************************/ +package org.eclipse.zest.core.viewers.internal; + +/** + * This class contains UI strings (translated, if available) that clients can + * use. + * + * @author Eric Bordeau + */ +public class SharedMessages { + + /** + * The string "Page". + */ + public static String FitAllAction_Label = "Page"; // GEFMessages.FitAllAction_Label; + /** + * The string "Width". + */ + public static String FitWidthAction_Label = "Width"; // GEFMessages.FitWidthAction_Label; + /** + * The string "Height". + */ + public static String FitHeightAction_Label = "Height"; // GEFMessages.FitHeightAction_Label; + +} |

