summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Bull2010-12-03 01:21:14 (EST)
committer Fabian Steeg2010-12-03 01:21:14 (EST)
commita0a02493b0af245b6ae73f7c5903fc9f297063ec (patch)
treea23b0ded1e95730677abd6d54f78c57f40206d24
parenteea63f32345a97afce2c6b8b9bf1a924f2836ce7 (diff)
downloadorg.eclipse.gef4-a0a02493b0af245b6ae73f7c5903fc9f297063ec.zip
org.eclipse.gef4-a0a02493b0af245b6ae73f7c5903fc9f297063ec.tar.gz
org.eclipse.gef4-a0a02493b0af245b6ae73f7c5903fc9f297063ec.tar.bz2
Added the jface bundle
-rw-r--r--org.eclipse.zest.jface/.classpath7
-rw-r--r--org.eclipse.zest.jface/.project28
-rw-r--r--org.eclipse.zest.jface/.settings/org.eclipse.jdt.core.prefs8
-rw-r--r--org.eclipse.zest.jface/META-INF/MANIFEST.MF12
-rw-r--r--org.eclipse.zest.jface/build.properties4
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/AbstractStructuredGraphViewer.java801
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/AbstractZoomableViewer.java43
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/EntityConnectionData.java61
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/GraphViewer.java380
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IConnectionStyleBezierExtension.java76
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IConnectionStyleProvider.java79
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IEntityConnectionStyleBezierExtension.java84
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IEntityConnectionStyleProvider.java86
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IEntityStyleProvider.java131
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IFigureProvider.java25
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IGraphContentProvider.java58
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IGraphEntityContentProvider.java32
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IGraphEntityRelationshipContentProvider.java39
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/INestedContentProvider.java43
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ISelfStyleProvider.java32
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/IZoomableWorkbenchPart.java28
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ZoomContributionViewItem.java247
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ZoomListener.java27
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/ZoomManager.java611
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java430
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphItemStyler.java279
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphModelEntityFactory.java229
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphModelEntityRelationshipFactory.java152
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/GraphModelFactory.java181
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/IStylingGraphModelFactory.java172
-rw-r--r--org.eclipse.zest.jface/src/org/eclipse/zest/core/viewers/internal/SharedMessages.java32
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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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;
+
+}