Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 145959 Details for
Bug 277534
[tree] Add Space Tree support to Graph widget
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read
this important communication.
[patch]
collective patch
ultimate-patch-01.txt (text/plain), 1.03 MB, created by
Mateusz Matela
on 2009-08-28 12:37:09 EDT
(
hide
)
Description:
collective patch
Filename:
MIME Type:
Creator:
Mateusz Matela
Created:
2009-08-28 12:37:09 EDT
Size:
1.03 MB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.zest >Index: META-INF/MANIFEST.MF >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest/META-INF/MANIFEST.MF,v >retrieving revision 1.1 >diff -u -r1.1 MANIFEST.MF >--- META-INF/MANIFEST.MF 17 Dec 2008 21:33:26 -0000 1.1 >+++ META-INF/MANIFEST.MF 28 Aug 2009 16:03:01 -0000 >@@ -2,5 +2,5 @@ > Bundle-ManifestVersion: 2 > Bundle-Name: Zest Plug-in > Bundle-SymbolicName: org.eclipse.zest >-Bundle-Version: 1.0.0 >+Bundle-Version: 2.0.0 > Bundle-RequiredExecutionEnvironment: J2SE-1.4 >#P org.eclipse.zest.layouts >Index: src/org/eclipse/zest/layouts/algorithms/ContinuousLayoutAlgorithm.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/ContinuousLayoutAlgorithm.java >diff -N src/org/eclipse/zest/layouts/algorithms/ContinuousLayoutAlgorithm.java >--- src/org/eclipse/zest/layouts/algorithms/ContinuousLayoutAlgorithm.java 12 Sep 2007 20:44:37 -0000 1.10 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,102 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.algorithms; >- >-import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >-import org.eclipse.zest.layouts.dataStructures.InternalNode; >-import org.eclipse.zest.layouts.dataStructures.InternalRelationship; >- >-/** >- * >- * @author Ian Bull >- * >- * Used to represent algorithms that can continuously run. >- * >- */ >-public abstract class ContinuousLayoutAlgorithm extends AbstractLayoutAlgorithm { >- >- double x, y, widht, height; >- >- public ContinuousLayoutAlgorithm(int styles) { >- super(styles); >- } >- >- /** >- * The logic to determine if a layout should continue running or not >- */ >- protected abstract boolean performAnotherNonContinuousIteration(); >- >- /** >- * Computes a single iteration of the layout algorithm >- * @return >- */ >- protected abstract void computeOneIteration(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height); >- >- private boolean continueRunning() { >- if (layoutStopped) { >- return false; >- } else if (this.internalContinuous && !layoutStopped) { >- return true; >- } else if (performAnotherNonContinuousIteration()) { >- return true; >- } else { >- return false; >- } >- } >- >- public void setLayoutArea(double x, double y, double width, double height) { >- this.setBounds(x, y, width, height); >- >- } >- >- public synchronized DisplayIndependentRectangle getBounds() { >- return new DisplayIndependentRectangle(this.x, this.y, this.widht, this.height); >- } >- >- public synchronized void setBounds(double x, double y, double width, double height) { >- this.x = x; >- this.y = y; >- this.widht = width; >- this.height = height; >- } >- >- /** >- * Calculates and applies the positions of the given entities based on a >- * spring layout using the given relationships. >- */ >- protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) { >- >- this.setBounds(x, y, width, height); >- >- while (continueRunning()) { >- // check for entities and relationships to add or remove >- entitiesToLayout = updateEntities(entitiesToLayout); >- relationshipsToConsider = updateRelationships(relationshipsToConsider); >- DisplayIndependentRectangle bounds = this.getBounds(); >- double localX = bounds.x; >- double localY = bounds.y; >- double localWidth = bounds.width; >- double localHeight = bounds.height; >- >- computeOneIteration(entitiesToLayout, relationshipsToConsider, localX, localY, localWidth, localHeight); >- >- updateLayoutLocations(entitiesToLayout); >- >- if (this.internalContinuous) { >- fireProgressEvent(1, 1); >- } else { >- fireProgressEvent(getCurrentLayoutStep(), getTotalNumberOfLayoutSteps()); >- } >- >- } >- } >- >-} >Index: src/org/eclipse/zest/layouts/algorithms/GridLayoutAlgorithm.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.layouts/src/org/eclipse/zest/layouts/algorithms/GridLayoutAlgorithm.java,v >retrieving revision 1.7 >diff -u -r1.7 GridLayoutAlgorithm.java >--- src/org/eclipse/zest/layouts/algorithms/GridLayoutAlgorithm.java 12 Sep 2007 20:44:37 -0000 1.7 >+++ src/org/eclipse/zest/layouts/algorithms/GridLayoutAlgorithm.java 28 Aug 2009 16:03:03 -0000 >@@ -1,20 +1,20 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >+ * Copyright (c) 2005-2009 The Chisel Group 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: The Chisel Group - initial API and implementation >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ * Ian Bull >+ ******************************************************************************/ > package org.eclipse.zest.layouts.algorithms; > >-import java.util.Arrays; >- >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.dataStructures.InternalNode; >-import org.eclipse.zest.layouts.dataStructures.InternalRelationship; >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; > > > /** >@@ -22,127 +22,93 @@ > * @author Ian Bull > * @author Casey Best and Rob Lintern > */ >-public class GridLayoutAlgorithm extends AbstractLayoutAlgorithm { >+public class GridLayoutAlgorithm implements LayoutAlgorithm { > > private static final double PADDING_PERCENTAGE = 0.95; >+ private static final int MIN_ENTITY_SIZE = 5; > >+ protected double aspectRatio = 1.0; > protected int rowPadding = 0; >- >- public void setLayoutArea(double x, double y, double width, double height) { >- throw new RuntimeException("Operation not implemented"); >+ private boolean resize = false; >+ protected int rows, cols, numChildren; >+ protected double colWidth, rowHeight, offsetX, offsetY; >+ protected double childrenHeight, childrenWidth; >+ >+ private LayoutContext context; >+ >+ >+ public void setLayoutContext(LayoutContext context) { >+ this.context = context; > } >- >- int rows, cols, numChildren; >- double colWidth, rowHeight, offsetX, offsetY; >- int totalProgress; >- double h, w; > >- /** >- * Initializes the grid layout. >- * @param styles >- * @see LayoutStyles >- */ >- public GridLayoutAlgorithm(int styles) { >- super(styles); >+ public void applyLayout(boolean clean) { >+ if (!clean) >+ return; >+ DisplayIndependentRectangle bounds = context.getBounds(); >+ calculateGrid(bounds); >+ applyLayoutInternal(context.getEntities(), bounds); > } >- >+ > /** >- * Inititalizes the grid layout with no style. >+ * Calculates all the dimensions of grid that layout entities will be fit >+ * in. The following fields are set by this method: {@link #numChildren}, >+ * {@link #rows}, {@link #cols}, {@link #colWidth}, {@link #rowHeight}, >+ * {@link #offsetX}, {@link #offsetY} >+ * >+ * @param bounds > */ >- public GridLayoutAlgorithm() { >- this(LayoutStyles.NONE); >- } >- >- >- protected int getCurrentLayoutStep() { >- // TODO: This isn't right >- return 0; >- } >- >- protected int getTotalNumberOfLayoutSteps() { >- return totalProgress; >- } >- >- /** >- * >- */ >- protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) { >+ protected void calculateGrid(DisplayIndependentRectangle bounds) { >+ numChildren = context.getNodes().length; >+ int[] result = calculateNumberOfRowsAndCols(numChildren, bounds.x, bounds.y, bounds.width, bounds.height); >+ cols = result[0]; >+ rows = result[1]; > >- // TODO: Filter unwanted entities and relationships >- //super.applyLayout (entitiesToLayout, relationshipsToConsider, boundsX, boundsY, boundsWidth, boundsHeight); >- // now begin >- numChildren = entitiesToLayout.length; >- if (numChildren < 1) return; >+ colWidth = bounds.width / cols; >+ rowHeight = bounds.height / rows; > >- int[] colsAndRows = calculateNumberOfRowsAndCols(numChildren, x, y, width, height); >- cols = colsAndRows[0]; >- rows = colsAndRows[1]; >- >- totalProgress = rows + 2; >- fireProgressEvent (1, totalProgress); >- >- // sort the entities >- if (comparator != null) { >- Arrays.sort(entitiesToLayout, comparator); >- } else { >- Arrays.sort(entitiesToLayout); >- } >- fireProgressEvent (2, totalProgress); >- >- // Calculate row height and column width >- colWidth = width/cols; >- rowHeight = height/rows; >- >- // Calculate amount to scale children > double [] nodeSize = calculateNodeSize (colWidth, rowHeight); >- w = nodeSize[0]; >- h = nodeSize[1]; >- offsetX = (colWidth - w)/2.0; // half of the space between columns >- offsetY = (rowHeight - h)/2.0; // half of the space between rows >+ childrenWidth = nodeSize[0]; >+ childrenHeight = nodeSize[1]; >+ offsetX = (colWidth - childrenWidth) / 2.0; // half of the space between >+ // columns >+ offsetY = (rowHeight - childrenHeight) / 2.0; // half of the space >+ // between rows > } >- >+ > /** >- * Use this algorithm to layout the given entities, using the given relationships and bounds. >- * The entities will be placed in the same order as they are passed in, unless a comparator >- * is supplied. >- * >- * @param entitiesToLayout Apply the algorithm to these entities >- * @param relationshipsToConsider Only consider these relationships when applying the algorithm. >- * @param boundsX The left side of the bounds in which the layout can place the entities. >- * @param boundsY The top side of the bounds in which the layout can place the entities. >- * @param boundsWidth The width of the bounds in which the layout can place the entities. >- * @param boundsHeight The height of the bounds in which the layout can place the entities. >- * @throws RuntimeException Thrown if entitiesToLayout doesn't contain all of the endpoints for each relationship in relationshipsToConsider >+ * Use this algorithm to layout the given entities and bounds. The entities >+ * will be placed in the same order as they are passed in, unless a >+ * comparator is supplied. >+ * >+ * @param entitiesToLayout >+ * apply the algorithm to these entities >+ * @param bounds >+ * the bounds in which the layout can place the entities. > */ >- protected synchronized void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY, double boundsWidth, double boundsHeight) { >+ protected synchronized void applyLayoutInternal(EntityLayout[] entitiesToLayout, DisplayIndependentRectangle bounds) { > > int index = 0; > for( int i = 0; i < rows; i++ ) { > for( int j = 0; j < cols; j++ ) { > if( (i*cols + j) < numChildren ) { >- // find new position for child >- double xmove = boundsX + j * colWidth + offsetX; >- double ymove = boundsY + i * rowHeight + offsetY; >- InternalNode sn = entitiesToLayout[index++]; >- sn.setInternalLocation( xmove, ymove ); >- sn.setInternalSize( Math.max(w, MIN_ENTITY_SIZE), Math.max(h, MIN_ENTITY_SIZE) ); >+ EntityLayout node = entitiesToLayout[index++]; >+ if (resize && node.isResizable()) >+ node.setSize(Math.max(childrenWidth, MIN_ENTITY_SIZE), Math.max(childrenHeight, MIN_ENTITY_SIZE)); >+ DisplayIndependentDimension size = node.getSize(); >+ double xmove = bounds.x + j * colWidth + offsetX + size.width / 2; >+ double ymove = bounds.y + i * rowHeight + offsetY + size.height / 2; >+ if (node.isMovable()) >+ node.setLocation(xmove, ymove); > } > } >- fireProgressEvent (2 + i, totalProgress); >- } >- updateLayoutLocations(entitiesToLayout); >- fireProgressEvent (totalProgress, totalProgress); >- } >- >- protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) { >- >+ } > } > > /** > * Calculates and returns an array containing the number of columns, followed by the number of rows > */ >- protected int[] calculateNumberOfRowsAndCols (int numChildren, double boundX, double boundY, double boundWidth, double boundHeight) { >- if (getEntityAspectRatio() == 1.0) { >+ protected int[] calculateNumberOfRowsAndCols(int numChildren, double boundX, double boundY, double boundWidth, double boundHeight) { >+ if (aspectRatio == 1.0) { > return calculateNumberOfRowsAndCols_square (numChildren, boundX, boundY, boundWidth, boundHeight); > } else { > return calculateNumberOfRowsAndCols_rectangular (numChildren); >@@ -201,33 +167,56 @@ > double childW = Math.max (MIN_ENTITY_SIZE, PADDING_PERCENTAGE*colWidth); > double childH = Math.max (MIN_ENTITY_SIZE, PADDING_PERCENTAGE*(rowHeight - rowPadding)); > double whRatio = colWidth/rowHeight; >- if (whRatio < getEntityAspectRatio()) { >- childH = childW/getEntityAspectRatio(); >+ if (whRatio < aspectRatio) { >+ childH = childW / aspectRatio; > } else { >- childW = childH*getEntityAspectRatio(); >+ childW = childH * aspectRatio; > } > double [] result = {childW, childH}; > return result; > } >- >+ > /** >- * Increases the padding between rows in the grid >- * @param rowPadding Value will not be set if less than 0. >+ * Sets the padding between rows in the grid >+ * >+ * @param rowPadding >+ * padding - should be greater than or equal to 0 > */ > public void setRowPadding(int rowPadding) { >- if (rowPadding < 0 ) { >- return; >+ if (rowPadding >= 0) { >+ this.rowPadding = rowPadding; > } >- this.rowPadding = rowPadding; > } > >- protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) { >- if ( asynchronous && continueous ) return false; >- else if ( asynchronous && !continueous ) return true; >- else if ( !asynchronous && continueous ) return false; >- else if ( !asynchronous && !continueous ) return true; >- >- return false; >+ /** >+ * Sets the preferred aspect ratio for layout entities. The default aspect >+ * ratio is 1. >+ * >+ * @param aspectRatio >+ * aspect ratio - should be greater than 0 >+ */ >+ public void setAspectRatio(double aspectRatio) { >+ if (aspectRatio > 0) { >+ this.aspectRatio = aspectRatio; >+ } >+ } >+ >+ /** >+ * >+ * @return true if this algorithm is set to resize elements >+ */ >+ public boolean isResizing() { >+ return resize; >+ } >+ >+ /** >+ * >+ * @param resizing >+ * true if this algorithm should resize elements (default is >+ * false) >+ */ >+ public void setResizing(boolean resizing) { >+ resize = resizing; > } > > } >Index: src/org/eclipse/zest/layouts/algorithms/HorizontalTreeLayoutAlgorithm.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/HorizontalTreeLayoutAlgorithm.java >diff -N src/org/eclipse/zest/layouts/algorithms/HorizontalTreeLayoutAlgorithm.java >--- src/org/eclipse/zest/layouts/algorithms/HorizontalTreeLayoutAlgorithm.java 12 Sep 2007 20:44:37 -0000 1.5 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,68 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.algorithms; >- >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.dataStructures.InternalNode; >-import org.eclipse.zest.layouts.dataStructures.InternalRelationship; >- >- >- >- >-/** >- * A simple algorithm to arrange graph nodes in a layered horizontal tree-like layout. >- * @see TreeLayoutAlgorithm >- * >- * @version 1.0 >- * @author Rob Lintern >- */ >-public class HorizontalTreeLayoutAlgorithm extends TreeLayoutAlgorithm { >- >- >- /** >- * Creates a horizontal tree layout with no style >- */ >- public HorizontalTreeLayoutAlgorithm() { >- this( LayoutStyles.NONE ); >- } >- >- /** >- * >- */ >- public HorizontalTreeLayoutAlgorithm( int styles ) { >- super( styles ); >- } >- >- protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) { >- // NOTE: width and height are swtiched here when calling super method >- super.preLayoutAlgorithm(entitiesToLayout, relationshipsToConsider, x, y, height, width); >- } >- >- protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) { >- // swap x->y and width->height >- for (int i = 0; i < entitiesToLayout.length; i++) { >- InternalNode entity = entitiesToLayout[i]; >- entity.setInternalLocation(entity.getInternalY(), entity.getInternalX() ); >- entity.setInternalSize( entity.getInternalWidth(), entity.getInternalHeight() ); >- } >- super.postLayoutAlgorithm(entitiesToLayout, relationshipsToConsider); >- } >- >- protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) { >- if ( asynchronous && continueous ) return false; >- else if ( asynchronous && !continueous ) return true; >- else if ( !asynchronous && continueous ) return false; >- else if ( !asynchronous && !continueous ) return true; >- >- return false; >- } >- >-} >Index: src/org/eclipse/zest/layouts/algorithms/SpringLayoutAlgorithm.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.layouts/src/org/eclipse/zest/layouts/algorithms/SpringLayoutAlgorithm.java,v >retrieving revision 1.12 >diff -u -r1.12 SpringLayoutAlgorithm.java >--- src/org/eclipse/zest/layouts/algorithms/SpringLayoutAlgorithm.java 12 Sep 2007 20:44:37 -0000 1.12 >+++ src/org/eclipse/zest/layouts/algorithms/SpringLayoutAlgorithm.java 28 Aug 2009 16:03:04 -0000 >@@ -1,23 +1,27 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >+ * Copyright (c) 2005-2009 The Chisel Group 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: The Chisel Group - initial API and implementation >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ * Ian Bull >+ ******************************************************************************/ > package org.eclipse.zest.layouts.algorithms; > >-import java.util.Date; > import java.util.HashMap; >-import java.util.Map; > >-import org.eclipse.zest.layouts.LayoutStyles; >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint; > import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >-import org.eclipse.zest.layouts.dataStructures.InternalNode; >-import org.eclipse.zest.layouts.dataStructures.InternalRelationship; >+import org.eclipse.zest.layouts.interfaces.ConnectionLayout; >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+import org.eclipse.zest.layouts.interfaces.LayoutListener; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+import org.eclipse.zest.layouts.interfaces.SubgraphLayout; > > /** > * The SpringLayoutAlgorithm has its own data repository and relation >@@ -37,9 +41,7 @@ > * @author Ian Bull > * @author Casey Best (version 1.0 by Jingwei Wu/Rob Lintern) > */ >-public class SpringLayoutAlgorithm extends ContinuousLayoutAlgorithm { >- >- private final static boolean DEFAULT_ANCHOR = false; >+public class SpringLayoutAlgorithm implements LayoutAlgorithm { > > /** > * The default value for the spring layout number of interations. >@@ -57,16 +59,6 @@ > public static final boolean DEFAULT_SPRING_RANDOM = true; > > /** >- * The default value for ignoring unconnected nodes. >- */ >- public static final boolean DEFAULT_SPRING_IGNORE_UNCON = true; >- >- /** >- * The default value for separating connected components. >- */ >- public static final boolean DEFAULT_SPRING_SEPARATE_COMPONENTS = true; >- >- /** > * The default value for the spring layout move-control. > */ > public static final double DEFAULT_SPRING_MOVE = 1.0f; >@@ -74,7 +66,7 @@ > /** > * The default value for the spring layout strain-control. > */ >- public static final double DEFAULT_SPRING_STRAIN = 1.0f; >+ public static final double DEFAULT_SPRING_STRAIN = 1.0f; > > /** > * The default value for the spring layout length-control. >@@ -84,129 +76,161 @@ > /** > * The default value for the spring layout gravitation-control. > */ >- public static final double DEFAULT_SPRING_GRAVITATION = 1.0f; >+ public static final double DEFAULT_SPRING_GRAVITATION = 1.0f; > >- /** >- * The variable can be customized to set the number of iterations used. >- */ >- private static int sprIterations = DEFAULT_SPRING_ITERATIONS; >+ /** >+ * Minimum distance considered between nodes >+ */ >+ protected static final double MIN_DISTANCE = 0.001d; >+ >+ /** >+ * An arbitrarily small value in mathematics. >+ */ >+ protected static final double EPSILON = 0.001d; >+ >+ /** >+ * The variable can be customized to set the number of iterations used. >+ */ >+ private int sprIterations = DEFAULT_SPRING_ITERATIONS; > > /** > * This variable can be customized to set the max number of MS the algorithm > * should run > */ >- private static long maxTimeMS = MAX_SPRING_TIME; >+ private long maxTimeMS = MAX_SPRING_TIME; > > /** > * The variable can be customized to set whether or not the spring layout > * nodes are positioned randomly before beginning iterations. > */ >- private static boolean sprRandom = DEFAULT_SPRING_RANDOM; >- >- /** >- * Minimum distance considered between nodes >- */ >- protected static final double MIN_DISTANCE = 0.001d; >- >- /** >- * An arbitrarily small value in mathematics. >- */ >- protected static final double EPSILON = 0.001d; >+ private boolean sprRandom = DEFAULT_SPRING_RANDOM; > >- /** >- * The variable can be customerized to set the spring layout move-control. >- */ >- private static double sprMove = DEFAULT_SPRING_MOVE; >+ /** >+ * The variable can be customized to set the spring layout move-control. >+ */ >+ private double sprMove = DEFAULT_SPRING_MOVE; > > /** > * The variable can be customized to set the spring layout strain-control. > */ >- private static double sprStrain = DEFAULT_SPRING_STRAIN; >+ private double sprStrain = DEFAULT_SPRING_STRAIN; > > /** > * The variable can be customized to set the spring layout length-control. > */ >- private static double sprLength = DEFAULT_SPRING_LENGTH; >+ private double sprLength = DEFAULT_SPRING_LENGTH; > > /** > * The variable can be customized to set the spring layout > * gravitation-control. > */ >- private static double sprGravitation = DEFAULT_SPRING_GRAVITATION; >+ private double sprGravitation = DEFAULT_SPRING_GRAVITATION; > >- /** >- * The largest movement of all vertices that has occured in the most recent >- * iteration. >- */ >- private double largestMovement = 0; >+ /** >+ * Variable indicating whether the algorithm should resize elements. >+ */ >+ private boolean resize = false; > >+ private int iteration; > >- /** >- * Maps a src and dest object to the number of relations between them. Key >- * is src.toString() + dest.toString(), value is an Integer >- */ >- private Map srcDestToNumRelsMap; >+ private double[][] srcDestToSumOfWeights; > >- /** >- * Maps a src and dest object to the average weight of the relations between >- * them. Key is src.toString() + dest.toString(), value is a Double >- */ >- private Map srcDestToRelsAvgWeightMap; >+ private EntityLayout[] entities; > >- /** >- * Maps a relationship type to a weight. Key is a string, value is a Double >- */ >- private static Map relTypeToWeightMap = new HashMap(); >+ private double[] forcesX, forcesY; > >- private int iteration; >+ private double[] locationsX, locationsY; > >- private int[][] srcDestToNumRels; >+ private double[] sizeW, sizeH; > >- private double[][] srcDestToRelsAvgWeight; >+ private DisplayIndependentRectangle bounds; > >- private double[] tempLocationsX; >+ private double boundsScale = 0.2; > >- private double[] tempLocationsY; >+ private LayoutContext context; > >- private double[] forcesX; >+ private LayoutListener springLayoutListener = new LayoutListener() { > >- private double[] forcesY; >+ public boolean entityMoved(LayoutContext context, EntityLayout entity) { >+ updateLocation(entity); >+ return false; >+ } > >- private boolean[] anchors; >- >- private DisplayIndependentRectangle bounds = null; >- >- Date date = null; >+ public boolean entityResized(LayoutContext context, EntityLayout entity) { >+ updateLocation(entity); >+ return false; >+ } > >- /** >- * Constructor. >- */ >- public SpringLayoutAlgorithm( int styles ) { >- super( styles ); >- srcDestToNumRelsMap = new HashMap(); >- srcDestToRelsAvgWeightMap = new HashMap(); >- date = new Date(); >- } >+ private void updateLocation(EntityLayout entity) { >+ if (entities != null) { >+ for (int i = 0; i < entities.length; i++) { >+ if (entities[i] == entity) { >+ locationsX[i] = entities[i].getLocation().x; >+ locationsY[i] = entities[i].getLocation().y; >+ } >+ } >+ } >+ } >+ }; > >- >- /** >- * Creates a sprint layout algoirthm with no style >- * >- */ >- public SpringLayoutAlgorithm() { >- this( LayoutStyles.NONE ); >+ public void applyLayout(boolean clean) { >+ if (!clean) >+ return; >+ >+ initLayout(); >+ while (performAnotherNonContinuousIteration()) { >+ computeOneIteration(); >+ } >+ saveLocations(); >+ if (resize) >+ AlgorithmHelper.maximizeSizes(entities); >+ >+ DisplayIndependentRectangle bounds2 = new DisplayIndependentRectangle(bounds); >+ AlgorithmHelper.fitWithinBounds(entities, bounds2, resize); > } > >- public void setLayoutArea(double x, double y, double width, double height) { >- bounds = new DisplayIndependentRectangle(x,y,width,height); >- } >+ public void setLayoutContext(LayoutContext context) { >+ if (this.context != null) { >+ this.context.removeLayoutListener(springLayoutListener); >+ } >+ this.context = context; >+ this.context.addLayoutListener(springLayoutListener); >+ } > >- /** >- * Sets the spring layout move-control. >- * >- * @param move >- * The move-control value. >- */ >+ public void performOneIteration() { >+ if (entities == null) { >+ initLayout(); >+ } >+ bounds = context.getBounds(); >+ computeOneIteration(); >+ saveLocations(); >+ context.flushChanges(false); >+ } >+ >+ /** >+ * >+ * @return true if this algorithm is set to resize elements >+ */ >+ public boolean isResizing() { >+ return resize; >+ } >+ >+ /** >+ * >+ * @param resizing >+ * true if this algorithm should resize elements (default is >+ * false) >+ */ >+ public void setResizing(boolean resizing) { >+ resize = resizing; >+ } >+ >+ /** >+ * Sets the spring layout move-control. >+ * >+ * @param move >+ * The move-control value. >+ */ > public void setSpringMove(double move) { > sprMove = move; > } >@@ -337,192 +361,78 @@ > return sprRandom; > } > >- public void setWeight(String relType, double weight) { >- relTypeToWeightMap.put(relType, new Double(weight)); >- } >- >- public double getWeight(String relType) { >- Double weight = (Double) relTypeToWeightMap.get(relType); >- return (weight == null) ? 1 : weight.doubleValue(); >- } >- >- /** >- * Sets the default conditions. >- */ >- public void setDefaultConditions() { >- // sprMove = DEFAULT_SPRING_MOVE; >- // sprStrain = DEFAULT_SPRING_STRAIN; >- // sprLength = DEFAULT_SPRING_LENGTH; >- // sprGravitation = DEFAULT_SPRING_GRAVITATION; >- // sprIterations = DEFAULT_SPRING_ITERATIONS; >- } >- >- /** >- * Clean up after done >- * >- * @param entitiesToLayout >- */ >- private void reset(InternalNode[] entitiesToLayout) { >- tempLocationsX = null; >- tempLocationsY = null; >- forcesX = null; >- forcesY = null; >- anchors = null; >- setDefaultConditions(); >- srcDestToNumRelsMap = new HashMap(); >- srcDestToRelsAvgWeightMap = new HashMap(); >- relTypeToWeightMap = new HashMap(); >- } >- > private long startTime = 0; > >- protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) { >- // TODO: Filter out any non-wanted entities and relationships >- // super.applyLayout(entitiesToLayout, relationshipsToConsider, x, y, >- // width, height); >- //InternalNode[] a_entitiesToLayout = (InternalNode[]) entitiesToLayout.toArray(new InternalNode[entitiesToLayout.size()]); >- bounds = new DisplayIndependentRectangle(x,y,width,height); >- tempLocationsX = new double[entitiesToLayout.length]; >- tempLocationsY = new double[entitiesToLayout.length]; >- forcesX = new double[entitiesToLayout.length]; >- forcesY = new double[entitiesToLayout.length]; >- anchors = new boolean[entitiesToLayout.length]; >- >- for (int i = 0; i < entitiesToLayout.length; i++) { >- anchors[i] = DEFAULT_ANCHOR; >- } >- for (int i = 0; i < relationshipsToConsider.length; i++) { >- InternalRelationship layoutRelationship = relationshipsToConsider[i]; >- addRelation(layoutRelationship); >- } >- >- // do the calculations >- preCompute(entitiesToLayout); >- startTime = date.getTime(); >- } >- >- protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) { >- reset(entitiesToLayout); >- } >- >- /** >- * Adds a simple relation between two nodes to the relation repository. >- * >- * @param layoutRelationship >- * The simple relation to be added >- * @throws java.lang.NullPointerExcetption >- * If <code>sr</code> is null >- * @see SimpleRelation >- */ >- private void addRelation(InternalRelationship layoutRelationship) { >- if (layoutRelationship == null) { >- throw new IllegalArgumentException("The arguments can not be null!"); >- } else { >- double weight = layoutRelationship.getWeight(); >- weight = (weight <= 0 ? 0.1 : weight); >- String key1 = layoutRelationship.getSource().toString() + layoutRelationship.getDestination().toString(); >- String key2 = layoutRelationship.getDestination().toString() + layoutRelationship.getSource().toString(); >- String[] keys = { key1, key2 }; >- for (int i = 0; i < keys.length; i++) { >- String key = keys[i]; >- Integer count = (Integer) srcDestToNumRelsMap.get(key); >- Double avgWeight = (Double) srcDestToRelsAvgWeightMap.get(key); >- if (count == null) { >- count = new Integer(1); >- avgWeight = new Double(weight); >- } else { >- int newCount = count.intValue() + 1; >- double newAverage = (avgWeight.doubleValue() * count.doubleValue() + weight) / newCount; >- avgWeight = new Double(newAverage); >- count = new Integer(newCount); >- } >- srcDestToNumRelsMap.put(key, count); >- srcDestToRelsAvgWeightMap.put(key, avgWeight); >- } >- } >- } >- >- private void preCompute(InternalNode [] entitiesToLayout) { >- // count number of relationships between all nodes and the average >- // weight between them >- srcDestToNumRels = new int[entitiesToLayout.length][entitiesToLayout.length]; >- srcDestToRelsAvgWeight = new double[entitiesToLayout.length][entitiesToLayout.length]; >- >- for (int i = 0; i < entitiesToLayout.length - 1; i++) { >- InternalNode layoutEntity1 = entitiesToLayout[i]; >- for (int j = i + 1; j < entitiesToLayout.length; j++) { >- InternalNode layoutEntity2 = entitiesToLayout[j]; >- srcDestToNumRels[i][j] = numRelations(layoutEntity1, layoutEntity2); >- srcDestToNumRels[i][j] += numRelations(layoutEntity2, layoutEntity1); >- srcDestToRelsAvgWeight[i][j] = avgWeight(layoutEntity1, layoutEntity2); >- } >- } >+ private void initLayout() { >+ entities = context.getEntities(); >+ bounds = context.getBounds(); >+ loadLocations(); >+ >+ srcDestToSumOfWeights = new double[entities.length][entities.length]; >+ HashMap entityToPosition = new HashMap(); >+ for (int i = 0; i < entities.length; i++) { >+ entityToPosition.put(entities[i], new Integer(i)); >+ } >+ >+ ConnectionLayout[] connections = context.getConnections(); >+ for (int i = 0; i < connections.length; i++) { >+ ConnectionLayout connection = connections[i]; >+ Integer source = (Integer) entityToPosition.get(getEntity(connection.getSource())); >+ Integer target = (Integer) entityToPosition.get(getEntity(connection.getTarget())); >+ if (source == null || target == null) >+ continue; >+ double weight = connection.getWeight(); >+ weight = (weight <= 0 ? 0.1 : weight); >+ srcDestToSumOfWeights[source.intValue()][target.intValue()] += weight; >+ srcDestToSumOfWeights[target.intValue()][source.intValue()] += weight; >+ } > > if (sprRandom) >- placeRandomly(entitiesToLayout); // put vertices in random places >- else >- convertToUnitCoordinates(entitiesToLayout); >+ placeRandomly(); // put vertices in random places > > iteration = 1; >- largestMovement = Double.MAX_VALUE; >- } > >- // TODO: This is a complete Clone! (and not in a good way) >- protected DisplayIndependentRectangle getLayoutBoundsTemp(InternalNode [] entitiesToLayout, boolean includeNodeSize) { >- double rightSide = Double.MIN_VALUE; >- double bottomSide = Double.MIN_VALUE; >- double leftSide = Double.MAX_VALUE; >- double topSide = Double.MAX_VALUE; >- for (int i = 0; i < entitiesToLayout.length; i++) { >- double x = tempLocationsX[i]; >- double y = tempLocationsY[i]; >- >- leftSide = Math.min(x, leftSide); >- topSide = Math.min(y, topSide); >- rightSide = Math.max(x, rightSide); >- bottomSide = Math.max(y, bottomSide); >- >- } >- return new DisplayIndependentRectangle(leftSide, topSide, rightSide - leftSide, bottomSide - topSide); >+ startTime = System.currentTimeMillis(); > } > >- protected void convertNodePositionsBack(int i, InternalNode entityToConvert, double px, double py, double screenWidth, double screenHeight, DisplayIndependentRectangle layoutBounds) { >- >- // If the node selected is outside the screen, map it to the boarder >- if ( px > screenWidth ) px = screenWidth; >- if ( py > screenHeight ) py = screenHeight; >- >- if ( px < 0 ) px = 1; >- if ( py < 0 ) py = 1; >- >- double x = (px / screenWidth) * layoutBounds.width + layoutBounds.x; >- double y = (py / screenHeight) * layoutBounds.height + layoutBounds.y; >- >- tempLocationsX[i] = x; >- tempLocationsY[i] = y; >- //setTempLocation(entityToConvert, new DisplayIndependentPoint(x, y)); >- >- if (entityToConvert.getInternalX() < 0) { >- // System.out.println("We have nodes less than 0 here!"); >- } >+ private EntityLayout getEntity(NodeLayout node) { >+ if (!node.isPruned()) >+ return node; >+ SubgraphLayout subgraph = node.getSubgraph(); >+ if (subgraph.isGraphEntity()) >+ return subgraph; >+ return null; >+ } > >- } >+ private void loadLocations() { >+ if (locationsX == null || locationsX.length != entities.length) { >+ int length = entities.length; >+ locationsX = new double[length]; >+ locationsY = new double[length]; >+ sizeW = new double[length]; >+ sizeH = new double[length]; >+ forcesX = new double[length]; >+ forcesY = new double[length]; >+ } >+ for (int i = 0; i < entities.length; i++) { >+ DisplayIndependentPoint location = entities[i].getLocation(); >+ locationsX[i] = location.x; >+ locationsY[i] = location.y; >+ DisplayIndependentDimension size = entities[i].getSize(); >+ sizeW[i] = size.width; >+ sizeH[i] = size.height; >+ } >+ } > >- private void checkPreferredLocation(InternalNode [] entitiesToLayout, DisplayIndependentRectangle realBounds) { >- // use 10% for the border - 5% on each side >- double borderWidth = Math.min(realBounds.width, realBounds.height) / 10.0; >- DisplayIndependentRectangle screenBounds = new DisplayIndependentRectangle(realBounds.x + borderWidth / 2.0, realBounds.y + borderWidth / 2.0, realBounds.width - borderWidth, realBounds.height - borderWidth); >- >- DisplayIndependentRectangle layoutBounds = getLayoutBoundsTemp(entitiesToLayout, false); >- for (int i = 0; i < entitiesToLayout.length; i++) { >- InternalNode layoutEntity = entitiesToLayout[i]; >- if (layoutEntity.hasPreferredLocation()) { >- convertNodePositionsBack(i, layoutEntity, layoutEntity.getPreferredX(), layoutEntity.getPreferredY(), screenBounds.width, screenBounds.height, layoutBounds); >- } >- } >- } >+ private void saveLocations() { >+ if (entities == null) >+ return; >+ for (int i = 0; i < entities.length; i++) { >+ entities[i].setLocation(locationsX[i], locationsY[i]); >+ } >+ } > >- /** >+ /** > * Scales the current iteration counter based on how long the algorithm has > * been running for. You can set the MaxTime in maxTimeMS! > */ >@@ -530,7 +440,7 @@ > if (maxTimeMS <= 0) > return; > >- long currentTime = date.getTime(); >+ long currentTime = System.currentTimeMillis(); > double fractionComplete = (double) ((double) (currentTime - startTime) / ((double) maxTimeMS)); > int currentIteration = (int) (fractionComplete * sprIterations); > if (currentIteration > iteration) { >@@ -541,10 +451,7 @@ > > protected boolean performAnotherNonContinuousIteration() { > setSprIterationsBasedOnTime(); >- if (iteration <= sprIterations && largestMovement >= sprMove) >- return true; >- else >- return false; >+ return (iteration <= sprIterations); > } > > protected int getCurrentLayoutStep() { >@@ -554,46 +461,33 @@ > protected int getTotalNumberOfLayoutSteps() { > return sprIterations; > } >- >- protected void computeOneIteration(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) { >- if ( bounds == null ) >- bounds = new DisplayIndependentRectangle(x,y,width,height); >- checkPreferredLocation(entitiesToLayout, bounds ); >- computeForces(entitiesToLayout); >- largestMovement = Double.MAX_VALUE; >- computePositions(entitiesToLayout); >- >- for (int i = 0; i < entitiesToLayout.length; i++) { >- InternalNode layoutEntity = entitiesToLayout[i]; >- layoutEntity.setInternalLocation(tempLocationsX[i], tempLocationsY[i]); >- } >- >- defaultFitWithinBounds(entitiesToLayout, bounds); > >+ protected void computeOneIteration() { >+ computeForces(); >+ computePositions(); >+ DisplayIndependentRectangle currentBounds = getLayoutBounds(); >+ improveBoundsScale(currentBounds); >+ moveToCenter(currentBounds); > iteration++; > } > > /** > * Puts vertices in random places, all between (0,0) and (1,1). > */ >- public void placeRandomly(InternalNode[] entitiesToLayout) { >+ public void placeRandomly() { > // If only one node in the data repository, put it in the middle >- if (entitiesToLayout.length == 1) { >+ if (locationsX.length == 1) { > // If only one node in the data repository, put it in the middle >- tempLocationsX[0] = 0.5; >- tempLocationsY[0] = 0.5; >+ locationsX[0] = bounds.x + 0.5 * bounds.width; >+ locationsY[0] = bounds.y + 0.5 * bounds.height; > } else { >- for (int i = 0; i < entitiesToLayout.length; i++) { >- if (i == 0) { >- tempLocationsX[i] = 0.0; >- tempLocationsY[i] = 0.0; >- } else if (i == 1) { >- tempLocationsX[i] = 1.0; >- tempLocationsY[i] = 1.0; >- } else { >- tempLocationsX[i] = Math.random(); >- tempLocationsY[i] = Math.random(); >- } >+ locationsX[0] = bounds.x; >+ locationsY[0] = bounds.y; >+ locationsX[1] = bounds.x + bounds.width; >+ locationsY[1] = bounds.y + bounds.height; >+ for (int i = 2; i < locationsX.length; i++) { >+ locationsX[i] = bounds.x + Math.random() * bounds.width; >+ locationsY[i] = bounds.y + Math.random() * bounds.height; > } > } > } >@@ -606,79 +500,48 @@ > * Computes the force for each node in this SpringLayoutAlgorithm. The > * computed force will be stored in the data repository > */ >- protected void computeForces(InternalNode[] entitiesToLayout) { >+ protected void computeForces() { > > // initialize all forces to zero >- for (int i = 0; i < entitiesToLayout.length; i++) { >+ for (int i = 0; i < forcesX.length; i++) { > forcesX[i] = 0.0; > forcesY[i] = 0.0; > } >- > // TODO: Again really really slow! > >- for (int i = 0; i < entitiesToLayout.length - 1; i++) { >- InternalNode sourceEntity = entitiesToLayout[i]; >- >- double srcLocationX = tempLocationsX[i]; >- double srcLocationY = tempLocationsY[i]; >- double fx = forcesX[i]; // force in x direction >- double fy = forcesY[i]; // force in y direction >- >- >- for (int j = i + 1; j < entitiesToLayout.length; j++) { >- InternalNode destinationEntity = entitiesToLayout[j]; >- >- if (!destinationEntity.equals(sourceEntity)) { >- double destLocationX = tempLocationsX[j]; >- double destLocationY = tempLocationsY[j]; >- double dx = srcLocationX - destLocationX; >- double dy = srcLocationY- destLocationY; >- double distance = Math.sqrt(dx * dx + dy * dy); >- double distance_sq = distance * distance; >- // make sure distance and distance squared not too small >- distance = Math.max(MIN_DISTANCE, distance); >+ for (int i = 0; i < locationsX.length; i++) { >+ >+ for (int j = i + 1; j < locationsX.length; j++) { >+ double dx = (locationsX[i] - locationsX[j]) / bounds.width / boundsScale; >+ double dy = (locationsY[i] - locationsY[j]) / bounds.height / boundsScale; >+ double distance_sq = dx * dx + dy * dy; >+ // make sure distance and distance squared not too small >+ distance_sq = Math.max(MIN_DISTANCE * MIN_DISTANCE, distance_sq); >+ double distance = Math.sqrt(distance_sq); > > // If there are relationships between srcObj and destObj > // then decrease force on srcObj (a pull) in direction of destObj > // If no relation between srcObj and destObj then increase > // force on srcObj (a push) from direction of destObj. >- int numRels = srcDestToNumRels[i][j]; >- double avgWeight = srcDestToRelsAvgWeight[i][j]; >- if (numRels > 0) { >+ double sumOfWeights = srcDestToSumOfWeights[i][j]; >+ >+ double f; >+ if (sumOfWeights > 0) { > // nodes are pulled towards each other >- double f = sprStrain * Math.log(distance / sprLength) * numRels * avgWeight; >- >- fx = fx - (f * dx / distance); >- fy = fy - (f * dy / distance); >- >+ f = -sprStrain * Math.log(distance / sprLength) * sumOfWeights; > } else { > // nodes are repelled from each other >- //double f = Math.min(100, sprGravitation / (distance*distance)); >- double f = sprGravitation / (distance_sq); >- fx = fx + (f * dx / distance); >- fy = fy + (f * dy / distance); >+ f = sprGravitation / (distance_sq); > } >+ double dfx = f * dx / distance; >+ double dfy = f * dy / distance; > >- // According to Newton, "for every action, there is an equal >- // and opposite reaction." >- // so give the dest an opposite force >- forcesX[j] = forcesX[j] - fx; >- forcesY[j] = forcesY[j] - fy; >- } >- } >- >- /* >- * //make sure forces aren't too big if (fx > 0 ) fx = Math.min(fx, >- * 10*sprMove); else fx = Math.max(fx, -10*sprMove); if (fy > 0) fy = >- * Math.min(fy, 10*sprMove); else fy = Math.max(fy, -10*sprMove); >- */ >- forcesX[i] = fx; >- forcesY[i] = fy; >- // Remove the src object from the list of destinations since >- // we've already calculated the force from it on all other >- // objects. >- // dests.remove(srcObj); >+ forcesX[i] += dfx; >+ forcesY[i] += dfy; > >+ forcesX[j] -= dfx; >+ forcesY[j] -= dfy; >+ } > } > } > >@@ -687,122 +550,56 @@ > * The computed position will be stored in the data repository. position = > * position + sprMove * force > */ >- protected void computePositions(InternalNode[] entitiesToLayout) { >- for (int i = 0; i < entitiesToLayout.length; i++) { >- if (!anchors[i] || entitiesToLayout[i].hasPreferredLocation() ) { >- double oldX = tempLocationsX[i]; >- double oldY = tempLocationsY[i]; >+ protected void computePositions() { >+ for (int i = 0; i < entities.length; i++) { >+ if (entities[i].isMovable()) { > double deltaX = sprMove * forcesX[i]; > double deltaY = sprMove * forcesY[i]; > >- // constrain movement, so that nodes don't shoot way off to the edge >- double maxMovement = 0.2d * sprMove; >- if (deltaX >= 0) { >- deltaX = Math.min(deltaX, maxMovement); >- } else { >- deltaX = Math.max(deltaX, -maxMovement); >- } >- if (deltaY >= 0) { >- deltaY = Math.min(deltaY, maxMovement); >- } else { >- deltaY = Math.max(deltaY, -maxMovement); >- } >- >- >- largestMovement = Math.max(largestMovement, Math.abs(deltaX)); >- largestMovement = Math.max(largestMovement, Math.abs(deltaY)); >- >- double newX = oldX + deltaX; >- double newY = oldY + deltaY; >- tempLocationsX[i] = newX; >- tempLocationsY[i] = newY; >- } >- >- } >- >- } >- >- /** >- * Converts the position for each node in this SpringLayoutAlgorithm >- * to unit coordinates in double precision. The computed positions will be >- * still stored in the data repository. >- */ >- protected void convertToUnitCoordinates(InternalNode[] entitiesToLayout) { >- double minX = Double.MAX_VALUE; >- double maxX = Double.MIN_VALUE; >- double minY = Double.MAX_VALUE; >- double maxY = Double.MIN_VALUE; >- for (int i = 0; i < entitiesToLayout.length; i++) { >- InternalNode layoutEntity = entitiesToLayout[i]; >- minX = Math.min(minX, layoutEntity.getInternalX()); >- minY = Math.min(minY, layoutEntity.getInternalY()); >- maxX = Math.max(maxX, layoutEntity.getInternalX()); >- maxY = Math.max(maxY, layoutEntity.getInternalY()); >- } >+ // constrain movement, so that nodes don't shoot way off to the >+ // edge >+ double dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY); >+ double maxMovement = 0.2d * sprMove; >+ if (dist > maxMovement) { >+ deltaX *= maxMovement / dist; >+ deltaY *= maxMovement / dist; >+ } > >- double spanX = maxX - minX; >- double spanY = maxY - minY; >- double maxSpan = Math.max(spanX, spanY); >- >- if (maxSpan > EPSILON) { >- for (int i = 0; i < entitiesToLayout.length; i++) { >- InternalNode layoutEntity = entitiesToLayout[i]; >- double x = (layoutEntity.getInternalX() - minX) / spanX; >- double y = (layoutEntity.getInternalY() - minY) / spanY; >- tempLocationsX[i] = x; >- tempLocationsY[i] = y; >+ locationsX[i] += deltaX * bounds.width * boundsScale; >+ locationsY[i] += deltaY * bounds.height * boundsScale; > } >- } else { >- placeRandomly(entitiesToLayout); > } >- } >- >- /** >- * Examines the number of specified relation between the <code>src</code> >- * and the <code>dest</code> that exist in this >- * SpringLayoutAlgorithm's relation repository. >- * >- * @param src >- * The source part of the relaton to be examined. >- * @param dest >- * The destination part of the relation to be examined. >- * @return The number of relations between src and dest. >- */ >- private int numRelations(Object src, Object dest) { >- String key = src.toString() + dest.toString(); >- Integer count = (Integer) srcDestToNumRelsMap.get(key); >- int intCount = (count == null) ? 0 : count.intValue(); >- return intCount; >- } >- >- /** >- * Returns the average weight between a src and dest object. >- * >- * @param src >- * @param dest >- * @return The average weight between the given src and dest nodes >- */ >- private double avgWeight(Object src, Object dest) { >- String key = src.toString() + dest.toString(); >- Double avgWeight = (Double) srcDestToRelsAvgWeightMap.get(key); >- double doubleWeight = (avgWeight == null) ? 1 : avgWeight.doubleValue(); >- return doubleWeight; >- } >- >- >- protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) { >- if (asynchronous && continueous) >- return true; >- else if (asynchronous && !continueous) >- return true; >- else if (!asynchronous && continueous) >- return false; >- else if (!asynchronous && !continueous) >- return true; >+ } > >- return false; >- } >+ private DisplayIndependentRectangle getLayoutBounds() { >+ double minX, maxX, minY, maxY; >+ minX = minY = Double.POSITIVE_INFINITY; >+ maxX = maxY = Double.NEGATIVE_INFINITY; >+ >+ for (int i = 0; i < locationsX.length; i++) { >+ maxX = Math.max(maxX, locationsX[i] + sizeW[i] / 2); >+ minX = Math.min(minX, locationsX[i] - sizeW[i] / 2); >+ maxY = Math.max(maxY, locationsY[i] + sizeH[i] / 2); >+ minY = Math.min(minY, locationsY[i] - sizeH[i] / 2); >+ } >+ return new DisplayIndependentRectangle(minX, minY, maxX - minX, maxY - minY); >+ } > >+ private void improveBoundsScale(DisplayIndependentRectangle currentBounds) { >+ double boundaryProportion = Math.max(currentBounds.width / bounds.width, currentBounds.height / bounds.height); >+ if (boundaryProportion < 0.9) >+ boundsScale *= 1.01; >+ if (boundaryProportion > 1) >+ boundsScale /= 1.01; >+ } > >+ private void moveToCenter(DisplayIndependentRectangle currentBounds) { >+ double moveX = (currentBounds.x + currentBounds.width / 2) - (bounds.x + bounds.width / 2); >+ double moveY = (currentBounds.y + currentBounds.height / 2) - (bounds.y + bounds.height / 2); >+ for (int i = 0; i < locationsX.length; i++) { >+ locationsX[i] -= moveX; >+ locationsY[i] -= moveY; >+ } >+ } > } > >Index: src/org/eclipse/zest/layouts/algorithms/AbstractLayoutAlgorithm.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/AbstractLayoutAlgorithm.java >diff -N src/org/eclipse/zest/layouts/algorithms/AbstractLayoutAlgorithm.java >--- src/org/eclipse/zest/layouts/algorithms/AbstractLayoutAlgorithm.java 12 Jan 2008 01:34:29 -0000 1.24 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,1035 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.algorithms; >- >-import java.util.ArrayList; >-import java.util.Arrays; >-import java.util.Calendar; >-import java.util.Collection; >-import java.util.Comparator; >-import java.util.Iterator; >-import java.util.List; >- >-import org.eclipse.zest.layouts.Filter; >-import org.eclipse.zest.layouts.InvalidLayoutConfiguration; >-import org.eclipse.zest.layouts.LayoutAlgorithm; >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.LayoutItem; >-import org.eclipse.zest.layouts.LayoutRelationship; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.Stoppable; >-import org.eclipse.zest.layouts.constraints.BasicEntityConstraint; >-import org.eclipse.zest.layouts.dataStructures.BendPoint; >-import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension; >-import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint; >-import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >-import org.eclipse.zest.layouts.dataStructures.InternalNode; >-import org.eclipse.zest.layouts.dataStructures.InternalRelationship; >-import org.eclipse.zest.layouts.progress.ProgressEvent; >-import org.eclipse.zest.layouts.progress.ProgressListener; >- >-/** >- * Handles common elements in all layout algorithms >- * [irbull] Refactored into a template pattern. ApplyLayout now delegates the >- * task to ApplyLayoutInternal >- * >- * [irbull] Included asynchronous layouts >- * >- * @version 1.0 >- * @author Casey Best >- * @author Ian Bull >- * @author Chris Callendar >- * @author Rob Lintern >- * @author Chris Bennett >- */ >-public abstract class AbstractLayoutAlgorithm implements LayoutAlgorithm, Stoppable { >- >- public void removeRelationships(Collection collection) { >- >- } >- >- public final static int MIN_ENTITY_SIZE = 5; >- private final static int MIN_TIME_DELAY_BETWEEN_PROGRESS_EVENTS = 1; >- >- private Thread creationThread = null; >- protected Comparator comparator; >- protected Filter filter; >- private List progressListeners; >- private Calendar lastProgressEventFired; >- private double widthToHeightRatio; >- >- class InternalComparator implements Comparator { >- Comparator externalComparator = null; >- >- public InternalComparator(Comparator externalComparator) { >- this.externalComparator = externalComparator; >- } >- >- public int compare(Object o1, Object o2) { >- InternalNode internalNode1 = (InternalNode) o1; >- InternalNode internalNode2 = (InternalNode) o2; >- >- return this.externalComparator.compare(internalNode1.getLayoutEntity(), internalNode2.getLayoutEntity()); >- } >- >- } >- >- /* >- * Internal Nodes. >- */ >- private InternalNode[] internalNodes; >- private InternalRelationship[] internalRelationships; >- private double internalX; >- private double internalY; >- private double internalWidth; >- private double internalHeight; >- protected boolean internalContinuous; >- protected boolean internalAsynchronous; >- >- /* >- * A queue of entities and relationships to add or remove. Each layout >- * algorithm should check these and update their internal lists. >- */ >- >- /** A list of LayoutEntity objects to be removed from the layout. */ >- private List entitiesToRemove; >- /** A list of LayoutRelationship objects to be removed. */ >- private List relationshipsToRemove; >- /** A list of LayoutEntity objects to be added to the layout. */ >- private List entitiesToAdd; >- /** A list of LayoutRelationship objects to be added. */ >- private List relationshipsToAdd; >- >- //protected boolean cancelled = false; >- >- protected boolean layoutStopped = true; >- >- protected int layout_styles = 0; >- >- // Child classes can set to false to retain node shapes and sizes >- protected boolean resizeEntitiesAfterLayout = true; >- >- /** >- * Initializes the abstract layout algorithm. >- * @see LayoutStyles >- */ >- public AbstractLayoutAlgorithm(int styles) { >- this.creationThread = Thread.currentThread(); >- this.progressListeners = new ArrayList(); >- this.lastProgressEventFired = Calendar.getInstance(); >- this.widthToHeightRatio = 1.0; >- >- this.entitiesToRemove = new ArrayList(); >- this.relationshipsToRemove = new ArrayList(); >- this.entitiesToAdd = new ArrayList(); >- this.relationshipsToAdd = new ArrayList(); >- this.layout_styles = styles; >- } >- >- /** >- * Queues up the given entity (if it isn't in the list) to be added to the algorithm. >- * @param entity >- */ >- public void addEntity(LayoutEntity entity) { >- if ((entity != null) && !entitiesToAdd.contains(entity)) { >- entitiesToAdd.add(entity); >- } >- } >- >- /** >- * Queues up the given relationshp (if it isn't in the list) to be added to the algorithm. >- * @param relationship >- */ >- public void addRelationship(LayoutRelationship relationship) { >- if ((relationship != null) && !relationshipsToAdd.contains(relationship)) { >- relationshipsToAdd.add(relationship); >- } >- } >- >- /** >- * Queues up the given entity to be removed from the algorithm next time it runs. >- * @param entity The entity to remove >- */ >- public void removeEntity(LayoutEntity entity) { >- if ((entity != null) && !entitiesToRemove.contains(entity)) { >- entitiesToRemove.add(entity); >- } >- } >- >- /** >- * Queues up the given relationship to be removed from the algorithm next time it runs. >- * @param relationship The relationship to remove. >- */ >- public void removeRelationship(LayoutRelationship relationship) { >- if ((relationship != null) && !relationshipsToRemove.contains(relationship)) { >- relationshipsToRemove.add(relationship); >- } >- } >- >- /** >- * Queues up all the relationships in the list to be removed. >- * @param relationships >- */ >- public void removeRelationships(List relationships) { >- // note we don't check if the relationshipsToRemove contains >- // any of the objects in relationships. >- relationshipsToRemove.addAll(relationships); >- } >- >- /** >- * Sets the current layout style. This overwrites all other layout styles. >- * Use getStyle to get the current style. >- * @param style >- */ >- public void setStyle(int style) { >- this.layout_styles = style; >- } >- >- /** >- * Gets the current layout style >- * @return >- */ >- public int getStyle() { >- return this.layout_styles; >- } >- >- public abstract void setLayoutArea(double x, double y, double width, double height); >- >- /** >- * Determines if the configuration is valid for this layout >- * @param asynchronous >- * @param continuous >- */ >- protected abstract boolean isValidConfiguration(boolean asynchronous, boolean continuous); >- >- /** >- * Apply the layout to the given entities. The entities will be moved and resized based >- * on the algorithm. >- * >- * @param entitiesToLayout Apply the algorithm to these entities >- * @param relationshipsToConsider Only consider these relationships when applying the algorithm. >- * @param x The left side of the bounds in which the layout can place the entities. >- * @param y The top side of the bounds in which the layout can place the entities. >- * @param width The width of the bounds in which the layout can place the entities. >- * @param height The height of the bounds in which the layout can place the entities. >- */ >- abstract protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY, double boundsWidth, double boundsHeight); >- >- /** >- * Updates the given array of entities checking if any need to be removed or added. >- * @param entities the current entities >- * @return the updated entities array >- */ >- protected InternalNode[] updateEntities(InternalNode[] entities) { >- if ((entitiesToRemove.size() > 0) || (entitiesToAdd.size() > 0)) { >- List internalNodesList = new ArrayList(Arrays.asList(entities)); >- >- // remove nodes >- for (Iterator iter = entitiesToRemove.iterator(); iter.hasNext();) { >- LayoutEntity entity = (LayoutEntity) iter.next(); >- if (entity.getLayoutInformation() != null) { >- internalNodesList.remove(entity.getLayoutInformation()); >- } >- } >- >- // Also remove from _internalNodes >- ArrayList updatedEntities = new ArrayList(internalNodes.length - entitiesToRemove.size() + entitiesToAdd.size()); >- for (int i = 0; i < internalNodes.length; i++) { >- InternalNode node = internalNodes[i]; >- if (entitiesToRemove.contains(node.getLayoutEntity())) { >- entitiesToRemove.remove(node.getLayoutEntity()); >- } else { >- updatedEntities.add(node); >- } >- } >- entitiesToRemove.clear(); >- >- // Add any new nodes >- LayoutEntity[] entitiesArray = new LayoutEntity[entitiesToAdd.size()]; >- entitiesArray = (LayoutEntity[]) entitiesToAdd.toArray(entitiesArray); >- InternalNode[] newNodes = createInternalNodes(entitiesArray); >- for (int i = 0; i < newNodes.length; i++) { >- internalNodesList.add(newNodes[i]); >- updatedEntities.add(newNodes[i]); >- } >- entitiesToAdd.clear(); >- >- entities = new InternalNode[internalNodesList.size()]; >- entities = (InternalNode[]) internalNodesList.toArray(entities); >- >- internalNodes = new InternalNode[updatedEntities.size()]; >- internalNodes = (InternalNode[]) updatedEntities.toArray(internalNodes); >- } >- >- return entities; >- } >- >- /** >- * Updates the given array of relationships checking if any need to be removed or added. >- * Also updates the original array of relationships. >- * @param relationships the current relationships >- * @return the update relationships array >- */ >- protected InternalRelationship[] updateRelationships(InternalRelationship[] relationships) { >- if ((relationshipsToRemove.size() > 0) || (relationshipsToAdd.size() > 0)) { >- List internalRelsList = new ArrayList(Arrays.asList(relationships)); >- >- // remove relationships >- if (relationshipsToRemove.size() > 0) { >- for (Iterator iter = relationshipsToRemove.iterator(); iter.hasNext();) { >- LayoutRelationship relation = (LayoutRelationship) iter.next(); >- if (relation.getLayoutInformation() != null) { >- internalRelsList.remove(relation.getLayoutInformation()); >- } >- } >- } >- >- // Also remove from _internalRelationships >- ArrayList updatedRelationships = new ArrayList(internalRelationships.length - relationshipsToRemove.size() + relationshipsToAdd.size()); >- for (int i = 0; i < internalRelationships.length; i++) { >- InternalRelationship relation = internalRelationships[i]; >- if (relationshipsToRemove.contains(relation.getLayoutRelationship())) { >- relationshipsToRemove.remove(relation.getLayoutRelationship()); >- } else { >- updatedRelationships.add(relation); >- } >- } >- relationshipsToRemove.clear(); >- >- // add relationships >- if (relationshipsToAdd.size() > 0) { >- LayoutRelationship[] relsArray = new LayoutRelationship[relationshipsToAdd.size()]; >- relsArray = (LayoutRelationship[]) relationshipsToAdd.toArray(relsArray); >- InternalRelationship[] newRelationships = createInternalRelationships(relsArray); >- for (int i = 0; i < newRelationships.length; i++) { >- internalRelsList.add(newRelationships[i]); >- updatedRelationships.add(newRelationships[i]); >- } >- } >- relationshipsToAdd.clear(); >- >- relationships = new InternalRelationship[internalRelsList.size()]; >- relationships = (InternalRelationship[]) internalRelsList.toArray(relationships); >- >- internalRelationships = new InternalRelationship[updatedRelationships.size()]; >- internalRelationships = (InternalRelationship[]) updatedRelationships.toArray(internalRelationships); >- } >- >- return relationships; >- } >- >- /** >- * Moves all the entities by the given amount. >- * @param dx the amount to shift the entities in the x-direction >- * @param dy the amount to shift the entities in the y-direction >- */ >- /* >- public void moveAllEntities(double dx, double dy) { >- if ((dx != 0) || (dy != 0)) { >- synchronized (_internalNodes) { >- for (int i = 0; i < _internalNodes.length; i++) { >- InternalNode node = _internalNodes[i]; >- node.setInternalLocation(node.getInternalX()+dx, node.getInternalY()+dy); >- node.setLocation(node.getX()+dx, node.getY()+dy); >- } >- } >- } >- } >- */ >- >- /** >- * Returns true if the layout algorithm is running >- * @return boolean if the layout algorithm is running >- */ >- public synchronized boolean isRunning() { >- return !layoutStopped; >- } >- >- /** >- * Stops the current layout from running. >- * All layout algorithms should constantly check isLayoutRunning >- */ >- public synchronized void stop() { >- layoutStopped = true; >- postLayoutAlgorithm(internalNodes, internalRelationships); >- fireProgressEnded(getTotalNumberOfLayoutSteps()); >- } >- >- // /** >- // * Sleeps while the algorithm is paused. >- // */ >- // protected void sleepWhilePaused() { >- // // do nothing while the algorithm is paused >- // boolean wasPaused = false; >- // while (isPaused()) { >- // try { >- // Thread.sleep(200); >- // } catch (InterruptedException e) { >- // } >- // wasPaused = true; >- // } >- // // update the node positions (they might have been moved while paused) >- // if (wasPaused) { >- // for (int i = 0; i < internalNodes.length; i++) { >- // InternalNode node = internalNodes[i]; >- // node.setInternalLocation(node.getPreferredX(), node.getPreferredY()); >- // } >- // } >- // } >- >- private void setupLayout(LayoutEntity[] entitiesToLayout, LayoutRelationship[] relationshipsToConsider, double x, double y, double width, double height) { >- internalX = x; >- internalY = y; >- internalHeight = height; >- internalWidth = width; >- // Filter all the unwanted entities and relationships >- entitiesToLayout = (LayoutEntity[]) filterUnwantedObjects(entitiesToLayout); >- relationshipsToConsider = (LayoutRelationship[]) filterUnwantedObjects(relationshipsToConsider); >- >- // Check that the input is valid >- if (!verifyInput(entitiesToLayout, relationshipsToConsider)) { >- layoutStopped = true; >- throw new RuntimeException("The relationships in relationshipsToConsider don't contain the entities in entitiesToLayout"); >- } >- >- // Create the internal nodes and relationship >- internalNodes = createInternalNodes(entitiesToLayout); >- internalRelationships = createInternalRelationships(relationshipsToConsider); >- } >- >- // public synchronized Stoppable getLayoutThread(LayoutEntity[] entitiesToLayout, LayoutRelationship[] relationshipsToConsider, double x, double y, double width, double height, boolean continuous) { >- // //setupLayout( entitiesToLayout, relationshipsToConsider, x, y, width, height ); >- // this.layoutStopped = false; >- // this.runContinuously = continuous; >- // setupLayout(entitiesToLayout, relationshipsToConsider, x, y, width, height); >- // preLayoutAlgorithm(internalNodes, internalRelationships, internalX, internalY, internalWidth, internalHeight); >- // fireProgressStarted(getTotalNumberOfLayoutSteps()); >- // return this; >- // } >- >- /** >- * Code called before the layout algorithm starts >- */ >- protected abstract void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height); >- >- /** >- * Code called after the layout algorithm ends >- */ >- protected abstract void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider); >- >- /** >- * Gets the total number of steps in this layout >- */ >- protected abstract int getTotalNumberOfLayoutSteps(); >- >- /** >- * Gets the current layout step >- * @return >- */ >- protected abstract int getCurrentLayoutStep(); >- >- /** >- * This actually applies the layout >- */ >- public synchronized void applyLayout(final LayoutEntity[] entitiesToLayout, final LayoutRelationship[] relationshipsToConsider, final double x, final double y, final double width, final double height, boolean asynchronous, boolean continuous) throws InvalidLayoutConfiguration { >- checkThread(); >- this.internalAsynchronous = asynchronous; >- this.internalContinuous = continuous; >- >- if (!isValidConfiguration(asynchronous, continuous)) { >- throw new InvalidLayoutConfiguration(); >- } >- >- clearBendPoints(relationshipsToConsider); >- >- this.layoutStopped = false; >- >- // when an algorithm starts, reset the progress event >- lastProgressEventFired = Calendar.getInstance(); >- if (asynchronous) { >- >- Thread thread = new Thread(new Runnable() { >- >- public void run() { >- setupLayout(entitiesToLayout, relationshipsToConsider, x, y, width, height); >- preLayoutAlgorithm(internalNodes, internalRelationships, internalX, internalY, internalWidth, internalHeight); >- fireProgressStarted(getTotalNumberOfLayoutSteps()); >- >- applyLayoutInternal(internalNodes, internalRelationships, internalX, internalY, internalWidth, internalHeight); >- stop(); >- } >- >- }); >- thread.setPriority(Thread.MIN_PRIORITY); >- thread.start(); >- } else { >- >- // If we are running synchronously then we have to stop this at some >- // point? right? >- setupLayout(entitiesToLayout, relationshipsToConsider, x, y, width, height); >- preLayoutAlgorithm(internalNodes, internalRelationships, internalX, internalY, internalWidth, internalHeight); >- fireProgressStarted(getTotalNumberOfLayoutSteps()); >- >- applyLayoutInternal(internalNodes, internalRelationships, internalX, internalY, internalWidth, internalHeight); >- stop(); >- } >- >- } >- >- /** >- * Clear out all old bend points before doing a layout >- */ >- private void clearBendPoints(LayoutRelationship[] relationships) { >- for (int i = 0; i < relationships.length; i++) { >- LayoutRelationship rel = relationships[i]; >- rel.clearBendPoints(); >- } >- } >- >- /** >- * Update external bend points from the internal bendpoints list. Save the >- * source and destination points for later use in scaling and translating >- * @param relationshipsToConsider >- */ >- protected void updateBendPoints(InternalRelationship[] relationshipsToConsider) { >- for (int i = 0; i < relationshipsToConsider.length; i++) { >- InternalRelationship relationship = relationshipsToConsider[i]; >- List bendPoints = relationship.getBendPoints(); >- if (bendPoints.size() > 0) { >- // We will assume that source/dest coordinates are for center of node >- BendPoint[] externalBendPoints = new BendPoint[bendPoints.size() + 2]; >- InternalNode sourceNode = relationship.getSource(); >- externalBendPoints[0] = new BendPoint(sourceNode.getInternalX(), sourceNode.getInternalY()); >- InternalNode destNode = relationship.getDestination(); >- externalBendPoints[externalBendPoints.length - 1] = new BendPoint(destNode.getInternalX(), destNode.getInternalY()); >- >- for (int j = 0; j < bendPoints.size(); j++) { >- BendPoint bp = (BendPoint) bendPoints.get(j); >- externalBendPoints[j + 1] = new BendPoint(bp.x, bp.y, bp.getIsControlPoint()); >- } >- relationship.getLayoutRelationship().setBendPoints(externalBendPoints); >- } >- } >- } >- >- // public void run() { >- // >- // if (started == true) { >- // throw new RuntimeException("Layout has already run!"); >- // } >- // started = true; >- // //layoutStopped = false; >- // isLayoutPaused = false; >- // applyLayoutInternal(internalNodes, internalRelationships, internalX, internalY, internalWidth, internalHeight); >- // stop(); >- // layoutStopped = true; >- // isLayoutPaused = false; >- // } >- >- /** >- * Creates a list of InternalNode objects from the list of LayoutEntity objects the user >- * wants layed out. Sets the internal nodes' positions and sizes from the >- * external entities. >- */ >- private InternalNode[] createInternalNodes(LayoutEntity[] nodes) { >- InternalNode[] internalNodes = new InternalNode[nodes.length]; >- BasicEntityConstraint basicEntityConstraint = new BasicEntityConstraint(); >- for (int i = 0; i < nodes.length; i++) { >- basicEntityConstraint.clear(); >- LayoutEntity externalNode = nodes[i]; >- InternalNode internalNode = new InternalNode(externalNode); >- externalNode.populateLayoutConstraint(basicEntityConstraint); >- internalNode.setInternalLocation(externalNode.getXInLayout(), externalNode.getYInLayout()); >- internalNodes[i] = internalNode; >- } // end of for >- return internalNodes; >- } >- >- /** >- * Creates a list of InternalRelationship objects from the given list of LayoutRelationship objects. >- * @param rels >- * @return List of internal relationships >- */ >- private InternalRelationship[] createInternalRelationships(LayoutRelationship[] rels) { >- ArrayList listOfInternalRelationships = new ArrayList(rels.length); >- for (int i = 0; i < rels.length; i++) { >- LayoutRelationship relation = rels[i]; >- InternalNode src = (InternalNode) relation.getSourceInLayout().getLayoutInformation(); >- InternalNode dest = (InternalNode) relation.getDestinationInLayout().getLayoutInformation(); >- if ((src != null) && (dest != null)) { >- InternalRelationship internalRelationship = new InternalRelationship(relation, src, dest); >- listOfInternalRelationships.add(internalRelationship); >- } else { >- throw new RuntimeException("Error creating internal relationship, one of the nodes is null: src=" + src + ", dest=" + dest); >- } >- } >- InternalRelationship[] internalRelationships = new InternalRelationship[listOfInternalRelationships.size()]; >- listOfInternalRelationships.toArray(internalRelationships); >- return internalRelationships; >- } >- >- /** >- * Removes any objects that are currently filtered >- */ >- private Object[] filterUnwantedObjects(LayoutItem[] objects) { >- // first remove any entities or relationships that are filtered. >- List unfilteredObjsList = new ArrayList(); >- if (filter != null) { >- for (int i = 0; i < objects.length; i++) { >- LayoutItem object = objects[i]; >- if (!filter.isObjectFiltered(object)) { >- unfilteredObjsList.add(object); >- } >- } >- //@tag bug.156266-ClassCast.fix : use reflection to create the array. >- Object[] unfilteredObjs = (Object[]) java.lang.reflect.Array.newInstance(objects.getClass().getComponentType(), unfilteredObjsList.size()); >- unfilteredObjsList.toArray(unfilteredObjs); >- return unfilteredObjs; >- } >- return objects; >- } >- >- /** >- * Filters the entities and relationships to apply the layout on >- */ >- public void setFilter(Filter filter) { >- this.filter = filter; >- } >- >- /** >- * Determines the order in which the objects should be displayed. >- * Note: Some algorithms force a specific order. >- */ >- public void setComparator(Comparator comparator) { >- this.comparator = new InternalComparator(comparator); >- } >- >- /** >- * Verifies the endpoints of the relationships are entities in the entitiesToLayout list. >- * Allows other classes in this package to use this method to verify the input >- */ >- public static boolean verifyInput(LayoutEntity[] entitiesToLayout, LayoutRelationship[] relationshipsToConsider) { >- boolean stillValid = true; >- for (int i = 0; i < relationshipsToConsider.length; i++) { >- LayoutRelationship relationship = relationshipsToConsider[i]; >- LayoutEntity source = relationship.getSourceInLayout(); >- LayoutEntity destination = relationship.getDestinationInLayout(); >- boolean containsSrc = false; >- boolean containsDest = false; >- int j = 0; >- while (j < entitiesToLayout.length && !(containsSrc && containsDest)) { >- if (entitiesToLayout[j].equals(source)) { >- containsSrc = true; >- } >- if (entitiesToLayout[j].equals(destination)) { >- containsDest = true; >- } >- j++; >- } >- stillValid = containsSrc && containsDest; >- } >- return stillValid; >- } >- >- /** >- * Gets the location in the layout bounds for this node >- * @param x >- * @param y >- * @return >- */ >- protected DisplayIndependentPoint getLocalLocation(InternalNode[] entitiesToLayout, double x, double y, DisplayIndependentRectangle realBounds) { >- >- double screenWidth = realBounds.width; >- double screenHeight = realBounds.height; >- DisplayIndependentRectangle layoutBounds = getLayoutBounds(entitiesToLayout, false); >- double localX = (x / screenWidth) * layoutBounds.width + layoutBounds.x; >- double localY = (y / screenHeight) * layoutBounds.height + layoutBounds.y; >- return new DisplayIndependentPoint(localX, localY); >- } >- >- /** >- * Find an appropriate size for the given nodes, then fit them into the given bounds. >- * The relative locations of the nodes to each other must be preserved. >- * Child classes should set flag reresizeEntitiesAfterLayout to false if they >- * want to preserve node sizes. >- */ >- protected void defaultFitWithinBounds(InternalNode[] entitiesToLayout, DisplayIndependentRectangle realBounds) { >- defaultFitWithinBounds(entitiesToLayout, new InternalRelationship[0], realBounds); >- } >- >- /** >- * Find an appropriate size for the given nodes, then fit them into the given bounds. >- * The relative locations of the nodes to each other must be preserved. >- * Child classes should set flag reresizeEntitiesAfterLayout to false if they >- * want to preserve node sizes. >- */ >- protected void defaultFitWithinBounds(InternalNode[] entitiesToLayout, InternalRelationship[] relationships, DisplayIndependentRectangle realBounds) { >- >- DisplayIndependentRectangle layoutBounds; >- >- if (resizeEntitiesAfterLayout) { >- layoutBounds = getLayoutBounds(entitiesToLayout, false); >- >- // Convert node x,y to be in percent rather than absolute coords >- convertPositionsToPercentage(entitiesToLayout, relationships, layoutBounds, false /*do not update size*/); >- >- // Resize and shift nodes >- resizeAndShiftNodes(entitiesToLayout); >- } >- >- // Recalculate layout, allowing for the node width, which we now know >- layoutBounds = getLayoutBounds(entitiesToLayout, true); >- >- // adjust node positions again, to the new coordinate system (still as a percentage) >- convertPositionsToPercentage(entitiesToLayout, relationships, layoutBounds, true /*update node size*/); >- >- DisplayIndependentRectangle screenBounds = calcScreenBounds(realBounds, layoutBounds); >- >- // Now convert to real screen coordinates >- convertPositionsToCoords(entitiesToLayout, relationships, screenBounds); >- } >- >- /** >- * Calculate the screen bounds, maintaining the >- * @param realBounds >- * @return >- */ >- private DisplayIndependentRectangle calcScreenBounds(DisplayIndependentRectangle realBounds, DisplayIndependentRectangle layoutBounds) { >- if (resizeEntitiesAfterLayout) { // OK to alter aspect ratio >- double borderWidth = Math.min(realBounds.width, realBounds.height) / 10.0; // use 10% for the border - 5% on each side >- return new DisplayIndependentRectangle(realBounds.x + borderWidth / 2.0, realBounds.y + borderWidth / 2.0, realBounds.width - borderWidth, realBounds.height - borderWidth); >- } else { // retain layout aspect ratio >- double heightAdjustment = realBounds.height / layoutBounds.height; >- double widthAdjustment = realBounds.width / layoutBounds.width; >- double ratio = Math.min(heightAdjustment, widthAdjustment); >- double adjustedHeight = layoutBounds.height * ratio; >- double adjustedWidth = layoutBounds.width * ratio; >- double adjustedX = realBounds.x + (realBounds.width - adjustedWidth) / 2.0; >- double adjustedY = realBounds.y + (realBounds.height - adjustedHeight) / 2.0; >- double borderWidth = Math.min(adjustedWidth, adjustedHeight) / 10.0; // use 10% for the border - 5% on each side >- return new DisplayIndependentRectangle(adjustedX + borderWidth / 2.0, adjustedY + borderWidth / 2.0, adjustedWidth - borderWidth, adjustedHeight - borderWidth); >- } >- } >- >- /** >- * Find and set the node size - shift the nodes to the right and down to make >- * room for the width and height. >- * @param entitiesToLayout >- * @param relationships >- */ >- private void resizeAndShiftNodes(InternalNode[] entitiesToLayout) { >- // get maximum node size as percent of screen dimmensions >- double nodeSize = getNodeSize(entitiesToLayout); >- double halfNodeSize = nodeSize / 2; >- >- // Resize and shift nodes >- for (int i = 0; i < entitiesToLayout.length; i++) { >- InternalNode node = entitiesToLayout[i]; >- node.setInternalSize(nodeSize, nodeSize); >- node.setInternalLocation(node.getInternalX() + halfNodeSize, node.getInternalY() + halfNodeSize); >- } >- } >- >- /** >- * Convert all node positions into a percentage of the screen. If includeNodeSize >- * is true then this also updates the node's internal size. >- * @param entitiesToLayout >- */ >- private void convertPositionsToPercentage(InternalNode[] entitiesToLayout, InternalRelationship[] relationships, DisplayIndependentRectangle layoutBounds, boolean includeNodeSize) { >- >- // Adjust node positions and sizes >- for (int i = 0; i < entitiesToLayout.length; i++) { >- InternalNode node = entitiesToLayout[i]; >- DisplayIndependentPoint location = node.getInternalLocation().convertToPercent(layoutBounds); >- node.setInternalLocation(location.x, location.y); >- if (includeNodeSize) { // adjust node sizes >- double width = node.getInternalWidth() / layoutBounds.width; >- double height = node.getInternalHeight() / layoutBounds.height; >- node.setInternalSize(width, height); >- } >- } >- >- // Adjust bendpoint positions >- for (int i = 0; i < relationships.length; i++) { >- InternalRelationship rel = relationships[i]; >- for (int j = 0; j < rel.getBendPoints().size(); j++) { >- BendPoint bp = (BendPoint) rel.getBendPoints().get(j); >- DisplayIndependentPoint toPercent = bp.convertToPercent(layoutBounds); >- bp.setX(toPercent.x); >- bp.setY(toPercent.y); >- } >- } >- } >- >- /** >- * Convert the positions from a percentage of bounds area to fixed >- * coordinates. NOTE: ALL OF THE POSITIONS OF NODES UNTIL NOW WERE FOR THE >- * CENTER OF THE NODE - Convert it to the left top corner. >- * >- * @param entitiesToLayout >- * @param relationships >- * @param realBounds >- */ >- private void convertPositionsToCoords(InternalNode[] entitiesToLayout, InternalRelationship[] relationships, DisplayIndependentRectangle screenBounds) { >- >- // Adjust node positions and sizes >- for (int i = 0; i < entitiesToLayout.length; i++) { >- InternalNode node = entitiesToLayout[i]; >- double width = node.getInternalWidth() * screenBounds.width; >- double height = node.getInternalHeight() * screenBounds.height; >- DisplayIndependentPoint location = node.getInternalLocation().convertFromPercent(screenBounds); >- node.setInternalLocation(location.x - width / 2, location.y - height / 2); >- if (resizeEntitiesAfterLayout) { >- adjustNodeSizeAndPos(node, height, width); >- } else { >- node.setInternalSize(width, height); >- } >- } >- >- // Adjust bendpoint positions and shift based on source node size >- for (int i = 0; i < relationships.length; i++) { >- InternalRelationship rel = relationships[i]; >- for (int j = 0; j < rel.getBendPoints().size(); j++) { >- BendPoint bp = (BendPoint) rel.getBendPoints().get(j); >- DisplayIndependentPoint fromPercent = bp.convertFromPercent(screenBounds); >- bp.setX(fromPercent.x); >- bp.setY(fromPercent.y); >- } >- } >- } >- >- /** >- * Adjust node size to take advantage of space. Reset position to top left corner of node. >- * @param node >- * @param height >- * @param width >- */ >- private void adjustNodeSizeAndPos(InternalNode node, double height, double width) { >- double widthUsingHeight = height * widthToHeightRatio; >- if (widthToHeightRatio <= 1.0 && widthUsingHeight <= width) { >- double widthToUse = height * widthToHeightRatio; >- double leftOut = width - widthToUse; >- node.setInternalSize(Math.max(height * widthToHeightRatio, MIN_ENTITY_SIZE), Math.max(height, MIN_ENTITY_SIZE)); >- node.setInternalLocation(node.getInternalX() + leftOut / 2, node.getInternalY()); >- >- } else { >- double heightToUse = height / widthToHeightRatio; >- double leftOut = height - heightToUse; >- >- node.setInternalSize(Math.max(width, MIN_ENTITY_SIZE), Math.max(width / widthToHeightRatio, MIN_ENTITY_SIZE)); >- node.setInternalLocation(node.getInternalX(), node.getInternalY() + leftOut / 2); >- } >- >- } >- >- /** >- * Returns the maximum possible node size as a percentage of the width or height in current coord system. >- */ >- private double getNodeSize(InternalNode[] entitiesToLayout) { >- double width, height; >- if (entitiesToLayout.length == 1) { >- width = 0.8; >- height = 0.8; >- } else { >- DisplayIndependentDimension minimumDistance = getMinimumDistance(entitiesToLayout); >- width = 0.8 * minimumDistance.width; >- height = 0.8 * minimumDistance.height; >- } >- return Math.max(width, height); >- } >- >- /** >- * Find the bounds in which the nodes are located. Using the bounds against the real bounds >- * of the screen, the nodes can proportionally be placed within the real bounds. >- * The bounds can be determined either including the size of the nodes or not. If the size >- * is not included, the bounds will only be guaranteed to include the center of each node. >- */ >- protected DisplayIndependentRectangle getLayoutBounds(InternalNode[] entitiesToLayout, boolean includeNodeSize) { >- double rightSide = Double.MIN_VALUE; >- double bottomSide = Double.MIN_VALUE; >- double leftSide = Double.MAX_VALUE; >- double topSide = Double.MAX_VALUE; >- for (int i = 0; i < entitiesToLayout.length; i++) { >- InternalNode entity = entitiesToLayout[i]; >- if (entity.hasPreferredLocation()) { >- continue; >- } >- >- if (includeNodeSize) { >- leftSide = Math.min(entity.getInternalX() - entity.getInternalWidth() / 2, leftSide); >- topSide = Math.min(entity.getInternalY() - entity.getInternalHeight() / 2, topSide); >- rightSide = Math.max(entity.getInternalX() + entity.getInternalWidth() / 2, rightSide); >- bottomSide = Math.max(entity.getInternalY() + entity.getInternalHeight() / 2, bottomSide); >- } else { >- leftSide = Math.min(entity.getInternalX(), leftSide); >- topSide = Math.min(entity.getInternalY(), topSide); >- rightSide = Math.max(entity.getInternalX(), rightSide); >- bottomSide = Math.max(entity.getInternalY(), bottomSide); >- } >- } >- return new DisplayIndependentRectangle(leftSide, topSide, rightSide - leftSide, bottomSide - topSide); >- } >- >- /** >- * minDistance is the closest that any two points are together. >- * These two points become the center points for the two closest nodes, >- * which we wish to make them as big as possible without overlapping. >- * This will be the maximum of minDistanceX and minDistanceY minus a bit, lets say 20% >- * >- * We make the recommended node size a square for convenience. >- * >- * >- * _______ >- * | | >- * | | >- * | + | >- * | |\ | >- * |___|_\_|_____ >- * | | \ | >- * | | \ | >- * +-|---+ | >- * | | >- * |_______| >- * >- * >- * >- */ >- private DisplayIndependentDimension getMinimumDistance(InternalNode[] entitiesToLayout) { >- DisplayIndependentDimension horAndVertdistance = new DisplayIndependentDimension(Double.MAX_VALUE, Double.MAX_VALUE); >- double minDistance = Double.MAX_VALUE; // the minimum distance between all the nodes >- //TODO: Very Slow! >- for (int i = 0; i < entitiesToLayout.length; i++) { >- InternalNode layoutEntity1 = entitiesToLayout[i]; >- double x1 = layoutEntity1.getInternalX(); >- double y1 = layoutEntity1.getInternalY(); >- for (int j = i + 1; j < entitiesToLayout.length; j++) { >- InternalNode layoutEntity2 = entitiesToLayout[j]; >- double x2 = layoutEntity2.getInternalX(); >- double y2 = layoutEntity2.getInternalY(); >- double distanceX = Math.abs(x1 - x2); >- double distanceY = Math.abs(y1 - y2); >- double distance = Math.sqrt(Math.pow(distanceX, 2) + Math.pow(distanceY, 2)); >- >- if (distance < minDistance) { >- minDistance = distance; >- horAndVertdistance.width = distanceX; >- horAndVertdistance.height = distanceY; >- } >- } >- } >- return horAndVertdistance; >- } >- >- /** >- * Set the width to height ratio you want the entities to use >- */ >- public void setEntityAspectRatio(double ratio) { >- widthToHeightRatio = ratio; >- } >- >- /** >- * Returns the width to height ratio this layout will use to set the size of the entities. >- */ >- public double getEntityAspectRatio() { >- return widthToHeightRatio; >- } >- >- /** >- * A layout algorithm could take an uncomfortable amout of time to complete. To relieve some of >- * the mystery, the layout algorithm will notify each ProgressListener of its progress. >- */ >- public void addProgressListener(ProgressListener listener) { >- if (!progressListeners.contains(listener)) { >- progressListeners.add(listener); >- } >- } >- >- /** >- * Removes the given progress listener, preventing it from receiving any more updates. >- */ >- public void removeProgressListener(ProgressListener listener) { >- if (progressListeners.contains(listener)) { >- progressListeners.remove(listener); >- } >- } >- >- /** >- * Updates the layout locations so the external nodes know about the new locations >- */ >- protected void updateLayoutLocations(InternalNode[] nodes) { >- for (int i = 0; i < nodes.length; i++) { >- InternalNode node = nodes[i]; >- if (!node.hasPreferredLocation()) { >- node.setLocation(node.getInternalX(), node.getInternalY()); >- >- if ((layout_styles & LayoutStyles.NO_LAYOUT_NODE_RESIZING) != 1) { >- // Only set the size if we are supposed to >- node.setSize(node.getInternalWidth(), node.getInternalHeight()); >- } >- } >- } >- } >- >- protected void fireProgressStarted(int totalNumberOfSteps) { >- ProgressEvent event = new ProgressEvent(0, totalNumberOfSteps); >- for (int i = 0; i < progressListeners.size(); i++) { >- ProgressListener listener = (ProgressListener) progressListeners.get(i); >- >- listener.progressStarted(event); >- } >- } >- >- protected void fireProgressEnded(int totalNumberOfSteps) { >- ProgressEvent event = new ProgressEvent(totalNumberOfSteps, totalNumberOfSteps); >- for (int i = 0; i < progressListeners.size(); i++) { >- ProgressListener listener = (ProgressListener) progressListeners.get(i); >- listener.progressEnded(event); >- } >- >- } >- >- /** >- * Fires an event to notify all of the registered ProgressListeners that another step >- * has been completed in the algorithm. >- * @param currentStep The current step completed. >- * @param totalNumberOfSteps The total number of steps in the algorithm. >- */ >- protected void fireProgressEvent(int currentStep, int totalNumberOfSteps) { >- >- // Update the layout locations to the external nodes >- Calendar now = Calendar.getInstance(); >- now.add(Calendar.MILLISECOND, -MIN_TIME_DELAY_BETWEEN_PROGRESS_EVENTS); >- >- if (now.after(lastProgressEventFired) || currentStep == totalNumberOfSteps) { >- ProgressEvent event = new ProgressEvent(currentStep, totalNumberOfSteps); >- >- for (int i = 0; i < progressListeners.size(); i++) { >- >- ProgressListener listener = (ProgressListener) progressListeners.get(i); >- listener.progressUpdated(event); >- } >- lastProgressEventFired = Calendar.getInstance(); >- } >- >- } >- >- protected int getNumberOfProgressListeners() { >- return progressListeners.size(); >- } >- >- private void checkThread() { >- if (this.creationThread != Thread.currentThread()) { >- throw new RuntimeException("Invalid Thread Access."); >- } >- } >- >-} >Index: src/org/eclipse/zest/layouts/algorithms/HorizontalLayoutAlgorithm.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/HorizontalLayoutAlgorithm.java >diff -N src/org/eclipse/zest/layouts/algorithms/HorizontalLayoutAlgorithm.java >--- src/org/eclipse/zest/layouts/algorithms/HorizontalLayoutAlgorithm.java 12 Sep 2007 20:44:37 -0000 1.6 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,55 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * Ian Bull - updated and modified >- *******************************************************************************/ >-package org.eclipse.zest.layouts.algorithms; >- >-import org.eclipse.zest.layouts.LayoutStyles; >- >-/** >- * @version 2.0 >- * @author Casey Best and Rob Lintern >- */ >-public class HorizontalLayoutAlgorithm extends GridLayoutAlgorithm { >- >- >- public HorizontalLayoutAlgorithm(int styles) { >- super(styles); >- } >- >- /** >- * Horizontal Layout Algorithm constructor. Sets the Style to none. >- */ >- public HorizontalLayoutAlgorithm() { >- this( LayoutStyles.NONE ); >- } >- /** >- * Calculates and returns an array containing the number of columns, followed by the number of rows >- */ >- protected int[] calculateNumberOfRowsAndCols (int numChildren, double boundX, double boundY, double boundWidth, double boundHeight) { >- int rows = 1; >- int cols = numChildren; >- int[] result = {cols, rows}; >- return result; >- } >- >- protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) { >- if ( asynchronous && continueous ) { >- return false; >- } else if ( asynchronous && !continueous ) { >- return true; >- } else if ( !asynchronous && continueous ) { >- return false; >- } else if ( !asynchronous && !continueous ) { >- return true; >- } >- >- return false; >- } >-} >Index: src/org/eclipse/zest/layouts/algorithms/TreeLayoutAlgorithm.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.layouts/src/org/eclipse/zest/layouts/algorithms/TreeLayoutAlgorithm.java,v >retrieving revision 1.7 >diff -u -r1.7 TreeLayoutAlgorithm.java >--- src/org/eclipse/zest/layouts/algorithms/TreeLayoutAlgorithm.java 12 Sep 2007 20:44:37 -0000 1.7 >+++ src/org/eclipse/zest/layouts/algorithms/TreeLayoutAlgorithm.java 28 Aug 2009 16:03:04 -0000 >@@ -1,580 +1,174 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >+ * Copyright (c) 2005-2009 The Chisel Group 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: The Chisel Group - initial API and implementation >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ * Ian Bull >+ ******************************************************************************/ > package org.eclipse.zest.layouts.algorithms; > >-import java.util.ArrayList; >-import java.util.Arrays; >-import java.util.Collection; >-import java.util.Collections; >-import java.util.Comparator; >-import java.util.HashSet; > import java.util.Iterator; >-import java.util.List; >-import java.util.Set; > >-import org.eclipse.zest.layouts.LayoutStyles; >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.algorithms.TreeLayoutObserver.TreeNode; > import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >-import org.eclipse.zest.layouts.dataStructures.InternalNode; >-import org.eclipse.zest.layouts.dataStructures.InternalRelationship; >-import org.eclipse.zest.layouts.exampleStructures.SimpleRelationship; >- >- >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; > > /** >- * The TreeLayoutAlgorithm class implements a simple algorithm to >- * arrange graph nodes in a layered vertical tree-like layout. >+ * The TreeLayoutAlgorithm class implements a simple algorithm to arrange graph >+ * nodes in a layered tree-like layout. > * >- * This is by no means an efficiently coded algorithm. >- * >- * @version 2.0 >- * @author Casey Best and Rob Lintern (version 1.0 by Jingwei Wu) >+ * @version 3.0 >+ * @author Mateusz Matela >+ * @author Casey Best and Rob Lintern (version 2.0) >+ * @author Jingwei Wu (version 1.0) > */ >-public class TreeLayoutAlgorithm extends AbstractLayoutAlgorithm { >- >- private final static double DEFAULT_WEIGHT = 0; >- private final static boolean DEFAULT_MARKED = false; >- >- private final static boolean AS_DESTINATION = false; >- private final static boolean AS_SOURCE = true; >- >- private final static int NUM_DESCENDENTS_INDEX = 0; >- private final static int NUM_LEVELS_INDEX = 1; >- >- private ArrayList treeRoots; >- >- private double boundsX; >- private double boundsY; >- private double boundsWidth; >- private double boundsHeight; >- private DisplayIndependentRectangle layoutBounds = null; >- >- private List [] parentLists; >- private List [] childrenLists; >- private double [] weights; >- private boolean [] markedArr; >- >- ///////////////////////////////////////////////////////////////////////// >- ///// Constructors ///// >- ///////////////////////////////////////////////////////////////////////// >+public class TreeLayoutAlgorithm implements LayoutAlgorithm { > > /** >- * Constructs a new TreeLayoutAlgorithm object. >- */ >- public TreeLayoutAlgorithm( int styles ) { >- super( styles ); >- } >- >- /** >- * Tree layout algorithm Constructor with NO Style >- * >+ * Tree direction constant for which root is placed at the top and branches >+ * spread downwards > */ >- public TreeLayoutAlgorithm() { >- this( LayoutStyles.NONE ); >- } >- >- ///////////////////////////////////////////////////////////////////////// >- ///// Public Methods ///// >- ///////////////////////////////////////////////////////////////////////// >- >- public void setLayoutArea(double x, double y, double width, double height) { >- throw new RuntimeException(); >- } >- >- protected int getCurrentLayoutStep() { >- // TODO Auto-generated method stub >- return 0; >- } >- >- protected int getTotalNumberOfLayoutSteps() { >- return 4; >- } >+ public final static int TOP_DOWN = 1; > > /** >- * Executes this TreeLayoutAlgorithm layout algorithm by referencing the >- * data stored in the repository system. Once done, the result >- * will be saved to the data repository. >- * >- * @param entitiesToLayout Apply the algorithm to these entities >- * @param relationshipsToConsider Only consider these relationships when applying the algorithm. >- * @param boundsX The left side of the bounds in which the layout can place the entities. >- * @param boundsY The top side of the bounds in which the layout can place the entities. >- * @param boundsWidth The width of the bounds in which the layout can place the entities. >- * @param boundsHeight The height of the bounds in which the layout can place the entities. >- * @throws RuntimeException Thrown if entitiesToLayout doesn't contain all of the endpoints for each relationship in relationshipsToConsider >+ * Tree direction constant for which root is placed at the bottom and >+ * branches spread upwards > */ >- protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) { >- // Filter unwanted entities and relationships >- //super.applyLayout (entitiesToLayout, relationshipsToConsider, boundsX, boundsY, boundsWidth, boundsHeight); >- >- parentLists = new List [entitiesToLayout.length]; >- childrenLists = new List [entitiesToLayout.length]; >- weights = new double [entitiesToLayout.length]; >- markedArr = new boolean [entitiesToLayout.length]; >- for (int i = 0; i < entitiesToLayout.length; i++) { >- parentLists[i] = new ArrayList(); >- childrenLists[i] = new ArrayList(); >- weights[i] = DEFAULT_WEIGHT; >- markedArr[i] = DEFAULT_MARKED; >- } >- >- this.boundsHeight = height; >- this.boundsWidth = width; >- this.boundsX = x; >- this.boundsY = y; >- layoutBounds = new DisplayIndependentRectangle(boundsX, boundsY, boundsWidth, boundsHeight); >- >- } >+ public final static int BOTTOM_UP = 2; > >- protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY, double boundsWidth, double boundsHeight) { >- >- if (entitiesToLayout.length > 0) { >- int totalProgress = 4; >- fireProgressEvent (1, totalProgress); >- >- //List roots = new ArrayList(); >- treeRoots = new ArrayList(); >- buildForest(treeRoots, entitiesToLayout, relationshipsToConsider); >- fireProgressEvent (2, totalProgress); >- computePositions(treeRoots, entitiesToLayout); >- fireProgressEvent (3, totalProgress); >- defaultFitWithinBounds(entitiesToLayout, layoutBounds); >- >- } >- } >- >- protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) { >- updateLayoutLocations(entitiesToLayout); >- fireProgressEvent (4, 4); >- } >- > /** >- * Returns the last found roots >+ * Tree direction constant for which root is placed at the left and branches >+ * spread to the right > */ >- public List getRoots () { >- return treeRoots; >- } >+ public final static int LEFT_RIGHT = 3; > > /** >- * Finds all the relationships in which the node <code>obj<code> >- * plays the specified <code>role</code>. >- * @param entity The node that concerns the relations to be found. >- * @param role The role played by the <code>obj</code>. Its type >- * must be of <code>ACTOR_ROLE</code> or <code>ACTEE_ROLE</code>. >- * @see SimpleRelationship >+ * Tree direction constant for which root is placed at the right and >+ * branches spread to the left > */ >- private Collection findRelationships(Object entity, boolean objectAsSource, InternalRelationship [] relationshipsToConsider) { >- Collection foundRels = new ArrayList(); >- for (int i = 0; i < relationshipsToConsider.length; i++) { >- InternalRelationship rel = relationshipsToConsider[i]; >- if (objectAsSource && rel.getSource().equals (entity)) { >- foundRels.add(rel); >- } else if (!objectAsSource && rel.getDestination().equals (entity)) { >- foundRels.add(rel); >- } >- } >- return foundRels; >- } >+ public final static int RIGHT_LEFT = 4; > >- /** >- * Finds the relation that has the lowest index in the relation >- * repository in which the node <code>obj<code> plays the specified >- * <code>role</code>. >- * @param obj The node that concerns the relations to be found. >- * @param role The role played by the <code>obj</code>. Its type must >- * be of <code>ACTOR_ROLE</code> or <code>ACTEE_ROLE</code>. >- * @see SimpleRelationship >- * @see SimpleRelationship#ACTOR_ROLE >- * @see SimpleRelationship#ACTEE_ROLE >- */ >- private InternalRelationship findRelationship(Object entity, boolean objectAsSource, InternalRelationship [] relationshipsToConsider) { >- InternalRelationship relationship = null; >- for (int i = 0; i < relationshipsToConsider.length && relationship == null; i++) { >- InternalRelationship possibleRel = relationshipsToConsider[i]; >- if (objectAsSource && possibleRel.getSource().equals (entity)) { >- relationship = possibleRel; >- } else if (!objectAsSource && possibleRel.getDestination().equals (entity)) { >- relationship = possibleRel; >- } >- } >- return relationship; >- } >+ private int direction = TOP_DOWN; > >+ private boolean resize = false; > >+ private LayoutContext context; > >- ///////////////////////////////////////////////////////////////////////// >- ///// Private Methods ///// >- ///////////////////////////////////////////////////////////////////////// >+ private DisplayIndependentRectangle bounds; > >+ private double leafSize, layerSize; > >- /** >- * Builds the tree forest that is used to calculate positions >- * for each node in this TreeLayoutAlgorithm. >- */ >- private void buildForest(List roots, InternalNode [] entities, InternalRelationship [] relationships) { >- List unplacedEntities = new ArrayList (Arrays.asList(entities)); >- buildForestRecursively(roots, unplacedEntities, entities, relationships); >+ private TreeLayoutObserver treeObserver; >+ >+ public TreeLayoutAlgorithm() { > } > >- /** >- * Builds the forest recursively. All entities >- * will be placed somewhere in the forest. >- */ >- private void buildForestRecursively(List roots, List unplacedEntities, InternalNode [] entities, InternalRelationship [] relationships) { >- if (unplacedEntities.size() == 0) { >- return; // no more entities to place >- } >- >- // get the first entity in the list of unplaced entities, find its root, and build this root's tree >- InternalNode layoutEntity = (InternalNode) unplacedEntities.get(0); >- InternalNode rootEntity = findRootObjectRecursive(layoutEntity, new HashSet(), relationships); >- int rootEntityIndex = indexOfInternalNode(entities, rootEntity); >- buildTreeRecursively(rootEntity, rootEntityIndex, 0, entities, relationships); >- roots.add(rootEntity); >- >- // now see which nodes are left to be placed in a tree somewhere >- List unmarkedCopy = new ArrayList(unplacedEntities); >- for (Iterator iter = unmarkedCopy.iterator(); iter.hasNext();) { >- InternalNode tmpEntity = (InternalNode) iter.next(); >- int tmpEntityIndex = indexOfInternalNode(entities, tmpEntity); >- boolean isMarked = markedArr[tmpEntityIndex]; >- if (isMarked) { >- unplacedEntities.remove(tmpEntity); >- } >- } >- buildForestRecursively(roots, unplacedEntities, entities, relationships); >+ public TreeLayoutAlgorithm(int direction) { >+ setDirection(direction); > } > >- /** >- * Finds the root node that can be treated as the root of a tree. >- * The found root node should be one of the unmarked nodes. >- */ >- private InternalNode findRootObjectRecursive(InternalNode currentEntity, Set seenAlready, InternalRelationship [] relationshipsToConsider) { >- InternalNode rootEntity = null; >- InternalRelationship rel = findRelationship(currentEntity, AS_DESTINATION, relationshipsToConsider); >- if (rel == null) { >- rootEntity = currentEntity; >- } else { >- InternalNode parentEntity = rel.getSource(); >- if (!seenAlready.contains(parentEntity)) { >- seenAlready.add(parentEntity); >- rootEntity = findRootObjectRecursive(parentEntity, seenAlready, relationshipsToConsider); >- } else { >- rootEntity = currentEntity; >- } >- } >- return rootEntity; >+ public int getDirection() { >+ return direction; > } > >+ public void setDirection(int direction) { >+ if (direction == TOP_DOWN || direction == BOTTOM_UP || direction == LEFT_RIGHT || direction == RIGHT_LEFT) >+ this.direction = direction; >+ else >+ throw new IllegalArgumentException("Invalid direction: " + direction); >+ } > >- > /** >- * Builds a tree of the passed in entity. >- * The entity will pass a weight value to all of its children recursively. >+ * >+ * @return true if this algorithm is set to resize elements > */ >- private void buildTreeRecursively(InternalNode layoutEntity, int i, double weight, InternalNode [] entities, final InternalRelationship [] relationships) { >- // No need to do further computation! >- if (layoutEntity == null) { >- return; >- } >- >- // A marked entity means that it has been added to the >- // forest, and its weight value needs to be modified. >- if (markedArr[i]) { >- modifyWeightRecursively(layoutEntity, i, weight, new HashSet(), entities, relationships); >- return; //No need to do further computation. >- } >- >- // Mark this entity, set its weight value and create a new tree node. >- markedArr[i] = true; >- weights[i] = weight; >- >- // collect the children of this entity and put them in order >- Collection rels = findRelationships(layoutEntity, AS_SOURCE, relationships); >- List children = new ArrayList (); >- for (Iterator iter = rels.iterator(); iter.hasNext();) { >- InternalRelationship layoutRel = (InternalRelationship) iter.next(); >- InternalNode childEntity = layoutRel.getDestination(); >- children.add(childEntity); >- } >- >- if (comparator != null) { >- Collections.sort(children, comparator); >- } else { >- // sort the children by level, then by number of descendents, then by number of children >- // TODO: SLOW >- Collections.sort(children, new Comparator () { >- public int compare(Object o1, Object o2) { >- InternalNode node1 = (InternalNode) o1; >- InternalNode node2 = (InternalNode) o2; >- int [] numDescendentsAndLevel1 = new int [2]; >- int [] numDescendentsAndLevel2 = new int [2]; >- int level1 = numDescendentsAndLevel1[NUM_LEVELS_INDEX]; >- int level2 = numDescendentsAndLevel2[NUM_LEVELS_INDEX]; >- if (level1 == level2) { >- getNumDescendentsAndLevel(node1, relationships, numDescendentsAndLevel1); >- getNumDescendentsAndLevel(node2, relationships, numDescendentsAndLevel2); >- int numDescendents1 = numDescendentsAndLevel1[NUM_DESCENDENTS_INDEX]; >- int numDescendents2 = numDescendentsAndLevel2[NUM_DESCENDENTS_INDEX]; >- if (numDescendents1 == numDescendents2) { >- int numChildren1 = getNumChildren(node1, relationships); >- int numChildren2 = getNumChildren(node1, relationships); >- return numChildren2 - numChildren1; >- } else { >- return numDescendents2 - numDescendents1; >- } >- } else { >- return level2 - level1; >- } >- //return getNumChildren(node2, relationships) - getNumChildren(node1, relationships); >- } >- }); >- } >- >- // map children to this parent, and vice versa >- for (Iterator iter = children.iterator(); iter.hasNext();) { >- InternalNode childEntity = (InternalNode) iter.next(); >- int childEntityIndex = indexOfInternalNode(entities, childEntity); >- if (!childrenLists[i].contains(childEntity)) { >- childrenLists[i].add(childEntity); >- } >- if (!parentLists[childEntityIndex].contains(layoutEntity)) { >- parentLists[childEntityIndex].add(layoutEntity); >- } >- } >- >- for (Iterator iter = children.iterator(); iter.hasNext();) { >- InternalNode childEntity = (InternalNode) iter.next(); >- int childEntityIndex = indexOfInternalNode(entities, childEntity); >- buildTreeRecursively(childEntity, childEntityIndex, weight + 1, entities, relationships); >- } >+ public boolean isResizing() { >+ return resize; > } >- >- private int getNumChildren (InternalNode layoutEntity, InternalRelationship [] relationships) { >- return findRelationships(layoutEntity, AS_SOURCE, relationships).size(); >- } >- >- private void getNumDescendentsAndLevel (InternalNode layoutEntity, InternalRelationship [] relationships, int [] numDescendentsAndLevel) { >- getNumDescendentsAndLevelRecursive(layoutEntity, relationships, new HashSet(), numDescendentsAndLevel, 0); >- } >- >- private void getNumDescendentsAndLevelRecursive (InternalNode layoutEntity, InternalRelationship [] relationships, Set seenAlready, int [] numDescendentsAndLevel, int currentLevel) { >- if (seenAlready.contains(layoutEntity)) { >- return; >- } >- seenAlready.add(layoutEntity); >- numDescendentsAndLevel[NUM_LEVELS_INDEX] = Math.max(numDescendentsAndLevel[NUM_LEVELS_INDEX], currentLevel); >- Collection rels = findRelationships(layoutEntity, AS_SOURCE, relationships); >- for (Iterator iter = rels.iterator(); iter.hasNext();) { >- InternalRelationship layoutRel = (InternalRelationship) iter.next(); >- InternalNode childEntity = layoutRel.getDestination(); >- numDescendentsAndLevel[NUM_DESCENDENTS_INDEX]++; >- getNumDescendentsAndLevelRecursive(childEntity, relationships, seenAlready, numDescendentsAndLevel, currentLevel + 1); >- >- } >- } >- >- >+ > /** >- * Modifies the weight value of the marked node recursively. >+ * >+ * @param resizing >+ * true if this algorithm should resize elements (default is >+ * false) > */ >- private void modifyWeightRecursively(InternalNode layoutEntity, int i, double weight, Set descendentsSeenSoFar, InternalNode [] entities, InternalRelationship [] relationships) { >- // No need to do further computation! >- if (layoutEntity == null) { >- return; >- } >+ public void setResizing(boolean resizing) { >+ resize = resizing; >+ } > >- if (descendentsSeenSoFar.contains(layoutEntity)) { >- return; //No need to do further computation. >+ public void setLayoutContext(LayoutContext context) { >+ if (treeObserver != null) { >+ treeObserver.stop(); > } >- >- descendentsSeenSoFar.add(layoutEntity); >- // No need to do further computation! >- if (weight < weights[i]) { >+ this.context = context; >+ treeObserver = new TreeLayoutObserver(context, null); >+ } >+ >+ public void applyLayout(boolean clean) { >+ if (!clean) > return; >- } > >- weights[i] = weight; >- Collection rels = findRelationships(layoutEntity, AS_SOURCE, relationships); >- >- >- for (Iterator iter = rels.iterator(); iter.hasNext();) { >- InternalRelationship tmpRel = (InternalRelationship) iter.next(); >- InternalNode tmpEntity = tmpRel.getDestination(); >- int tmpEntityIndex = indexOfInternalNode(entities, tmpEntity); >- modifyWeightRecursively(tmpEntity, tmpEntityIndex, weight + 1, descendentsSeenSoFar, entities, relationships); >- } >- } >+ internalApplyLayout(); > >- /** >- * Gets the maxium weight of a tree in the forest of this TreeLayoutAlgorithm. >- */ >- private double getMaxiumWeightRecursive(InternalNode layoutEntity, int i, Set seenAlready, InternalNode [] entities) { >- double result = 0; >- if (seenAlready.contains(layoutEntity)) { >- return result; >- } >- seenAlready.add(layoutEntity); >- List children = childrenLists[i]; >- if (children.isEmpty()) { >- result = weights[i]; >- } else { >- //TODO: SLOW >- for (Iterator iter = children.iterator(); iter.hasNext();) { >- InternalNode childEntity = (InternalNode) iter.next(); >- int childEntityIndex = indexOfInternalNode(entities, childEntity); >- result = Math.max(result, getMaxiumWeightRecursive(childEntity, childEntityIndex, seenAlready, entities)); >- } >+ EntityLayout[] entities = context.getEntities(); >+ >+ if (resize) { >+ AlgorithmHelper.maximizeSizes(entities); > } >- return result; >+ >+ DisplayIndependentRectangle bounds2 = new DisplayIndependentRectangle(bounds); >+ AlgorithmHelper.fitWithinBounds(entities, bounds2, resize); > } >- >- /** >- * Computes positions for each node in this TreeLayoutAlgorithm by >- * referencing the forest that holds those nodes. >- */ >- private void computePositions(List roots, InternalNode [] entities) { >- // No need to do further computation! >- if (roots.size() == 0) { >- return; >- } > >- int totalLeafCount = 0; >- double maxWeight = 0; >- for (int i = 0; i < roots.size(); i++) { >- InternalNode rootEntity = (InternalNode) roots.get(i); >- int rootEntityIndex = indexOfInternalNode(entities, rootEntity); >- totalLeafCount = totalLeafCount + getNumberOfLeaves(rootEntity, rootEntityIndex, entities); >- maxWeight = Math.max(maxWeight, getMaxiumWeightRecursive(rootEntity, rootEntityIndex, new HashSet(), entities) + 1.0); >+ void internalApplyLayout() { >+ TreeNode superRoot = treeObserver.getSuperRoot(); >+ bounds = context.getBounds(); >+ if (direction == TOP_DOWN || direction == BOTTOM_UP) { >+ leafSize = bounds.width / superRoot.numOfLeaves; >+ layerSize = bounds.height / superRoot.height; >+ } else { >+ leafSize = bounds.height / superRoot.numOfLeaves; >+ layerSize = bounds.width / superRoot.height; > } >- >- double width = 1.0 / totalLeafCount; >- double height = 1.0 / maxWeight; >- > int leafCountSoFar = 0; >- >- //TODO: SLOW! >- for (int i = 0; i < roots.size(); i++) { >- InternalNode rootEntity = (InternalNode) roots.get(i); >- int rootEntityIndex = indexOfInternalNode(entities, rootEntity); >- computePositionRecursively(rootEntity, rootEntityIndex, leafCountSoFar, width, height, new HashSet(), entities); >- leafCountSoFar = leafCountSoFar + getNumberOfLeaves(rootEntity, rootEntityIndex, entities); >+ for (Iterator iterator = superRoot.getChildren().iterator(); iterator.hasNext();) { >+ TreeNode rootInfo = (TreeNode) iterator.next(); >+ computePositionRecursively(rootInfo, leafCountSoFar); >+ leafCountSoFar = leafCountSoFar + rootInfo.numOfLeaves; > } > } >- >+ > /** > * Computes positions recursively until the leaf nodes are reached. > */ >- private void computePositionRecursively(InternalNode layoutEntity, int i, int relativePosition, double width, double height, Set seenAlready, InternalNode [] entities) { >- if (seenAlready.contains(layoutEntity)) { >- return; >- } >- seenAlready.add(layoutEntity); >- double level = getLevel(layoutEntity, i, entities); >- int breadth = getNumberOfLeaves(layoutEntity, i, entities); >- double absHPosition = relativePosition + breadth / 2.0; >- double absVPosition = (level + 0.5); >- >- double posx = absHPosition * width; >- double posy = absVPosition * height; >- double weight = weights[i]; >- posy = posy + height * (weight - level); >- layoutEntity.setInternalLocation( posx, posy ); >- >- >- int relativeCount = 0; >- List children = childrenLists[i]; >- //TODO: Slow >- for (Iterator iter = children.iterator(); iter.hasNext();) { >- InternalNode childEntity = (InternalNode) iter.next(); >- int childEntityIndex = indexOfInternalNode(entities, childEntity); >- computePositionRecursively(childEntity, childEntityIndex, relativePosition + relativeCount, width, height, seenAlready, entities); >- relativeCount = relativeCount + getNumberOfLeaves(childEntity, childEntityIndex, entities); >+ private void computePositionRecursively(TreeNode entityInfo, int relativePosition) { >+ double breadthPosition = relativePosition + entityInfo.numOfLeaves / 2.0; >+ double depthPosition = (entityInfo.depth + 0.5); >+ >+ switch (direction) { >+ case TOP_DOWN: >+ entityInfo.getNode().setLocation(breadthPosition * leafSize, depthPosition * layerSize); >+ break; >+ case BOTTOM_UP: >+ entityInfo.getNode().setLocation(breadthPosition * leafSize, bounds.height - depthPosition * layerSize); >+ break; >+ case LEFT_RIGHT: >+ entityInfo.getNode().setLocation(depthPosition * layerSize, breadthPosition * leafSize); >+ break; >+ case RIGHT_LEFT: >+ entityInfo.getNode().setLocation(bounds.width - depthPosition * layerSize, breadthPosition * leafSize); >+ break; >+ } >+ >+ for (Iterator iterator = entityInfo.children.iterator(); iterator.hasNext();) { >+ TreeNode childInfo = (TreeNode) iterator.next(); >+ computePositionRecursively(childInfo, relativePosition); >+ relativePosition += childInfo.numOfLeaves; > } > } >- >- private int getNumberOfLeaves (InternalNode layoutEntity, int i, InternalNode [] entities) { >- return getNumberOfLeavesRecursive(layoutEntity, i, new HashSet(), entities); >- } >- >- private int getNumberOfLeavesRecursive(InternalNode layoutEntity, int i, Set seen, InternalNode [] entities) { >- int numLeaves = 0; >- List children = childrenLists[i]; >- if (children.size() == 0) { >- numLeaves = 1; >- } else { >- //TODO: SLOW! >- for (Iterator iter = children.iterator(); iter.hasNext();) { >- InternalNode childEntity = (InternalNode) iter.next(); >- if (!seen.contains(childEntity)) { >- seen.add (childEntity); >- int childEntityIndex = indexOfInternalNode(entities, childEntity); >- numLeaves += getNumberOfLeavesRecursive(childEntity, childEntityIndex, seen, entities); >- } else { >- numLeaves = 1; >- } >- } >- } >- return numLeaves; >- } >- >- private int getLevel (InternalNode layoutEntity, int i, InternalNode [] entities) { >- return getLevelRecursive(layoutEntity, i, new HashSet(), entities); >- } >- >- private int getLevelRecursive(InternalNode layoutEntity, int i, Set seen, InternalNode [] entities) { >- if (seen.contains(layoutEntity)) { >- return 0; >- } >- seen.add(layoutEntity); >- List parents = parentLists[i]; >- int maxParentLevel = 0; >- for (Iterator iter = parents.iterator(); iter.hasNext();) { >- InternalNode parentEntity = (InternalNode) iter.next(); >- int parentEntityIndex = indexOfInternalNode(entities, parentEntity); >- int parentLevel = getLevelRecursive(parentEntity, parentEntityIndex, seen, entities) + 1; >- maxParentLevel = Math.max(maxParentLevel, parentLevel); >- } >- return maxParentLevel; >- } >- >- /** >- * Note: Use this as little as possible! >- * TODO limit the use of this method >- * @param nodes >- * @param nodeToFind >- * @return >- */ >- private int indexOfInternalNode (InternalNode [] nodes, InternalNode nodeToFind) { >- for (int i = 0; i < nodes.length; i++) { >- InternalNode node = nodes[i]; >- if (node.equals(nodeToFind)) { >- return i; >- } >- } >- throw new RuntimeException("Couldn't find index of internal node: " + nodeToFind); >- } >- >- >- protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) { >- if ( asynchronous && continueous ) { >- return false; >- } else if ( asynchronous && !continueous ) { >- return true; >- } else if ( !asynchronous && continueous ) { >- return false; >- } else if ( !asynchronous && !continueous ) { >- return true; >- } >- >- return false; >- } >- > } >Index: src/org/eclipse/zest/layouts/algorithms/VerticalLayoutAlgorithm.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/VerticalLayoutAlgorithm.java >diff -N src/org/eclipse/zest/layouts/algorithms/VerticalLayoutAlgorithm.java >--- src/org/eclipse/zest/layouts/algorithms/VerticalLayoutAlgorithm.java 12 Sep 2007 20:44:37 -0000 1.5 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,52 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.algorithms; >- >-import org.eclipse.zest.layouts.LayoutStyles; >- >-/** >- * @version 2.0 >- * @author Casey Best and Rob Lintern (version 1.0 by Rob Lintern) >- */ >-public class VerticalLayoutAlgorithm extends GridLayoutAlgorithm { >- >- >- /** >- * Veertical Layout Algorithm constructor with no styles. >- * >- */ >- public VerticalLayoutAlgorithm() { >- this(LayoutStyles.NONE ); >- } >- >- public VerticalLayoutAlgorithm(int styles) { >- super(styles); >- } >- >- /** >- * Calculates and returns an array containing the number of columns, followed by the number of rows >- */ >- protected int[] calculateNumberOfRowsAndCols (int numChildren, double boundX, double boundY, double boundWidth, double boundHeight) { >- int cols = 1; >- int rows = numChildren; >- int[] result = {cols, rows}; >- return result; >- } >- >- protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) { >- if ( asynchronous && continueous ) return false; >- else if ( asynchronous && !continueous ) return true; >- else if ( !asynchronous && continueous ) return false; >- else if ( !asynchronous && !continueous ) return true; >- >- return false; >- } >-} >Index: src/org/eclipse/zest/layouts/algorithms/DirectedGraphLayoutAlgorithm.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.layouts/src/org/eclipse/zest/layouts/algorithms/DirectedGraphLayoutAlgorithm.java,v >retrieving revision 1.5 >diff -u -r1.5 DirectedGraphLayoutAlgorithm.java >--- src/org/eclipse/zest/layouts/algorithms/DirectedGraphLayoutAlgorithm.java 4 May 2009 05:47:36 -0000 1.5 >+++ src/org/eclipse/zest/layouts/algorithms/DirectedGraphLayoutAlgorithm.java 28 Aug 2009 16:03:02 -0000 >@@ -1,13 +1,13 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >+ * Copyright (c) 2005-2009 The Chisel Group 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: The Chisel Group - initial API and implementation >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ * Ian Bull >+ ******************************************************************************/ > package org.eclipse.zest.layouts.algorithms; > > import java.lang.reflect.Field; >@@ -20,11 +20,14 @@ > import org.eclipse.draw2d.graph.DirectedGraphLayout; > import org.eclipse.draw2d.graph.Edge; > import org.eclipse.draw2d.graph.Node; >-import org.eclipse.swt.SWT; >-import org.eclipse.zest.layouts.dataStructures.InternalNode; >-import org.eclipse.zest.layouts.dataStructures.InternalRelationship; >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.interfaces.ConnectionLayout; >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+import org.eclipse.zest.layouts.interfaces.SubgraphLayout; > >-public class DirectedGraphLayoutAlgorithm extends AbstractLayoutAlgorithm { >+public class DirectedGraphLayoutAlgorithm implements LayoutAlgorithm { > > class ExtendedDirectedGraphLayout extends DirectedGraphLayout { > >@@ -51,74 +54,84 @@ > e.printStackTrace(); > } > } >+ } >+ >+ public static final int HORIZONTAL = 1; >+ >+ public static final int VERTICAL = 2; >+ >+ private int orientation = VERTICAL; >+ >+ private LayoutContext context; >+ >+ private HorizontalShiftAlgorithm hsAlgorithm = new HorizontalShiftAlgorithm(); > >+ public DirectedGraphLayoutAlgorithm() { > } > >- public DirectedGraphLayoutAlgorithm(int styles) { >- super(styles); >+ public DirectedGraphLayoutAlgorithm(int orientation) { >+ if (orientation == VERTICAL) >+ this.orientation = orientation; > } > >- protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY, double boundsWidth, double boundsHeight) { >- HashMap mapping = new HashMap(entitiesToLayout.length); >+ public int getOrientation() { >+ return orientation; >+ } >+ >+ public void setOrientation(int orientation) { >+ if (orientation == HORIZONTAL || orientation == VERTICAL) >+ this.orientation = orientation; >+ } >+ >+ public void applyLayout(boolean clean) { >+ if (!clean) >+ return; >+ HashMap mapping = new HashMap(); > DirectedGraph graph = new DirectedGraph(); >- for (int i = 0; i < entitiesToLayout.length; i++) { >- InternalNode internalNode = entitiesToLayout[i]; >- Node node = new Node(internalNode); >+ EntityLayout[] entities = context.getEntities(); >+ for (int i = 0; i < entities.length; i++) { >+ Node node = new Node(entities[i]); > node.setSize(new Dimension(10, 10)); >- mapping.put(internalNode, node); >+ mapping.put(entities[i], node); > graph.nodes.add(node); > } >- for (int i = 0; i < relationshipsToConsider.length; i++) { >- InternalRelationship relationship = relationshipsToConsider[i]; >- Node source = (Node) mapping.get(relationship.getSource()); >- Node dest = (Node) mapping.get(relationship.getDestination()); >- Edge edge = new Edge(relationship, source, dest); >- graph.edges.add(edge); >+ ConnectionLayout[] connections = context.getConnections(); >+ for (int i = 0; i < connections.length; i++) { >+ Node source = (Node) mapping.get(getEntity(connections[i].getSource())); >+ Node dest = (Node) mapping.get(getEntity(connections[i].getTarget())); >+ if (source != null && dest != null) { >+ Edge edge = new Edge(connections[i], source, dest); >+ graph.edges.add(edge); >+ } > } > DirectedGraphLayout directedGraphLayout = new ExtendedDirectedGraphLayout(); > directedGraphLayout.visit(graph); > > for (Iterator iterator = graph.nodes.iterator(); iterator.hasNext();) { > Node node = (Node) iterator.next(); >- InternalNode internalNode = (InternalNode) node.data; >- // For horizontal layout transpose the x and y coordinates >- if ((layout_styles & SWT.HORIZONTAL) == SWT.HORIZONTAL) { >- internalNode.setInternalLocation(node.y, node.x); >- }else { >- internalNode.setInternalLocation(node.x, node.y); >+ EntityLayout entity = (EntityLayout) node.data; >+ if (orientation == VERTICAL) { >+ entity.setLocation(node.x, node.y); >+ } else { >+ entity.setLocation(node.y, node.x); > } > } >- updateLayoutLocations(entitiesToLayout); >- } >- >- protected int getCurrentLayoutStep() { >- // TODO Auto-generated method stub >- return 0; >- } >- >- protected int getTotalNumberOfLayoutSteps() { >- // TODO Auto-generated method stub >- return 0; >- } > >- protected boolean isValidConfiguration(boolean asynchronous, boolean continuous) { >- // TODO Auto-generated method stub >- return true; >+ hsAlgorithm.applyLayout(clean); > } > >- protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) { >- // TODO Auto-generated method stub >- >+ private EntityLayout getEntity(NodeLayout node) { >+ if (!node.isPruned()) >+ return node; >+ SubgraphLayout subgraph = node.getSubgraph(); >+ if (subgraph.isGraphEntity()) >+ return subgraph; >+ return null; > } > >- protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) { >- // TODO Auto-generated method stub >- >- } >- >- public void setLayoutArea(double x, double y, double width, double height) { >- // TODO Auto-generated method stub >- >+ public void setLayoutContext(LayoutContext context) { >+ this.context = context; >+ hsAlgorithm.setLayoutContext(context); > } > > } >Index: src/org/eclipse/zest/layouts/algorithms/CompositeLayoutAlgorithm.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.layouts/src/org/eclipse/zest/layouts/algorithms/CompositeLayoutAlgorithm.java,v >retrieving revision 1.5 >diff -u -r1.5 CompositeLayoutAlgorithm.java >--- src/org/eclipse/zest/layouts/algorithms/CompositeLayoutAlgorithm.java 31 Mar 2009 16:42:20 -0000 1.5 >+++ src/org/eclipse/zest/layouts/algorithms/CompositeLayoutAlgorithm.java 28 Aug 2009 16:03:02 -0000 >@@ -1,77 +1,35 @@ > /******************************************************************************* >- * Copyright 2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >+ * Copyright (c) 2005-2009 The Chisel Group 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: The Chisel Group - initial API and implementation >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ * Ian Bull >+ ******************************************************************************/ > package org.eclipse.zest.layouts.algorithms; > >-import org.eclipse.zest.layouts.InvalidLayoutConfiguration; > import org.eclipse.zest.layouts.LayoutAlgorithm; >-import org.eclipse.zest.layouts.dataStructures.InternalNode; >-import org.eclipse.zest.layouts.dataStructures.InternalRelationship; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; > >-public class CompositeLayoutAlgorithm extends AbstractLayoutAlgorithm { >+public class CompositeLayoutAlgorithm implements LayoutAlgorithm { > >- LayoutAlgorithm[] algorithms = null; >+ private LayoutAlgorithm[] algorithms = null; > >- public CompositeLayoutAlgorithm(int styles, LayoutAlgorithm[] algoirthms) { >- super(styles); >- this.algorithms = algoirthms; >+ public CompositeLayoutAlgorithm(LayoutAlgorithm[] algorithms) { >+ this.algorithms = algorithms; > } >- >- public CompositeLayoutAlgorithm( LayoutAlgorithm[] algoirthms) { >- this(0, algoirthms); >- } >- >- protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY, double boundsWidth, double boundsHeight) { > >+ public void applyLayout(boolean clean) { > for (int i = 0; i < algorithms.length; i++) { >- try { >- algorithms[i].applyLayout(entitiesToLayout, relationshipsToConsider, boundsX, boundsY, boundsWidth, boundsHeight, this.internalAsynchronous, this.internalContinuous); >- } catch (InvalidLayoutConfiguration e) { >- e.printStackTrace(); >- } >- } >- for (int i = 0; i < entitiesToLayout.length; i++) { >- entitiesToLayout[i].getLayoutEntity().setLocationInLayout(entitiesToLayout[i].getXInLayout(), entitiesToLayout[i].getYInLayout()); >+ algorithms[i].applyLayout(clean); > } >- >- //updateLayoutLocations(entitiesToLayout); >- } >- >- protected int getCurrentLayoutStep() { >- // TODO Auto-generated method stub >- return 0; >- } >- >- protected int getTotalNumberOfLayoutSteps() { >- // TODO Auto-generated method stub >- return 0; >- } >- >- protected boolean isValidConfiguration(boolean asynchronous, boolean continuous) { >- // TODO Auto-generated method stub >- return true; > } > >- protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) { >- // TODO Auto-generated method stub >- >- } >- >- protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) { >- // TODO Auto-generated method stub >- >- } >- >- public void setLayoutArea(double x, double y, double width, double height) { >- // TODO Auto-generated method stub >- >+ public void setLayoutContext(LayoutContext context) { >+ for (int i = 0; i < algorithms.length; i++) { >+ algorithms[i].setLayoutContext(context); >+ } > } >- > } >Index: src/org/eclipse/zest/layouts/algorithms/HorizontalShift.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/HorizontalShift.java >diff -N src/org/eclipse/zest/layouts/algorithms/HorizontalShift.java >--- src/org/eclipse/zest/layouts/algorithms/HorizontalShift.java 12 Sep 2007 20:44:37 -0000 1.6 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,131 +0,0 @@ >-/******************************************************************************* >- * Copyright 2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >-package org.eclipse.zest.layouts.algorithms; >- >-import java.util.ArrayList; >-import java.util.Collections; >-import java.util.Comparator; >-import java.util.Iterator; >-import java.util.List; >- >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.dataStructures.InternalNode; >-import org.eclipse.zest.layouts.dataStructures.InternalRelationship; >- >-/** >- * This layout shifts overlapping nodes to the right. >- * @author Ian Bull >- */ >-public class HorizontalShift extends AbstractLayoutAlgorithm { >- >- private static final double DELTA = 10; >- private static final double VSPACING = 2; >- >- public HorizontalShift(int styles) { >- super(styles); >- } >- >- protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, >- double boundsX, double boundsY, double boundsWidth, double boundsHeight) { >- >- ArrayList row = new ArrayList(); >- for ( int i =0; i < entitiesToLayout.length; i++) { >- addToRowList(entitiesToLayout[i], row); >- } >- >- int heightSoFar = 0; >- >- Collections.sort(row, new Comparator() { >- >- public int compare(Object arg0, Object arg1) { >- // TODO Auto-generated method stub >- List a0 = (List) arg0; >- List a1 = (List) arg1; >- LayoutEntity node0 = ((InternalNode)a0.get(0)).getLayoutEntity(); >- LayoutEntity node1 = ((InternalNode)a1.get(0)).getLayoutEntity(); >- return (int) (node0.getYInLayout() - (node1.getYInLayout())); >- } >- >- }); >- >- Iterator iterator = row.iterator(); >- while (iterator.hasNext() ) { >- List currentRow = (List) iterator.next(); >- Collections.sort(currentRow, new Comparator() { >- public int compare(Object arg0, Object arg1) { >- return (int) (((InternalNode)arg1).getLayoutEntity().getYInLayout() - ((InternalNode)arg0).getLayoutEntity().getYInLayout()); >- } >- }); >- Iterator iterator2 = currentRow.iterator(); >- int i = 0; >- int width = (int) ((boundsWidth / 2) - currentRow.size() * 75); >- >- heightSoFar += ((InternalNode)currentRow.get(0)).getLayoutEntity().getHeightInLayout() + VSPACING*8 ; >- while(iterator2.hasNext()) { >- InternalNode currentNode = (InternalNode) iterator2.next(); >- >- double location = width + 10*++i; >- currentNode.setLocation(location , heightSoFar); >- width += currentNode.getLayoutEntity().getWidthInLayout(); >- } >- } >- } >- >- >- private void addToRowList( InternalNode node, ArrayList list) { >- double layoutY = node.getLayoutEntity().getYInLayout(); >- >- for ( int i = 0; i < list.size(); i++ ) { >- List currentRow = (List) list.get(i); >- InternalNode currentRowNode = (InternalNode) currentRow.get(0); >- double currentRowY = currentRowNode.getLayoutEntity().getYInLayout(); >- //double currentRowHeight = currentRowNode.getLayoutEntity().getHeightInLayout(); >- if ( layoutY >= (currentRowY-DELTA) && layoutY <= currentRowY + DELTA ) { >- currentRow.add(node); >- //list.add(i, currentRow); >- return; >- } >- } >- List newRow = new ArrayList(); >- newRow.add(node); >- list.add(newRow); >- } >- >- protected int getCurrentLayoutStep() { >- // TODO Auto-generated method stub >- return 0; >- } >- >- protected int getTotalNumberOfLayoutSteps() { >- // TODO Auto-generated method stub >- return 0; >- } >- >- protected boolean isValidConfiguration(boolean asynchronous, boolean continuous) { >- // TODO Auto-generated method stub >- return true; >- } >- >- protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) { >- // TODO Auto-generated method stub >- } >- >- protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, >- double x, double y, double width, double height) { >- // TODO Auto-generated method stub >- >- } >- >- public void setLayoutArea(double x, double y, double width, double height) { >- // TODO Auto-generated method stub >- } >-} >- >Index: src/org/eclipse/zest/layouts/algorithms/RadialLayoutAlgorithm.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.layouts/src/org/eclipse/zest/layouts/algorithms/RadialLayoutAlgorithm.java,v >retrieving revision 1.5 >diff -u -r1.5 RadialLayoutAlgorithm.java >--- src/org/eclipse/zest/layouts/algorithms/RadialLayoutAlgorithm.java 12 Sep 2007 20:44:37 -0000 1.5 >+++ src/org/eclipse/zest/layouts/algorithms/RadialLayoutAlgorithm.java 28 Aug 2009 16:03:03 -0000 >@@ -1,149 +1,96 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >+ * Copyright (c) 2005-2009 The Chisel Group 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: The Chisel Group - initial API and implementation >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ * Ian Bull >+ ******************************************************************************/ > package org.eclipse.zest.layouts.algorithms; > >-import java.util.Iterator; >-import java.util.List; >- >-import org.eclipse.zest.layouts.LayoutStyles; >+import org.eclipse.zest.layouts.LayoutAlgorithm; > import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint; > import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >-import org.eclipse.zest.layouts.dataStructures.InternalNode; >-import org.eclipse.zest.layouts.dataStructures.InternalRelationship; >- >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; > > /** >- * This layout will take the given entities, apply a tree layout to them, and then display the >- * tree in a circular fashion with the roots in the center. >+ * This layout will take the given entities, apply a tree layout to them, and >+ * then display the tree in a circular fashion with the roots in the center. > * > * @author Casey Best > * @auhtor Rob Lintern > */ >-public class RadialLayoutAlgorithm extends TreeLayoutAlgorithm { >+public class RadialLayoutAlgorithm implements LayoutAlgorithm { >+ > private static final double MAX_DEGREES = Math.PI * 2; >- private double startDegree; >- private double endDegree; >- private TreeLayoutAlgorithm treeLayout; >- private List roots; >- >- >- /** >- * Creates a radial layout with no style. >- */ >- public RadialLayoutAlgorithm() { >- this ( LayoutStyles.NONE ); >- } >- >- //TODO: This is a really strange pattern. It extends tree layout and it contains a tree layout ? >- public RadialLayoutAlgorithm ( int styles ) { >- super( styles ); >- treeLayout = new TreeLayoutAlgorithm( styles ); >- startDegree = 0; >- endDegree = MAX_DEGREES; >- } >- >- public void setLayoutArea(double x, double y, double width, double height) { >- throw new RuntimeException("Operation not implemented"); >- } >- >+ private double startDegree = 0; >+ private double endDegree = MAX_DEGREES; >+ >+ private LayoutContext context; >+ private boolean resize = false; >+ >+ private TreeLayoutAlgorithm treeLayout = new TreeLayoutAlgorithm(); > >- protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) { >- if ( asynchronous && continueous ) return false; >- else if ( asynchronous && !continueous ) return true; >- else if ( !asynchronous && continueous ) return false; >- else if ( !asynchronous && !continueous ) return true; >- >- return false; >+ public void applyLayout(boolean clean) { >+ if (!clean) >+ return; >+ treeLayout.internalApplyLayout(); >+ EntityLayout[] entities = context.getEntities(); >+ DisplayIndependentRectangle bounds = context.getBounds(); >+ computeRadialPositions(entities, bounds); >+ if (resize) >+ AlgorithmHelper.maximizeSizes(entities); >+ AlgorithmHelper.fitWithinBounds(entities, bounds, resize); >+ } >+ >+ private void computeRadialPositions(EntityLayout[] entities, DisplayIndependentRectangle bounds) { >+ DisplayIndependentRectangle layoutBounds = AlgorithmHelper.getLayoutBounds(entities, false); >+ layoutBounds.x = bounds.x; >+ layoutBounds.width = bounds.width; >+ for (int i = 0; i < entities.length; i++) { >+ DisplayIndependentPoint location = entities[i].getLocation(); >+ double percenttheta = (location.x - layoutBounds.x) / layoutBounds.width; >+ double distance = (location.y - layoutBounds.y) / layoutBounds.height; >+ double theta = startDegree + Math.abs(endDegree - startDegree) * percenttheta; >+ location.x = distance * Math.cos(theta); >+ location.y = distance * Math.sin(theta); >+ entities[i].setLocation(location.x, location.y); >+ } > } >- > >- DisplayIndependentRectangle layoutBounds = null; >- protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) { >- // TODO Auto-generated method stub >- layoutBounds = new DisplayIndependentRectangle(x, y, width, height); >- super.preLayoutAlgorithm(entitiesToLayout, relationshipsToConsider, x, y, >- width, height); >+ public void setLayoutContext(LayoutContext context) { >+ this.context = context; >+ treeLayout.setLayoutContext(context); > } >- >- protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) { >- roots = treeLayout.getRoots(); >- computeRadialPositions (entitiesToLayout, layoutBounds); >- >- defaultFitWithinBounds(entitiesToLayout, layoutBounds); >- >- super.postLayoutAlgorithm(entitiesToLayout, relationshipsToConsider); > >- } >- > /** >- * Set the range the radial layout will use when applyLayout is called. >- * Both values must be in radians. >+ * Set the range the radial layout will use when applyLayout is called. Both >+ * values must be in radians. > */ >- public void setRangeToLayout (double startDegree, double endDegree) { >- this.startDegree = startDegree; >- this.endDegree = endDegree; >+ public void setRangeToLayout(double startDegree, double endDegree) { >+ this.startDegree = startDegree; >+ this.endDegree = endDegree; > } >- >- /** >- * Take the tree and make it round. This is done by determining the location of each entity in terms >- * of its percentage in the tree layout. Then apply that percentage to the radius and distance from >- * the center. >- */ >- protected void computeRadialPositions (InternalNode[] entities, DisplayIndependentRectangle bounds2) { //TODO TODO TODO >- DisplayIndependentRectangle bounds = new DisplayIndependentRectangle(getLayoutBounds(entities, true)); >- bounds.height = bounds2.height; >- bounds.y = bounds2.y; >- for (int i = 0; i < entities.length; i++) { >- InternalNode entity = entities[i]; >- double percentTheta = (entity.getInternalX() - bounds.x) / bounds.width; >- double distance = (entity.getInternalY() - bounds.y) / bounds.height; >- double theta = startDegree + Math.abs(endDegree - startDegree) * percentTheta; >- double newX = distance * Math.cos (theta); >- double newY = distance * Math.sin (theta); >- >- entity.setInternalLocation( newX, newY ); >- } >- } >- >+ > /** >- * Find the bounds in which the nodes are located. Using the bounds against the real bounds >- * of the screen, the nodes can proportionally be placed within the real bounds. >- * The bounds can be determined either including the size of the nodes or not. If the size >- * is not included, the bounds will only be guaranteed to include the center of each node. >+ * >+ * @return true if this algorithm is set to resize elements > */ >- protected DisplayIndependentRectangle getLayoutBounds (InternalNode[] entitiesToLayout, boolean includeNodeSize) { >- DisplayIndependentRectangle layoutBounds = super.getLayoutBounds(entitiesToLayout, includeNodeSize); >- DisplayIndependentPoint centerPoint = (roots != null) ? determineCenterPoint(roots) : >- new DisplayIndependentPoint (layoutBounds.x + layoutBounds.width / 2, layoutBounds.y + layoutBounds.height / 2); >- // The center entity is determined in applyLayout >- double maxDistanceX = Math.max( >- Math.abs (layoutBounds.x + layoutBounds.width - centerPoint.x), >- Math.abs (centerPoint.x - layoutBounds.x)); >- double maxDistanceY = Math.max( >- Math.abs (layoutBounds.y + layoutBounds.height - centerPoint.y), >- Math.abs (centerPoint.y - layoutBounds.y)); >- layoutBounds = new DisplayIndependentRectangle (centerPoint.x - maxDistanceX, centerPoint.y - maxDistanceY, maxDistanceX * 2, maxDistanceY * 2); >- return layoutBounds; >+ public boolean isResizing() { >+ return resize; > } >- >+ > /** >- * Find the center point between the roots >+ * >+ * @param resizing >+ * true if this algorithm should resize elements (default is >+ * false) > */ >- private DisplayIndependentPoint determineCenterPoint (List roots) { >- double totalX = 0, totalY = 0; >- for ( Iterator iterator = roots.iterator(); iterator.hasNext(); ) { >- InternalNode entity = (InternalNode)iterator.next(); >- totalX += entity.getInternalX(); >- totalY += entity.getInternalY(); >- } >- return new DisplayIndependentPoint (totalX / roots.size(), totalY / roots.size()); >+ public void setResizing(boolean resizing) { >+ resize = resizing; >+ treeLayout.setResizing(resize); > } > } >Index: src/org/eclipse/zest/layouts/algorithms/internal/DynamicScreen.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/internal/DynamicScreen.java >diff -N src/org/eclipse/zest/layouts/algorithms/internal/DynamicScreen.java >--- src/org/eclipse/zest/layouts/algorithms/internal/DynamicScreen.java 12 Sep 2007 20:44:38 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,126 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.algorithms.internal; >- >-import java.util.Comparator; >-import java.util.TreeSet; >- >-import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint; >-import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >-import org.eclipse.zest.layouts.dataStructures.InternalNode; >- >- >-public class DynamicScreen { >- >- private TreeSet XCoords = null; >- private TreeSet YCoords = null; >- >- >- >- private DisplayIndependentRectangle screenBounds = null; >- >- >- double minX = 0.0; >- double minY = 0.0; >- double maxX = 0.0; >- double maxY = 0.0; >- public void cleanScreen() { >- minX = 0.0; >- minY = 0.0; >- maxX = 0.0; >- maxY = 0.0; >- } >- >- class XComparator implements Comparator { >- public int compare(Object arg0, Object arg1) { >- InternalNode n1 = (InternalNode)arg0; >- InternalNode n2 = (InternalNode)arg1; >- if ( n1.getInternalX() > n2.getInternalX() ) return +1; >- else if ( n1.getInternalX() < n2.getInternalX() ) return -1; >- else { >- return n1.toString().compareTo( n2.toString() ); >- } >- >- } >- } >- class YComparator implements Comparator { >- public int compare(Object arg0, Object arg1) { >- InternalNode n1 = (InternalNode)arg0; >- InternalNode n2 = (InternalNode)arg1; >- if ( n1.getInternalY() > n2.getInternalY() ) return +1; >- else if ( n1.getInternalY() < n2.getInternalY() ) return -1; >- else { >- return n1.toString().compareTo( n2.toString() ); >- } >- >- } >- } >- >- >- >- >- public DynamicScreen(int x, int y, int width, int height) { >- XCoords = new TreeSet(new XComparator()); >- YCoords = new TreeSet(new YComparator()); >- >- >- >- this.screenBounds = new DisplayIndependentRectangle(x,y,width,height); >- } >- >- >- public void removeNode( InternalNode node ) { >- XCoords.remove( node ); >- YCoords.remove( node ); >- } >- >- public void addNode( InternalNode node ) { >- XCoords.add( node ); >- YCoords.add( node ); >- } >- >- public DisplayIndependentPoint getScreenLocation( InternalNode node ) { >- >- DisplayIndependentRectangle layoutBounds = calculateBounds(); >- >- double x = (layoutBounds.width == 0) ? 0 : (node.getInternalX() - layoutBounds.x) / layoutBounds.width; >- double y = (layoutBounds.height == 0) ? 0 : (node.getInternalY() - layoutBounds.y) / layoutBounds.height; >- >- x = screenBounds.x + x * screenBounds.width; >- y = screenBounds.y + y * screenBounds.height; >- >- return new DisplayIndependentPoint( x, y ); >- } >- >- public DisplayIndependentPoint getVirtualLocation( DisplayIndependentPoint point ) { >- >- DisplayIndependentRectangle layoutBounds = calculateBounds(); >- >- >- double x = (point.x/screenBounds.width) * layoutBounds.width + layoutBounds.x; >- double y = (point.y/screenBounds.height) * layoutBounds.height + layoutBounds.y; >- >- return new DisplayIndependentPoint( x, y ); >- } >- >- private DisplayIndependentRectangle calculateBounds() { >- InternalNode n1 = (InternalNode) XCoords.first(); >- InternalNode n2 = (InternalNode) XCoords.last(); >- InternalNode n3 = (InternalNode) YCoords.first(); >- InternalNode n4 = (InternalNode) YCoords.last(); >- double x = n1.getInternalX(); >- double width = n2.getInternalX(); >- double y = n3.getInternalY(); >- double height = n4.getInternalY(); >- return new DisplayIndependentRectangle(x, y, width - x, height - y); >- } >- >-} >Index: src/org/eclipse/zest/layouts/algorithms/internal/CycleChecker.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/internal/CycleChecker.java >diff -N src/org/eclipse/zest/layouts/algorithms/internal/CycleChecker.java >--- src/org/eclipse/zest/layouts/algorithms/internal/CycleChecker.java 12 Sep 2007 20:44:38 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,119 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.algorithms.internal; >- >-import java.util.ArrayList; >-import java.util.Arrays; >-import java.util.Hashtable; >-import java.util.Iterator; >-import java.util.List; >- >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.LayoutRelationship; >-import org.eclipse.zest.layouts.algorithms.AbstractLayoutAlgorithm; >-import org.eclipse.zest.layouts.exampleStructures.SimpleRelationship; >- >- >-/** >- * Checks for cycles in the given graph. >- * >- * @author Casey Best >- */ >-public class CycleChecker { >- /** >- * Tests if there is a directed cirlce in the graph formed by the given entities and relationships. >- * @param entities The entities in the graph to check >- * @param relationships The relationships in the graph to check >- * @param cycle Populated with the cycle encountered, if there is one. >- * @throws RuntimeException Thrown if entities doesn't contain all of the endpoints for each relationship in relationships >- * @return <code>true</code> if there is a directed circle. >- * Otherwise, <code>false</code>. >- */ >- public static boolean hasDirectedCircles(LayoutEntity[] entities, LayoutRelationship[] relationships, List cycle) { >- if (!AbstractLayoutAlgorithm.verifyInput(entities, relationships)) { >- throw new RuntimeException ("The endpoints of the relationships aren't contained in the entities list."); >- } >- //Enumeration enum; >- //Iterator iterator; >- >- Hashtable endPoints = new Hashtable(); >- >- // Initialize the relation(transitive) vector. >- for (int i = 0; i < relationships.length; i++) { >- LayoutRelationship rel = relationships[i]; >- >- //Add the relationship to the source endpoint >- Object subject = rel.getSourceInLayout(); >- List rels = (List) endPoints.get(subject); >- if (rels == null) { >- rels = new ArrayList(); >- endPoints.put(subject, rels); >- } >- if (!rels.contains(rel)) >- rels.add(rel); >- } >- boolean hasCyle = hasCycle(new ArrayList(Arrays.asList(entities)), endPoints, cycle); >- return hasCyle; >- } >- >- /** >- * Check passed in nodes for a cycle >- */ >- private static boolean hasCycle(List nodesToCheck, Hashtable endPoints, List cycle) { >- while (nodesToCheck.size() > 0) { >- Object checkNode = nodesToCheck.get(0); >- List checkedNodes = new ArrayList(); >- if (hasCycle(checkNode, new ArrayList(), null, endPoints, checkedNodes, cycle)) { >- return true; >- } >- nodesToCheck.removeAll(checkedNodes); >- } >- return false; >- } >- >- /** >- * Checks all the nodes attached to the nodeToCheck node for a cycle. All nodes >- * checked are placed in nodePathSoFar. >- * >- * @returns true if there is a cycle >- */ >- private static boolean hasCycle(Object nodeToCheck, List nodePathSoFar, SimpleRelationship cameFrom, Hashtable endPoints, List nodesChecked, List cycle) { >- if (nodePathSoFar.contains(nodeToCheck)) { >- cycle.addAll(nodePathSoFar); >- cycle.add(nodeToCheck); >- return true; >- } >- nodePathSoFar.add(nodeToCheck); >- nodesChecked.add(nodeToCheck); >- >- List relations = (List) endPoints.get(nodeToCheck); >- if (relations != null) { >- for (Iterator iter = relations.iterator(); iter.hasNext();) { >- SimpleRelationship rel = (SimpleRelationship) iter.next(); >- >- if (cameFrom == null || !rel.equals(cameFrom)) { >- Object currentNode = null; >- currentNode = rel.getDestinationInLayout(); >- if (hasCycle(currentNode, nodePathSoFar, rel, endPoints, nodesChecked, cycle)) { >- return true; >- } >- } >- >- } >- } >- >- nodePathSoFar.remove(nodeToCheck); >- >- return false; >- } >- >-} >Index: src/org/eclipse/zest/layouts/progress/ProgressEvent.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/progress/ProgressEvent.java >diff -N src/org/eclipse/zest/layouts/progress/ProgressEvent.java >--- src/org/eclipse/zest/layouts/progress/ProgressEvent.java 12 Sep 2007 20:44:38 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,47 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.progress; >- >-/** >- * When an algorithm wants to notify everyone it has completely part of its task, it >- * throws a ProgressEvent. The progress is a number (currentProgress) representing the >- * current steps completed out of the total number of steps (totalProgress) >- * >- * @author Casey Best >- */ >-public class ProgressEvent { >- int stepsCompleted; >- int totalSteps; >- >- /** >- * Creates a progress event. >- * @param stepsCompleted The current progress out of the total >- * @param totalNumberOfSteps The number used to indicate when the algorithm will finish >- */ >- public ProgressEvent (int stepsCompleted, int totalNumberOfSteps) { >- this.stepsCompleted = stepsCompleted; >- this.totalSteps = totalNumberOfSteps; >- } >- >- /** >- * Returns the number of steps already completed. >- */ >- public int getStepsCompleted() { >- return stepsCompleted; >- } >- >- /** >- * Returns the total number of steps to complete. >- */ >- public int getTotalNumberOfSteps() { >- return totalSteps; >- } >-} >Index: src/org/eclipse/zest/layouts/progress/ProgressListener.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/progress/ProgressListener.java >diff -N src/org/eclipse/zest/layouts/progress/ProgressListener.java >--- src/org/eclipse/zest/layouts/progress/ProgressListener.java 12 Sep 2007 20:44:38 -0000 1.4 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,38 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.progress; >- >- >-/** >- * Listens for ProgressEvents which are thrown by layout algorithms at frequent intervals. >- * >- * @author Ian Bull >- * @author Casey Best >- */ >-public interface ProgressListener { >- >- /** >- * >- * @param e >- */ >- public void progressStarted( ProgressEvent e ); >- >- /** >- * Called when the progress of a layout changes >- */ >- public void progressUpdated (ProgressEvent e); >- >- /** >- * >- * @param e >- */ >- public void progressEnded( ProgressEvent e ); >-} >Index: src/org/eclipse/zest/layouts/constraints/BasicEntityConstraint.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/constraints/BasicEntityConstraint.java >diff -N src/org/eclipse/zest/layouts/constraints/BasicEntityConstraint.java >--- src/org/eclipse/zest/layouts/constraints/BasicEntityConstraint.java 12 Sep 2007 20:44:38 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,46 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.constraints; >- >-/** >- * >- * @author Chris Bennett >- * >- */ >-public class BasicEntityConstraint implements LayoutConstraint { >- >- >- public boolean hasPreferredLocation = false; >- >- public double preferredX; >- public double preferredY; >- >- public boolean hasPreferredSize = false; >- public double preferredWidth; >- public double preferredHeight; >- >- public BasicEntityConstraint() { >- clear(); >- } >- >- /* >- * (non-Javadoc) >- * @see org.eclipse.zest.layouts.constraints.LayoutConstraint#clear() >- */ >- public void clear() { >- this.hasPreferredLocation = false; >- this.hasPreferredSize = false; >- this.preferredX = 0.0; >- this.preferredY = 0.0; >- this.preferredWidth = 0.0; >- this.preferredHeight = 0.0; >- } >-} >Index: src/org/eclipse/zest/layouts/constraints/EntityPriorityConstraint.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/constraints/EntityPriorityConstraint.java >diff -N src/org/eclipse/zest/layouts/constraints/EntityPriorityConstraint.java >--- src/org/eclipse/zest/layouts/constraints/EntityPriorityConstraint.java 12 Sep 2007 20:44:38 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,31 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.constraints; >- >-/** >- * A layout constraint that uses priorities >- * @author Ian Bull >- */ >-public class EntityPriorityConstraint implements LayoutConstraint { >- >- // A priority that can be set for nodes. This could be used >- // for a treemap layout >- public double priority = 1.0; >- >- /* >- * (non-Javadoc) >- * @see org.eclipse.zest.layouts.constraints.LayoutConstraint#clear() >- */ >- public void clear() { >- this.priority = 1.0; >- } >- >-} >Index: src/org/eclipse/zest/layouts/constraints/LayoutConstraint.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/constraints/LayoutConstraint.java >diff -N src/org/eclipse/zest/layouts/constraints/LayoutConstraint.java >--- src/org/eclipse/zest/layouts/constraints/LayoutConstraint.java 12 Sep 2007 20:44:38 -0000 1.4 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,26 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.constraints; >- >-/** >- * @author Ian Bull >- * @author Chris Bennett >- */ >-public interface LayoutConstraint { >- >- // Empty interface >- >- /** >- * This method clears all the fields of the layout constraints. >- * This should not be called outside the layout package >- */ >- public void clear(); >-} >Index: src/org/eclipse/zest/layouts/constraints/BasicEdgeConstraints.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/constraints/BasicEdgeConstraints.java >diff -N src/org/eclipse/zest/layouts/constraints/BasicEdgeConstraints.java >--- src/org/eclipse/zest/layouts/constraints/BasicEdgeConstraints.java 12 Sep 2007 20:44:38 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,32 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.constraints; >- >-/** >- * @author Ian Bull >- * @author Chris Bennett >- */ >-public class BasicEdgeConstraints implements LayoutConstraint { >- >- // These should all be accessed directly. >- public boolean isBiDirectional = false; >- public int weight = 1; >- >- /* >- * (non-Javadoc) >- * @see org.eclipse.zest.layouts.constraints.LayoutConstraint#clear() >- */ >- public void clear() { >- this.isBiDirectional = false; >- this.weight = 1; >- } >- >-} >Index: src/org/eclipse/zest/layouts/constraints/LabelLayoutConstraint.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/constraints/LabelLayoutConstraint.java >diff -N src/org/eclipse/zest/layouts/constraints/LabelLayoutConstraint.java >--- src/org/eclipse/zest/layouts/constraints/LabelLayoutConstraint.java 12 Sep 2007 20:44:38 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,33 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.constraints; >- >-/** >- * @author Ian Bull >- * @author Chris Bennett >- */ >-public class LabelLayoutConstraint implements LayoutConstraint { >- >- // These should be accessed directly >- public String label; >- public int pointSize; >- >- /* >- * (non-Javadoc) >- * @see org.eclipse.zest.layouts.constraints.LayoutConstraint#clear() >- */ >- public void clear() { >- label = null; >- pointSize = 1; >- } >- >-} >- >Index: src/org/eclipse/zest/layouts/exampleStructures/SimpleNode.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/exampleStructures/SimpleNode.java >diff -N src/org/eclipse/zest/layouts/exampleStructures/SimpleNode.java >--- src/org/eclipse/zest/layouts/exampleStructures/SimpleNode.java 12 Jan 2008 01:44:24 -0000 1.9 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,318 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.exampleStructures; >- >-import java.util.Comparator; >-import java.util.HashMap; >-import java.util.LinkedList; >-import java.util.List; >-import java.util.Map; >-import java.util.TreeSet; >- >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.constraints.BasicEntityConstraint; >-import org.eclipse.zest.layouts.constraints.EntityPriorityConstraint; >-import org.eclipse.zest.layouts.constraints.LabelLayoutConstraint; >-import org.eclipse.zest.layouts.constraints.LayoutConstraint; >- >-/** >- * Rerpresents a simple node that can be used in the layout algorithms. >- * >- * @author Ian Bull >- * @author Casey Best (Version 1 by Rob Lintern) >- * @version 2 >- */ >-public class SimpleNode implements LayoutEntity { >- private static Object NODE_NORMAL_COLOR; >- private static Object NODE_SELECTED_COLOR; >- private static Object NODE_ADJACENT_COLOR; >- private static Object BORDER_NORMAL_COLOR; >- private static Object BORDER_SELECTED_COLOR; >- private static Object BORDER_ADJACENT_COLOR; >- >- private static final int BORDER_NORMAL_STROKE = 1; >- private static final int BORDER_STROKE_SELECTED = 2; >- >- /** >- * A list of layout dependent attributes >- */ >- private Map attributes; >- >- protected double x, y, width, height; >- protected Object realObject; >- private boolean ignoreInLayout = false; >- >- private Object colour = null; >- private Object borderColor = null; >- private int borderWidth; >- >- private TreeSet listOfRels = null; >- >- private Object internalNode; >- >- >- /** >- * Constructs a new SimpleNode. >- */ >- public SimpleNode(Object realObject) { >- this (realObject, -1, -1, 110, 110); >- } >- >- class UniqueCompare implements Comparator { >- public int compare(Object o1, Object o2) { >- // TODO this may not always be a unique comparison >- return o1.toString().compareTo( o2.toString() ); >- } >- } >- >- /** >- * Constructs a new SimpleNode. >- */ >- public SimpleNode(Object realObject, double x, double y, double width, double height) { >- this.realObject = realObject; >- this.x = x; >- this.y = y; >- this.width = width; >- this.height = height; >- this.attributes = new HashMap(); >- this.borderWidth = BORDER_NORMAL_STROKE; >- listOfRels = new TreeSet( new UniqueCompare() ); >- this.colour = NODE_NORMAL_COLOR; >- this.borderColor = BORDER_NORMAL_COLOR; >- } >- >- public static void setNodeColors (Object nodeNormalColor, Object borderNormalColor, Object nodeSelectedColor, Object nodeAdjacentColor, Object borderSelectedColor, Object borderAdjacentColor) { >- NODE_NORMAL_COLOR = nodeNormalColor; >- BORDER_NORMAL_COLOR = borderNormalColor; >- NODE_SELECTED_COLOR = nodeSelectedColor; >- NODE_ADJACENT_COLOR = nodeAdjacentColor; >- BORDER_SELECTED_COLOR = borderSelectedColor; >- BORDER_ADJACENT_COLOR = borderAdjacentColor; >- } >- >- public void addRelationship( SimpleRelationship rel ) { >- listOfRels.add( rel ); >- } >- >- >- public SimpleRelationship[] getRelationships() { >- int size = listOfRels.size(); >- return (SimpleRelationship[]) this.listOfRels.toArray( new SimpleRelationship[ size ] ); >- } >- >- public List getRelatedEntities() { >- int size = listOfRels.size(); >- SimpleRelationship[] a_listOfRels = (SimpleRelationship[]) this.listOfRels.toArray( new SimpleRelationship[ size ] ); >- LinkedList listOfRelatedEntities = new LinkedList(); >- for (int i = 0; i < a_listOfRels.length; i++) { >- SimpleRelationship rel = a_listOfRels[ i ]; >- if ( rel.sourceEntity != this && rel.destinationEntity != this ) { >- throw new RuntimeException("Problem, we have a relationship and we are not the source or the dest"); >- } >- if ( rel.sourceEntity != this ) { >- listOfRelatedEntities.add( rel.sourceEntity ); >- } >- if ( rel.destinationEntity != this ) { >- listOfRelatedEntities.add( rel.destinationEntity ); >- } >- >- } >- return listOfRelatedEntities; >- } >- >- >- >- /** >- * Ignores this entity in the layout >- * @param ignore Should this entity be ignored >- */ >- public void ignoreInLayout( boolean ignore ) { >- this.ignoreInLayout = ignore; >- } >- >- public Object getRealObject() { >- return realObject; >- } >- >- public boolean hasPreferredLocation() { >- return this.ignoreInLayout; >- } >- >- /** >- * Gets the x position of this SimpleNode. >- */ >- public double getX() { >- return x; >- } >- >- /** >- * Gets the y position of this SimpleNode. >- */ >- public double getY() { >- return y; >- } >- >- /** >- * Get the size of this node >- */ >- public double getWidth() { >- return width; >- } >- >- /** >- * Get the size of this node >- */ >- public double getHeight() { >- return height; >- } >- >- public void setSizeInLayout(double width, double height) { >- if (!ignoreInLayout) { >- this.width = width; >- this.height = height; >- } >- } >- >- public void setLocation( double x, double y ) { >- this.x = x; >- this.y = y; >- } >- >- public void setLocationInLayout(double x, double y) { >- if (!ignoreInLayout) { >- this.x = x; >- this.y = y; >- } >- } >- >- /** >- * An algorithm may require a place to store information. Use this structure for that purpose. >- */ >- public void setAttributeInLayout (Object attribute, Object value) { >- attributes.put (attribute, value); >- } >- >- /** >- * An algorithm may require a place to store information. Use this structure for that purpose. >- */ >- public Object getAttributeInLayout (Object attribute) { >- return attributes.get (attribute); >- } >- >- public boolean equals(Object object) { >- boolean result = false; >- if (object instanceof SimpleNode) { >- SimpleNode node = (SimpleNode)object; >- result = realObject.equals (node.getRealObject()); >- } >- return result; >- } >- >- public int hashCode() { >- return realObject.hashCode(); >- } >- >- // all objects are equal >- public int compareTo(Object arg0) { >- return 0; >- } >- >- public String toString() { >- return realObject.toString(); >- } >- >- public void setSelected() { >- this.colour = NODE_SELECTED_COLOR; >- this.borderColor = BORDER_SELECTED_COLOR; >- this.borderWidth = BORDER_STROKE_SELECTED; >- } >- >- public void setUnSelected() { >- this.colour = NODE_NORMAL_COLOR; >- this.borderColor = BORDER_NORMAL_COLOR; >- this.borderWidth = BORDER_NORMAL_STROKE; >- } >- >- public void setAdjacent() { >- this.colour = NODE_ADJACENT_COLOR; >- this.borderColor = BORDER_ADJACENT_COLOR; >- this.borderWidth = BORDER_STROKE_SELECTED; >- } >- >- public Object getColor() { >- return this.colour; >- } >- >- public int getBorderWidth() { >- return borderWidth; >- } >- >- public Object getBorderColor() { >- return borderColor; >- } >- >- /* (non-Javadoc) >- * @see ca.uvic.cs.chisel.layouts.LayoutEntity#getInternalEntity() >- */ >- public Object getLayoutInformation() { >- return internalNode; >- } >- >- /* (non-Javadoc) >- * @see ca.uvic.cs.chisel.layouts.LayoutEntity#setInternalEntity(java.lang.Object) >- */ >- public void setLayoutInformation(Object internalEntity) { >- this.internalNode = internalEntity; >- } >- >- /** >- * Populate the specified layout constraint >- */ >- public void populateLayoutConstraint(LayoutConstraint constraint) { >- if ( constraint instanceof LabelLayoutConstraint ) { >- LabelLayoutConstraint labelConstraint = (LabelLayoutConstraint) constraint; >- labelConstraint.label = realObject.toString(); >- labelConstraint.pointSize = 18; >- } >- else if ( constraint instanceof BasicEntityConstraint ) { >- // noop >- } >- else if ( constraint instanceof EntityPriorityConstraint ) { >- EntityPriorityConstraint priorityConstraint = (EntityPriorityConstraint) constraint; >- priorityConstraint.priority = Math.random() * 10 + 1; >- } >- } >- >- public double getHeightInLayout() { >- return this.height; >- } >- >- public double getWidthInLayout() { >- return this.width; >- } >- >- public double getXInLayout() { >- return this.x; >- } >- >- public double getYInLayout() { >- return this.y; >- } >- >- public Object getGraphData() { >- return null; >- } >- >- public void setGraphData(Object o) { >- >- } >- >-} >Index: src/org/eclipse/zest/layouts/exampleStructures/SimpleGraph.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/exampleStructures/SimpleGraph.java >diff -N src/org/eclipse/zest/layouts/exampleStructures/SimpleGraph.java >--- src/org/eclipse/zest/layouts/exampleStructures/SimpleGraph.java 12 Sep 2007 20:44:37 -0000 1.4 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,140 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.exampleStructures; >- >-import java.util.ArrayList; >-import java.util.HashMap; >-import java.util.Iterator; >-import java.util.List; >-import java.util.Map; >- >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.LayoutGraph; >-import org.eclipse.zest.layouts.LayoutRelationship; >- >- >-/** >- * Create a very simple graph that can be used in the layout algorithms >- * >- * @author Casey Best >- * @author Chris Callendar >- */ >-public class SimpleGraph implements LayoutGraph { >- >- Map objectsToNodes; >- List relationships; >- >- public SimpleGraph() { >- objectsToNodes = new HashMap(); >- relationships = new ArrayList(); >- } >- >- /** >- * Adds the node. >- * @param node The node to add. >- */ >- public void addEntity(LayoutEntity node) { >- if (node instanceof SimpleNode) { >- objectsToNodes.put(((SimpleNode)node).getRealObject(), node); >- } >- } >- >- /** >- * Creates a LayoutEntity containing an object. >- */ >- public LayoutEntity addObjectNode(Object object) { >- SimpleNode simpleNode = (SimpleNode) objectsToNodes.get (object); >- if (simpleNode == null) { >- simpleNode = new SimpleNode(object); >- objectsToNodes.put (object, simpleNode); >- } >- return simpleNode; >- >- } >- >- /** >- * Add a relationship between two objects. Layout algorithms need to know >- * whether a relationship is one way or bi-directional. This method assumes that >- * all relationships are bi-direcional and have the same weight. >- */ >- public void addObjectRelationship (Object sourceNode, Object destinationNode) { >- addObjectRelationship(sourceNode, destinationNode, true, 1); >- } >- >- /** >- * Add a relationship between two objects. Layout algorithms need to know >- * whether a relationship is one way or bi-directional. >- */ >- public void addObjectRelationship (Object sourceObject, Object destinationObject, boolean bidirectional, int weight) { >- addObjectNode(sourceObject); >- addObjectNode(destinationObject); >- SimpleNode sourceNode = (SimpleNode) objectsToNodes.get(sourceObject); >- SimpleNode destinationNode = (SimpleNode) objectsToNodes.get(destinationObject); >- SimpleRelationship simpleRelationship = new SimpleRelationship(sourceNode, destinationNode, bidirectional, weight); >- relationships.add(simpleRelationship); >- } >- >- /* (non-Javadoc) >- * @see ca.uvic.cs.chisel.layouts.LayoutGraph#addRelationship(ca.uvic.cs.chisel.layouts.LayoutEntity, ca.uvic.cs.chisel.layouts.LayoutEntity) >- */ >- public void addRelationship(LayoutEntity srcNode, LayoutEntity destNode) { >- addRelationship(srcNode, destNode, true, 1); >- } >- >- /* (non-Javadoc) >- * @see ca.uvic.cs.chisel.layouts.LayoutGraph#addRelationship(ca.uvic.cs.chisel.layouts.LayoutEntity, ca.uvic.cs.chisel.layouts.LayoutEntity, boolean, int) >- */ >- public void addRelationship(LayoutEntity srcNode, LayoutEntity destNode, boolean bidirectional, int weight) { >- addEntity(srcNode); >- addEntity(destNode); >- SimpleRelationship rel = new SimpleRelationship(srcNode, destNode, bidirectional, weight); >- relationships.add(rel); >- } >- >- /* (non-Javadoc) >- * @see ca.uvic.cs.chisel.layouts.LayoutGraph#addRelationship(ca.uvic.cs.chisel.layouts.LayoutRelationship) >- */ >- public void addRelationship(LayoutRelationship relationship) { >- relationships.add(relationship); >- } >- >- /** >- * Returns a list of SimpleNodes that represent the objects added to this graph using addNode. Note that >- * any manipulation to this graph was done on the SimpleNodes, not the real objects. You >- * must still manipulate them yourself. >- */ >- public List getEntities() { >- return new ArrayList (objectsToNodes.values()); >- } >- >- /** >- * Returns a list of SimpleRelationships that represent the objects added to this graph using addRelationship. >- */ >- public List getRelationships() { >- return relationships; >- } >- >- /** >- * Checks the relationships to see if they are all bidirectional. >- * @return boolean if all edges are bidirectional. >- */ >- public boolean isBidirectional() { >- boolean isBidirectional = true; >- for (Iterator iter = relationships.iterator(); iter.hasNext(); ) { >- SimpleRelationship rel = (SimpleRelationship) iter.next(); >- if (!rel.isBidirectionalInLayout()) { >- isBidirectional = false; >- break; >- } >- } >- return isBidirectional; >- } >-} >Index: src/org/eclipse/zest/layouts/exampleStructures/SimpleRelationship.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/exampleStructures/SimpleRelationship.java >diff -N src/org/eclipse/zest/layouts/exampleStructures/SimpleRelationship.java >--- src/org/eclipse/zest/layouts/exampleStructures/SimpleRelationship.java 12 Jan 2008 01:44:24 -0000 1.7 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,274 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.exampleStructures; >- >-import java.util.HashMap; >-import java.util.Map; >- >-import org.eclipse.zest.layouts.LayoutBendPoint; >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.LayoutRelationship; >-import org.eclipse.zest.layouts.constraints.BasicEdgeConstraints; >-import org.eclipse.zest.layouts.constraints.LabelLayoutConstraint; >-import org.eclipse.zest.layouts.constraints.LayoutConstraint; >-import org.eclipse.zest.layouts.dataStructures.BendPoint; >- >- >-/** >- * The SimpleRelation class describes the relationship between >- * two objects: source and destination. Each relationship >- * has a weight and direction associated with it. >- * Note: The source object is at the beginning of the relationship. >- * Note: The destination object is at the end of the relationship. >- * >- * @version 2.0 >- * @author Casey Best (version 1.0 by Jingwei Wu) >- * @author Chris Bennett >- */ >-public class SimpleRelationship implements LayoutRelationship { >- >- private static int DEFAULT_REL_LINE_WIDTH = 1; >- private static int DEFAULT_REL_LINE_WIDTH_SELECTED = DEFAULT_REL_LINE_WIDTH + 2; >- private static Object DEFAULT_RELATIONSHIP_COLOR; >- private static Object DEFAULT_RELATIONSHIP_HIGHLIGHT_COLOR; >- >- /** The line width for this relationship. */ >- private int lineWidth = DEFAULT_REL_LINE_WIDTH; >- >- /** The color for this relationship. */ >- private Object color = DEFAULT_RELATIONSHIP_COLOR; >- >- /** >- * A list of layout dependent attributes >- */ >- private Map attributes; >- >- /** >- * The sourceEntity of this SimpleRelation. >- */ >- protected LayoutEntity sourceEntity; >- >- /** >- * The object of this SimpleRelation. >- */ >- protected LayoutEntity destinationEntity; >- >- /** >- * If directional, algorithms must note the direction of the relationship. >- * If not directional, algorithms are to ignore which direction the relationship is going. >- * Switching the source and destination should make no difference. >- */ >- protected boolean bidirectional; >- >- /** >- * The weight given to this relation. >- */ >- private double weight; >- >- private Object internalRelationship; >- >- private LayoutBendPoint[] bendPoints; >- >- private String label; >- >- /** >- * Constructor. >- * @param sourceEntity The sourceEntity of this SimpleRelation. >- * @param destinationEntity The object of this SimpleRelation. >- * @param bidirectional Determines if the <code>sourceEntity</code> and >- * <code>destinationEntity</code> are equal(exchangeable). >- * @throws java.lang.NullPointerException If either <code>sourceEntity >- * </code> or <code>destinationEntity</code> is <code>null</code>. >- */ >- public SimpleRelationship(LayoutEntity sourceEntity, LayoutEntity destinationEntity, boolean bidirectional) { >- this (sourceEntity, destinationEntity, bidirectional, 1); >- } >- >- /** >- * Constructor. >- * @param sourceEntity The sourceEntity of this SimpleRelation. >- * @param destinationEntity The destinationEntity of this SimpleRelation. >- * @param exchangeable Determines if the <code>sourceEntity</code> and >- * <code>destinationEntity</code> are equal(exchangeable). >- * @throws java.lang.NullPointerException If either <code>sourceEntity >- * </code> or <code>destinationEntity</code> is <code>null</code>. >- */ >- public SimpleRelationship(LayoutEntity sourceEntity, LayoutEntity destinationEntity, boolean bidirectional, double weight) { >- this.destinationEntity = destinationEntity; >- this.sourceEntity = sourceEntity; >- this.bidirectional = bidirectional; >- this.weight = weight; >- this.attributes = new HashMap(); >- this.lineWidth = DEFAULT_REL_LINE_WIDTH; >- this.color = DEFAULT_RELATIONSHIP_COLOR; >- } >- >- /** >- * Gets the sourceEntity of this SimpleRelation whether the relation is >- * exchangeable or not. >- * @return The sourceEntity. >- */ >- public LayoutEntity getSourceInLayout() { >- return sourceEntity; >- } >- >- /** >- * Gets the destinationEntity of this SimpleRelation whether the relation is >- * exchangeable or not. >- * @return The destinationEntity of this SimpleRelation. >- */ >- public LayoutEntity getDestinationInLayout() { >- return destinationEntity; >- } >- >- /** >- * If bidirectional, the direction of the relationship doesn't matter. Switching the source and destination should make no difference. >- * If not bidirectional, layout algorithms need to take into account the direction of the relationship. The direction is based on the >- * source and destination entities. >- */ >- public boolean isBidirectionalInLayout() { >- return bidirectional; >- } >- >- public void setWeightInLayout(double weight) { >- this.weight = weight; >- } >- >- public double getWeightInLayout() { >- return weight; >- } >- >- /** >- * An algorithm may require a place to store information. Use this structure for that purpose. >- */ >- public void setAttributeInLayout (String attribute, Object value) { >- attributes.put (attribute, value); >- } >- >- /** >- * An algorithm may require a place to store information. Use this structure for that purpose. >- */ >- public Object getAttributeInLayout (String attribute) { >- return attributes.get (attribute); >- } >- >- public String toString() { >- String arrow = (isBidirectionalInLayout() ? " <-> " : " -> "); >- return "(" + sourceEntity + arrow + destinationEntity + ")"; >- } >- >- public int getLineWidth() { >- return this.lineWidth; >- } >- >- public void setLineWidth( int lineWidth ) { >- this.lineWidth = lineWidth; >- } >- >- public void resetLineWidth() { >- this.lineWidth = DEFAULT_REL_LINE_WIDTH; >- } >- >- public static void setDefaultSize(int i) { >- DEFAULT_REL_LINE_WIDTH = i; >- DEFAULT_REL_LINE_WIDTH_SELECTED = DEFAULT_REL_LINE_WIDTH + 2; >- } >- >- public void setSelected() { >- this.color = DEFAULT_RELATIONSHIP_HIGHLIGHT_COLOR; >- this.lineWidth = DEFAULT_REL_LINE_WIDTH_SELECTED; >- } >- >- public void setUnSelected() { >- this.color = DEFAULT_RELATIONSHIP_COLOR; >- this.lineWidth = DEFAULT_REL_LINE_WIDTH; >- } >- >- public Object getColor() { >- return color; >- } >- >- public void setColor(Object c) { >- this.color = c; >- } >- >- public static void setDefaultColor(Object c) { >- DEFAULT_RELATIONSHIP_COLOR = c; >- } >- >- public static void setDefaultHighlightColor(Object c) { >- DEFAULT_RELATIONSHIP_HIGHLIGHT_COLOR = c; >- } >- >- /* (non-Javadoc) >- * @see ca.uvic.cs.chisel.layouts.LayoutRelationship#getInternalRelationship() >- */ >- public Object getLayoutInformation() { >- return internalRelationship; >- } >- >- /* (non-Javadoc) >- * @see ca.uvic.cs.chisel.layouts.LayoutRelationship#setInternalRelationship(java.lang.Object) >- */ >- public void setLayoutInformation(Object layoutInformation) { >- this.internalRelationship = layoutInformation; >- } >- >- >- public void setBendPoints(LayoutBendPoint[] bendPoints) { >- this.bendPoints = bendPoints; >- } >- >- public LayoutBendPoint[] getBendPoints() { >- return this.bendPoints; >- } >- >- public void clearBendPoints() { >- this.bendPoints = new BendPoint[0]; >- } >- >- >- public void setDestinationInLayout(LayoutEntity destination) { >- this.destinationEntity = destination; >- } >- >- /** >- * Set the label for this edge (available in the label layout constraint). >- */ >- public void setLabel(String label) { >- this.label = label; >- } >- >- /** >- * Populate the specified layout constraint >- */ >- public void populateLayoutConstraint(LayoutConstraint constraint) { >- if ( constraint instanceof LabelLayoutConstraint ) { >- LabelLayoutConstraint labelConstraint = (LabelLayoutConstraint) constraint; >- labelConstraint.label = this.label; >- labelConstraint.pointSize = 18; >- } >- else if ( constraint instanceof BasicEdgeConstraints ) { >- // noop >- >- } >- } >- >- public Object getGraphData() { >- return null; >- } >- >- public void setGraphData(Object o) { >- >- } >- >- >-} >Index: src/org/eclipse/zest/layouts/exampleStructures/SimpleFilter.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/exampleStructures/SimpleFilter.java >diff -N src/org/eclipse/zest/layouts/exampleStructures/SimpleFilter.java >--- src/org/eclipse/zest/layouts/exampleStructures/SimpleFilter.java 12 Jan 2008 01:44:24 -0000 1.4 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,30 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.exampleStructures; >- >-import org.eclipse.zest.layouts.Filter; >-import org.eclipse.zest.layouts.LayoutItem; >- >-/** >- * A very simple example of a filter. This filter never filters >- * any object. >- * >- * @author Casey Best >- */ >-public class SimpleFilter implements Filter { >- >- /** >- * Doesn't filter anything >- */ >- public boolean isObjectFiltered(LayoutItem object) { >- return false; >- } >-} >Index: META-INF/MANIFEST.MF >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.layouts/META-INF/MANIFEST.MF,v >retrieving revision 1.14 >diff -u -r1.14 MANIFEST.MF >--- META-INF/MANIFEST.MF 23 Apr 2009 03:41:00 -0000 1.14 >+++ META-INF/MANIFEST.MF 28 Aug 2009 16:03:02 -0000 >@@ -7,12 +7,8 @@ > Bundle-Localization: plugin > Export-Package: org.eclipse.zest.layouts, > org.eclipse.zest.layouts.algorithms, >- org.eclipse.zest.layouts.algorithms.internal, >- org.eclipse.zest.layouts.constraints, > org.eclipse.zest.layouts.dataStructures, >- org.eclipse.zest.layouts.exampleStructures, >- org.eclipse.zest.layouts.exampleUses, >- org.eclipse.zest.layouts.progress >+ org.eclipse.zest.layouts.interfaces > Require-Bundle: org.eclipse.swt;visibility:=reexport, > org.eclipse.core.runtime, > org.eclipse.jface, >Index: src/org/eclipse/zest/layouts/LayoutRelationship.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/LayoutRelationship.java >diff -N src/org/eclipse/zest/layouts/LayoutRelationship.java >--- src/org/eclipse/zest/layouts/LayoutRelationship.java 12 Jan 2008 01:42:53 -0000 1.9 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,82 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts; >- >-import org.eclipse.zest.layouts.constraints.LayoutConstraint; >- >- >- >-/** >- * This represents a single relationship, providing the layout algorithms with >- * a common interface to run on. >- * >- * @author Casey Best >- * @author Chris Callendar >- */ >-public interface LayoutRelationship extends LayoutItem { >- >- >- /** >- * Gets the sourceEntity of this SimpleRelation whether the relation is >- * exchangeable or not. >- * @return The sourceEntity. >- */ >- public LayoutEntity getSourceInLayout(); >- >- /** >- * Gets the destinationEntity of this SimpleRelation whether the relation is >- * exchangeable or not. >- * @return The destinationEntity of this SimpleRelation. >- */ >- public LayoutEntity getDestinationInLayout(); >- >- >- /** >- * Sets the internal relationship object. >- * @param layoutInformation >- */ >- public void setLayoutInformation(Object layoutInformation); >- >- /** >- * Returns the internal relationship object. >- * @return Object >- */ >- public Object getLayoutInformation(); >- >- /** >- * Specify a set of bend points. The layout algorithm using this will pass >- * in an empty array of bendPoints, or not even call this method, >- * if there are no bend points associated with this edge. >- * >- * If you are updating an existing application you can just implement this >- * method to do nothing. >- * >- * @param bendPoints A list of bend points. All bendpoint locations are expressed >- * as percentages of the bounds (0,0 to 1,1).The first bendpoint in the list must be the >- * source point of this relationship and the last bendpoint the destination point >- * for this relationship. This allows the correct positioning of bendpoints >- * relative to the source and destination points when drawing the graph. >- */ >- public void setBendPoints(LayoutBendPoint[] bendPoints); >- >- /** >- * Clear bend points and related bounds >- * If you are updating an existing application you can just implement this >- * method to do nothing. >- */ >- public void clearBendPoints(); >- >- /** >- * Classes should update the specirfied layout constraint if recognized >- * @return >- */ >- public void populateLayoutConstraint(LayoutConstraint constraint); >-} >Index: src/org/eclipse/zest/layouts/LayoutAlgorithm.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.layouts/src/org/eclipse/zest/layouts/LayoutAlgorithm.java,v >retrieving revision 1.7 >diff -u -r1.7 LayoutAlgorithm.java >--- src/org/eclipse/zest/layouts/LayoutAlgorithm.java 12 Sep 2007 20:44:37 -0000 1.7 >+++ src/org/eclipse/zest/layouts/LayoutAlgorithm.java 28 Aug 2009 16:03:02 -0000 >@@ -1,111 +1,50 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >+ * Copyright (c) 2005-2009 The Chisel Group 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: The Chisel Group - initial API and implementation >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ * Ian Bull >+ ******************************************************************************/ > package org.eclipse.zest.layouts; > >-import java.util.Comparator; >-import java.util.List; >- >-import org.eclipse.zest.layouts.progress.ProgressListener; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; > > /** >- * A simple interface used by all layouts. >+ * An interface for all layout algorithms. > * >- * Each layout Algorithm must implement the applyLayoutInternal method which actually compute the layout > * >- * @author Casey Best >- * @author Ian Bull > */ > public interface LayoutAlgorithm { > > /** >- * Apply the layout to the given entities. The entities will be moved and resized based >- * on the algorithm. >+ * Sets the layout context for this algorithm. The receiver will unregister >+ * from its previous layout context and register to the new one >+ * (registration means for example adding listeners). After a call to this >+ * method, the receiving algorithm can compute and cache internal data >+ * related to given context and perform an initial layout. > * >- * @param entitiesToLayout Apply the algorithm to these entities >- * @param relationshipsToConsider Only consider these relationships when applying the algorithm. >- * @param x The left side of the bounds in which the layout can place the entities. >- * @param y The top side of the bounds in which the layout can place the entities. >- * @param width The width of the bounds in which the layout can place the entities. >- * @param height The height of the bounds in which the layout can place the entities. >- * @param asynchronous Should the algorithm run Asynchronously >- */ >- public void applyLayout(LayoutEntity[] entitiesToLayout, LayoutRelationship[] relationshipsToConsider, double x, double y, double width, double height, boolean asynchronous, boolean continuous) throws InvalidLayoutConfiguration; >- >- /** >- * Returns whether or not the algorithm is currenly running >- * @return True if a layout algorithm is currenly running, false otherwise >- */ >- public boolean isRunning(); >- >- /** >- * Determines the order in which the objects should be displayed. >- * Note: Some algorithms force a specific order, in which case >- * this comparator will be ignored. >- */ >- public void setComparator(Comparator comparator); >- >- /** >- * Filters the entities and relationships to apply the layout on >- */ >- public void setFilter(Filter filter); >- >- /** >- * Set the width to height ratio you want the entities to use >- * Note: Each layout is responsible for ensuring this ratio is used. >- * Note: By default the layout will use a ratio of 1.0 for each entity. >- */ >- public void setEntityAspectRatio(double ratio); >- >- /** >- * Returns the width to height ratio this layout will use to set the size of the entities. >- * Note: By default the layout will use a ratio of 1.0 for each entity. >+ * @param context >+ * a new layout context or null if this algorithm should not >+ * perform any layout > */ >- public double getEntityAspectRatio(); >- >- /** >- * A layout algorithm could take an uncomfortable amout of time to complete. To relieve some of >- * the mystery, the layout algorithm will notify each ProgressListener of its progress. >- */ >- public void addProgressListener(ProgressListener listener); >- >- /** >- * Removes the given progress listener, preventing it from receiving any more updates. >- */ >- public void removeProgressListener(ProgressListener listener); >- >- /** >- * Makes a request to this layout algorithm to stop running. >- */ >- public void stop(); >- >- /** >- * Sets the style for this layout algorithm. This will overwrite any other style set. >- * @param style >- */ >- public void setStyle(int style); >+ public void setLayoutContext(LayoutContext context); > > /** >+ * Makes this algorithm perform layout computation and apply it to its >+ * context. > * >- * @return >+ * @param clean >+ * if true the receiver should assume that the layout context has >+ * changed significantly and recompute the whole layout even if >+ * it keeps track of changes with listeners. False can be used >+ * after dynamic layout in a context is turned back on so that >+ * layout algorithm working in background can apply accumulated >+ * changes. Static layout algorithm can ignore this call entirely >+ * if clean is false. > */ >- public int getStyle(); >- >- public void addEntity(LayoutEntity entity); >- >- public void addRelationship(LayoutRelationship relationship); >- >- public void removeEntity(LayoutEntity entity); >- >- public void removeRelationship(LayoutRelationship relationship); >- >- public void removeRelationships(List relationships); >+ public void applyLayout(boolean clean); > > } >Index: src/org/eclipse/zest/layouts/LayoutBendPoint.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/LayoutBendPoint.java >diff -N src/org/eclipse/zest/layouts/LayoutBendPoint.java >--- src/org/eclipse/zest/layouts/LayoutBendPoint.java 12 Sep 2007 20:44:37 -0000 1.4 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,22 +0,0 @@ >-/******************************************************************************* >- * Copyright 2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >-package org.eclipse.zest.layouts; >- >-/** >- * Specifies a single bend point in a graph relationship. >- * @author Ian Bull >- * @author Chris Bennett >- */ >-public interface LayoutBendPoint { >- public double getX(); >- public double getY(); >- public boolean getIsControlPoint(); >-} >Index: src/org/eclipse/zest/layouts/LayoutItem.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/LayoutItem.java >diff -N src/org/eclipse/zest/layouts/LayoutItem.java >--- src/org/eclipse/zest/layouts/LayoutItem.java 12 Jan 2008 01:42:28 -0000 1.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,24 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts; >- >-/** >- * Super interface for both Layout Entities and Layout Relationships >- * >- * @author Ian Bull >- * >- */ >-public interface LayoutItem { >- >- public void setGraphData(Object o); >- public Object getGraphData(); >- >-} >Index: src/org/eclipse/zest/layouts/InvalidLayoutConfiguration.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/InvalidLayoutConfiguration.java >diff -N src/org/eclipse/zest/layouts/InvalidLayoutConfiguration.java >--- src/org/eclipse/zest/layouts/InvalidLayoutConfiguration.java 12 Sep 2007 20:44:37 -0000 1.4 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,23 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts; >- >-/** >- * >- * @author Ian Bull >- * >- */ >-public class InvalidLayoutConfiguration extends Exception { >- >- static final long serialVersionUID = 0; >- >- >-} >Index: src/org/eclipse/zest/layouts/LayoutIterationEvent.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/LayoutIterationEvent.java >diff -N src/org/eclipse/zest/layouts/LayoutIterationEvent.java >--- src/org/eclipse/zest/layouts/LayoutIterationEvent.java 12 Sep 2007 20:44:37 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,49 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts; >- >-import java.util.List; >- >-/** >- * When a layout completes an iteration, it throws this event >- * to allow the application to update. For example, at the >- * end of an iteration is can be assumed the layout has placed >- * each entity into a new location. This event allows the application >- * to update the GUI to represent the new locations >- * >- * @author Casey Best and Rob Lintern >- */ >-public class LayoutIterationEvent { >- private List relationshipsToLayout, entitiesToLayout; >- private int iterationCompleted; >- >- /** >- * Return the relationships used in this layout. >- */ >- public List getRelationshipsToLayout() { >- return relationshipsToLayout; >- } >- >- /** >- * Return the entities used in this layout. >- */ >- public List getEntitiesToLayout() { >- return entitiesToLayout; >- } >- >- /** >- * Return the iteration of the layout algorithm that was >- * just completed. >- */ >- public int getIterationCompleted() { >- return iterationCompleted; >- } >-} >Index: src/org/eclipse/zest/layouts/NestedLayoutEntity.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/NestedLayoutEntity.java >diff -N src/org/eclipse/zest/layouts/NestedLayoutEntity.java >--- src/org/eclipse/zest/layouts/NestedLayoutEntity.java 12 Sep 2007 20:44:37 -0000 1.4 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,32 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts; >- >-import java.util.List; >- >- >-/** >- * Extends LayoutEntity to provide methods for dealing with nested entities. >- * >- * @author Chris Callendar >- */ >-public interface NestedLayoutEntity extends LayoutEntity { >- >- /** Returns the parent entity. */ >- NestedLayoutEntity getParent(); >- >- /** Returns the list of children. */ >- List getChildren(); >- >- /** Returns true if this entity has children. */ >- boolean hasChildren(); >- >-} >Index: src/org/eclipse/zest/layouts/LayoutStyles.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/LayoutStyles.java >diff -N src/org/eclipse/zest/layouts/LayoutStyles.java >--- src/org/eclipse/zest/layouts/LayoutStyles.java 12 Sep 2007 20:44:38 -0000 1.5 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,33 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts; >- >-/** >- * @author Ian Bull >- */ >-public interface LayoutStyles { >- >- /** Default layout style constant. */ >- public final static int NONE = 0x00; >- >- /** >- * Layout constant indicating that the layout algorithm >- * should NOT resize any of the nodes. >- */ >- public final static int NO_LAYOUT_NODE_RESIZING = 0x01; >- >- /** >- * Some layouts may prefer to expand their bounds beyond those of the requested bounds. This >- * flag asks the layout not to do so. >- */ >- public static final int ENFORCE_BOUNDS = 0X02; >- >-} >Index: src/org/eclipse/zest/layouts/Stoppable.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/Stoppable.java >diff -N src/org/eclipse/zest/layouts/Stoppable.java >--- src/org/eclipse/zest/layouts/Stoppable.java 12 Sep 2007 20:44:37 -0000 1.5 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,27 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts; >- >-import org.eclipse.zest.layouts.progress.ProgressListener; >- >-/** >- * @author Ian Bull >- */ >-public interface Stoppable { >- >- /** >- * This ends the runnable >- */ >- public void stop(); >- >- public void addProgressListener(ProgressListener listener); >- >-} >Index: src/org/eclipse/zest/layouts/LayoutGraph.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/LayoutGraph.java >diff -N src/org/eclipse/zest/layouts/LayoutGraph.java >--- src/org/eclipse/zest/layouts/LayoutGraph.java 12 Sep 2007 20:44:37 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,52 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts; >- >-import java.util.List; >- >-/** >- * The LayoutGraph interface defines the methods used to add nodes and edges (relationships). >- * @author Chris >- */ >-public interface LayoutGraph { >- >- /** >- * Adds a node to this graph. >- * @param node The new node. >- * @return LayoutEntity The created node >- */ >- public void addEntity(LayoutEntity node); >- >- /** >- * Adds the given relationship. >- * @param relationship >- */ >- public void addRelationship(LayoutRelationship relationship); >- >- /** >- * Returns a list of LayoutEntity objects that represent the objects added to this graph using addNode. >- * @return List A List of LayoutEntity objects. >- */ >- public List getEntities(); >- >- /** >- * Returns a list of LayoutRelationship objects that represent the objects added to this graph using addRelationship. >- * @return List A List of LayoutRelationship objects. >- */ >- public List getRelationships(); >- >- /** >- * Determines if the graph is bidirectional. >- * @return boolean If the graph is bidirectional. >- */ >- public boolean isBidirectional(); >- >-} >Index: src/org/eclipse/zest/layouts/LayoutEntity.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/LayoutEntity.java >diff -N src/org/eclipse/zest/layouts/LayoutEntity.java >--- src/org/eclipse/zest/layouts/LayoutEntity.java 12 Jan 2008 01:42:53 -0000 1.6 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,44 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts; >- >-import org.eclipse.zest.layouts.constraints.LayoutConstraint; >- >-/** >- * This represents a single entity, providing the layout algorithms with >- * a common interface to run on. >- * >- * @author Casey Best >- * @author Ian Bull >- * @author Chris Bennett >- */ >-public interface LayoutEntity extends Comparable, LayoutItem { >- >- public final static String ATTR_PREFERRED_WIDTH = "tree-preferred-width"; >- public final static String ATTR_PREFERRED_HEIGHT = "tree-preferred-height"; >- >- public void setLocationInLayout (double x, double y); >- public void setSizeInLayout (double width, double height); >- >- public double getXInLayout(); >- public double getYInLayout(); >- public double getWidthInLayout(); >- public double getHeightInLayout(); >- >- public Object getLayoutInformation(); >- public void setLayoutInformation(Object internalEntity); >- >- /** >- * Classes should update the specified layout constraint if recognized >- * @return >- */ >- public void populateLayoutConstraint(LayoutConstraint constraint); >-} >Index: src/org/eclipse/zest/layouts/Filter.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/Filter.java >diff -N src/org/eclipse/zest/layouts/Filter.java >--- src/org/eclipse/zest/layouts/Filter.java 12 Jan 2008 01:43:30 -0000 1.4 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,30 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts; >- >-/** >- * A filter is used to filter objects. Once implemented, interested >- * parties can ask this filter whether or not a specific object >- * is filtered. >- * >- * For example, in a visualization tool, only unfiltered objects should >- * be displayed. Before displaying an object, the display can ask >- * this filter if the object is filtered. >- * >- * @author Casey Best >- */ >-public interface Filter { >- >- /** >- * Returns true if the object is filtered, or false if it's not filtered. >- */ >- public boolean isObjectFiltered (LayoutItem object); >-} >Index: src/org/eclipse/zest/layouts/dataStructures/InternalRelationship.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/dataStructures/InternalRelationship.java >diff -N src/org/eclipse/zest/layouts/dataStructures/InternalRelationship.java >--- src/org/eclipse/zest/layouts/dataStructures/InternalRelationship.java 12 Jan 2008 01:44:03 -0000 1.10 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,138 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.dataStructures; >- >-import java.util.LinkedList; >-import java.util.List; >- >-import org.eclipse.zest.layouts.LayoutBendPoint; >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.LayoutRelationship; >-import org.eclipse.zest.layouts.constraints.BasicEdgeConstraints; >-import org.eclipse.zest.layouts.constraints.LayoutConstraint; >- >-/** >- * @author Ian Bull >- */ >-public class InternalRelationship implements LayoutRelationship{ >- >- private LayoutRelationship externalRelationship; >- private InternalNode source; >- private InternalNode destination; >- private Object layoutInfo; >- private List bendPoints = new LinkedList(); >- BasicEdgeConstraints basicEdgeConstraints = new BasicEdgeConstraints(); >- >- public InternalRelationship( LayoutRelationship externalRelationship, InternalNode source, InternalNode destination) { >- this.externalRelationship = externalRelationship; >- this.externalRelationship.setLayoutInformation(this); >- this.source = source; >- this.destination = destination; >- this.externalRelationship.populateLayoutConstraint(basicEdgeConstraints); >- } >- >- public LayoutRelationship getLayoutRelationship() { >- return externalRelationship; >- } >- >- public InternalNode getSource() { >- if ( this.source == null ) { >- throw new RuntimeException("Source is null"); >- } >- return this.source; >- } >- >- public InternalNode getDestination() { >- if ( this.destination == null ) { >- throw new RuntimeException("Dest is null"); >- } >- return this.destination; >- } >- >- public double getWeight() { >- return this.basicEdgeConstraints.weight; >- } >- >- public boolean isBidirectional() { >- return this.basicEdgeConstraints.isBiDirectional; >- } >- >- /** >- * Ensure this is called in order of source to target node position. >- * @param x >- * @param y >- */ >- public void addBendPoint(double x, double y) { >- bendPoints.add(new BendPoint(x, y)); >- } >- >- /** >- * Ensure this is called in order of source to target node position. >- * Specifies if the bendpoint is a curve control point >- * @param x >- * @param y >- * @param isControlPoint >- */ >- public void addBendPoint(double x, double y, boolean isControlPoint) { >- bendPoints.add(new BendPoint(x, y, isControlPoint)); >- } >- >- public List getBendPoints() { >- return this.bendPoints; >- } >- >- public void clearBendPoints() { >- // TODO Auto-generated method stub >- >- } >- >- >- >- public LayoutEntity getDestinationInLayout() { >- // TODO Auto-generated method stub >- return destination; >- } >- >- >- public Object getLayoutInformation() { >- // TODO Auto-generated method stub >- return layoutInfo; >- } >- >- public LayoutEntity getSourceInLayout() { >- // TODO Auto-generated method stub >- return source; >- } >- >- public void populateLayoutConstraint(LayoutConstraint constraint) { >- // TODO Auto-generated method stub >- >- } >- >- public void setBendPoints(LayoutBendPoint[] bendPoints) { >- // TODO Auto-generated method stub >- >- } >- >- public void setLayoutInformation(Object layoutInformation) { >- this.layoutInfo = layoutInformation; >- >- } >- >- public Object getGraphData() { >- return null; >- } >- >- public void setGraphData(Object o) { >- >- } >- >-} >Index: src/org/eclipse/zest/layouts/dataStructures/BendPoint.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/dataStructures/BendPoint.java >diff -N src/org/eclipse/zest/layouts/dataStructures/BendPoint.java >--- src/org/eclipse/zest/layouts/dataStructures/BendPoint.java 12 Sep 2007 20:44:37 -0000 1.5 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,54 +0,0 @@ >-/******************************************************************************* >- * Copyright 2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >-package org.eclipse.zest.layouts.dataStructures; >- >-import org.eclipse.zest.layouts.LayoutBendPoint; >- >-/** >- * Implements a single bend point in a graph relationship. >- * >- * @author Ian Bull >- * @author Chris Bennett >- */ >-public class BendPoint extends DisplayIndependentPoint implements LayoutBendPoint { >- >- private boolean isControlPoint = false; // is this a control point (for use in curves) >- >- public BendPoint(double x, double y) { >- super(x, y); >- } >- >- public BendPoint(double x, double y, boolean isControlPoint) { >- this(x, y); >- this.isControlPoint = isControlPoint; >- } >- >- public double getX() { >- return x; >- } >- >- public double getY() { >- return y; >- } >- >- public void setX(double x) { >- this.x = x; >- } >- >- public void setY(double y) { >- this.y = y; >- } >- >- public boolean getIsControlPoint() { >- return isControlPoint; >- } >- >-} >Index: src/org/eclipse/zest/layouts/dataStructures/InternalNode.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/dataStructures/InternalNode.java >diff -N src/org/eclipse/zest/layouts/dataStructures/InternalNode.java >--- src/org/eclipse/zest/layouts/dataStructures/InternalNode.java 12 Jan 2008 01:44:03 -0000 1.7 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,240 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which 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.layouts.dataStructures; >- >-import java.util.HashMap; >- >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.constraints.BasicEntityConstraint; >-import org.eclipse.zest.layouts.constraints.LayoutConstraint; >- >-/** >- * @author Ian Bull >- */ >-public class InternalNode implements Comparable, LayoutEntity { >- >- private LayoutEntity entity = null; >- private HashMap attributeMap = new HashMap(); >- BasicEntityConstraint basicEntityConstraint = new BasicEntityConstraint(); >- >- public InternalNode( LayoutEntity entity ) { >- this.entity = entity; >- this.entity.setLayoutInformation(this); >- this.layoutWidth = entity.getWidthInLayout(); >- this.layoutHeight = entity.getHeightInLayout(); >- entity.populateLayoutConstraint(basicEntityConstraint); >- } >- >- public LayoutEntity getLayoutEntity() { >- return this.entity; >- } >- >- public double getPreferredX() { >- return basicEntityConstraint.preferredX; >- >- } >- >- public double getPreferredY() { >- return basicEntityConstraint.preferredY; >- } >- >- public boolean hasPreferredLocation() { >- return basicEntityConstraint.hasPreferredLocation; >- } >- >- double dx, dy; >- public void setDx( double x ) { >- this.dx = x; >- } >- public void setDy( double y ) { >- this.dy = y; >- } >- public double getDx() { >- return this.dx; >- } >- public double getDy() { >- return this.dy; >- } >- >- public double getCurrentX() { >- return entity.getXInLayout(); >- } >- public double getCurrentY() { >- return entity.getYInLayout(); >- } >- >- public void setLocation( double x, double y ) { >- entity.setLocationInLayout( x, y ); >- } >- public void setSize( double width, double height ) { >- entity.setSizeInLayout( width, height ); >- } >- >- double normalizedX = 0.0; >- double normalizedY = 0.0; >- double normalizedWidth = 0.0; >- double normalizedHeight = 0.0; >- >- public void setInternalLocation( double x, double y ) { >- //entity.setLocationInLayout(x,y); >- >- normalizedX = x; >- normalizedY = y; >- >- } >- >- public DisplayIndependentPoint getInternalLocation() { >- return new DisplayIndependentPoint(getInternalX(),getInternalY()); >- } >- >- public void setInternalSize( double width, double height ) { >- normalizedWidth = width; >- normalizedHeight = height; >- } >- >- public double getInternalX() { >- //return entity.getXInLayout(); >- return normalizedX; >- } >- public double getInternalY() { >- //return entity.getYInLayout(); >- return normalizedY; >- } >- public double getInternalWidth() { >- return normalizedWidth; >- } >- public double getInternalHeight() { >- return normalizedHeight; >- } >- >- >- /** >- * An algorithm may require a place to store information. Use this structure for that purpose. >- */ >- public void setAttributeInLayout (Object attribute, Object value) { >- attributeMap.put(attribute, value); >- } >- >- /** >- * An algorithm may require a place to store information. Use this structure for that purpose. >- */ >- public Object getAttributeInLayout (Object attribute) { >- return attributeMap.get( attribute ); >- } >- >- >- //TODO: Fix all these preferred stuff!!!!! NOW! >- >- public boolean hasPreferredWidth () { >- return false; >- //return enity.getAttributeInLayout(LayoutEntity.ATTR_PREFERRED_WIDTH) != null; >- } >- >- public double getPreferredWidth () { >- return 0.0; >-// if (hasPreferredWidth()) { >-// return ((Double)entity.getAttributeInLayout(LayoutEntity.ATTR_PREFERRED_WIDTH)).doubleValue(); >-// } else { >-// return 10.0; >-// } >- } >- >- public boolean hasPreferredHeight () { >- return false; >- // return entity.getAttributeInLayout(LayoutEntity.ATTR_PREFERRED_HEIGHT) != null; >- } >- >- public double getPreferredHeight () { >- return 0.0; >-// if (hasPreferredHeight()) { >-// return ((Double)entity.getAttributeInLayout(LayoutEntity.ATTR_PREFERRED_HEIGHT)).doubleValue(); >-// } else { >-// return 10.0; >-// } >- } >- >- /* (non-Javadoc) >- * @see java.lang.Comparable#compareTo(java.lang.Object) >- */ >- public int compareTo(Object arg0) { >- return 0; >- } >- >- /* (non-Javadoc) >- * @see java.lang.Object#toString() >- */ >- public String toString() { >- return (entity != null ? entity.toString() : ""); >- } >- >- double layoutHeight; >- double layoutWidth; >- double layoutX; >- double layoutY; >- Object layoutInfo; >- >- public double getHeightInLayout() { >- // TODO Auto-generated method stub >- return layoutHeight; >- } >- >- public Object getLayoutInformation() { >- // TODO Auto-generated method stub >- return this.layoutInfo; >- } >- >- public double getWidthInLayout() { >- // TODO Auto-generated method stub >- return layoutWidth; >- } >- >- public double getXInLayout() { >- // TODO Auto-generated method stub >- return layoutX; >- } >- >- public double getYInLayout() { >- // TODO Auto-generated method stub >- return layoutY; >- } >- >- public void populateLayoutConstraint(LayoutConstraint constraint) { >- // TODO Auto-generated method stub >- >- } >- >- public void setLayoutInformation(Object internalEntity) { >- this.layoutInfo = internalEntity; >- >- } >- >- public void setLocationInLayout(double x, double y) { >- // TODO Auto-generated method stub >- this.layoutX = x; >- this.layoutY = y; >- >- } >- >- public void setSizeInLayout(double width, double height) { >- this.layoutWidth = width; >- this.layoutHeight = height; >- } >- >- public Object getGraphData() { >- return null; >- } >- >- public void setGraphData(Object o) { >- // TODO Auto-generated method stub >- >- } >- >-} >Index: src/org/eclipse/zest/layouts/interfaces/ConnectionLayout.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/interfaces/ConnectionLayout.java >diff -N src/org/eclipse/zest/layouts/interfaces/ConnectionLayout.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/interfaces/ConnectionLayout.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,48 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.interfaces; >+ >+ >+public interface ConnectionLayout { >+ >+ public NodeLayout getSource(); >+ >+ public NodeLayout getTarget(); >+ >+ /** >+ * >+ * @return weight assigned to this connection >+ */ >+ public double getWeight(); >+ >+ /** >+ * Checks if this connection is directed. For undirected connections, source >+ * and target nodes should be considered just adjacent nodes without >+ * dividing to source/target. >+ * >+ * @return true if this connection is directed >+ */ >+ public boolean isDirected(); >+ >+ /** >+ * Changes the visibility state of this connection. >+ * >+ * @param visible >+ * true if this connection should be visible, false otherwise >+ */ >+ public void setVisible(boolean visible); >+ >+ /** >+ * Checks the visibility state of this connection. >+ * >+ * @return true if this connection is visible, false otherwise >+ */ >+ public boolean isVisible(); >+} >Index: src/org/eclipse/zest/layouts/interfaces/ExpandCollapseManager.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/interfaces/ExpandCollapseManager.java >diff -N src/org/eclipse/zest/layouts/interfaces/ExpandCollapseManager.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/interfaces/ExpandCollapseManager.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,63 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.interfaces; >+ >+/** >+ * A manager that controls expanding and collapsing nodes in a Graph. >+ */ >+public interface ExpandCollapseManager { >+ >+ /** >+ * Initializes the expansion state of all nodes in given layout context. The >+ * receiver can initialize its internal state related to the layout context >+ * and add its listeners if necessary. >+ * >+ * @param context >+ * the context to initialize >+ */ >+ public void initExpansion(LayoutContext context); >+ >+ /** >+ * Changes the expanded state of given node. It prunes/unprunes nodes and >+ * hides/shows connections in the graph according to its policy. If >+ * requested operation cannot be currently performed on the node, it does >+ * nothing. >+ * >+ * @param context >+ * context in which to perform the operation >+ * @param node >+ * node to expand or collapse >+ * @param expanded >+ * true to expand, false to collapse >+ */ >+ public void setExpanded(LayoutContext context, NodeLayout node, boolean expanded); >+ >+ /** >+ * Checks if given node can be expanded. >+ * >+ * @param context >+ * context containing the node >+ * @param node >+ * node to check >+ * @return >+ */ >+ public boolean canExpand(LayoutContext context, NodeLayout node); >+ >+ /** >+ * Checks if given node can be collapsed. >+ * >+ * @param context >+ * context containing the node >+ * @param node >+ * node to check >+ * @return >+ */ >+ public boolean canCollapse(LayoutContext context, NodeLayout node); >+} >\ No newline at end of file >Index: .refactorings/2009/8/35/refactorings.history >=================================================================== >RCS file: .refactorings/2009/8/35/refactorings.history >diff -N .refactorings/2009/8/35/refactorings.history >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ .refactorings/2009/8/35/refactorings.history 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,3 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<session version="1.0">
<refactoring accessors="true" comment="Delete 11 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original elements:
 org.eclipse.zest.layouts.Filter.java
 org.eclipse.zest.layouts.InvalidLayoutConfiguration.java
 org.eclipse.zest.layouts.LayoutBendPoint.java
 org.eclipse.zest.layouts.LayoutEntity.java
 org.eclipse.zest.layouts.LayoutGraph.java
 org.eclipse.zest.layouts.LayoutItem.java
 org.eclipse.zest.layouts.LayoutIterationEvent.java
 org.eclipse.zest.layouts.LayoutRelationship.java
 org.eclipse.zest.layouts.LayoutStyles.java
 org.eclipse.zest.layouts.NestedLayoutEntity.java
 org.eclipse.zest.layouts.Stoppable.java" description="Delete elements" element1="/src<org.eclipse.zest.layouts{LayoutStyles.java" element10="/src<org.eclipse.zest.layouts{InvalidLayoutConfiguration.java" element11="/src<org.eclipse.zest.layouts{LayoutItem.java" element2="/src<org.eclipse.zest.layouts{Stoppable.java" element3="/src<org.eclipse.zest.layouts{Filter.java" element4="/src<org.eclipse.zest.layouts{LayoutGraph.java" element5="/src<org.eclipse.zest.layouts{LayoutIterationEvent.java" element6="/src<org.eclipse.zest.layouts{NestedLayoutEntity.java" element7="/src<org.eclipse.zest.layouts{LayoutEntity.java" element8="/src<org.eclipse.zest.layouts{LayoutBendPoint.java" element9="/src<org.eclipse.zest.layouts{LayoutRelationship.java" elements="11" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470143328" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original element: 'org.eclipse.zest.layouts/src/org.eclipse.zest.layouts.algorithms.internal'" description="Delete element" element1="/src<org.eclipse.zest.layouts.algorithms.internal" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470164817" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original element: 'org.eclipse.zest.layouts/src/org.eclipse.zest.layouts.constraints'" description="Delete element" element1="/src<org.eclipse.zest.layouts.constraints" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470169378" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original element: 'org.eclipse.zest.layouts/src/org.eclipse.zest.layouts.progress'" description="Delete element" element1="/src<org.eclipse.zest.layouts.progress" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470188073" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original element: 'org.eclipse.zest.layouts/src/interfaces'" description="Delete element" element1="/src<interfaces" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470206585" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 3 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original elements:
 org.eclipse.zest.layouts.dataStructures.BendPoint.java
 org.eclipse.zest.layouts.dataStructures.InternalNode.java
 org.eclipse.zest.layouts.dataStructures.InternalRelationship.java" description="Delete elements" element1="/src<org.eclipse.zest.layouts.dataStructures{InternalNode.java" element2="/src<org.eclipse.zest.layouts.dataStructures{InternalRelationship.java" element3="/src<org.eclipse.zest.layouts.dataStructures{BendPoint.java" elements="3" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470236983" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original element: 'org.eclipse.zest.layouts.algorithms.AbstractLayoutAlgorithm.java'" description="Delete element" element1="/src<org.eclipse.zest.layouts.algorithms{AbstractLayoutAlgorithm.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470323797" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original element: 'org.eclipse.zest.layouts.algorithms.ContinuousLayoutAlgorithm.java'" description="Delete element" element1="/src<org.eclipse.zest.layouts.algorithms{ContinuousLayoutAlgorithm.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470330527" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original element: 'org.eclipse.zest.layouts.algorithms.HorizontalShift.java'" description="Delete element" element1="/src<org.eclipse.zest.layouts.algorithms{HorizontalShift.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470342814" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original element: 'org.eclipse.zest.layouts.algorithms.HorizontalLayoutAlgorithm.java'" description="Delete element" element1="/src<org.eclipse.zest.layouts.algorithms{HorizontalLayoutAlgorithm.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470441706" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original element: 'org.eclipse.zest.layouts.algorithms.HorizontalTreeLayoutAlgorithm.java'" description="Delete element" element1="/src<org.eclipse.zest.layouts.algorithms{HorizontalTreeLayoutAlgorithm.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470459491" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original element: 'org.eclipse.zest.layouts.algorithms.VerticalLayoutAlgorithm.java'" description="Delete element" element1="/src<org.eclipse.zest.layouts.algorithms{VerticalLayoutAlgorithm.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470478305" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.layouts'
- Original project: 'org.eclipse.zest.layouts'
- Original element: 'org.eclipse.zest.layouts/src/org.eclipse.zest.layouts.exampleStructures'" description="Delete element" element1="/src<org.eclipse.zest.layouts.exampleStructures" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251471154148" subPackages="false" version="1.0"/> >+</session> >\ No newline at end of file >Index: src/org/eclipse/zest/layouts/algorithms/TreeLayoutObserver.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/TreeLayoutObserver.java >diff -N src/org/eclipse/zest/layouts/algorithms/TreeLayoutObserver.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/algorithms/TreeLayoutObserver.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,563 @@ >+/******************************************************************************* >+ * Copyright (c) 2005-2009 The Chisel Group 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: The Chisel Group - initial API and implementation >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.algorithms; >+ >+import java.util.ArrayList; >+import java.util.Collections; >+import java.util.HashMap; >+import java.util.HashSet; >+import java.util.Iterator; >+import java.util.LinkedList; >+import java.util.List; >+import java.util.ListIterator; >+import java.util.Set; >+ >+import org.eclipse.zest.layouts.interfaces.ConnectionLayout; >+import org.eclipse.zest.layouts.interfaces.GraphStructureListener; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+ >+/** >+ * A helper class for layout algorithms that are based on tree structure. It >+ * keeps track of changes in observed layout context and stores current >+ * information about the tree structure - children of each node and several >+ * other parameters. >+ */ >+public class TreeLayoutObserver { >+ >+ /** >+ * <code>TreeLayoutObserver</code> uses instance of this class to create >+ * instances of {@link TreeNode}. It may be extended and passed to >+ * <code>TreeLayoutObserver</code>'s constructor in order to build a tree >+ * structure made of <code>TreeNode</code>'s subclasses. >+ */ >+ public static class TreeNodeFactory { >+ public TreeNode createTreeNode(NodeLayout nodeLayout, TreeLayoutObserver observer) { >+ return new TreeNode(nodeLayout, observer); >+ } >+ } >+ >+ /** >+ * Represents a node in a tree structure and stores all information related >+ * to it. May be subclassed if additional data and behavior is necessary. >+ */ >+ public static class TreeNode { >+ final protected NodeLayout node; >+ final protected TreeLayoutObserver owner; >+ protected int height = 0; >+ protected int depth = -1; >+ protected int numOfLeaves = 0; >+ protected int numOfDescendants = 0; >+ protected int order = 0; >+ protected final List children = new ArrayList(); >+ protected TreeNode parent; >+ protected boolean firstChild = false, lastChild = false; >+ >+ /** >+ * >+ * @return node layout related to this tree node (null for >+ * {@link TreeLayoutObserver#getSuperRoot() Super Root}) >+ */ >+ public NodeLayout getNode() { >+ return node; >+ } >+ >+ /** >+ * >+ * @return <code>TreeLayoutObserver</code> owning this tree node >+ */ >+ public TreeLayoutObserver getOwner() { >+ return owner; >+ } >+ >+ /** >+ * >+ * @return height of this node in the tree (the longest distance to a >+ * leaf, 0 for a leaf itself) >+ */ >+ public int getHeight() { >+ return height; >+ } >+ >+ /** >+ * >+ * @return depth of this node in the tree (distance from root, 0 for a >+ * root and -1 for {@link TreeLayoutObserver#getSuperRoot() >+ * Super Root} >+ */ >+ public int getDepth() { >+ return depth; >+ } >+ >+ /** >+ * >+ * @return number of all leaves descending from this node (1 for a leaf >+ * itself) >+ */ >+ public int getNumOfLeaves() { >+ return numOfLeaves; >+ } >+ >+ /** >+ * >+ * @return total number of descendants of this node (0 for leafs) >+ */ >+ public int getNumOfDescendants() { >+ return numOfDescendants; >+ } >+ >+ /** >+ * Returns order in which nodes are visited during Deep First Search. >+ * Children are visited in the same order as they were added to their >+ * layout context, unless {@link TreeLayoutObserver#recomputeTree()} was >+ * called after the nodes were added. In that case the order is >+ * determined by order of nodes returned by >+ * {@link NodeLayout#getSuccessingNodes()}. Leaves are assigned >+ * successive numbers starting from 0, other nodes have order equal to >+ * the smallest order of their children. >+ * >+ * @return order of this node >+ */ >+ public int getOrder() { >+ return order; >+ } >+ >+ /** >+ * >+ * @return an unmodifiable list of this node's children >+ */ >+ public List getChildren() { >+ return Collections.unmodifiableList(children); >+ } >+ >+ /** >+ * >+ * @return this node's parent >+ */ >+ public TreeNode getParent() { >+ return parent; >+ } >+ >+ /** >+ * >+ * @return true if this node is the first child of its parent (has the >+ * smallest order) >+ */ >+ public boolean isFirstChild() { >+ return firstChild; >+ } >+ >+ /** >+ * >+ * @return >+ */ >+ public boolean isLastChild() { >+ return lastChild; >+ } >+ >+ /** >+ * Creates a tree node related to given layout node >+ * >+ * @param node >+ * the layout node >+ * @param owner >+ * <code>TreeLayoutObserver</code> owning created node >+ */ >+ protected TreeNode(NodeLayout node, TreeLayoutObserver owner) { >+ this.node = node; >+ this.owner = owner; >+ } >+ >+ /** >+ * Adds given node to the list of this node's children and set its >+ * parent to this node. >+ * >+ * @param child >+ * node to add >+ */ >+ protected void addChild(TreeNode child) { >+ children.add(child); >+ child.parent = this; >+ } >+ >+ /** >+ * Performs a DFS on the tree structure and calculates all parameters of >+ * its nodes. Should be called on >+ * {@link TreeLayoutObserver#getSuperRoot() Super Root}. Uses recurrence >+ * to go through all the nodes. >+ */ >+ protected void precomputeTree() { >+ if (children.isEmpty()) { >+ height = 0; >+ numOfLeaves = 1; >+ numOfDescendants = 0; >+ } else { >+ height = 0; >+ numOfLeaves = 0; >+ numOfDescendants = 0; >+ for (ListIterator iterator = children.listIterator(); iterator.hasNext();) { >+ TreeNode child = (TreeNode) iterator.next(); >+ child.depth = this.depth + 1; >+ child.order = this.order + this.numOfLeaves; >+ child.precomputeTree(); >+ child.firstChild = (this.numOfLeaves == 0); >+ child.lastChild = !iterator.hasNext(); >+ >+ this.height = Math.max(this.height, child.height + 1); >+ this.numOfLeaves += child.numOfLeaves; >+ this.numOfDescendants += child.numOfDescendants + 1; >+ } >+ } >+ } >+ >+ /** >+ * Finds a node that is the best parent for this node. Add this node as >+ * a child of the found node. >+ */ >+ protected void findNewParent() { >+ if (parent != null) >+ parent.children.remove(this); >+ NodeLayout[] predecessingNodes = node.getPredecessingNodes(); >+ parent = null; >+ for (int i = 0; i < predecessingNodes.length; i++) { >+ TreeNode potentialParent = (TreeNode) owner.layoutToTree.get(predecessingNodes[i]); >+ if (!children.contains(potentialParent) && isBetterParent(potentialParent)) >+ parent = potentialParent; >+ } >+ if (parent == null) >+ parent = owner.superRoot; >+ >+ parent.addChild(this); >+ } >+ >+ /** >+ * Checks if a potential parent would be better for this node than its >+ * current parent. A better parent has smaller depth (with exception to >+ * {@link TreeLayoutObserver#getSuperRoot() Super Root}, which has depth >+ * equal to -1 but is never a better parent than any other node). >+ * >+ * @param potentialParent >+ * potential parent to check >+ * @return true if potentialParent can be a parent of this node and is >+ * better than its current parent >+ */ >+ protected boolean isBetterParent(TreeNode potentialParent) { >+ if (this.parent == null && !this.isAncestorOf(potentialParent)) >+ return true; >+ if (potentialParent.depth <= this.depth && potentialParent.depth != -1) >+ return true; >+ if (this.parent.depth == -1 && potentialParent.depth >= 0 && !this.isAncestorOf(potentialParent)) >+ return true; >+ return false; >+ } >+ >+ /** >+ * >+ * @param descendant >+ * @return true if this node is an ancestor if given descendant node >+ */ >+ public boolean isAncestorOf(TreeNode descendant) { >+ while (descendant.depth > this.depth) >+ descendant = descendant.parent; >+ return descendant == this; >+ } >+ } >+ >+ /** >+ * A superclass for listeners that can be added to this observer to get >+ * notification whenever the tree structure changes. >+ */ >+ public static class TreeListener { >+ /** >+ * Called when new node is added to the tree structure. The new node >+ * will not have any connections, so it will be a child of >+ * {@link TreeLayoutObserver#getSuperRoot() Super Root} >+ * >+ * @param newNode >+ * the added node >+ */ >+ public void nodeAdded(TreeNode newNode) { >+ defaultHandle(newNode); >+ } >+ >+ /** >+ * Called when a node is removed from the tree structure. The given node >+ * no longer exists in the tree at the moment of call. >+ * >+ * @param removedNode >+ * the removed node >+ */ >+ public void nodeRemoved(TreeNode removedNode) { >+ defaultHandle(removedNode); >+ } >+ >+ /** >+ * Called when a node changes its parent. >+ * >+ * @param node >+ * node that changes its parent >+ * @param previousParent >+ * previous parent of the node >+ */ >+ public void parentChanged(TreeNode node, TreeNode previousParent) { >+ defaultHandle(node); >+ } >+ >+ /** >+ * A convenience method that can be overridden if a listener reacts the >+ * same way to all events. By default it's called in every event handler >+ * and does nothing. >+ * >+ * @param changedNode >+ * the node that has changed >+ */ >+ protected void defaultHandle(TreeNode changedNode) { >+ } >+ } >+ >+ private GraphStructureListener structureListener = new GraphStructureListener() { >+ >+ public boolean nodeRemoved(LayoutContext context, NodeLayout node) { >+ TreeNode treeNode = (TreeNode) layoutToTree.get(node); >+ treeNode.parent.children.remove(treeNode); >+ superRoot.precomputeTree(); >+ for (Iterator iterator = treeListeners.iterator(); iterator.hasNext();) { >+ TreeListener listener = (TreeListener) iterator.next(); >+ listener.nodeRemoved(treeNode); >+ } >+ return false; >+ } >+ >+ public boolean nodeAdded(LayoutContext context, NodeLayout node) { >+ TreeNode treeNode = getTreeNode(node); >+ superRoot.addChild(treeNode); >+ superRoot.precomputeTree(); >+ for (Iterator iterator = treeListeners.iterator(); iterator.hasNext();) { >+ TreeListener listener = (TreeListener) iterator.next(); >+ listener.nodeAdded(treeNode); >+ } >+ return false; >+ } >+ >+ public boolean connectionRemoved(LayoutContext context, ConnectionLayout connection) { >+ TreeNode node1 = (TreeNode) layoutToTree.get(connection.getSource()); >+ TreeNode node2 = (TreeNode) layoutToTree.get(connection.getTarget()); >+ if (node1.parent == node2) { >+ node1.findNewParent(); >+ if (node1.parent != node2) { >+ superRoot.precomputeTree(); >+ fireParentChanged(node1, node2); >+ } >+ } >+ if (node2.parent == node1) { >+ node2.findNewParent(); >+ if (node2.parent != node1) { >+ superRoot.precomputeTree(); >+ fireParentChanged(node2, node1); >+ } >+ } >+ return false; >+ } >+ >+ public boolean connectionAdded(LayoutContext context, ConnectionLayout connection) { >+ TreeNode source = (TreeNode) layoutToTree.get(connection.getSource()); >+ TreeNode target = (TreeNode) layoutToTree.get(connection.getTarget()); >+ if (source == target) >+ return false; >+ if (target.isBetterParent(source)) { >+ TreeNode previousParent = target.parent; >+ previousParent.children.remove(target); >+ source.addChild(target); >+ superRoot.precomputeTree(); >+ fireParentChanged(target, previousParent); >+ } >+ if (!connection.isDirected() && source.isBetterParent(target)) { >+ TreeNode previousParent = source.parent; >+ previousParent.children.remove(source); >+ target.addChild(source); >+ superRoot.precomputeTree(); >+ fireParentChanged(source, previousParent); >+ } >+ return false; >+ } >+ >+ public boolean connectionWeightChanged(LayoutContext context, ConnectionLayout connection) { >+ // do nothing >+ return false; >+ } >+ >+ public boolean connectionDirectedChanged(LayoutContext context, ConnectionLayout connection) { >+ connectionRemoved(context, connection); >+ connectionAdded(context, connection); >+ return false; >+ } >+ >+ private void fireParentChanged(TreeNode node, TreeNode previousParent) { >+ for (Iterator iterator = treeListeners.iterator(); iterator.hasNext();) { >+ TreeListener listener = (TreeListener) iterator.next(); >+ listener.parentChanged(node, previousParent); >+ } >+ } >+ }; >+ >+ private final HashMap layoutToTree = new HashMap(); >+ private final TreeNodeFactory factory; >+ private final LayoutContext context; >+ private TreeNode superRoot; >+ private ArrayList treeListeners = new ArrayList(); >+ >+ /** >+ * Creates a >+ * >+ * @param context >+ * @param nodeFactory >+ */ >+ public TreeLayoutObserver(LayoutContext context, TreeNodeFactory nodeFactory) { >+ if (nodeFactory == null) >+ this.factory = new TreeNodeFactory(); >+ else >+ this.factory = nodeFactory; >+ this.context = context; >+ context.addGraphStructureListener(structureListener); >+ recomputeTree(); >+ } >+ >+ /** >+ * Recomputes all the information about the tree structure (the same effect >+ * as creating new <code>TreeLayoutObserver</code>). >+ */ >+ public void recomputeTree() { >+ superRoot = factory.createTreeNode(null, this); >+ layoutToTree.put(null, superRoot); >+ createTrees(context.getNodes()); >+ } >+ >+ /** >+ * Stops this observer from listening to changes in observed layout context. >+ * After calling this method the information about tree structure can be >+ * updated only when {@link #recomputeTree()} is called. >+ */ >+ public void stop() { >+ context.removeGraphStructureListener(structureListener); >+ } >+ >+ /** >+ * Returns Super Root, that is an artificial node being a common parent for >+ * all nodes in observed tree structure. >+ * >+ * @return Super Root >+ */ >+ public TreeNode getSuperRoot() { >+ return superRoot; >+ } >+ >+ /** >+ * Returns a {@link TreeNode} related to given node layout. If such a >+ * <code>TreeNode</code> doesn't exist, it's created. >+ * >+ * @param node >+ * @return >+ */ >+ public TreeNode getTreeNode(NodeLayout node) { >+ TreeNode treeNode = (TreeNode) layoutToTree.get(node); >+ if (treeNode == null) { >+ treeNode = factory.createTreeNode(node, this); >+ layoutToTree.put(node, treeNode); >+ } >+ return treeNode; >+ } >+ >+ /** >+ * Adds a listener that will be informed about changes in tree structure. >+ * >+ * @param listener >+ * listener to add >+ */ >+ public void addTreeListener(TreeListener listener) { >+ treeListeners.add(listener); >+ } >+ >+ /** >+ * Removes a listener from list of listener to be informed about changes in >+ * tree structure. >+ * >+ * @param listener >+ * listener to remove >+ */ >+ public void removeTreeListener(TreeListener listener) { >+ treeListeners.add(listener); >+ } >+ >+ /** >+ * Builds a tree structure using BFS method. Created trees are children of >+ * {@link #superRoot}. >+ * >+ * @param nodes >+ */ >+ private void createTrees(NodeLayout[] nodes) { >+ HashSet alreadyVisited = new HashSet(); >+ LinkedList nodesToAdd = new LinkedList(); >+ for (int i = 0; i < nodes.length; i++) { >+ NodeLayout root = findRoot(nodes[i], alreadyVisited); >+ if (root != null) { >+ alreadyVisited.add(root); >+ nodesToAdd.addLast(new Object[] { root, superRoot }); >+ } >+ } >+ while (!nodesToAdd.isEmpty()) { >+ Object[] dequeued = (Object[]) nodesToAdd.removeFirst(); >+ TreeNode currentNode = factory.createTreeNode((NodeLayout) dequeued[0], this); >+ layoutToTree.put(dequeued[0], currentNode); >+ TreeNode currentRoot = (TreeNode) dequeued[1]; >+ >+ currentRoot.addChild(currentNode); >+ NodeLayout[] children = currentNode.node.getSuccessingNodes(); >+ for (int i = 0; i < children.length; i++) { >+ if (!alreadyVisited.contains(children[i])) { >+ alreadyVisited.add(children[i]); >+ nodesToAdd.addLast(new Object[] { children[i], currentNode }); >+ } >+ } >+ } >+ superRoot.precomputeTree(); >+ } >+ >+ /** >+ * Searches for a root of a tree containing given node by continuously >+ * grabbing a predecessor of current node. If it reaches an node that exists >+ * in alreadyVisited set, it returns null. If it detects a cycle, it returns >+ * the first found node of that cycle. If it reaches a node that has no >+ * predecessors, it returns that node. >+ * >+ * @param nodeLayout >+ * starting node >+ * @param alreadyVisited >+ * set of nodes that can't lay on path to the root (if one does, >+ * method stops and returns null). >+ * @return >+ */ >+ private NodeLayout findRoot(NodeLayout nodeLayout, Set alreadyVisited) { >+ HashSet alreadyVisitedRoot = new HashSet(); >+ while (true) { >+ if (alreadyVisited.contains(nodeLayout)) >+ return null; >+ if (alreadyVisitedRoot.contains(nodeLayout)) >+ return nodeLayout; >+ alreadyVisitedRoot.add(nodeLayout); >+ NodeLayout[] predecessingNodes = nodeLayout.getPredecessingNodes(); >+ if (predecessingNodes.length > 0) { >+ nodeLayout = predecessingNodes[0]; >+ } else { >+ return nodeLayout; >+ } >+ } >+ } >+} >Index: src/org/eclipse/zest/layouts/interfaces/LayoutListener.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/interfaces/LayoutListener.java >diff -N src/org/eclipse/zest/layouts/interfaces/LayoutListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/interfaces/LayoutListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,56 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.interfaces; >+ >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+ >+/** >+ * A listener added to {@link LayoutContext} that is notified about changes in >+ * this layout. >+ */ >+public interface LayoutListener { >+ >+ /** >+ * This method is called whenever location of a particular entity (node or >+ * subgraph) is changed within observed context. If true is returned, it >+ * means that the receiving listener has intercepted this event. Intercepted >+ * events will not be passed to the rest of the listeners. If the event is >+ * not intercepted by any listener, {@link LayoutAlgorithm#applyLayout() >+ * applyLayout()} will be called on the context's main algorithm. >+ * >+ * @param context >+ * the layout context that fired the event >+ * @param entity >+ * the entity that has moved >+ * @return true if no further operations after this event are required >+ */ >+ public boolean entityMoved(LayoutContext context, EntityLayout entity); >+ >+ /** >+ * This method is called whenever size of a particular entity (node or >+ * subgraph) is changed within observed context. This usually implicates >+ * change of position (the center of the entity) and the receiver should be >+ * aware of it (no additional >+ * {@link #entityMoved(LayoutContext, EntityLayout)} event will be fired). >+ * >+ * If true is returned, it means that the receiving listener has intercepted >+ * this event. Intercepted events will not be passed to the rest of the >+ * listeners. If the event is not intercepted by any listener, >+ * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the >+ * context's main algorithm. >+ * >+ * @param context >+ * the layout context that fired the event >+ * @param entity >+ * the entity that was resized >+ * @return true if no further operations after this event are required >+ */ >+ public boolean entityResized(LayoutContext context, EntityLayout entity); >+} >Index: .refactorings/2009/8/35/refactorings.index >=================================================================== >RCS file: .refactorings/2009/8/35/refactorings.index >diff -N .refactorings/2009/8/35/refactorings.index >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ .refactorings/2009/8/35/refactorings.index 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,13 @@ >+1251470143328 Delete elements >+1251470164817 Delete element >+1251470169378 Delete element >+1251470188073 Delete element >+1251470206585 Delete element >+1251470236983 Delete elements >+1251470323797 Delete element >+1251470330527 Delete element >+1251470342814 Delete element >+1251470441706 Delete element >+1251470459491 Delete element >+1251470478305 Delete element >+1251471154148 Delete element >Index: src/org/eclipse/zest/layouts/interfaces/SubgraphLayout.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/interfaces/SubgraphLayout.java >diff -N src/org/eclipse/zest/layouts/interfaces/SubgraphLayout.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/interfaces/SubgraphLayout.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,99 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.interfaces; >+ >+ >+/** >+ * An interface for subgraphs in layout. A subgraph is a set of pruned nodes >+ * that will be displayed as one element. A subgraph must contain at least one >+ * node (empty subgraphs will be removed from its context). Every node can >+ * belong to at most one subgraph. >+ */ >+public interface SubgraphLayout extends EntityLayout { >+ >+ /** >+ * Constant for top-down direction (default). >+ */ >+ public final int TOP_DOWN = 1; >+ >+ /** >+ * Constant for bottom-up direction. >+ */ >+ public final int BOTTOM_UP = 2; >+ >+ /** >+ * Constant for direction from left to right. >+ */ >+ public final int LEFT_RIGHT = 3; >+ >+ /** >+ * Constant for direction from right to left. >+ */ >+ public final int RIGHT_LEFT = 4; >+ >+ /** >+ * Returns all the nodes belonging to this subgraph. Replacing elements in >+ * the returned array does not affect this subgraph. >+ * >+ * @return array of nodes >+ */ >+ public NodeLayout[] getNodes(); >+ >+ /** >+ * >+ * @return number of nodes pruned into this subgraph >+ */ >+ public int countNodes(); >+ >+ /** >+ * Adds nodes to this subgraph. If given nodes already belong to another >+ * subgraph, they are first removed from them. >+ * >+ * @param nodes >+ * array of nodes to add >+ */ >+ public void addNodes(NodeLayout[] nodes); >+ >+ /** >+ * Removes nodes from this subgraph. >+ * >+ * @param nodes >+ * array of nodes to remove >+ */ >+ public void removeNodes(NodeLayout[] nodes); >+ >+ /** >+ * Returns true if this subgraph is visualized as a particular object on the >+ * graph. If this method returns false, it means that this subgraph will not >+ * be visible so all methods related to location, size and direction should >+ * be ignored. >+ * >+ * @return whether or not this subgraph is a graph entity that should be >+ * laid out. >+ */ >+ public boolean isGraphEntity(); >+ >+ /** >+ * @return true if this subgraph is visualized differently depending on >+ * direction >+ */ >+ public boolean isDirectionDependant(); >+ >+ /** >+ * Sets the direction of this subgraph (does nothing in case of subgraphs >+ * that don't depend on direction) >+ * >+ * @param direction >+ * one of constants: {@link #TOP_DOWN}, {@link #BOTTOM_UP}, >+ * {@link #LEFT_RIGHT}, {@link #RIGHT_LEFT} >+ */ >+ public void setDirection(int direction); >+ >+} >Index: src/org/eclipse/zest/layouts/algorithms/HorizontalShiftAlgorithm.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/HorizontalShiftAlgorithm.java >diff -N src/org/eclipse/zest/layouts/algorithms/HorizontalShiftAlgorithm.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/algorithms/HorizontalShiftAlgorithm.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,114 @@ >+/******************************************************************************* >+ * Copyright (c) 2005-2009 The Chisel Group 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: The Chisel Group - initial API and implementation >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.algorithms; >+ >+import java.util.ArrayList; >+import java.util.Collections; >+import java.util.Comparator; >+import java.util.Iterator; >+import java.util.List; >+ >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+ >+/** >+ * This layout shifts overlapping nodes to the right. >+ * >+ * @author Ian Bull >+ */ >+public class HorizontalShiftAlgorithm implements LayoutAlgorithm { >+ >+ private static final double DELTA = 10; >+ >+ private static final double VSPACING = 16; >+ >+ private static final double HSPACING = 10; >+ >+ private LayoutContext context; >+ >+ public void applyLayout(boolean clean) { >+ if (!clean) >+ return; >+ ArrayList rowsList = new ArrayList(); >+ EntityLayout[] entities = context.getEntities(); >+ >+ for (int i = 0; i < entities.length; i++) { >+ addToRowList(entities[i], rowsList); >+ } >+ >+ Collections.sort(rowsList, new Comparator() { >+ public int compare(Object o1, Object o2) { >+ List a0 = (List) o1; >+ List a1 = (List) o2; >+ EntityLayout entity0 = (EntityLayout) a0.get(0); >+ EntityLayout entity1 = (EntityLayout) a1.get(0); >+ return (int) (entity0.getLocation().y - entity1.getLocation().y); >+ } >+ }); >+ >+ Comparator entityComparator = new Comparator() { >+ public int compare(Object o1, Object o2) { >+ return (int) (((EntityLayout) o1).getLocation().y - ((EntityLayout) o2).getLocation().y); >+ } >+ }; >+ DisplayIndependentRectangle bounds = context.getBounds(); >+ int heightSoFar = 0; >+ >+ for (Iterator iterator = rowsList.iterator(); iterator.hasNext();) { >+ List currentRow = (List) iterator.next(); >+ Collections.sort(currentRow, entityComparator); >+ >+ int width = (int) (bounds.width - calculateRowWidth(currentRow)) / 2; >+ >+ heightSoFar += ((EntityLayout) currentRow.get(0)).getSize().height + VSPACING; >+ for (Iterator iterator2 = currentRow.iterator(); iterator2.hasNext();) { >+ EntityLayout entity = (EntityLayout) iterator2.next(); >+ DisplayIndependentDimension size = entity.getSize(); >+ entity.setLocation(width + size.width / 2, heightSoFar + size.height / 2); >+ width += size.width + HSPACING; >+ } >+ } >+ } >+ >+ private double calculateRowWidth(List row) { >+ double result = 0; >+ for (Iterator iterator = row.iterator(); iterator.hasNext();) { >+ EntityLayout entity = (EntityLayout) iterator.next(); >+ result += entity.getSize().width; >+ } >+ result += HSPACING * (row.size() - 1); >+ return result; >+ } >+ >+ public void setLayoutContext(LayoutContext context) { >+ this.context = context; >+ } >+ >+ private void addToRowList(EntityLayout entity, ArrayList rowsList) { >+ double layoutY = entity.getLocation().y; >+ >+ for (Iterator iterator = rowsList.iterator(); iterator.hasNext();) { >+ List currentRow = (List) iterator.next(); >+ EntityLayout currentRowEntity = (EntityLayout) currentRow.get(0); >+ double currentRowY = currentRowEntity.getLocation().y; >+ if (layoutY >= currentRowY - DELTA && layoutY <= currentRowY + DELTA) { >+ currentRow.add(entity); >+ return; >+ } >+ } >+ List newRow = new ArrayList(); >+ newRow.add(entity); >+ rowsList.add(newRow); >+ } >+} >Index: src/org/eclipse/zest/layouts/algorithms/BoxLayoutAlgorithm.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/BoxLayoutAlgorithm.java >diff -N src/org/eclipse/zest/layouts/algorithms/BoxLayoutAlgorithm.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/algorithms/BoxLayoutAlgorithm.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,48 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.algorithms; >+ >+/** >+ * Layout algorithm that places all elements in one column or one row, depending >+ * on set orientation. >+ */ >+public class BoxLayoutAlgorithm extends GridLayoutAlgorithm { >+ >+ public static final int HORIZONTAL = 1; >+ >+ public static final int VERTICAL = 2; >+ >+ private int orientation = HORIZONTAL; >+ >+ public BoxLayoutAlgorithm() { >+ } >+ >+ public BoxLayoutAlgorithm(int orientation) { >+ setOrientation(orientation); >+ } >+ >+ public int getOrientation() { >+ return orientation; >+ } >+ >+ public void setOrientation(int orientation) { >+ if (orientation == HORIZONTAL || orientation == VERTICAL) >+ this.orientation = orientation; >+ else >+ throw new RuntimeException("Invalid orientation: " + orientation); >+ } >+ >+ protected int[] calculateNumberOfRowsAndCols(int numChildren, double boundX, double boundY, double boundWidth, double boundHeight) { >+ if (orientation == HORIZONTAL) >+ return new int[] { numChildren, 1 }; >+ else >+ return new int[] { 1, numChildren }; >+ } >+} >Index: src/org/eclipse/zest/layouts/algorithms/AlgorithmHelper.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/AlgorithmHelper.java >diff -N src/org/eclipse/zest/layouts/algorithms/AlgorithmHelper.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/algorithms/AlgorithmHelper.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,208 @@ >+/******************************************************************************* >+ * Copyright (c) 2005-2009 The Chisel Group 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: The Chisel Group - initial API and implementation >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.algorithms; >+ >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+ >+class AlgorithmHelper { >+ >+ public static int MIN_NODE_SIZE = 8; >+ >+ public static double PADDING_PERCENT = 0.8; >+ >+ /** >+ * Fits given entities within given bounds, preserving their relative >+ * locations. >+ * >+ * @param entities >+ * @param destinationBounds >+ * @param resize >+ */ >+ public static void fitWithinBounds(EntityLayout[] entities, DisplayIndependentRectangle destinationBounds, boolean resize) { >+ if (entities.length == 1) { >+ fitSingleEntity(entities[0], destinationBounds, resize); >+ return; >+ } >+ >+ DisplayIndependentRectangle startingBounds = getLayoutBounds(entities, false); >+ >+ DisplayIndependentRectangle startingBoundsIncludingSize = getLayoutBounds(entities, true); >+ double sizeScale = Math.min(destinationBounds.width / startingBoundsIncludingSize.width, destinationBounds.height >+ / startingBoundsIncludingSize.height); >+ >+ for (int i = 0; i < entities.length; i++) { >+ EntityLayout entity = entities[i]; >+ DisplayIndependentDimension size = entity.getSize(); >+ if (entity.isMovable()) { >+ DisplayIndependentPoint location = entity.getLocation(); >+ double percentX = (location.x - startingBounds.x) / (startingBounds.width); >+ double percentY = (location.y - startingBounds.y) / (startingBounds.height); >+ >+ if (resize && entity.isResizable()) { >+ size.width *= sizeScale; >+ size.height *= sizeScale; >+ entity.setSize(size.width, size.height); >+ } >+ >+ location.x = destinationBounds.x + size.width / 2 + percentX * (destinationBounds.width - size.width); >+ location.y = destinationBounds.y + size.height / 2 + percentY * (destinationBounds.height - size.height); >+ entity.setLocation(location.x, location.y); >+ } else if (resize && entity.isResizable()) { >+ entity.setSize(size.width * sizeScale, size.height * sizeScale); >+ } >+ } >+ } >+ >+ private static void fitSingleEntity(EntityLayout entity, DisplayIndependentRectangle destinationBounds, boolean resize) { >+ if (entity.isMovable()) { >+ entity.setLocation(destinationBounds.x + destinationBounds.width / 2, destinationBounds.y + destinationBounds.height / 2); >+ } >+ if (resize && entity.isResizable()) { >+ double width = destinationBounds.width; >+ double height = destinationBounds.height; >+ double preferredAspectRatio = entity.getPreferredAspectRatio(); >+ if (preferredAspectRatio > 0) { >+ DisplayIndependentDimension fixedSize = fixAspectRatio(width, height, preferredAspectRatio); >+ entity.setSize(fixedSize.width, fixedSize.height); >+ } else { >+ entity.setSize(width, height); >+ } >+ } >+ } >+ >+ /** >+ * Resizes the nodes so that they have a maximal area without overlapping >+ * each other, with additional empty space of 20% of node's width (or >+ * height, if bigger). It does nothing if there's less than two nodes. >+ * >+ * @param entities >+ */ >+ public static void maximizeSizes(EntityLayout[] entities) { >+ if (entities.length > 1) { >+ DisplayIndependentDimension minDistance = getMinimumDistance(entities); >+ double nodeSize = Math.max(minDistance.width, minDistance.height) * PADDING_PERCENT; >+ double width = nodeSize; >+ double height = nodeSize; >+ for (int i = 0; i < entities.length; i++) { >+ EntityLayout entity = entities[i]; >+ if (entity.isResizable()) { >+ double preferredRatio = entity.getPreferredAspectRatio(); >+ if (preferredRatio > 0) { >+ DisplayIndependentDimension fixedSize = fixAspectRatio(width, height, preferredRatio); >+ entity.setSize(fixedSize.width, fixedSize.height); >+ } else { >+ entity.setSize(width, height); >+ } >+ } >+ } >+ } >+ } >+ >+ private static DisplayIndependentDimension fixAspectRatio(double width, double height, double preferredRatio) { >+ double actualRatio = width / height; >+ if (actualRatio > preferredRatio) { >+ width = height * preferredRatio; >+ if (width < MIN_NODE_SIZE) { >+ width = MIN_NODE_SIZE; >+ height = width / preferredRatio; >+ } >+ } >+ if (actualRatio < preferredRatio) { >+ height = width / preferredRatio; >+ if (height < MIN_NODE_SIZE) { >+ height = MIN_NODE_SIZE; >+ width = height * preferredRatio; >+ } >+ } >+ return new DisplayIndependentDimension(width, height); >+ } >+ >+ /** >+ * Find the bounds in which the nodes are located. Using the bounds against >+ * the real bounds of the screen, the nodes can proportionally be placed >+ * within the real bounds. The bounds can be determined either including the >+ * size of the nodes or not. If the size is not included, the bounds will >+ * only be guaranteed to include the center of each node. >+ */ >+ public static DisplayIndependentRectangle getLayoutBounds(EntityLayout[] entities, boolean includeNodeSize) { >+ double rightSide = Double.NEGATIVE_INFINITY; >+ double bottomSide = Double.NEGATIVE_INFINITY; >+ double leftSide = Double.POSITIVE_INFINITY; >+ double topSide = Double.POSITIVE_INFINITY; >+ for (int i = 0; i < entities.length; i++) { >+ EntityLayout entity = entities[i]; >+ DisplayIndependentPoint location = entity.getLocation(); >+ DisplayIndependentDimension size = entity.getSize(); >+ if (includeNodeSize) { >+ leftSide = Math.min(location.x - size.width / 2, leftSide); >+ topSide = Math.min(location.y - size.height / 2, topSide); >+ rightSide = Math.max(location.x + size.width / 2, rightSide); >+ bottomSide = Math.max(location.y + size.height / 2, bottomSide); >+ } else { >+ leftSide = Math.min(location.x, leftSide); >+ topSide = Math.min(location.y, topSide); >+ rightSide = Math.max(location.x, rightSide); >+ bottomSide = Math.max(location.y, bottomSide); >+ } >+ } >+ return new DisplayIndependentRectangle(leftSide, topSide, rightSide - leftSide, bottomSide - topSide); >+ } >+ >+ /** >+ * minDistance is the closest that any two points are together. These two >+ * points become the center points for the two closest nodes, which we wish >+ * to make them as big as possible without overlapping. This will be the >+ * maximum of minDistanceX and minDistanceY minus a bit, lets say 20% >+ * >+ * We make the recommended node size a square for convenience. >+ * >+ * <pre> >+ * _______ >+ * | | >+ * | | >+ * | + | >+ * | |\ | >+ * |___|_\_|_____ >+ * | | \ | >+ * | | \ | >+ * +-|---+ | >+ * | | >+ * |_______| >+ * </pre> >+ * >+ * >+ */ >+ public static DisplayIndependentDimension getMinimumDistance(EntityLayout[] entities) { >+ DisplayIndependentDimension horAndVertdistance = new DisplayIndependentDimension(Double.MAX_VALUE, Double.MAX_VALUE); >+ double minDistance = Double.MAX_VALUE; >+ >+ // TODO: Very Slow! >+ for (int i = 0; i < entities.length; i++) { >+ DisplayIndependentPoint location1 = entities[i].getLocation(); >+ for (int j = i + 1; j < entities.length; j++) { >+ DisplayIndependentPoint location2 = entities[j].getLocation(); >+ double distanceX = location1.x - location2.x; >+ double distanceY = location1.y - location2.y; >+ double distance = distanceX * distanceX + distanceY * distanceY; >+ >+ if (distance < minDistance) { >+ minDistance = distance; >+ horAndVertdistance.width = Math.abs(distanceX); >+ horAndVertdistance.height = Math.abs(distanceY); >+ } >+ } >+ } >+ return horAndVertdistance; >+ } >+} >Index: src/org/eclipse/zest/layouts/interfaces/PruningListener.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/interfaces/PruningListener.java >diff -N src/org/eclipse/zest/layouts/interfaces/PruningListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/interfaces/PruningListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,58 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.interfaces; >+ >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+ >+/** >+ * A listener added to {@link LayoutContext} that is notified about pruning and >+ * unpruning of nodes in this context. >+ */ >+public interface PruningListener { >+ >+ /** >+ * This method is called when some nodes are pruned in a layout context. >+ * >+ * If true is returned, it means that the receiving listener has intercepted >+ * this event. Intercepted events will not be passed to the rest of the >+ * listeners. If the event is not intercepted by any listener, >+ * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the >+ * context's main algorithm. >+ * >+ * @param context >+ * the layout context that fired the event >+ * @param nodes >+ * nodes that have been pruned. It can be assumed that all these >+ * nodes have been pruned into the same subgraph. >+ * @return true if no further operations after this event are required >+ */ >+ public boolean nodesPruned(LayoutContext context, NodeLayout[] nodes); >+ >+ /** >+ * This method is called when some nodes are unpruned in a layout context, >+ * that is they are no longer part of a subgraph. >+ * >+ * If true is returned, it means that the receiving listener has intercepted >+ * this event. Intercepted events will not be passed to the rest of the >+ * listeners. If the event is not intercepted by any listener, >+ * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the >+ * context's main algorithm. >+ * >+ * @param context >+ * the layout context that fired the event >+ * @param nodes >+ * nodes that have been unpruned >+ * @param subgraph >+ * subgraph that had contained the nodes while they were pruned >+ * @return true if no further operations after this event are required >+ */ >+ public boolean nodesUnpruned(LayoutContext context, NodeLayout[] nodes, SubgraphLayout subgraph); >+ >+} >Index: src/org/eclipse/zest/layouts/interfaces/NodeLayout.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/interfaces/NodeLayout.java >diff -N src/org/eclipse/zest/layouts/interfaces/NodeLayout.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/interfaces/NodeLayout.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,91 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.interfaces; >+ >+ >+public interface NodeLayout extends EntityLayout { >+ >+ public boolean isPrunable(); >+ >+ public boolean isPruned(); >+ >+ /** >+ * >+ * @return a subgraph this node belongs to or null if this node is not >+ * pruned >+ */ >+ public SubgraphLayout getSubgraph(); >+ >+ /** >+ * >+ * @param subgraph >+ * a subgraph this node should belong to or null if this node >+ * should not be pruned >+ */ >+ public void prune(SubgraphLayout subgraph); >+ >+ /** >+ * Returns all nodes that are direct successors of this node. Nodes >+ * connected with this node by a bidirectional connection are considered >+ * both successors and predecessors. Any subsequent changes to the returned >+ * array do not affect this node. >+ * >+ * @return array of successors of this node >+ */ >+ public NodeLayout[] getSuccessingNodes(); >+ >+ /** >+ * Returns all nodes that are direct predecessors of this node. Nodes >+ * connected with this node by a bidirectional connection are considered >+ * both successors and predecessors. Any subsequent changes to the returned >+ * array do not affect this node. >+ * >+ * @return array of predecessors of this node >+ */ >+ public NodeLayout[] getPredecessingNodes(); >+ >+ /** >+ * Returns all connections that have this node as a target. All connections >+ * that are bidirectional and are adjacent to this node will be also >+ * included in the result. Any subsequent changes to the returned array do >+ * not affect this node. >+ * >+ * @return array of connections entering this node >+ */ >+ public ConnectionLayout[] getIncomingConnections(); >+ >+ /** >+ * Returns all connections that have this node as a source. All connections >+ * that are bidirectional and are adjacent to this node will be also >+ * included in the result. Any subsequent changes to the returned array do >+ * not affect this node. >+ * >+ * @return array of connections leaving this node >+ */ >+ public ConnectionLayout[] getOutgoingConnections(); >+ >+ /** >+ * Sets the minimized state of this Node. Node that is minimized resizes its >+ * figure to (0, 0). When it is unminimized, it resizes back to previous >+ * dimension. The node's size property is not affected by minimized state, >+ * so an it can be minimized even if it's not resizable. >+ * >+ * @param minimized >+ * new minimized state >+ */ >+ public void setMinimized(boolean minimized); >+ >+ /** >+ * @see #setMinimized(boolean) >+ * >+ * @return true if this entity is minimized >+ */ >+ public boolean isMinimized(); >+} >Index: src/org/eclipse/zest/layouts/interfaces/EntityLayout.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/interfaces/EntityLayout.java >diff -N src/org/eclipse/zest/layouts/interfaces/EntityLayout.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/interfaces/EntityLayout.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,106 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.interfaces; >+ >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint; >+ >+/** >+ * A common interface for entities that are displayed on a graph, that is >+ * {@link NodeLayout nodes} and {@link SubgraphLayout subgraphs}. >+ */ >+public interface EntityLayout { >+ >+ /** >+ * Returns a point laying in the center of this entity. Any subsequent >+ * changes to the returned point won't affect this node. >+ * >+ * @return position of the center of this node >+ */ >+ public DisplayIndependentPoint getLocation(); >+ >+ /** >+ * Sets the position of this entity. The node will be moved so that it's >+ * center is located in the given point. >+ * >+ * @param x >+ * the x-position >+ * @param y >+ * the y-position >+ */ >+ public void setLocation(double x, double y); >+ >+ public DisplayIndependentDimension getSize(); >+ >+ public void setSize(double width, double height); >+ >+ /** >+ * Returns aspect ratio that is preferred for this entity. Can be 0 if this >+ * node can't be resized anyway or it doesn't care about about its ratio. >+ * >+ * @return aspect ratio (width / height) >+ */ >+ public double getPreferredAspectRatio(); >+ >+ public boolean isResizable(); >+ >+ public boolean isMovable(); >+ >+ /** >+ * Returns all entities that are direct successors of this entity. Successor >+ * entities of an unpruned node N are: >+ * <ul> >+ * <li>all unpruned successor nodes of node N</li> >+ * <li>all subgraphs that are <code>GraphEntities</code> and contain at >+ * least one successor node of node N</li> >+ * </ul> >+ * Successor entities of a subgraph S that is a <code>GraphEntity</code> >+ * are: >+ * <ul> >+ * <li>all unpruned nodes that are successor of at least one node from >+ * subgraph S</li> >+ * <li>all subgraphs that are <code>GraphEntities</code> and contain at >+ * least one node that is a successor of at least one node from subgraph S</li> >+ * </ul> >+ * For subgraphs that are not <code>GraphEntities</code> an empty array will >+ * be returned.</br>Entities connected with this node by a bidirectional >+ * connection are considered both successors and predecessors. Any >+ * subsequent changes to the returned array do not affect this node. >+ * >+ * @return array of successors of this node >+ */ >+ public EntityLayout[] getSuccessingEntities(); >+ >+ /** >+ * Returns all entities that are direct predecessors of this entity. >+ * Predecessor entities of an unpruned node A are: >+ * <ul> >+ * <li>all unpruned predecessor nodes of node N</li> >+ * <li>all subgraphs that are <code>GraphEntities</code> and contain at >+ * least one predecessor node of node N</li> >+ * </ul> >+ * Successor entities of a subgraph S that is a <code>GraphEntity</code> >+ * are: >+ * <ul> >+ * <li>all unpruned nodes that are predecessor of at least one node from >+ * subgraph S</li> >+ * <li>all subgraphs that are <code>GraphEntities</code> and contain at >+ * least one node that is a predecessor of at least one node from subgraph S >+ * </li> >+ * </ul> >+ * For subgraphs that are not <code>GraphEntities</code> an empty array will >+ * be returned.</br>Entities connected with this node by a bidirectional >+ * connection are considered both successors and predecessors. Any >+ * subsequent changes to the returned array do not affect this node. >+ * >+ * @return array of predecessors of this node >+ */ >+ public EntityLayout[] getPredecessingEntities(); >+} >Index: src/org/eclipse/zest/layouts/interfaces/LayoutContext.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/interfaces/LayoutContext.java >diff -N src/org/eclipse/zest/layouts/interfaces/LayoutContext.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/interfaces/LayoutContext.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,229 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.interfaces; >+ >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >+ >+/** >+ * Objects implementing LayoutContext interface are used for exchanging of >+ * information between layout algorithms and graphical objects displaying >+ * graphs. >+ */ >+public interface LayoutContext { >+ >+ /** >+ * Returns all the nodes that should be laid out. Replacing elements in the >+ * returned array does not affect this context. >+ * >+ * @return array of nodes to lay out >+ */ >+ public NodeLayout[] getNodes(); >+ >+ /** >+ * Returns all the connections between nodes that should be laid out. >+ * Replacing elements in the returned array does not affect this context. >+ * >+ * @return array of connections between nodes >+ */ >+ public ConnectionLayout[] getConnections(); >+ >+ /** >+ * Returns all entities that are currently placed on the graph, that is >+ * subgraphs and unpruned nodes. Replacing elements in the returned array >+ * does not affect this context. >+ * >+ * @return array of entities to layout >+ */ >+ public EntityLayout[] getEntities(); >+ >+ /** >+ * Returns all the connections between given source and target entities. If >+ * given entity is a subgraph, connections adjacent to each of its nodes >+ * will be included in the result. All the undirected nodes connecting the >+ * two nodes will be also included in the result. Replacing elements in the >+ * returned array does not affect this context. >+ * >+ * @param layoutEntity1 >+ * @param layoutEntity2 >+ * @return >+ */ >+ public ConnectionLayout[] getConnections(EntityLayout layoutEntity1, EntityLayout layoutEntity2); >+ >+ /** >+ * >+ * @return bounds in which the graph elements can be placed >+ */ >+ public DisplayIndependentRectangle getBounds(); >+ >+ /** >+ * >+ * @return true if a layout algorithm is allowed to place graph elements >+ * outside of suggested bounds >+ */ >+ public boolean isBoundsExpandable(); >+ >+ /** >+ * Returns all the subgraphs this context's nodes were pruned to. Replacing >+ * elements in the returned array does not affect this context. >+ * >+ * @return array of subgraphs (may be empty) >+ */ >+ public SubgraphLayout[] getSubgraphs(); >+ >+ /** >+ * Creates a subgraph containing given nodes and adds it to this context. If >+ * given nodes already belong to another subgraphs, they are removed from >+ * them prior to adding to the new subgraph. >+ * >+ * @param nodes >+ * nodes to add to the new subgraph >+ */ >+ public SubgraphLayout createSubgraph(NodeLayout[] nodes); >+ >+ /** >+ * >+ * @return true if this layout context allows pruning nodes into subgraphs >+ */ >+ public boolean isPruningEnabled(); >+ >+ /** >+ * Checks if this layout context allows layout algorithms to work >+ * continuously in background and change the layout with time or in reaction >+ * to some events. If background changes are not allowed, a layout algorithm >+ * can make changes in layout context only when >+ * {@link LayoutAlgorithm#applyLayout(boolean)} is called (otherwise a >+ * runtime exception will be thrown). >+ * >+ * @return true if background layout changes are enabled >+ */ >+ public boolean isBackgroundLayoutEnabled(); >+ >+ /** >+ * Sets the main layout algorithm for this context. Main algorithm will be >+ * used to relayout graph items using {@link LayoutAlgorithm#applyLayout()} >+ * after every event that is not intercepted by any listener. >+ * >+ * @param algorithm >+ */ >+ public void setMainLayoutAlgorithm(LayoutAlgorithm algorithm); >+ >+ /** >+ * >+ * @return the main algorithm of this context (see >+ * {@link #setMainLayoutAlgorithm(LayoutAlgorithm)} for details) >+ */ >+ public LayoutAlgorithm getMainLayoutAlgorithm(); >+ >+ /** >+ * Sets the expand/collapse manager for this context. The manger will be >+ * used to handle expansion related methods called on the owner of this >+ * context. >+ * >+ * @param expandCollapseManager >+ */ >+ public void setExpandCollapseManager(ExpandCollapseManager expandCollapseManager); >+ >+ /** >+ * >+ * @return current expand/collapse manager (can be null, which means that >+ * pruning is not enabled). >+ */ >+ public ExpandCollapseManager getExpandCollapseManager(); >+ >+ /** >+ * Adds a listener to the context that will be notified about changes in >+ * this context's layout, that is movement and resizing of nodes / >+ * subgraphs. The notifications will not include changes made with API >+ * included in layout related interfaces, so that layout algorithms won't be >+ * notified about changes they invoke. Only internal changes of the system >+ * will fire events. >+ * >+ * @param listener >+ * listener to add >+ */ >+ public void addLayoutListener(LayoutListener listener); >+ >+ /** >+ * Removes a layout listener from this context. >+ * >+ * @param listener >+ * listener to remove >+ */ >+ public void removeLayoutListener(LayoutListener listener); >+ >+ /** >+ * Adds a listener to the context that will be notified about changes in >+ * graph structure, that is addition and removal of nodes and connections. >+ * The notifications will not include changes made with API included in >+ * layout related interfaces, so that layout algorithms won't be notified >+ * about changes they invoke. Only internal changes of the system will fire >+ * events. >+ * >+ * @param listener >+ * listener to add >+ */ >+ public void addGraphStructureListener(GraphStructureListener listener); >+ >+ /** >+ * Removes a graph structure listener from this context. >+ * >+ * @param listener >+ * listener to remove >+ */ >+ public void removeGraphStructureListener(GraphStructureListener listener); >+ >+ /** >+ * Adds a listener to the context that will be notified about changes >+ * related to its configuration. >+ * >+ * @param listener >+ * listener to add >+ */ >+ public void addContextListener(ContextListener listener); >+ >+ /** >+ * Removes a context listener from this context. >+ * >+ * @param listener >+ * listener to remove >+ */ >+ public void removeContextListener(ContextListener listener); >+ >+ /** >+ * Adds a listener to the context that will be notified about changes in >+ * graph pruning, that is hiding and showing of nodes. The notifications >+ * will not include changes made with API included in layout related >+ * interfaces, so that layout algorithms won't be notified about changes >+ * they invoke. Only internal changes of the system will fire events. >+ * >+ * @param listener >+ * listener to add >+ */ >+ public void addPruningListener(PruningListener listener); >+ >+ /** >+ * Removes a pruning structure listener from this context. >+ * >+ * @param listener >+ * listener to remove >+ */ >+ public void removePruningListener(PruningListener listener); >+ >+ /** >+ * Causes all the changes made to elements in this context to affect the >+ * display. >+ * >+ * @param animationHint >+ * a hint for display mechanism indicating whether changes are >+ * major and should be animated (if true) or not. >+ */ >+ public void flushChanges(boolean animationHint); >+} >Index: src/org/eclipse/zest/layouts/interfaces/ContextListener.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/interfaces/ContextListener.java >diff -N src/org/eclipse/zest/layouts/interfaces/ContextListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/interfaces/ContextListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,78 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.interfaces; >+ >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+ >+/** >+ * A listener added to {@link LayoutContext} that is notified about general >+ * changes in this context. >+ */ >+public interface ContextListener { >+ public class Stub implements ContextListener { >+ >+ public boolean boundsChanged(LayoutContext context) { >+ return false; >+ } >+ >+ public void backgroundEnableChanged(LayoutContext context) { >+ // do nothing >+ } >+ >+ public boolean pruningEnablementChanged(LayoutContext context) { >+ return false; >+ } >+ >+ } >+ >+ /** >+ * This method is called whenever the bounds available in a layout context >+ * change. >+ * >+ * If true is returned, it means that the receiving listener has intercepted >+ * this event. Intercepted events will not be passed to the rest of the >+ * listeners. If the event is not intercepted by any listener, >+ * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the >+ * context's main algorithm. >+ * >+ * @param context >+ * the layout context that fired the event >+ * @return true if no further operations after this event are required >+ */ >+ public boolean boundsChanged(LayoutContext context); >+ >+ /** >+ * This method is called whenever graph pruning is enabled or disabled in a >+ * layout context. >+ * >+ * If true is returned, it means that the receiving listener has intercepted >+ * this event. Intercepted events will not be passed to the rest of the >+ * listeners. If the event is not intercepted by any listener, >+ * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the >+ * context's main algorithm. >+ * >+ * @param context >+ * the layout context that fired the event >+ * @return true if no further operations after this event are required >+ */ >+ public boolean pruningEnablementChanged(LayoutContext context); >+ >+ /** >+ * This method is called whenever background layout is enabled or disabled >+ * in a layout context. If the receiving listener is related to a layout >+ * algorithm that performs layout in reaction to events, it should turn >+ * automatic flush of changes on or off. Also, eventual additional threads >+ * responsible for layout should be stopped or started accordingly. >+ * >+ * @param context >+ * the layout context that fired the event >+ */ >+ public void backgroundEnableChanged(LayoutContext context); >+} >Index: src/org/eclipse/zest/layouts/interfaces/GraphStructureListener.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/interfaces/GraphStructureListener.java >diff -N src/org/eclipse/zest/layouts/interfaces/GraphStructureListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/interfaces/GraphStructureListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,168 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.interfaces; >+ >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+ >+/** >+ * A listener added to {@link LayoutContext} that is notified about changes in >+ * this context's graph structure. >+ */ >+public interface GraphStructureListener { >+ >+ /** >+ * A stub implementation of <code>GraphStructureListener</code>. Convenient >+ * for creating listeners that don't implements all required methods. >+ */ >+ public class Stub implements GraphStructureListener { >+ >+ public boolean nodeAdded(LayoutContext context, NodeLayout node) { >+ return false; >+ } >+ >+ public boolean nodeRemoved(LayoutContext context, NodeLayout node) { >+ return false; >+ } >+ >+ public boolean connectionAdded(LayoutContext context, ConnectionLayout connection) { >+ return false; >+ } >+ >+ public boolean connectionRemoved(LayoutContext context, ConnectionLayout connection) { >+ return false; >+ } >+ >+ public boolean connectionWeightChanged(LayoutContext context, ConnectionLayout connection) { >+ return false; >+ } >+ >+ public boolean connectionDirectedChanged(LayoutContext context, ConnectionLayout connection) { >+ return false; >+ } >+ } >+ >+ /** >+ * This method is called whenever a node is added to a context. No separate >+ * events will be fired for eventual connections adjacent to the added node. >+ * >+ * If true is returned, it means that the receiving listener has intercepted >+ * this event. Intercepted events will not be passed to the rest of the >+ * listeners. If the event is not intercepted by any listener, >+ * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the >+ * context's main algorithm. >+ * >+ * @param context >+ * the layout context that fired the event >+ * @param node >+ * the added node >+ * @return true if no further operations after this event are required >+ */ >+ public boolean nodeAdded(LayoutContext context, NodeLayout node); >+ >+ /** >+ * This method is called whenever a node is removed from a context. No >+ * separate events will be fired for eventual connections adjacent to the >+ * removed node. >+ * >+ * If true is returned, it means that the receiving listener has intercepted >+ * this event. Intercepted events will not be passed to the rest of the >+ * listeners. If the event is not intercepted by any listener, >+ * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the >+ * context's main algorithm. >+ * >+ * @param context >+ * the context that fired the event >+ * @param node >+ * the removed node >+ * @return true if no further operations after this event are required >+ */ >+ public boolean nodeRemoved(LayoutContext context, NodeLayout node); >+ >+ /** >+ * This method is called whenever a connection is added to a context. It can >+ * be assumed that both source and target nodes of the added connection >+ * already exist in the context. >+ * >+ * This method will be called only if both nodes connected by added >+ * connection lay directly in the node container owned by the notifying >+ * layout context. >+ * >+ * If true is returned, it means that the receiving listener has intercepted >+ * this event. Intercepted events will not be passed to the rest of the >+ * listeners. If the event is not intercepted by any listener, >+ * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the >+ * context's main algorithm. >+ * >+ * @param context >+ * the context that fired the event >+ * @param connection >+ * the added connection >+ * @return true if no further operations after this event are required >+ */ >+ public boolean connectionAdded(LayoutContext context, ConnectionLayout connection); >+ >+ /** >+ * This method is called whenever a connection is removed from a context. It >+ * can be assumed that both source and target nodes of the removed >+ * connection still exist in the context and will not necessarily be removed >+ * along with it. >+ * >+ * This method will be called only if both nodes connected by removed >+ * connection lay directly in the node container owned by the notifying >+ * layout context. >+ * >+ * If true is returned, it means that the receiving listener has intercepted >+ * this event. Intercepted events will not be passed to the rest of the >+ * listeners. If the event is not intercepted by any listener, >+ * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the >+ * context's main algorithm. >+ * >+ * @param context >+ * the context that fired the event >+ * @param connection >+ * the added connection >+ * @return true if no further operations after this event are required >+ */ >+ public boolean connectionRemoved(LayoutContext context, ConnectionLayout connection); >+ >+ /** >+ * This method is called whenever a connection changes its weight. >+ * >+ * If true is returned, it means that the receiving listener has intercepted >+ * this event. Intercepted events will not be passed to the rest of the >+ * listeners. If the event is not intercepted by any listener, >+ * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the >+ * context's main algorithm. >+ * >+ * @param context >+ * the context that fired the event >+ * @param connection >+ * the affected connection >+ * @return true if no further operations after this event are required >+ */ >+ public boolean connectionWeightChanged(LayoutContext context, ConnectionLayout connection); >+ >+ /** >+ * This method is called whenever a connection changes its directed state. >+ * >+ * If true is returned, it means that the receiving listener has intercepted >+ * this event. Intercepted events will not be passed to the rest of the >+ * listeners. If the event is not intercepted by any listener, >+ * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the >+ * context's main algorithm. >+ * >+ * @param context >+ * the context that fired the event >+ * @param connection >+ * the affected connection >+ * @return true if no further operations after this event are required >+ */ >+ public boolean connectionDirectedChanged(LayoutContext context, ConnectionLayout connection); >+} >Index: src/org/eclipse/zest/layouts/algorithms/SpaceTreeLayoutAlgorithm.java >=================================================================== >RCS file: src/org/eclipse/zest/layouts/algorithms/SpaceTreeLayoutAlgorithm.java >diff -N src/org/eclipse/zest/layouts/algorithms/SpaceTreeLayoutAlgorithm.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/layouts/algorithms/SpaceTreeLayoutAlgorithm.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,1206 @@ >+/******************************************************************************* >+ * Copyright (c) 2005-2009 The Chisel Group 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: The Chisel Group - initial API and implementation >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.layouts.algorithms; >+ >+import java.util.ArrayList; >+import java.util.Arrays; >+import java.util.Collections; >+import java.util.Comparator; >+import java.util.Iterator; >+import java.util.LinkedList; >+import java.util.List; >+import java.util.ListIterator; >+ >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >+import org.eclipse.zest.layouts.interfaces.ContextListener; >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+import org.eclipse.zest.layouts.interfaces.ExpandCollapseManager; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+import org.eclipse.zest.layouts.interfaces.LayoutListener; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+import org.eclipse.zest.layouts.interfaces.SubgraphLayout; >+ >+/** >+ * Layout algorithm implementing SpaceTree. It assumes that nodes in the layout >+ * context make a tree structure. >+ * >+ * It expands and collapses nodes to optimize use of available space. In order >+ * to keep the tree structure clearly visible, it also keeps track of the nodes' >+ * positions to makes sure they stay in their current layer and don't overlap >+ * with each other. >+ * >+ * It's recommended to set an <code>ExpandCollapseManger</code> returned by >+ * {@link #getExpandCollapseManager()} in the <code>LayoutContext</code> that >+ * will be used with this layout algorithm. Other >+ * <code>ExpandCollapseManager</code>s could also work, but the algorithm's >+ * functionality would be very limited. >+ */ >+public class SpaceTreeLayoutAlgorithm implements LayoutAlgorithm { >+ >+ /** >+ * Tree direction constant for which root is placed at the top and branches >+ * spread downwards >+ */ >+ public final static int TOP_DOWN = 1; >+ >+ /** >+ * Tree direction constant for which root is placed at the bottom and >+ * branches spread upwards >+ */ >+ public final static int BOTTOM_UP = 2; >+ >+ /** >+ * Tree direction constant for which root is placed at the left and branches >+ * spread to the right >+ */ >+ public final static int LEFT_RIGHT = 3; >+ >+ /** >+ * Tree direction constant for which root is placed at the right and >+ * branches spread to the left >+ */ >+ public final static int RIGHT_LEFT = 4; >+ >+ private class SpaceTreeNode extends TreeLayoutObserver.TreeNode { >+ public SubgraphLayout subgraph = null; >+ >+ public boolean expanded = false; >+ public double positionInLayer; >+ >+ public SpaceTreeNode(NodeLayout node, TreeLayoutObserver owner) { >+ super(node, owner); >+ } >+ >+ protected void addChild(TreeLayoutObserver.TreeNode child) { >+ super.addChild(child); >+ >+ SpaceTreeNode child2 = (SpaceTreeNode) child; >+ child2.expanded = false; >+ child2.setSubgraph(null); >+ >+ if (child.depth >= 0) >+ ((SpaceTreeLayer) spaceTreeLayers.get(child.depth)).removeNode(child2); >+ >+ if (expanded) { >+ child.depth = this.depth + 1; >+ >+ SpaceTreeLayer childLayer; >+ if (child.depth < spaceTreeLayers.size()) >+ childLayer = ((SpaceTreeLayer) spaceTreeLayers.get(child.depth)); >+ else >+ spaceTreeLayers.add(childLayer = new SpaceTreeLayer(child.depth)); >+ >+ if (childLayer.nodes.isEmpty()) >+ child.order = 0; >+ else >+ child.order = ((SpaceTreeNode) childLayer.nodes.get(childLayer.nodes.size() - 1)).order + 1; >+ childLayer.addNodes(Arrays.asList(new Object[] { child })); >+ } >+ } >+ >+ public void precomputeTree() { >+ super.precomputeTree(); >+ if (this == owner.getSuperRoot()) { >+ expanded = true; >+ while (spaceTreeLayers.size() <= this.height) >+ spaceTreeLayers.add(new SpaceTreeLayer(spaceTreeLayers.size())); >+ >+ if (treeObserver != null) >+ refreshLayout(true); >+ } >+ } >+ >+ public SubgraphLayout collapseAllChildrenIntoSubgraph(SubgraphLayout subgraph, boolean includeYourself) { >+ expanded = false; >+ ArrayList allChildren = new ArrayList(); >+ LinkedList nodesToVisit = new LinkedList(); >+ nodesToVisit.addLast(this); >+ while (!nodesToVisit.isEmpty()) { >+ SpaceTreeNode currentNode = (SpaceTreeNode) nodesToVisit.removeFirst(); >+ for (Iterator iterator = currentNode.children.iterator(); iterator.hasNext();) { >+ SpaceTreeNode child = (SpaceTreeNode) iterator.next(); >+ allChildren.add(child.node); >+ child.setSubgraph(null); >+ child.expanded = false; >+ nodesToVisit.addLast(child); >+ } >+ } >+ if (includeYourself) >+ allChildren.add(this.node); >+ if (allChildren.isEmpty()) { >+ setSubgraph(null); >+ return null; >+ } >+ NodeLayout[] childrenArray = (NodeLayout[]) allChildren.toArray(new NodeLayout[allChildren.size()]); >+ if (subgraph == null) { >+ subgraph = context.createSubgraph(childrenArray); >+ subgraph.setDirection(getSubgraphDirection()); >+ } else { >+ subgraph.addNodes(childrenArray); >+ } >+ if (!includeYourself) >+ setSubgraph(subgraph); >+ return subgraph; >+ } >+ >+ public void setSubgraph(SubgraphLayout subgraph) { // ! >+ if (this.subgraph != subgraph) { >+ this.subgraph = subgraph; >+ refreshSubgraphLocation(); >+ } >+ } >+ >+ /** >+ * Moves the node back to its layer, as close as possible to given >+ * preferred location >+ * >+ * @param preferredLocation >+ */ >+ public void adjustPosition(DisplayIndependentPoint preferredLocation) { // ! >+ protectedNode = (SpaceTreeNode) owner.getSuperRoot(); >+ >+ double newPositionInLayer = (direction == BOTTOM_UP || direction == TOP_DOWN) ? preferredLocation.x - bounds.x : preferredLocation.y >+ - bounds.y; >+ if (((SpaceTreeNode) parent).expanded) { >+ ((SpaceTreeLayer) spaceTreeLayers.get(depth)).moveNode(this, newPositionInLayer); >+ centerParentsTopDown(); >+ } >+ } >+ >+ public void refreshSubgraphLocation() { >+ if (subgraph != null && subgraph.isGraphEntity()) { >+ DisplayIndependentPoint nodeLocation = node.getLocation(); >+ DisplayIndependentDimension nodeSize = node.getSize(); >+ DisplayIndependentDimension subgraphSize = subgraph.getSize(); >+ double x = 0, y = 0; >+ switch (direction) { >+ case TOP_DOWN: >+ x = nodeLocation.x; >+ y = nodeLocation.y + (nodeSize.height + subgraphSize.height) / 2; >+ break; >+ case BOTTOM_UP: >+ x = nodeLocation.x; >+ y = nodeLocation.y - (nodeSize.height + subgraphSize.height) / 2; >+ break; >+ case LEFT_RIGHT: >+ x = nodeLocation.x + (nodeSize.width + subgraphSize.width) / 2; >+ y = nodeLocation.y; >+ break; >+ case RIGHT_LEFT: >+ x = nodeLocation.x - (nodeSize.width + subgraphSize.height) / 2; >+ y = nodeLocation.y; >+ break; >+ } >+ subgraph.setLocation(x, y); >+ } >+ ((SpaceTreeLayer) spaceTreeLayers.get(depth)).refreshThickness(); >+ } >+ >+ public double spaceRequiredForNode() { >+ if (node == null) >+ return 0; >+ switch (direction) { >+ case TOP_DOWN: >+ case BOTTOM_UP: >+ return node.getSize().width; >+ case LEFT_RIGHT: >+ case RIGHT_LEFT: >+ return node.getSize().height; >+ } >+ throw new RuntimeException("invalid direction"); >+ } >+ >+ public double spaceRequiredForChildren() { >+ if (children.isEmpty()) >+ return 0; >+ double result = 0; >+ for (Iterator iterator = children.iterator(); iterator.hasNext();) { >+ SpaceTreeNode child = (SpaceTreeNode) iterator.next(); >+ result += child.spaceRequiredForNode(); >+ } >+ result += leafGap * (children.size() - 1); >+ return result; >+ } >+ >+ /** >+ * Checks if nodes in given list have proper positions according to >+ * their children (a parent's position cannot be smaller than its first >+ * child's position nor bigger than its last child's position). If not, >+ * it tries to fix them. >+ * >+ * @param nodesToCheck >+ * @return true if all locations are correct or could be corrected while >+ * checking. >+ */ >+ public boolean childrenPositionsOK(ArrayList nodesToCheck) { >+ for (Iterator iterator = nodesToCheck.iterator(); iterator.hasNext();) { >+ SpaceTreeNode node = (SpaceTreeNode) iterator.next(); >+ if (node.depth < 0 || node.children.isEmpty()) >+ continue; >+ SpaceTreeNode child = ((SpaceTreeNode) node.children.get(0)); >+ if (child.positionInLayer > node.positionInLayer) { >+ ((SpaceTreeLayer) spaceTreeLayers.get(node.depth)).moveNode(node, child.positionInLayer); >+ if (child.positionInLayer > node.positionInLayer) { >+ ((SpaceTreeLayer) spaceTreeLayers.get(child.depth)).moveNode(child, node.positionInLayer); >+ if (child.positionInLayer > node.positionInLayer) { >+ return false; >+ } >+ } >+ } >+ child = ((SpaceTreeNode) node.children.get(node.children.size() - 1)); >+ if (child.positionInLayer < node.positionInLayer) { >+ ((SpaceTreeLayer) spaceTreeLayers.get(node.depth)).moveNode(node, child.positionInLayer); >+ if (child.positionInLayer < node.positionInLayer) { >+ ((SpaceTreeLayer) spaceTreeLayers.get(child.depth)).moveNode(child, node.positionInLayer); >+ if (child.positionInLayer < node.positionInLayer) { >+ return false; >+ } >+ } >+ } >+ } >+ return true; >+ } >+ >+ public void centerParentsBottomUp() { >+ if (!children.isEmpty() && expanded) { >+ for (Iterator iterator = children.iterator(); iterator.hasNext();) { >+ ((SpaceTreeNode) iterator.next()).centerParentsBottomUp(); >+ } >+ >+ if (depth >= 0) { >+ SpaceTreeNode firstChild = (SpaceTreeNode) children.get(0); >+ SpaceTreeNode lastChild = (SpaceTreeNode) children.get(children.size() - 1); >+ SpaceTreeLayer layer = (SpaceTreeLayer) spaceTreeLayers.get(depth); >+ layer.moveNode(this, (firstChild.positionInLayer + lastChild.positionInLayer) / 2); >+ } >+ } >+ } >+ >+ public void centerParentsTopDown() { >+ if (this == owner.getSuperRoot()) { >+ this.positionInLayer = getAvailableSpace() / 2; >+ } >+ if (!children.isEmpty() && expanded) { >+ SpaceTreeNode firstChild = (SpaceTreeNode) children.get(0); >+ SpaceTreeNode lastChild = (SpaceTreeNode) children.get(children.size() - 1); >+ double offset = this.positionInLayer - (firstChild.positionInLayer + lastChild.positionInLayer) / 2; >+ if (firstChild.positionInLayer - firstChild.spaceRequiredForNode() / 2 + offset < 0) >+ offset = -firstChild.positionInLayer + firstChild.spaceRequiredForNode() / 2; >+ double availableSpace = getAvailableSpace(); >+ if (lastChild.positionInLayer + lastChild.spaceRequiredForNode() / 2 + offset > availableSpace) { >+ offset = availableSpace - lastChild.positionInLayer - lastChild.spaceRequiredForNode() / 2; >+ } >+ SpaceTreeLayer layer = (SpaceTreeLayer) spaceTreeLayers.get(depth + 1); >+ layer.fitNodesWithinBounds(children, firstChild.positionInLayer + offset, lastChild.positionInLayer + offset); >+ >+ for (Iterator iterator = children.iterator(); iterator.hasNext();) { >+ ((SpaceTreeNode) iterator.next()).centerParentsTopDown(); >+ } >+ } >+ } >+ >+ public void flushExpansionChanges() { >+ if (node != null) >+ node.prune(null); >+ if (this.expanded) { >+ setSubgraph(null); >+ for (Iterator iterator = children.iterator(); iterator.hasNext();) { >+ ((SpaceTreeNode) iterator.next()).flushExpansionChanges(); >+ } >+ } >+ if (!this.expanded && subgraph == null) { >+ collapseAllChildrenIntoSubgraph(null, false); >+ } >+ } >+ >+ public boolean flushCollapseChanges() { >+ if (!expanded) { >+ int numberOfChildrenInSubgraph = subgraph == null ? 0 : subgraph.countNodes(); >+ collapseAllChildrenIntoSubgraph(subgraph, false); >+ int newNumberOfChildrenInSubgraph = (subgraph == null ? 0 : subgraph.countNodes()); >+ if (numberOfChildrenInSubgraph != newNumberOfChildrenInSubgraph && newNumberOfChildrenInSubgraph > 0) >+ refreshSubgraphLocation(); >+ return numberOfChildrenInSubgraph != newNumberOfChildrenInSubgraph; >+ } >+ if (expanded && subgraph == null) { >+ boolean madeChagnes = false; >+ for (Iterator iterator = children.iterator(); iterator.hasNext();) { >+ madeChagnes = ((SpaceTreeNode) iterator.next()).flushCollapseChanges() || madeChagnes; >+ } >+ return madeChagnes; >+ } >+ return false; >+ } >+ >+ /** >+ * Sets locations of nodes in the graph depending on their current layer >+ * and position in layer. >+ * >+ * @param thicknessSoFar >+ * sum of thicknesses and gaps for all layers 'above' this >+ * node (should be 0 if called on superRoot) >+ * @return true if location of at least one node has changed >+ */ >+ public boolean flushLocationChanges(double thicknessSoFar) { >+ boolean madeChanges = false; >+ if (node != null) { >+ DisplayIndependentDimension nodeSize = node.getSize(); >+ double x = 0, y = 0; >+ switch (direction) { >+ case TOP_DOWN: >+ x = bounds.x + positionInLayer; >+ y = thicknessSoFar + nodeSize.height / 2; >+ break; >+ case BOTTOM_UP: >+ x = bounds.x + positionInLayer; >+ y = bounds.y + bounds.height - thicknessSoFar - nodeSize.height / 2; >+ break; >+ case LEFT_RIGHT: >+ x = thicknessSoFar + nodeSize.height / 2; >+ y = bounds.y + positionInLayer; >+ break; >+ case RIGHT_LEFT: >+ x = bounds.x + bounds.width - thicknessSoFar - nodeSize.height / 2; >+ y = bounds.y + positionInLayer; >+ break; >+ } >+ DisplayIndependentPoint currentLocation = node.getLocation(); >+ if (currentLocation.x != x || currentLocation.y != y) { >+ node.setLocation(x, y); >+ refreshSubgraphLocation(); >+ madeChanges = true; >+ } >+ } >+ if (expanded && subgraph == null) { >+ thicknessSoFar += (depth >= 0 ? ((SpaceTreeLayer) spaceTreeLayers.get(depth)).thickness : 0) + layerGap; >+ for (Iterator iterator = children.iterator(); iterator.hasNext();) { >+ SpaceTreeNode child = (SpaceTreeNode) iterator.next(); >+ madeChanges = child.flushLocationChanges(thicknessSoFar) || madeChanges; >+ } >+ } >+ return madeChanges; >+ } >+ >+ public String toString() { >+ StringBuffer sb = new StringBuffer(); >+ for (int i = 0; i < depth; i++) >+ sb.append(" "); >+ if (node != null) >+ sb.append(node.toString()); >+ sb.append("|" + this.order); >+ sb.append('\n'); >+ for (Iterator iterator = children.iterator(); iterator.hasNext();) { >+ SpaceTreeNode child = (SpaceTreeNode) iterator.next(); >+ sb.append(child.toString()); >+ } >+ return sb.toString(); >+ } >+ } >+ >+ private TreeLayoutObserver.TreeNodeFactory spaceTreeNodeFactory = new TreeLayoutObserver.TreeNodeFactory() { >+ public TreeLayoutObserver.TreeNode createTreeNode(NodeLayout nodeLayout, TreeLayoutObserver observer) { >+ return new SpaceTreeNode(nodeLayout, observer); >+ }; >+ }; >+ >+ private class SpaceTreeLayer { >+ public ArrayList nodes = new ArrayList(); >+ private final int depth; >+ public double thickness = 0; >+ >+ public SpaceTreeLayer(int depth) { >+ this.depth = depth; >+ } >+ >+ public void addNodes(List nodesToAdd) { >+ ListIterator layerIterator = nodes.listIterator(); >+ SpaceTreeNode previousNode = null; >+ for (Iterator iterator = nodesToAdd.iterator(); iterator.hasNext();) { >+ SpaceTreeNode nodeToAdd = (SpaceTreeNode) iterator.next(); >+ >+ SpaceTreeNode nodeInLayer = null; >+ while (layerIterator.hasNext()) { >+ nodeInLayer = (SpaceTreeNode) layerIterator.next(); >+ if (nodeInLayer.order >= nodeToAdd.order) >+ break; >+ double expectedPostion = (previousNode == null) ? 0 : previousNode.positionInLayer + expectedDistance(previousNode, nodeInLayer); >+ nodeInLayer.positionInLayer = Math.max(nodeInLayer.positionInLayer, expectedPostion); >+ previousNode = nodeInLayer; >+ } >+ >+ if (nodeInLayer == null) { >+ layerIterator.add(nodeToAdd); >+ } else if (nodeInLayer.order == nodeToAdd.order) { >+ layerIterator.set(nodeToAdd); >+ } else { >+ if (nodeInLayer.order > nodeToAdd.order) >+ layerIterator.previous(); >+ layerIterator.add(nodeToAdd); >+ } >+ layerIterator.previous(); >+ } >+ // move the rest of nodes so that they don't overlap >+ while (layerIterator.hasNext()) { >+ SpaceTreeNode nodeInLayer = (SpaceTreeNode) layerIterator.next(); >+ double expectedPostion = (previousNode == null) ? 0 : previousNode.positionInLayer + expectedDistance(previousNode, nodeInLayer); >+ nodeInLayer.positionInLayer = Math.max(nodeInLayer.positionInLayer, expectedPostion); >+ previousNode = nodeInLayer; >+ } >+ >+ refreshThickness(); >+ } >+ >+ public void removeNode(SpaceTreeNode node) { >+ if (nodes.remove(node)) { >+ ((SpaceTreeLayer) spaceTreeLayers.get(depth + 1)).removeNodes(node.children); >+ refreshThickness(); >+ } >+ } >+ >+ public void removeNodes(List nodesToRemove) { >+ if (this.nodes.removeAll(nodesToRemove)) { >+ SpaceTreeLayer nextLayer = ((SpaceTreeLayer) spaceTreeLayers.get(depth + 1)); >+ for (Iterator iterator = nodesToRemove.iterator(); iterator.hasNext();) { >+ SpaceTreeNode nodeToRemove = (SpaceTreeNode) iterator.next(); >+ nextLayer.removeNodes(nodeToRemove.children); >+ } >+ refreshThickness(); >+ } >+ } >+ >+ public void checkThickness(SpaceTreeNode node) { >+ double nodeThickness = 0; >+ DisplayIndependentDimension size = node.node.getSize(); >+ nodeThickness = (direction == TOP_DOWN || direction == BOTTOM_UP) ? size.height : size.width; >+ if (node.subgraph != null && node.subgraph.isGraphEntity()) { >+ size = node.subgraph.getSize(); >+ nodeThickness += (direction == TOP_DOWN || direction == BOTTOM_UP) ? size.height : size.width; >+ } >+ this.thickness = Math.max(this.thickness, nodeThickness); >+ } >+ >+ public void refreshThickness() { >+ this.thickness = 0; >+ for (Iterator iterator = nodes.iterator(); iterator.hasNext();) { >+ checkThickness((SpaceTreeNode) iterator.next()); >+ } >+ } >+ >+ public void fitNodesWithinBounds(List nodeList, double startPosition, double endPosition) { >+ NodeSnapshot[][] snapShot = takeSnapShot(); >+ SpaceTreeNode[] nodes = (SpaceTreeNode[]) nodeList.toArray(new SpaceTreeNode[nodeList.size()]); >+ double initialStartPosition = nodes[0].positionInLayer; >+ double initialNodesBredth = nodes[nodes.length - 1].positionInLayer - initialStartPosition; >+ double[] desiredPositions = new double[nodes.length]; >+ // calculate desired positions for every node, regarding their >+ // initial initial proportions >+ for (int i = 0; i < nodes.length; i++) { >+ double initialPositionAsPercent = (initialNodesBredth > 0) ? (nodes[i].positionInLayer - initialStartPosition) / initialNodesBredth >+ : 0; >+ desiredPositions[i] = initialPositionAsPercent * (endPosition - startPosition); >+ } >+ // make sure there's proper distance between each pair of >+ // consecutive nodes >+ for (int i = 1; i < nodes.length; i++) { >+ SpaceTreeNode node = nodes[i]; >+ SpaceTreeNode previousNode = nodes[i - 1]; >+ double expectedDistance = expectedDistance(previousNode, node); >+ if (desiredPositions[i] - desiredPositions[i - 1] < expectedDistance) { >+ desiredPositions[i] = desiredPositions[i - 1] + expectedDistance; >+ } >+ } >+ // if the above operation caused some nodes to fall out of requested >+ // bounds, push them back >+ if (desiredPositions[nodes.length - 1] > (endPosition - startPosition)) { >+ desiredPositions[nodes.length - 1] = (endPosition - startPosition); >+ for (int i = nodes.length - 1; i > 0; i--) { >+ SpaceTreeNode node = nodes[i]; >+ SpaceTreeNode previousNode = nodes[i - 1]; >+ double expectedDistance = expectedDistance(previousNode, node); >+ if (desiredPositions[i] - desiredPositions[i - 1] < expectedDistance) { >+ desiredPositions[i - 1] = desiredPositions[i] - expectedDistance; >+ } else >+ break; >+ } >+ } >+ >+ for (int i = 0; i < nodeList.size(); i++) { >+ SpaceTreeNode node = (SpaceTreeNode) nodeList.get(i); >+ double desiredPosition = startPosition + desiredPositions[i]; >+ moveNode(node, desiredPosition); >+ if (Math.abs(node.positionInLayer - desiredPosition) > 0.5) { >+ startPosition += (node.positionInLayer - desiredPosition); >+ i = -1; >+ revertToShanpshot(snapShot); >+ } >+ } >+ } >+ >+ public void moveNode(SpaceTreeNode node, double newPosition) { >+ Collections.sort(nodes, new Comparator() { >+ public int compare(Object arg0, Object arg1) { >+ return ((SpaceTreeNode) arg0).order - ((SpaceTreeNode) arg1).order; >+ } >+ }); >+ double positionInLayerAtStart = node.positionInLayer; >+ if (newPosition >= positionInLayerAtStart) >+ moveNodeForward(node, newPosition); >+ if (newPosition <= positionInLayerAtStart) >+ moveNodeBackward(node, newPosition); >+ } >+ >+ /** >+ * Tries to increase node's position in layer. It can move a node only >+ * if it doesn't cause nodes to fall out of available space (see >+ * {@link SpaceTreeLayoutAlgorithm#getAvailableSpace()}. If there's not >+ * enough space available, some nodes may be collapsed to increase it as >+ * long as it doesn't cause >+ * {@link SpaceTreeLayoutAlgorithm#protectedNode} or any of its >+ * descendants to be collapsed. >+ * >+ * @param nodeToMove >+ * @param newPosition >+ */ >+ private void moveNodeForward(SpaceTreeNode nodeToMove, double newPosition) { >+ int nodeIndex = nodes.indexOf(nodeToMove); >+ if (nodeIndex == -1) >+ throw new IllegalArgumentException("node not on this layer"); >+ // move forward -> check space to the 'right' >+ NodeSnapshot[][] snapShot = takeSnapShot(); >+ boolean firstRun = true; >+ mainLoop: while (firstRun || nodeToMove.positionInLayer < newPosition) { >+ firstRun = false; >+ double requiredSpace = 0; >+ SpaceTreeNode previousNode = nodeToMove; >+ for (int i = nodeIndex + 1; i < nodes.size(); i++) { >+ SpaceTreeNode nextNode = (SpaceTreeNode) nodes.get(i); >+ requiredSpace += expectedDistance(previousNode, nextNode); >+ previousNode = nextNode; >+ } >+ requiredSpace += previousNode.spaceRequiredForNode() / 2; >+ if (requiredSpace > getAvailableSpace() - newPosition) { >+ // find nodes to remove >+ boolean removed = false; >+ for (int i = nodeIndex; i < nodes.size(); i++) { >+ SpaceTreeNode nextNode = ((SpaceTreeNode) nodes.get(i)); >+ if (protectedNode == null || (!protectedNode.isAncestorOf(nextNode) && !nextNode.parent.isAncestorOf(protectedNode))) { >+ collapseNode((SpaceTreeNode) nextNode.parent); >+ if (nextNode.parent == nodeToMove.parent) >+ break mainLoop; >+ removed = true; >+ break; >+ } >+ } >+ if (!removed) { >+ // not enough space, but we can't collapse anything... >+ newPosition = getAvailableSpace() - requiredSpace; >+ revertToShanpshot(snapShot); >+ continue mainLoop; >+ } >+ } >+ // move the node and all its neighbors to the 'right' >+ SpaceTreeNode currentNodeToMove = nodeToMove; >+ double newPositionForCurrent = newPosition; >+ for (int i = nodeIndex; i < nodes.size(); i++) { >+ currentNodeToMove.positionInLayer = newPositionForCurrent; >+ // move parent if moved node is its first child >+ if (currentNodeToMove.firstChild) { >+ SpaceTreeNode parent = (SpaceTreeNode) currentNodeToMove.parent; >+ if (depth > 0 && parent.positionInLayer <= newPositionForCurrent) { >+ SpaceTreeLayer parentLayer = (SpaceTreeLayer) spaceTreeLayers.get(depth - 1); >+ parentLayer.moveNodeForward(parent, newPositionForCurrent); >+ if (parent.positionInLayer < newPositionForCurrent) { >+ double delta = newPositionForCurrent - parent.positionInLayer; >+ newPosition -= delta; >+ revertToShanpshot(snapShot); >+ continue mainLoop; >+ } >+ } >+ } >+ // move children if necessary >+ if (currentNodeToMove.expanded && !currentNodeToMove.children.isEmpty()) { >+ SpaceTreeNode lastChild = (SpaceTreeNode) currentNodeToMove.children.get(currentNodeToMove.children.size() - 1); >+ if (lastChild.positionInLayer < newPositionForCurrent) { >+ // try to move all the children, that is move the >+ // first child and the rest will be pushed >+ SpaceTreeNode firstChild = (SpaceTreeNode) currentNodeToMove.children.get(0); >+ SpaceTreeLayer childLayer = (SpaceTreeLayer) spaceTreeLayers.get(depth + 1); >+ double expectedDistanceBetweenChildren = currentNodeToMove.spaceRequiredForChildren() - firstChild.spaceRequiredForNode() >+ / 2 - lastChild.spaceRequiredForNode() / 2; >+ childLayer.moveNodeForward(firstChild, newPositionForCurrent - expectedDistanceBetweenChildren); >+ if (currentNodeToMove.expanded && lastChild.positionInLayer < newPositionForCurrent) { >+ // the previous attempt failed -> try to move >+ // only the last child >+ childLayer.moveNodeForward(lastChild, newPositionForCurrent); >+ if (lastChild.positionInLayer < newPositionForCurrent) { >+ // child couldn't be moved as far as needed >+ // -> move current node back to the position >+ // over the child >+ double delta = newPositionForCurrent - lastChild.positionInLayer; >+ newPosition -= delta; >+ revertToShanpshot(snapShot); >+ continue mainLoop; >+ } >+ } >+ } >+ } >+ >+ if (i < nodes.size() - 1) { >+ SpaceTreeNode nextNode = (SpaceTreeNode) nodes.get(i + 1); >+ newPositionForCurrent += expectedDistance(currentNodeToMove, nextNode); >+ currentNodeToMove = nextNode; >+ if (currentNodeToMove.positionInLayer > newPositionForCurrent) >+ break; >+ } >+ } >+ } >+ } >+ >+ /** >+ * Method complementary to >+ * {@link #moveNodeForward(SpaceTreeNode, double)}. Decreases node's >+ * position in layer. >+ * >+ * @param nodeToMove >+ * @param newPosition >+ */ >+ private void moveNodeBackward(SpaceTreeNode nodeToMove, double newPosition) { >+ int nodeIndex = nodes.indexOf(nodeToMove); >+ if (nodeIndex == -1) >+ throw new IllegalArgumentException("node not on this layer"); >+ // move backward -> check space to the 'left' >+ // move and collapse until there's enough space >+ NodeSnapshot[][] snapShot = takeSnapShot(); >+ boolean firstRun = true; >+ mainLoop: while (firstRun || nodeToMove.positionInLayer > newPosition) { >+ firstRun = false; >+ double requiredSpace = 0; >+ SpaceTreeNode previousNode = nodeToMove; >+ for (int i = nodeIndex - 1; i >= 0; i--) { >+ SpaceTreeNode nextNode = (SpaceTreeNode) nodes.get(i); >+ requiredSpace += expectedDistance(previousNode, nextNode); >+ previousNode = nextNode; >+ } >+ requiredSpace += previousNode.spaceRequiredForNode() / 2; >+ if (requiredSpace > newPosition) { >+ // find nodes to remove >+ boolean removed = false; >+ for (int i = nodeIndex; i >= 0; i--) { >+ SpaceTreeNode nextNode = ((SpaceTreeNode) nodes.get(i)); >+ if (protectedNode == null || (!protectedNode.isAncestorOf(nextNode) && !nextNode.parent.isAncestorOf(protectedNode))) { >+ collapseNode((SpaceTreeNode) nextNode.parent); >+ if (nextNode.parent == nodeToMove.parent) >+ break mainLoop; >+ nodeIndex -= nextNode.parent.children.size(); >+ removed = true; >+ break; >+ } >+ } >+ if (!removed) { >+ // not enough space, but we can't collapse anything... >+ newPosition = requiredSpace; >+ revertToShanpshot(snapShot); >+ continue mainLoop; >+ } >+ } >+ // move the node and all its neighbors to the 'left' >+ SpaceTreeNode currentNodeToMove = nodeToMove; >+ double newPositionForCurrent = newPosition; >+ for (int i = nodeIndex; i >= 0; i--) { >+ currentNodeToMove.positionInLayer = newPositionForCurrent; >+ // move parent if moved node is its last child >+ if (currentNodeToMove.lastChild) { >+ SpaceTreeNode parent = (SpaceTreeNode) currentNodeToMove.parent; >+ if (depth > 0 && parent.positionInLayer >= newPositionForCurrent) { >+ SpaceTreeLayer parentLayer = (SpaceTreeLayer) spaceTreeLayers.get(depth - 1); >+ parentLayer.moveNodeBackward(parent, newPositionForCurrent); >+ if (parent.positionInLayer > newPositionForCurrent) { >+ double delta = parent.positionInLayer - newPositionForCurrent; >+ newPosition += delta; >+ revertToShanpshot(snapShot); >+ continue mainLoop; >+ } >+ } >+ } >+ // move children if necessary >+ if (currentNodeToMove.expanded && !currentNodeToMove.children.isEmpty()) { >+ SpaceTreeNode firstChild = (SpaceTreeNode) currentNodeToMove.children.get(0); >+ if (firstChild.positionInLayer > newPositionForCurrent) { >+ // try to move all the children, that is move the >+ // last child and the rest will be pushed >+ SpaceTreeNode lastChild = (SpaceTreeNode) currentNodeToMove.children.get(currentNodeToMove.children.size() - 1); >+ SpaceTreeLayer childLayer = (SpaceTreeLayer) spaceTreeLayers.get(depth + 1); >+ double expectedDistanceBetweenChildren = currentNodeToMove.spaceRequiredForChildren() - firstChild.spaceRequiredForNode() >+ / 2 - lastChild.spaceRequiredForNode() / 2; >+ childLayer.moveNodeBackward(lastChild, newPositionForCurrent + expectedDistanceBetweenChildren); >+ if (currentNodeToMove.expanded && firstChild.positionInLayer > newPositionForCurrent) { >+ // the previous attempt failed -> try to move >+ // only the first child >+ childLayer.moveNodeBackward(firstChild, newPositionForCurrent); >+ if (firstChild.positionInLayer > newPositionForCurrent) { >+ // child couldn't be moved as far as needed >+ // -> move current node back to the position >+ // over the child >+ double delta = firstChild.positionInLayer - newPositionForCurrent; >+ newPosition += delta; >+ revertToShanpshot(snapShot); >+ continue mainLoop; >+ } >+ } >+ } >+ } >+ if (i > 0) { >+ SpaceTreeNode nextNode = (SpaceTreeNode) nodes.get(i - 1); >+ newPositionForCurrent -= expectedDistance(currentNodeToMove, nextNode); >+ currentNodeToMove = nextNode; >+ if (currentNodeToMove.positionInLayer < newPositionForCurrent) >+ break; >+ } >+ } >+ } >+ } >+ >+ public String toString() { >+ StringBuffer buffer = new StringBuffer(); >+ buffer.append("Layer ").append(depth).append(": "); >+ for (Iterator iterator = nodes.iterator(); iterator.hasNext();) { >+ SpaceTreeNode node = (SpaceTreeNode) iterator.next(); >+ buffer.append(node.node).append(", "); >+ } >+ return buffer.toString(); >+ } >+ >+ private void collapseNode(SpaceTreeNode node) { >+ node.expanded = false; >+ SpaceTreeLayer layer = (SpaceTreeLayer) spaceTreeLayers.get(node.depth + 1); >+ layer.removeNodes(node.children); >+ for (Iterator iterator = node.children.iterator(); iterator.hasNext();) { >+ SpaceTreeNode child = (SpaceTreeNode) iterator.next(); >+ if (child.expanded) >+ collapseNode(child); >+ } >+ } >+ } >+ >+ private class SpaceTreeExpandCollapseManager implements ExpandCollapseManager { >+ public void initExpansion(LayoutContext context) { >+ // do nothing - initialization performed in #setLayoutContext() >+ } >+ >+ public void setExpanded(LayoutContext context, NodeLayout node, boolean expanded) { >+ SpaceTreeNode spaceTreeNode = (SpaceTreeNode) treeObserver.getTreeNode(node); >+ if (expanded) { >+ maximizeExpansion(spaceTreeNode); >+ refreshLayout(true); >+ } else if (spaceTreeNode.expanded) { >+ spaceTreeNode.expanded = false; >+ ((SpaceTreeLayer) spaceTreeLayers.get(spaceTreeNode.depth + 1)).removeNodes(spaceTreeNode.children); >+ refreshLayout(true); >+ } >+ } >+ >+ public boolean canExpand(LayoutContext context, NodeLayout node) { >+ SpaceTreeNode spaceTreeNode = (SpaceTreeNode) treeObserver.getTreeNode(node); >+ if (spaceTreeNode != null) { >+ // we don't check if node is expanded because it can be expanded >+ // again >+ return !spaceTreeNode.children.isEmpty(); >+ } >+ return false; >+ } >+ >+ public boolean canCollapse(LayoutContext context, NodeLayout node) { >+ SpaceTreeNode spaceTreeNode = (SpaceTreeNode) treeObserver.getTreeNode(node); >+ if (spaceTreeNode != null) { >+ return spaceTreeNode.expanded && !spaceTreeNode.children.isEmpty(); >+ } >+ return false; >+ } >+ >+ public void maximizeExpansion(SpaceTreeNode nodeToExpand) { >+ protectedNode = nodeToExpand; >+ double availableSpace = getAvailableSpace(); >+ double requiredSpace = 0; >+ >+ ((SpaceTreeLayer) spaceTreeLayers.get(nodeToExpand.depth + 1)).removeNodes(nodeToExpand.children); >+ >+ ArrayList nodesInThisLayer = null; >+ ArrayList nodesInNextLayer = new ArrayList(); >+ nodesInNextLayer.add(nodeToExpand); >+ double spaceRequiredInNextLayer = nodeToExpand.spaceRequiredForNode(); >+ for (int layer = 0; !nodesInNextLayer.isEmpty(); layer++) { >+ NodeSnapshot[][] snapShot = takeSnapShot(); >+ requiredSpace = Math.max(requiredSpace, spaceRequiredInNextLayer); >+ spaceRequiredInNextLayer = 0; >+ >+ nodesInThisLayer = nodesInNextLayer; >+ nodesInNextLayer = new ArrayList(); >+ >+ int numOfNodesWithChildren = 0; >+ for (Iterator iterator = nodesInThisLayer.iterator(); iterator.hasNext();) { >+ SpaceTreeNode node = (SpaceTreeNode) iterator.next(); >+ if (!node.children.isEmpty()) { >+ node.expanded = true; >+ spaceRequiredInNextLayer += node.spaceRequiredForChildren(); >+ nodesInNextLayer.addAll(node.children); >+ numOfNodesWithChildren++; >+ } >+ } >+ >+ for (Iterator iterator = nodesInNextLayer.iterator(); iterator.hasNext();) { >+ SpaceTreeNode node = (SpaceTreeNode) iterator.next(); >+ node.expanded = false; >+ } >+ >+ if (numOfNodesWithChildren == 0) >+ break; >+ >+ spaceRequiredInNextLayer += branchGap * (numOfNodesWithChildren - 1); >+ >+ boolean addedNewLayer = false; >+ if ((spaceRequiredInNextLayer <= requiredSpace || spaceRequiredInNextLayer <= availableSpace || (layer < 1 && nodeToExpand.depth >+ + layer < 1)) >+ && !nodesInNextLayer.isEmpty()) { >+ // add next layer and center its nodes >+ >+ SpaceTreeLayer childLayer = (SpaceTreeLayer) spaceTreeLayers.get(nodeToExpand.depth + layer + 1); >+ childLayer.addNodes(nodesInNextLayer); >+ SpaceTreeNode firstChild = ((SpaceTreeNode) nodesInNextLayer.get(0)); >+ SpaceTreeNode lastChild = ((SpaceTreeNode) nodesInNextLayer.get(nodesInNextLayer.size() - 1)); >+ double boundsWidth = spaceRequiredInNextLayer - firstChild.spaceRequiredForNode() / 2 - lastChild.spaceRequiredForNode() / 2; >+ double startPosition = Math.max((availableSpace - boundsWidth) / 2, firstChild.spaceRequiredForNode() / 2); >+ setAvailableSpace(spaceRequiredInNextLayer); >+ childLayer.fitNodesWithinBounds(nodesInNextLayer, startPosition, startPosition + boundsWidth); >+ setAvailableSpace(0); >+ if (nodeToExpand.childrenPositionsOK(nodesInThisLayer) || layer == 0 || nodeToExpand.depth + layer < 1) >+ addedNewLayer = true; >+ } >+ if (!addedNewLayer) { >+ revertToShanpshot(snapShot); >+ break; >+ } >+ } >+ nodeToExpand.centerParentsBottomUp(); >+ nodeToExpand.centerParentsTopDown(); >+ } >+ }; >+ >+ private SpaceTreeExpandCollapseManager expandCollapseManager = new SpaceTreeExpandCollapseManager(); >+ >+ private ContextListener contextListener = new ContextListener.Stub() { >+ public boolean boundsChanged(LayoutContext context) { >+ boolean previousBoundsWrong = (bounds == null || bounds.width <= 0 || bounds.height <= 0); >+ bounds = context.getBounds(); >+ if (bounds.width > 0 && bounds.height > 0 && previousBoundsWrong) { >+ expandCollapseManager.maximizeExpansion((SpaceTreeNode) treeObserver.getSuperRoot()); >+ refreshLayout(false); >+ } >+ return false; >+ } >+ }; >+ >+ private LayoutListener layoutListener = new LayoutListener() { >+ >+ public boolean entityMoved(LayoutContext context, EntityLayout entity) { >+ if (entity instanceof NodeLayout) { >+ defaultNodeHandle(context, (NodeLayout) entity); >+ } >+ if (entity instanceof SubgraphLayout) { >+ defaultSubgraphHandle(context, (SubgraphLayout) entity); >+ } >+ return false; >+ } >+ >+ public boolean entityResized(LayoutContext context, EntityLayout entity) { >+ if (entity instanceof NodeLayout) { >+ setAvailableSpace(getAvailableSpace() + ((SpaceTreeNode) treeObserver.getTreeNode((NodeLayout) entity)).spaceRequiredForNode()); >+ defaultNodeHandle(context, (NodeLayout) entity); >+ setAvailableSpace(0); >+ } >+ if (entity instanceof SubgraphLayout) { >+ defaultSubgraphHandle(context, (SubgraphLayout) entity); >+ } >+ return false; >+ } >+ >+ /** >+ * Finds a root of given subgraph, updates the root position and moves >+ * the subgraph to proper position >+ * >+ * @param context >+ * @param subgraph >+ */ >+ private void defaultSubgraphHandle(LayoutContext context, SubgraphLayout subgraph) { >+ SpaceTreeNode node = (SpaceTreeNode) treeObserver.getTreeNode(subgraph.getNodes()[0]); >+ while (node != null && node.node != null && node.node.getSubgraph() == subgraph) { >+ node = (SpaceTreeNode) node.parent; >+ } >+ if (node != null && node.subgraph == subgraph) { >+ node.adjustPosition(subgraph.getLocation()); >+ if (context.isBackgroundLayoutEnabled()) { >+ ((SpaceTreeNode) treeObserver.getSuperRoot()).flushLocationChanges(0); >+ node.refreshSubgraphLocation(); >+ context.flushChanges(false); >+ } >+ } >+ } >+ >+ private void defaultNodeHandle(LayoutContext context, NodeLayout node) { >+ if (bounds.width <= 0 || bounds.height <= 0) >+ return; >+ SpaceTreeNode spaceTreeNode = (SpaceTreeNode) treeObserver.getTreeNode(node); >+ spaceTreeNode.adjustPosition(node.getLocation()); >+ if (context.isBackgroundLayoutEnabled()) { >+ ((SpaceTreeNode) treeObserver.getSuperRoot()).flushLocationChanges(0); >+ spaceTreeNode.refreshSubgraphLocation(); >+ context.flushChanges(false); >+ } >+ } >+ }; >+ >+ private int direction = TOP_DOWN; >+ >+ private double leafGap = 15; >+ private double branchGap = leafGap + 5; >+ private double layerGap = 20; >+ >+ private boolean directionChanged = false; >+ >+ private LayoutContext context; >+ >+ private DisplayIndependentRectangle bounds; >+ >+ private TreeLayoutObserver treeObserver; >+ >+ private double availableSpace; >+ >+ private ArrayList spaceTreeLayers = new ArrayList(); >+ >+ /** >+ * If not null, this node and all of its children shall not be collapsed >+ * during node movements. >+ */ >+ private SpaceTreeNode protectedNode = null; >+ >+ /** >+ * Constructs an instance of <code>SpaceTreeLayoutAlgorithm</code> that >+ * places the root of a tree at the top of the graph. >+ */ >+ public SpaceTreeLayoutAlgorithm() { >+ } >+ >+ /** >+ * Constructs an instance of <code>SpaceTreeLayoutAlgorithm</code> that >+ * places the root of a tree according to given direction >+ * >+ * @param direction >+ * direction of the tree, sould be one of the following: >+ * {@link #TOP_DOWN}, {@link #BOTTOM_UP}, {@link #LEFT_RIGHT}, >+ * {@link #RIGHT_LEFT}. >+ */ >+ public SpaceTreeLayoutAlgorithm(int direction) { >+ setDirection(direction); >+ } >+ >+ /** >+ * >+ * @return current direction (placement) of the tree >+ */ >+ public int getDirection() { >+ return direction; >+ } >+ >+ /** >+ * Sets direction (placement) of the tree >+ * >+ * @param direction >+ * direction of the tree, sould be one of the following: >+ * {@link #TOP_DOWN}, {@link #BOTTOM_UP}, {@link #LEFT_RIGHT}, >+ * {@link #RIGHT_LEFT}. >+ */ >+ public void setDirection(int direction) { >+ if (direction == this.direction) >+ return; >+ if (direction == TOP_DOWN || direction == BOTTOM_UP || direction == LEFT_RIGHT || direction == RIGHT_LEFT) { >+ this.direction = direction; >+ directionChanged = true; >+ if (context.isBackgroundLayoutEnabled()) >+ checkPendingChangeDirection(); >+ } else >+ throw new IllegalArgumentException("Invalid direction: " + direction); >+ } >+ >+ public void applyLayout(boolean clean) { >+ bounds = context.getBounds(); >+ >+ if (bounds.width <= 0 || bounds.height <= 0) >+ return; >+ >+ if (clean) { >+ treeObserver.recomputeTree(); >+ expandCollapseManager.maximizeExpansion((SpaceTreeNode) treeObserver.getSuperRoot()); >+ } >+ SpaceTreeNode superRoot = ((SpaceTreeNode) treeObserver.getSuperRoot()); >+ superRoot.flushExpansionChanges(); >+ superRoot.flushLocationChanges(0); >+ checkPendingChangeDirection(); >+ } >+ >+ public void setLayoutContext(LayoutContext context) { >+ if (this.context != null) { >+ this.context.removeContextListener(contextListener); >+ this.context.removeLayoutListener(layoutListener); >+ treeObserver.stop(); >+ } >+ this.context = context; >+ context.addContextListener(contextListener); >+ context.addLayoutListener(layoutListener); >+ treeObserver = new TreeLayoutObserver(context, spaceTreeNodeFactory); >+ >+ bounds = context.getBounds(); >+ } >+ >+ /** >+ * >+ * @return <code>ExpandCollapseManager</code> that can (and should) be used >+ * on layout context managed by this layout algorithm. >+ */ >+ public ExpandCollapseManager getExpandCollapseManager() { >+ return expandCollapseManager; >+ } >+ >+ private void checkPendingChangeDirection() { >+ if (directionChanged) { >+ SubgraphLayout[] subgraphs = context.getSubgraphs(); >+ int subgraphDirection = getSubgraphDirection(); >+ for (int i = 0; i < subgraphs.length; i++) { >+ subgraphs[i].setDirection(subgraphDirection); >+ } >+ directionChanged = false; >+ } >+ } >+ >+ private int getSubgraphDirection() { >+ switch (direction) { >+ case TOP_DOWN: >+ return SubgraphLayout.TOP_DOWN; >+ case BOTTOM_UP: >+ return SubgraphLayout.BOTTOM_UP; >+ case LEFT_RIGHT: >+ return SubgraphLayout.LEFT_RIGHT; >+ case RIGHT_LEFT: >+ return SubgraphLayout.RIGHT_LEFT; >+ } >+ throw new RuntimeException(); >+ } >+ >+ protected void refreshLayout(boolean animation) { >+ if (!context.isBackgroundLayoutEnabled()) >+ return; >+ SpaceTreeNode superRoot = (SpaceTreeNode) treeObserver.getSuperRoot(); >+ if (animation && superRoot.flushCollapseChanges()) >+ context.flushChanges(true); >+ if (superRoot.flushLocationChanges(0) && animation) >+ context.flushChanges(true); >+ superRoot.flushExpansionChanges(); >+ superRoot.flushLocationChanges(0); >+ context.flushChanges(animation); >+ } >+ >+ /** >+ * Available space is the biggest of the following values: >+ * <ul> >+ * <li>Space provided by current context bounds</li> >+ * <li>Space already taken by the widest layer</li> >+ * <li>Value set with {@link #setAvailableSpace(double)}</li> >+ * </ul> >+ * >+ * @return >+ */ >+ private double getAvailableSpace() { >+ double result = (direction == TOP_DOWN || direction == BOTTOM_UP) ? bounds.width : bounds.height; >+ result = Math.max(result, this.availableSpace); >+ for (Iterator iterator = spaceTreeLayers.iterator(); iterator.hasNext();) { >+ SpaceTreeLayer layer = (SpaceTreeLayer) iterator.next(); >+ if (!layer.nodes.isEmpty()) { >+ SpaceTreeNode first = (SpaceTreeNode) layer.nodes.get(0); >+ SpaceTreeNode last = (SpaceTreeNode) layer.nodes.get(layer.nodes.size() - 1); >+ result = Math.max(result, last.positionInLayer - first.positionInLayer + (first.spaceRequiredForNode() + last.spaceRequiredForNode()) >+ / 2); >+ } else >+ break; >+ } >+ return result; >+ } >+ >+ /** >+ * This method allows to reserve more space than actual layout bounds >+ * provide or nodes currently occupy. >+ * >+ * @param availableSpace >+ */ >+ private void setAvailableSpace(double availableSpace) { >+ this.availableSpace = availableSpace; >+ } >+ >+ private double expectedDistance(SpaceTreeNode node, SpaceTreeNode neighbor) { >+ double expectedDistance = (node.spaceRequiredForNode() + neighbor.spaceRequiredForNode()) / 2; >+ expectedDistance += (node.parent == neighbor.parent) ? leafGap : branchGap; >+ return expectedDistance; >+ } >+ >+ private class NodeSnapshot { >+ SpaceTreeNode node; >+ double position; >+ boolean expanded; >+ } >+ >+ /** >+ * Stores current expansion state of tree nodes and their position in layers >+ * >+ * @return array containing state of all unpruned nodes >+ */ >+ private NodeSnapshot[][] takeSnapShot() { >+ NodeSnapshot[][] result = new NodeSnapshot[spaceTreeLayers.size()][]; >+ for (int i = 0; i < result.length; i++) { >+ SpaceTreeLayer layer = (SpaceTreeLayer) spaceTreeLayers.get(i); >+ result[i] = new NodeSnapshot[layer.nodes.size()]; >+ for (int j = 0; j < result[i].length; j++) { >+ result[i][j] = new NodeSnapshot(); >+ result[i][j].node = ((SpaceTreeNode) layer.nodes.get(j)); >+ result[i][j].position = result[i][j].node.positionInLayer; >+ result[i][j].expanded = result[i][j].node.expanded; >+ } >+ } >+ return result; >+ } >+ >+ /** >+ * Restores tree nodes' expansion state and position in layers >+ * >+ * @param snapShot >+ * state obtained with {@link #takeSnapShot()} >+ */ >+ private void revertToShanpshot(NodeSnapshot[][] snapShot) { >+ for (int i = 0; i < snapShot.length; i++) { >+ SpaceTreeLayer layer = (SpaceTreeLayer) spaceTreeLayers.get(i); >+ layer.nodes.clear(); >+ for (int j = 0; j < snapShot[i].length; j++) { >+ snapShot[i][j].node.positionInLayer = snapShot[i][j].position; >+ snapShot[i][j].node.expanded = snapShot[i][j].expanded; >+ layer.nodes.add(snapShot[i][j].node); >+ } >+ } >+ } >+} >#P org.eclipse.zest.tests >Index: src/org/eclipse/zest/tests/swt/PaintSnippet.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/test/org.eclipse.zest.tests/src/org/eclipse/zest/tests/swt/PaintSnippet.java,v >retrieving revision 1.2 >diff -u -r1.2 PaintSnippet.java >--- src/org/eclipse/zest/tests/swt/PaintSnippet.java 12 Sep 2007 20:44:36 -0000 1.2 >+++ src/org/eclipse/zest/tests/swt/PaintSnippet.java 28 Aug 2009 16:03:12 -0000 >@@ -1,11 +1,13 @@ > /******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, > * Canada. All rights reserved. This program and the accompanying materials are > * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html > * >- * Contributors: The Chisel Group, University of Victoria >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 > ******************************************************************************/ > package org.eclipse.zest.tests.swt; > >@@ -13,7 +15,6 @@ > import org.eclipse.zest.core.widgets.Graph; > import org.eclipse.zest.core.widgets.GraphConnection; > import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.layouts.LayoutStyles; > import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; > import org.eclipse.swt.SWT; > import org.eclipse.swt.events.PaintEvent; >@@ -66,7 +67,7 @@ > new GraphConnection(g, SWT.NONE, n, n2); > new GraphConnection(g, SWT.NONE, n2, n3); > new GraphConnection(g, SWT.NONE, n3, n); >- g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >+ g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true); > > b.addSelectionListener(new SelectionListener() { > >Index: src/org/eclipse/zest/tests/swt/GraphSnippet7.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet7.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet7.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet7.java 12 May 2008 18:14:29 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,71 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.events.MouseEvent; >-import org.eclipse.swt.events.MouseMoveListener; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >- >-/** >- * This snippet shows how to use the findFigureAt to get the figure under the mouse >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet7 { >- >- /** >- * @param args >- */ >- public static void main(String[] args) { >- Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("GraphSnippet7"); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- final Graph g = new Graph(shell, SWT.NONE); >- >- GraphNode n = new GraphNode(g, SWT.NONE, "Paper"); >- GraphNode n2 = new GraphNode(g, SWT.NONE, "Rock"); >- GraphNode n3 = new GraphNode(g, SWT.NONE, "Scissors"); >- new GraphConnection(g, SWT.NONE, n, n2); >- new GraphConnection(g, SWT.NONE, n2, n3); >- new GraphConnection(g, SWT.NONE, n3, n); >- g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- >- g.addMouseMoveListener(new MouseMoveListener() { >- >- public void mouseMove(MouseEvent e) { >- // Get the figure at the current mouse location >- Object o = g.getFigureAt(e.x, e.y); >- if ( o != null ) { >- System.out.println(o + " is at: (" + e.x + "," + e.y + ")"); >- } >- } >- >- }); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- } >-} >Index: src/org/eclipse/zest/tests/swt/GraphSnippet12.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet12.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet12.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet12.java 31 Mar 2009 16:43:00 -0000 1.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,164 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import java.util.Iterator; >- >-import org.eclipse.draw2d.ColorConstants; >-import org.eclipse.draw2d.Ellipse; >-import org.eclipse.draw2d.Figure; >-import org.eclipse.draw2d.FreeformLayout; >-import org.eclipse.draw2d.IFigure; >-import org.eclipse.draw2d.ImageFigure; >-import org.eclipse.draw2d.PolylineShape; >-import org.eclipse.draw2d.geometry.Point; >-import org.eclipse.draw2d.geometry.Rectangle; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.events.SelectionEvent; >-import org.eclipse.swt.events.SelectionListener; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >-import org.eclipse.zest.core.widgets.CGraphNode; >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >- >-/** >- * >- * This snippet shows how to create a curved connection using Zest. >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet12 { >- >- public static IFigure createPersonFigure(Image headImage) { >- Figure person = new Figure(); >- person.setLayoutManager(new FreeformLayout()); >- IFigure head = null; >- if ( headImage != null ) { >- headImage = new Image(headImage.getDevice(), headImage.getImageData().scaledTo(40, 50)); >- head = new ImageFigure(headImage); >- } >- else >- head = new Ellipse(); >- head.setSize(40, 50); >- >- PolylineShape body = new PolylineShape(); >- body.setLineWidth(1); >- body.setStart(new Point(20,40)); >- body.setEnd(new Point(20,100)); >- body.setBounds(new Rectangle(0,0,40,100)); >- >- PolylineShape leftLeg = new PolylineShape(); >- leftLeg.setLineWidth(1); >- leftLeg.setStart(new Point(20,100)); >- leftLeg.setEnd(new Point(0,130)); >- leftLeg.setBounds(new Rectangle(0,0,40,130)); >- >- PolylineShape rightLeg = new PolylineShape(); >- rightLeg.setLineWidth(1); >- rightLeg.setStart(new Point(20,100)); >- rightLeg.setEnd(new Point(40,130)); >- rightLeg.setBounds(new Rectangle(0,0,40,130)); >- >- PolylineShape leftArm = new PolylineShape(); >- leftArm.setLineWidth(1); >- leftArm.setStart(new Point(20,60)); >- leftArm.setEnd(new Point(0,50)); >- leftArm.setBounds(new Rectangle(0,0,40,130)); >- >- PolylineShape rightArm = new PolylineShape(); >- rightArm.setLineWidth(1); >- rightArm.setStart(new Point(20,60)); >- rightArm.setEnd(new Point(40,50)); >- rightArm.setBounds(new Rectangle(0,0,40,130)); >- >- person.add(head); >- person.add(body); >- person.add(leftLeg); >- person.add(rightLeg); >- person.add(leftArm); >- person.add(rightArm); >- person.setSize(40,130); >- return person; >- } >- >- public static void main(String[] args) { >- final Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("GraphSnippet11"); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- >- final Graph g = new Graph(shell, SWT.NONE); >- g.addSelectionListener(new SelectionListener(){ >- >- public void widgetSelected(SelectionEvent e) { >- Iterator iter = g.getSelection().iterator(); >- while(iter.hasNext()) { >- Object o = iter.next(); >- if ( o instanceof CGraphNode) { >- IFigure figure = ((CGraphNode)o).getFigure(); >- figure.setBackgroundColor(ColorConstants.blue); >- figure.setForegroundColor(ColorConstants.blue); >- } >- } >- iter = g.getNodes().iterator(); >- while ( iter.hasNext()) { >- Object o = iter.next(); >- if ( o instanceof CGraphNode) { >- if ( !g.getSelection().contains(o)) { >- ((CGraphNode)o).getFigure().setBackgroundColor(ColorConstants.black); >- ((CGraphNode)o).getFigure().setForegroundColor(ColorConstants.black); >- } >- } >- } >- } >- >- public void widgetDefaultSelected(SelectionEvent e) { >- // TODO Auto-generated method stub >- >- } >- }); >- >- Image zx = new Image(d, "zx.png"); >- Image ibull = new Image(d, "ibull.jpg"); >- CGraphNode n = new CGraphNode(g, SWT.NONE, createPersonFigure(zx)); >- CGraphNode n2 = new CGraphNode(g, SWT.NONE, createPersonFigure(ibull)); >- GraphNode n3 = new GraphNode(g, SWT.NONE, "PDE"); >- GraphNode n4 = new GraphNode(g, SWT.NONE, "Zest"); >- GraphNode n5 = new GraphNode(g, SWT.NONE, "PDE Viz tool"); >- >- new GraphConnection(g, SWT.NONE, n, n2); >- new GraphConnection(g, SWT.NONE, n, n3); >- new GraphConnection(g, SWT.NONE, n2, n4); >- new GraphConnection(g, SWT.NONE, n, n5); >- new GraphConnection(g, SWT.NONE, n2, n5); >- new GraphConnection(g, SWT.NONE, n3, n5); >- new GraphConnection(g, SWT.NONE, n4, n5); >- g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- zx.dispose(); >- ibull.dispose(); >- } >- >-} >Index: src/org/eclipse/zest/tests/swt/GraphSnippet10.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet10.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet10.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet10.java 20 Nov 2008 23:51:04 -0000 1.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,78 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.events.SelectionAdapter; >-import org.eclipse.swt.events.SelectionEvent; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Button; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >- >-/** >- * >- * This snippet shows how to create a curved connection using Zest. >- * Each time the Button is clicked, the curve changes. >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet10 { >- >- public static void main(String[] args) { >- Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("GraphSnippet1"); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- final Graph g = new Graph(shell, SWT.NONE); >- >- GraphNode n = new GraphNode(g, SWT.NONE, "Paper"); >- n.setBorderColor(org.eclipse.draw2d.ColorConstants.yellow); >- n.setBorderWidth(3); >- GraphNode n2 = new GraphNode(g, SWT.NONE, "Rock"); >- GraphNode n3 = new GraphNode(g, SWT.NONE, "Scissors"); >- final GraphConnection connection = new GraphConnection(g, SWT.NONE, n, n2); >- connection.setLineWidth(3); >- new GraphConnection(g, SWT.NONE, n2, n3); >- new GraphConnection(g, SWT.NONE, n3, n); >- g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- >- Button button = new Button(shell, SWT.PUSH); >- button.setText("Change Curve"); >- button.addSelectionListener(new SelectionAdapter() { >- int count = 0; >- public void widgetSelected(SelectionEvent e) { >- count = ++count % 16; >- if ( count > 8 ) { >- connection.setCurveDepth((-16 + count) * 10); >- } >- else { >- connection.setCurveDepth(count * 10); >- } >- } >- }); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- } >- >-} >Index: src/org/eclipse/zest/tests/swt/GraphSnippet8.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet8.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet8.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet8.java 12 May 2008 18:22:24 -0000 1.2 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,120 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import org.eclipse.draw2d.ColorConstants; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.core.widgets.ZestStyles; >-import org.eclipse.zest.layouts.Filter; >-import org.eclipse.zest.layouts.LayoutItem; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; >- >-/** >- * This snippet shows how to filter elements in the layout. The Data on the tree >- * connections are set to "False", meaning they won't be filtered. >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet8 { >- >- /** >- * @param args >- */ >- public static void main(String[] args) { >- Display display = new Display(); >- Shell shell = new Shell(display); >- shell.setText("GraphSnippet8"); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- final Graph graph = new Graph(shell, SWT.NONE); >- >- GraphNode a = new GraphNode(graph, SWT.NONE, "Root"); >- GraphNode b = new GraphNode(graph, SWT.NONE, "B"); >- GraphNode c = new GraphNode(graph, SWT.NONE, "C"); >- GraphNode d = new GraphNode(graph, SWT.NONE, "D"); >- GraphNode e = new GraphNode(graph, SWT.NONE, "E"); >- GraphNode f = new GraphNode(graph, SWT.NONE, "F"); >- GraphNode g = new GraphNode(graph, SWT.NONE, "G"); >- GraphNode h = new GraphNode(graph, SWT.NONE, "H"); >- GraphConnection connection = new GraphConnection(graph, SWT.NONE, a, b); >- connection.setData(Boolean.FALSE); >- connection = new GraphConnection(graph, SWT.NONE, a, c); >- connection.setData(Boolean.FALSE); >- connection = new GraphConnection(graph, SWT.NONE, a, c); >- connection.setData(Boolean.FALSE); >- connection = new GraphConnection(graph, SWT.NONE, a, d); >- connection.setData(Boolean.FALSE); >- connection = new GraphConnection(graph, SWT.NONE, b, e); >- connection.setData(Boolean.FALSE); >- connection = new GraphConnection(graph, SWT.NONE, b, f); >- connection.setData(Boolean.FALSE); >- connection = new GraphConnection(graph, SWT.NONE, c, g); >- connection.setData(Boolean.FALSE); >- connection = new GraphConnection(graph, SWT.NONE, d, h); >- connection.setData(Boolean.FALSE); >- >- connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, b, c); >- connection.setLineColor(ColorConstants.red); >- connection.setLineWidth(3); >- connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, c, d); >- connection.setLineColor(ColorConstants.red); >- connection.setLineWidth(3); >- connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, e, f); >- connection.setLineColor(ColorConstants.red); >- connection.setLineWidth(3); >- connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, f, g); >- connection.setLineColor(ColorConstants.red); >- connection.setLineWidth(3); >- >- connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, h, e); >- connection.setLineColor(ColorConstants.red); >- connection.setLineWidth(3); >- >- TreeLayoutAlgorithm treeLayoutAlgorithm = new TreeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING); >- Filter filter = new Filter() { >- public boolean isObjectFiltered(LayoutItem item) { >- >- // Get the "Connection" from the Layout Item >- // and use this connection to get the "Graph Data" >- Object object = item.getGraphData(); >- if (object instanceof GraphConnection ) { >- GraphConnection connection = (GraphConnection) object; >- if ( connection.getData() != null && connection.getData() instanceof Boolean ) { >- // If the data is false, don't filter, otherwise, filter. >- return ((Boolean)connection.getData()).booleanValue(); >- } >- return true; >- } >- return false; >- } >- >- }; >- treeLayoutAlgorithm.setFilter(filter); >- graph.setLayoutAlgorithm(treeLayoutAlgorithm, true); >- >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!display.readAndDispatch()) { >- display.sleep(); >- } >- } >- } >- >-} >Index: src/org/eclipse/zest/tests/swt/ZoomSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/ZoomSnippet.java >diff -N src/org/eclipse/zest/tests/swt/ZoomSnippet.java >--- src/org/eclipse/zest/tests/swt/ZoomSnippet.java 12 Sep 2007 20:44:36 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,151 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-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.layouts.LayoutAlgorithm; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.CompositeLayoutAlgorithm; >-import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm; >-import org.eclipse.zest.layouts.algorithms.HorizontalShift; >-import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm; >-import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.events.KeyEvent; >-import org.eclipse.swt.events.KeyListener; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >- >-public class ZoomSnippet { >- >- private static Image image1; >- private static Image classImage; >- >- public static void createContainer(Graph g) { >- GraphContainer a = new GraphContainer(g, SWT.NONE, "SomeClass.java", classImage); >- int r = (int) ((Math.random() * 3) + 1); >- r = 2; >- populateContainer(a, g, r, true); >- for (int i = 0; i < 4; i++) { >- GraphContainer b = new GraphContainer(g, SWT.NONE, "SomeNestedClass.java", classImage); >- r = (int) ((Math.random() * 3) + 1); >- r = 2; >- populateContainer(b, g, r, false); >- new GraphConnection(g, SWT.NONE, a, b); >- for (int j = 0; j < 4; j++) { >- GraphContainer c = new GraphContainer(g, SWT.NONE, "DefaultAction.java", classImage); >- r = (int) ((Math.random() * 3) + 1); >- r = 2; >- populateContainer(c, g, r, true); >- new GraphConnection(g, SWT.NONE, b, c); >- } >- } >- } >- >- public static void populateContainer(GraphContainer c, Graph g, int number, boolean radial) { >- GraphNode a = new GraphNode(c, ZestStyles.NODES_FISHEYE | ZestStyles.NODES_HIDE_TEXT, "SomeClass.java", classImage); >- for (int i = 0; i < 4; i++) { >- GraphNode b = new GraphNode(c, ZestStyles.NODES_FISHEYE | ZestStyles.NODES_HIDE_TEXT, "SomeNestedClass.java", classImage); >- new GraphConnection(g, SWT.NONE, a, b); >- for (int j = 0; j < 4; j++) { >- GraphNode d = new GraphNode(c, ZestStyles.NODES_FISHEYE | ZestStyles.NODES_HIDE_TEXT, "DefaultAction.java", classImage); >- new GraphConnection(g, SWT.NONE, b, d); >- if (number > 2) { >- for (int k = 0; k < 4; k++) { >- GraphNode e = new GraphNode(c, ZestStyles.NODES_FISHEYE | ZestStyles.NODES_HIDE_TEXT, "LastAction(Hero).java", classImage); >- new GraphConnection(g, SWT.NONE, d, e); >- if (number > 3) { >- for (int l = 0; l < 4; l++) { >- GraphNode f = new GraphNode(c, ZestStyles.NODES_FISHEYE | ZestStyles.NODES_HIDE_TEXT, "LastAction(Hero).java", classImage); >- new GraphConnection(g, SWT.NONE, e, f); >- } >- } >- } >- } >- } >- } >- if (number == 1) { >- c.setScale(0.75); >- } else if (number == 2) { >- c.setScale(0.50); >- } else { >- c.setScale(0.25); >- } >- if (radial) { >- c.setLayoutAlgorithm(new RadialLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- } else { >- c.setLayoutAlgorithm(new TreeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- } >- } >- >- /** >- * @param args >- */ >- public static void main(String[] args) { >- // Create the shell >- Display d = new Display(); >- >- image1 = new Image(Display.getDefault(), ZoomSnippet.class.getResourceAsStream("package_obj.gif")); >- classImage = new Image(Display.getDefault(), ZoomSnippet.class.getResourceAsStream("class_obj.gif")); >- >- Shell shell = new Shell(d); >- shell.setText("GraphSnippet1"); >- shell.setLayout(new FillLayout()); >- shell.setSize(500, 800); >- >- final Graph g = new Graph(shell, SWT.NONE); >- createContainer(g); >- >- CompositeLayoutAlgorithm compositeLayoutAlgorithm = new CompositeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING, new LayoutAlgorithm[] { new GridLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), new HorizontalShift(LayoutStyles.NO_LAYOUT_NODE_RESIZING) }); >- //g.setLayoutAlgorithm(new GridLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- g.setLayoutAlgorithm(compositeLayoutAlgorithm, true); >- >- g.addKeyListener(new KeyListener() { >- boolean flip = true; >- >- public void keyPressed(KeyEvent e) { >- >- if (g.getSelection().size() == 1) { >- GraphNode item = (GraphNode) g.getSelection().get(0); >- if (item.getItemType() == GraphItem.CONTAINER) { >- if (flip) { >- (item).setSize(500, 100); >- } else { >- (item).setSize(0, 0); >- } >- flip = !flip; >- } >- } >- >- } >- >- public void keyReleased(KeyEvent e) { >- // TODO Auto-generated method stub >- >- } >- >- }); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- image1.dispose(); >- } >-} >Index: src/org/eclipse/zest/tests/swt/GraphSnippet3.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet3.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet3.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet3.java 9 May 2008 20:42:48 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,73 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.core.widgets.ZestStyles; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.events.SelectionAdapter; >-import org.eclipse.swt.events.SelectionEvent; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >- >-/** >- * Adds a selection listener to the nodes to tell when a selection event has >- * happened. >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet3 { >- >- public static void main(String[] args) { >- Display d = new Display(); >- Shell shell = new Shell(d); >- Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION); >- Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >- Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- Graph g = new Graph(shell, SWT.NONE); >- g.addSelectionListener(new SelectionAdapter() { >- public void widgetSelected(SelectionEvent e) { >- System.out.println(((Graph) e.widget).getSelection()); >- } >- }); >- >- g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED); >- GraphNode n1 = new GraphNode(g, SWT.NONE, "Information", image1); >- GraphNode n2 = new GraphNode(g, SWT.NONE, "Warning", image2); >- GraphNode n3 = new GraphNode(g, SWT.NONE, "Error", image3); >- >- new GraphConnection(g, SWT.NONE, n1, n2); >- new GraphConnection(g, SWT.NONE, n2, n3); >- >- g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- image1.dispose(); >- image2.dispose(); >- image3.dispose(); >- >- } >-} >Index: src/org/eclipse/zest/tests/swt/CustomLayout.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/test/org.eclipse.zest.tests/src/org/eclipse/zest/tests/swt/CustomLayout.java,v >retrieving revision 1.1 >diff -u -r1.1 CustomLayout.java >--- src/org/eclipse/zest/tests/swt/CustomLayout.java 17 Jun 2008 04:40:03 -0000 1.1 >+++ src/org/eclipse/zest/tests/swt/CustomLayout.java 28 Aug 2009 16:03:12 -0000 >@@ -1,3 +1,14 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ > package org.eclipse.zest.tests.swt; > > import org.eclipse.swt.SWT; >@@ -7,10 +18,9 @@ > import org.eclipse.zest.core.widgets.Graph; > import org.eclipse.zest.core.widgets.GraphConnection; > import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.algorithms.AbstractLayoutAlgorithm; >-import org.eclipse.zest.layouts.dataStructures.InternalNode; >-import org.eclipse.zest.layouts.dataStructures.InternalRelationship; >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; > > /** > * This snippet shows how to create a custom layout. This layout simply lays the nodes out vertically >@@ -36,59 +46,28 @@ > new GraphConnection(g, SWT.NONE, n, n2); > new GraphConnection(g, SWT.NONE, n2, n3); > new GraphConnection(g, SWT.NONE, n3, n); >- g.setLayoutAlgorithm(new AbstractLayoutAlgorithm(SWT.NONE) { >- >+ >+ LayoutAlgorithm layoutAlgorithm = new LayoutAlgorithm() { >+ private LayoutContext context; >+ public void setLayoutContext(LayoutContext context) { >+ this.context = context; >+ } > >- private int totalSteps; >- private int currentStep; >- >- protected void applyLayoutInternal(InternalNode[] entitiesToLayout, >- InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY, double boundsWidth, >- double boundsHeight) { >- >- totalSteps = entitiesToLayout.length; >- double distance = boundsWidth / totalSteps; >+ public void applyLayout(boolean clean) { >+ EntityLayout[] entitiesToLayout = context.getEntities(); >+ int totalSteps = entitiesToLayout.length; >+ double distance = context.getBounds().width / totalSteps; > int xLocation = 0; >- >- fireProgressStarted(totalSteps); >- >- for (currentStep = 0; currentStep < entitiesToLayout.length; currentStep++) { >- LayoutEntity layoutEntity = entitiesToLayout[currentStep].getLayoutEntity(); >- layoutEntity.setLocationInLayout(xLocation, layoutEntity.getYInLayout()); >+ >+ for (int currentStep = 0; currentStep < entitiesToLayout.length; currentStep++) { >+ EntityLayout layoutEntity = entitiesToLayout[currentStep]; >+ layoutEntity.setLocation(xLocation, layoutEntity.getLocation().y); > xLocation+= distance; >- fireProgressEvent(currentStep, totalSteps); > } >- fireProgressEnded(totalSteps); >- } >- >- protected int getCurrentLayoutStep() { >- return 0; >- } >- >- protected int getTotalNumberOfLayoutSteps() { >- return totalSteps; > } >- >- protected boolean isValidConfiguration(boolean asynchronous, boolean continuous) { >- return true; >- } >- >- protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, >- InternalRelationship[] relationshipsToConsider) { >- // Do nothing >- } >- >- protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, >- InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) { >- // do nothing >- } >- >- public void setLayoutArea(double x, double y, double width, double height) { >- // do nothing >- } >- >- }, true); >- >+ }; >+ g.setLayoutAlgorithm(layoutAlgorithm, true); >+ > shell.open(); > while (!shell.isDisposed()) { > while (!d.readAndDispatch()) { >Index: src/org/eclipse/zest/tests/swt/GraphSnippet13.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet13.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet13.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet13.java 31 Mar 2009 16:43:00 -0000 1.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,182 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import java.util.Iterator; >- >-import org.eclipse.draw2d.ColorConstants; >-import org.eclipse.draw2d.Ellipse; >-import org.eclipse.draw2d.Figure; >-import org.eclipse.draw2d.FlowLayout; >-import org.eclipse.draw2d.FreeformLayout; >-import org.eclipse.draw2d.IFigure; >-import org.eclipse.draw2d.ImageFigure; >-import org.eclipse.draw2d.Label; >-import org.eclipse.draw2d.MarginBorder; >-import org.eclipse.draw2d.PolylineShape; >-import org.eclipse.draw2d.geometry.Point; >-import org.eclipse.draw2d.geometry.Rectangle; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.events.SelectionEvent; >-import org.eclipse.swt.events.SelectionListener; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >-import org.eclipse.zest.core.widgets.CGraphNode; >-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.GraphNode; >-import org.eclipse.zest.core.widgets.ZestStyles; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >- >-/** >- * >- * This snippet shows how to create a curved connection using Zest. >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet13 { >- >- public static IFigure createPersonFigure(Image headImage) { >- Figure person = new Figure(); >- person.setLayoutManager(new FreeformLayout()); >- IFigure head = null; >- if ( headImage != null ) { >- headImage = new Image(headImage.getDevice(), headImage.getImageData().scaledTo(40, 50)); >- head = new ImageFigure(headImage); >- } >- else >- head = new Ellipse(); >- head.setSize(40, 50); >- >- PolylineShape body = new PolylineShape(); >- body.setLineWidth(1); >- body.setStart(new Point(20,40)); >- body.setEnd(new Point(20,100)); >- body.setBounds(new Rectangle(0,0,40,100)); >- >- PolylineShape leftLeg = new PolylineShape(); >- leftLeg.setLineWidth(1); >- leftLeg.setStart(new Point(20,100)); >- leftLeg.setEnd(new Point(0,130)); >- leftLeg.setBounds(new Rectangle(0,0,40,130)); >- >- PolylineShape rightLeg = new PolylineShape(); >- rightLeg.setLineWidth(1); >- rightLeg.setStart(new Point(20,100)); >- rightLeg.setEnd(new Point(40,130)); >- rightLeg.setBounds(new Rectangle(0,0,40,130)); >- >- PolylineShape leftArm = new PolylineShape(); >- leftArm.setLineWidth(1); >- leftArm.setStart(new Point(20,60)); >- leftArm.setEnd(new Point(0,50)); >- leftArm.setBounds(new Rectangle(0,0,40,130)); >- >- PolylineShape rightArm = new PolylineShape(); >- rightArm.setLineWidth(1); >- rightArm.setStart(new Point(20,60)); >- rightArm.setEnd(new Point(40,50)); >- rightArm.setBounds(new Rectangle(0,0,40,130)); >- >- person.add(head); >- person.add(body); >- person.add(leftLeg); >- person.add(rightLeg); >- person.add(leftArm); >- person.add(rightArm); >- person.setSize(40,130); >- return person; >- } >- >- public static void main(String[] args) { >- final Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("GraphSnippet11"); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- >- final Graph g = new Graph(shell, SWT.NONE); >- g.addSelectionListener(new SelectionListener(){ >- >- public void widgetSelected(SelectionEvent e) { >- Iterator iter = g.getSelection().iterator(); >- while(iter.hasNext()) { >- Object o = iter.next(); >- if ( o instanceof CGraphNode) { >- IFigure figure = ((CGraphNode)o).getFigure(); >- figure.setBackgroundColor(ColorConstants.blue); >- figure.setForegroundColor(ColorConstants.blue); >- } >- } >- iter = g.getNodes().iterator(); >- while ( iter.hasNext()) { >- Object o = iter.next(); >- if ( o instanceof CGraphNode) { >- if ( !g.getSelection().contains(o)) { >- ((CGraphNode)o).getFigure().setBackgroundColor(ColorConstants.black); >- ((CGraphNode)o).getFigure().setForegroundColor(ColorConstants.black); >- } >- } >- } >- } >- >- public void widgetDefaultSelected(SelectionEvent e) { >- // TODO Auto-generated method stub >- >- } >- }); >- >- Image zx = new Image(d, "zxsnow.png"); >- IFigure tooltip = new Figure(); >- tooltip.setBorder(new MarginBorder(5,5,5,5)); >- FlowLayout layout = new FlowLayout(false); >- layout.setMajorSpacing(3); >- layout.setMinorAlignment(3); >- tooltip.setLayoutManager(new FlowLayout(false)); >- tooltip.add(new ImageFigure(zx)); >- tooltip.add(new Label("Name: " + "Chris Aniszczyk")); >- tooltip.add(new Label("Location: " + "Austin, Texas")); >- >- Image ibull = new Image(d, "ibull.jpg"); >- GraphContainer c1 = new GraphContainer(g, SWT.NONE); >- c1.setText("Canada"); >- GraphContainer c2 = new GraphContainer(g, SWT.NONE); >- c2.setText("USA"); >- >- GraphNode n1 = new GraphNode(c1, SWT.NONE, "Ian B."); >- n1.setSize(200, 100); >- GraphNode n2 = new GraphNode(c2, SWT.NONE, "Chris A."); >- n2.setTooltip(tooltip); >- >- GraphConnection connection = new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, n1, n2); >- connection.setCurveDepth(-30); >- GraphConnection connection2 = new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, n2, n1); >- connection2.setCurveDepth(-30); >- >- >- g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- zx.dispose(); >- ibull.dispose(); >- } >- >-} >Index: src/org/eclipse/zest/tests/swt/GraphSnippet4.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet4.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet4.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet4.java 12 Sep 2007 20:44:36 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,103 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import org.eclipse.draw2d.IFigure; >-import org.eclipse.draw2d.Label; >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.core.widgets.ZestStyles; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.graphics.GC; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >- >-/** >- * This snippet shows how a custom figure can be used as a ToolTip for connections. >- * Let your mouse hover over an edge to see the custom tooltip. >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet4 { >- >- >- /** >- * Merges 2 images so they appear beside each other >- * >- * You must dispose this image! >- * @param image1 >- * @param image2 >- * @param result >- * @return >- */ >- public static Image mergeImages(Image image1, Image image2) { >- Image mergedImage = new Image(Display.getDefault(), image1.getBounds().width + image2.getBounds().width, image1.getBounds().height); >- GC gc = new GC(mergedImage); >- gc.drawImage(image1, 0, 0); >- gc.drawImage(image2, image1.getBounds().width, 0); >- gc.dispose(); >- return mergedImage; >- } >- >- >- /** >- * @param args >- */ >- public static void main(String[] args) { >- Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("Graph Snippet 4"); >- Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION); >- Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >- Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- Graph g = new Graph(shell, SWT.NONE); >- g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED ); >- GraphNode n1 = new GraphNode(g, SWT.NONE, "Information", image1); >- GraphNode n2 = new GraphNode(g, SWT.NONE, "Warning", image2); >- GraphNode n3 = new GraphNode(g, SWT.NONE, "Error", image3); >- >- GraphConnection connection1 = new GraphConnection(g, SWT.NONE, n1, n2); >- GraphConnection connection2 = new GraphConnection(g, SWT.NONE, n2, n3); >- >- Image information2warningImage = mergeImages(image1, image2); >- Image warning2error = mergeImages(image2, image3); >- IFigure tooltip1 = new Label("Information to Warning", information2warningImage); >- IFigure tooltip2 = new Label("Warning to Error", warning2error); >- connection1.setTooltip(tooltip1); >- connection2.setTooltip(tooltip2); >- >- n1.setLocation(10, 10); >- n2.setLocation(200, 10); >- n3.setLocation(200, 200); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- >- image1.dispose(); >- image2.dispose(); >- image3.dispose(); >- >- information2warningImage.dispose(); >- warning2error.dispose(); >- >- } >-} >Index: src/org/eclipse/zest/tests/swt/GraphSnippet2.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet2.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet2.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet2.java 9 May 2008 20:42:48 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,66 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.core.widgets.ZestStyles; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >- >-/** >- * This snippet creates a very simple graph with an Icon and Label. >- * >- * This snippet shows how to use directed edges and self loops. >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet2 { >- >- public static void main(String[] args) { >- Display d = new Display(); >- Shell shell = new Shell(d); >- Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION); >- Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >- Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- Graph g = new Graph(shell, SWT.NONE); >- g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED); >- GraphNode n1 = new GraphNode(g, SWT.NONE, "Information", image1); >- GraphNode n2 = new GraphNode(g, SWT.NONE, "Warning", image2); >- GraphNode n3 = new GraphNode(g, SWT.NONE, "Error", image3); >- >- new GraphConnection(g, SWT.NONE, n1, n2); >- new GraphConnection(g, SWT.NONE, n2, n3); >- new GraphConnection(g, SWT.NONE, n3, n3); >- >- g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- image1.dispose(); >- image2.dispose(); >- image3.dispose(); >- } >-} >Index: src/org/eclipse/zest/tests/swt/GraphSnippet5.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet5.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet5.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet5.java 9 May 2008 20:48:40 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,137 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import java.util.ArrayList; >-import java.util.HashMap; >-import java.util.Iterator; >-import java.util.List; >-import java.util.Map; >- >-import org.eclipse.draw2d.ColorConstants; >-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; >-import org.eclipse.zest.core.widgets.ZestStyles; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.events.KeyAdapter; >-import org.eclipse.swt.events.KeyEvent; >-import org.eclipse.swt.events.PaintEvent; >-import org.eclipse.swt.events.PaintListener; >-import org.eclipse.swt.graphics.Font; >-import org.eclipse.swt.graphics.FontData; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.graphics.Region; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >- >-/** >- * This snippet shows how you can add a paint listener to a Zest graph to paint on top of >- * the widget. This snippet allows you to type and it selects all the nodes that match >- * what you type. >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet5 { >- public static final int BACKSPACE = 8; >- public static final int ENTER = 13; >- >- /** >- * @param args >- */ >- public static void main(String[] args) { >- final Map figureListing = new HashMap(); >- final StringBuffer stringBuffer = new StringBuffer(); >- final Display d = new Display(); >- FontData fontData = d.getSystemFont().getFontData()[0]; >- fontData.height = 42; >- >- final Font font = new Font(d, fontData); >- >- Shell shell = new Shell(d); >- shell.setText("Graph Snippet 5"); >- Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION); >- Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >- Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- final Graph g = new Graph(shell, SWT.NONE); >- g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED); >- GraphNode n1 = new GraphNode(g, SWT.NONE, "org.eclipse.Information", image1); >- GraphNode n2 = new GraphNode(g, SWT.NONE, "org.eclipse.Warning", image2); >- GraphNode n3 = new GraphNode(g, SWT.NONE, "org.eclipse.Error", image3); >- figureListing.put(n1.getText().toLowerCase(), n1); >- figureListing.put(n2.getText().toLowerCase(), n2); >- figureListing.put(n3.getText().toLowerCase(), n3); >- >- new GraphConnection(g, SWT.NONE, n1, n2); >- new GraphConnection(g, SWT.NONE, n2, n3); >- n1.setLocation(10, 10); >- n2.setLocation(200, 10); >- n3.setLocation(200, 200); >- >- g.addKeyListener(new KeyAdapter() { >- >- public void keyPressed(KeyEvent e) { >- boolean complete = false; >- if (e.keyCode == BACKSPACE) { >- if (stringBuffer.length() > 0) { >- stringBuffer.deleteCharAt(stringBuffer.length() - 1); >- } >- } else if (e.keyCode == ENTER) { >- complete = true; >- } else if ((e.character >= 'a' && e.character <= 'z') || (e.character >= 'A' && e.character <= 'Z') || (e.character == '.') || (e.character >= '0' && e.character <= '9')) { >- stringBuffer.append(e.character); >- } >- Iterator iterator = figureListing.keySet().iterator(); >- List list = new ArrayList(); >- if (stringBuffer.length() > 0) { >- while (iterator.hasNext()) { >- String string = (String) iterator.next(); >- if (string.indexOf(stringBuffer.toString().toLowerCase()) >= 0) { >- list.add(figureListing.get(string)); >- } >- } >- } >- g.setSelection((GraphItem[]) list.toArray(new GraphItem[list.size()])); >- if (complete && stringBuffer.length() > 0) { >- stringBuffer.delete(0, stringBuffer.length()); >- } >- >- g.redraw(); >- } >- >- }); >- >- g.addPaintListener(new PaintListener() { >- public void paintControl(PaintEvent e) { >- e.gc.setFont(font); >- e.gc.setClipping((Region) null); >- e.gc.setForeground(ColorConstants.black); >- e.gc.drawText(stringBuffer.toString(), 50, 50, true); >- } >- }); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- image1.dispose(); >- image2.dispose(); >- image3.dispose(); >- font.dispose(); >- } >-} >Index: src/org/eclipse/zest/tests/swt/GraphSnippet1.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet1.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet1.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet1.java 9 May 2008 20:42:48 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,60 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >- >-/** >- * This snippet creates a very simple graph where Rock is connected to Paper >- * which is connected to scissors which is connected to rock. >- * >- * The nodes a positioned using a SpringLayout Algorithm, and they can be moved >- * around. >- * >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet1 { >- >- public static void main(String[] args) { >- Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("GraphSnippet1"); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- Graph g = new Graph(shell, SWT.NONE); >- >- GraphNode n = new GraphNode(g, SWT.NONE, "Paper"); >- GraphNode n2 = new GraphNode(g, SWT.NONE, "Rock"); >- GraphNode n3 = new GraphNode(g, SWT.NONE, "Scissors"); >- new GraphConnection(g, SWT.NONE, n, n2); >- new GraphConnection(g, SWT.NONE, n2, n3); >- new GraphConnection(g, SWT.NONE, n3, n); >- g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- } >- >-} >Index: src/org/eclipse/zest/tests/swt/GraphSnippet9.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet9.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet9.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet9.java 12 May 2008 19:03:15 -0000 1.2 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,54 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.core.widgets.ZestStyles; >- >-/** >- * This snippet demonstrates a self loop with a label. >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet9 { >- >- /** >- * @param args >- */ >- public static void main(String[] args) { >- Display display = new Display(); >- Shell shell = new Shell(display); >- shell.setText("GraphSnippet9"); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- final Graph graph = new Graph(shell, SWT.NONE); >- >- GraphNode a = new GraphNode(graph, ZestStyles.CONNECTIONS_DIRECTED, "Root"); >- GraphConnection connection = new GraphConnection(graph, SWT.NONE, a, a); >- connection.setText("A to A"); >- a.setLocation(100, 100); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!display.readAndDispatch()) { >- display.sleep(); >- } >- } >- } >- >-} >Index: src/org/eclipse/zest/tests/swt/LayoutExample.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/LayoutExample.java >diff -N src/org/eclipse/zest/tests/swt/LayoutExample.java >--- src/org/eclipse/zest/tests/swt/LayoutExample.java 12 Sep 2007 20:44:36 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,86 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import org.eclipse.zest.core.widgets.ConstraintAdapter; >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >-import org.eclipse.zest.layouts.constraints.BasicEdgeConstraints; >-import org.eclipse.zest.layouts.constraints.LayoutConstraint; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >- >-/** >- * This snippet shows how to use the findFigureAt to get the figure under the >- * mouse >- * >- * @author Ian Bull >- * >- */ >-public class LayoutExample { >- >- /** >- * @param args >- */ >- public static void main(String[] args) { >- // Create the shell >- Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("GraphSnippet1"); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- final Graph g = new Graph(shell, SWT.NONE); >- GraphNode root = new GraphNode(g, SWT.NONE, "Root"); >- for (int i = 0; i < 3; i++) { >- GraphNode n = new GraphNode(g, SWT.NONE, "1 - " + i); >- for (int j = 0; j < 3; j++) { >- GraphNode n2 = new GraphNode(g, SWT.NONE, "2 - " + j); >- new GraphConnection(g, SWT.NONE, n, n2); >- } >- new GraphConnection(g, SWT.NONE, root, n); >- } >- >- SpringLayoutAlgorithm springLayoutAlgorithm = new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING); >- >- ConstraintAdapter constraintAdapters = new ConstraintAdapter() { >- >- public void populateConstraint(Object object, LayoutConstraint constraint) { >- if (constraint instanceof BasicEdgeConstraints) { >- BasicEdgeConstraints basicEdgeConstraints = (BasicEdgeConstraints) constraint; >- GraphConnection connection = (GraphConnection) object; >- if (connection.getSource().getText().equals("Root")) { >- basicEdgeConstraints.weight = 1; >- } >- else { >- basicEdgeConstraints.weight = -1; >- } >- } >- >- } >- }; >- >- g.addConstraintAdapter(constraintAdapters); >- g.setLayoutAlgorithm(springLayoutAlgorithm, true); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- } >- >-} >Index: src/org/eclipse/zest/tests/swt/GraphSnippet6.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet6.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet6.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet6.java 9 May 2008 20:48:40 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,71 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.core.widgets.ZestStyles; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >- >-/** >- * This snippet creates a graph with 80*3 nodes (240 nodes). Only the icons are shown for the nodes, but if >- * you mouse over the node you get the entire text. >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet6 { >- >- /** >- * @param args >- */ >- public static void main(String[] args) { >- Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("GraphSnippet6"); >- Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION); >- Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >- Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR); >- shell.setLayout(new FillLayout()); >- shell.setSize(800, 800); >- >- Graph g = new Graph(shell, SWT.NONE); >- g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED); >- for (int i = 0; i < 80; i++) { >- GraphNode n1 = new GraphNode(g, ZestStyles.NODES_HIDE_TEXT | ZestStyles.NODES_FISHEYE, "Information", image1); >- GraphNode n2 = new GraphNode(g, ZestStyles.NODES_HIDE_TEXT | ZestStyles.NODES_FISHEYE, "Warning", image2); >- GraphNode n3 = new GraphNode(g, ZestStyles.NODES_HIDE_TEXT | ZestStyles.NODES_FISHEYE, "Error", image3); >- new GraphConnection(g, SWT.NONE, n1, n2); >- new GraphConnection(g, SWT.NONE, n2, n3); >- new GraphConnection(g, SWT.NONE, n3, n3); >- } >- g.setLayoutAlgorithm(new GridLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- image1.dispose(); >- image2.dispose(); >- image3.dispose(); >- >- } >- >-} >Index: src/org/eclipse/zest/tests/swt/GraphSnippet11.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/GraphSnippet11.java >diff -N src/org/eclipse/zest/tests/swt/GraphSnippet11.java >--- src/org/eclipse/zest/tests/swt/GraphSnippet11.java 21 Nov 2008 16:43:44 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,69 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.swt; >- >-import org.eclipse.draw2d.ColorConstants; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.graphics.Color; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.core.widgets.ZestStyles; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >- >-/** >- * >- * This snippet shows how to create a curved connection using Zest. >- * >- * @author Ian Bull >- * >- */ >-public class GraphSnippet11 { >- >- >- public static void createConnection( Graph g, GraphNode n1, GraphNode n2, Color color, int curve) { >- GraphConnection connection = new GraphConnection(g, SWT.NONE, n1, n2); >- connection.setLineColor(color); >- connection.setCurveDepth(curve); >- connection.setLineWidth(1); >- } >- >- public static void main(String[] args) { >- Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("GraphSnippet11"); >- shell.setLayout(new FillLayout()); >- shell.setSize(400, 400); >- >- final Graph g = new Graph(shell, SWT.NONE); >- GraphNode n = new GraphNode(g, SWT.NONE, "Node 1"); >- GraphNode n2 = new GraphNode(g, SWT.NONE, "Node 2"); >- createConnection(g, n, n2, ColorConstants.darkGreen, 20); >- createConnection(g, n, n2, ColorConstants.darkGreen, -20); >- createConnection(g, n, n2, ColorConstants.darkBlue, 40); >- createConnection(g, n, n2, ColorConstants.darkBlue, -40); >- createConnection(g, n, n2, ColorConstants.darkGray, 60); >- createConnection(g, n, n2, ColorConstants.darkGray, -60); >- createConnection(g, n, n2, ColorConstants.black, 0); >- g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- } >- >-} >Index: src/org/eclipse/zest/tests/swt/HelloWorld.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/test/org.eclipse.zest.tests/src/org/eclipse/zest/tests/swt/HelloWorld.java,v >retrieving revision 1.3 >diff -u -r1.3 HelloWorld.java >--- src/org/eclipse/zest/tests/swt/HelloWorld.java 12 May 2008 18:47:53 -0000 1.3 >+++ src/org/eclipse/zest/tests/swt/HelloWorld.java 28 Aug 2009 16:03:12 -0000 >@@ -1,18 +1,19 @@ > /******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, > * Canada. All rights reserved. This program and the accompanying materials are > * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html > * >- * Contributors: The Chisel Group, University of Victoria >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 > ******************************************************************************/ > package org.eclipse.zest.tests.swt; > > import org.eclipse.zest.core.widgets.Graph; > import org.eclipse.zest.core.widgets.GraphConnection; > import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.layouts.LayoutStyles; > import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; > import org.eclipse.swt.SWT; > import org.eclipse.swt.layout.FillLayout; >@@ -41,7 +42,7 @@ > GraphNode hello = new GraphNode(g, SWT.NONE, "Hello"); > GraphNode world = new GraphNode(g, SWT.NONE, "World"); > new GraphConnection(g, SWT.NONE, hello, world); >- g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >+ g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true); > > shell.open(); > while (!shell.isDisposed()) { >Index: src/org/eclipse/zest/tests/uml/UMLExample.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/test/org.eclipse.zest.tests/src/org/eclipse/zest/tests/uml/UMLExample.java,v >retrieving revision 1.4 >diff -u -r1.4 UMLExample.java >--- src/org/eclipse/zest/tests/uml/UMLExample.java 12 Sep 2007 20:44:36 -0000 1.4 >+++ src/org/eclipse/zest/tests/uml/UMLExample.java 28 Aug 2009 16:03:12 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,19 +7,13 @@ > * > * Contributors: > * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 > *******************************************************************************/ > package org.eclipse.zest.tests.uml; > > import org.eclipse.draw2d.IFigure; > import org.eclipse.draw2d.Label; >-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.GraphNode; >-import org.eclipse.zest.core.widgets.IContainer; >-import org.eclipse.zest.core.widgets.ZestStyles; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+import org.eclipse.draw2d.geometry.Dimension; > import org.eclipse.swt.SWT; > import org.eclipse.swt.graphics.Color; > import org.eclipse.swt.graphics.Font; >@@ -27,6 +21,14 @@ > import org.eclipse.swt.layout.FillLayout; > import org.eclipse.swt.widgets.Display; > import org.eclipse.swt.widgets.Shell; >+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.GraphNode; >+import org.eclipse.zest.core.widgets.ZestStyles; >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; > > /** > * Adds a selection listener to the nodes to tell when a selection event has >@@ -82,13 +84,21 @@ > > IFigure customFigure = null; > >- public UMLNode(IContainer graphModel, int style, IFigure figure) { >+ public UMLNode(Graph graphModel, int style, IFigure figure) { >+ super(graphModel, style, figure); >+ } >+ >+ public UMLNode(GraphContainer graphModel, int style, IFigure figure) { > super(graphModel, style, figure); > } > > protected IFigure createFigureForModel() { > return (IFigure) this.getData(); > } >+ >+ public Dimension getSize() { >+ return ((IFigure) this.getData()).getPreferredSize(); >+ } > > } > >@@ -119,8 +129,8 @@ > new GraphConnection(g, SWT.NONE, n1, n2); > new GraphConnection(g, SWT.NONE, n, n1); > >- c.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >- g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >+ c.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true); >+ g.setLayoutAlgorithm(new TreeLayoutAlgorithm(), true); > > shell.open(); > while (!shell.isDisposed()) { >Index: src/org/eclipse/zest/tests/jface/GraphJFaceSnippet3.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/jface/GraphJFaceSnippet3.java >diff -N src/org/eclipse/zest/tests/jface/GraphJFaceSnippet3.java >--- src/org/eclipse/zest/tests/jface/GraphJFaceSnippet3.java 12 Sep 2007 20:44:36 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,135 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.jface; >- >-import java.io.BufferedReader; >-import java.io.File; >-import java.io.FileReader; >-import java.io.IOException; >-import java.util.ArrayList; >-import java.util.StringTokenizer; >- >-import org.eclipse.jface.viewers.LabelProvider; >-import org.eclipse.jface.viewers.Viewer; >-import org.eclipse.zest.core.viewers.GraphViewer; >-import org.eclipse.zest.core.viewers.IGraphContentProvider; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.FileDialog; >-import org.eclipse.swt.widgets.Shell; >- >-/** >- * This snippet uses a very simple file format to read a graph. Edges are listed >- * on a new line in a file as such: >- * a calls b >- * b calls c >- * c calld d >- * >- * The content provider creates an edge for each line in the file and names the >- * sources and destination from the line. >- * >- * >- * @author Ian Bull >- * >- */ >-public class GraphJFaceSnippet3 { >- >- public static final String graph = "a calls b\n" + "a calls c\n" + "b calld d\n" + "b calls e\n" + "c calls f\n" + "c calls g\n" + "d calls h\n" + "d calls i\n" + "e calls j\n" + "e calls k\n" + "f calls l\n" + "f calls m\n"; >- >- static class SimpleGraphContentProvider implements IGraphContentProvider { >- >- private StringTokenizer graph; >- >- public Object getDestination(Object rel) { >- String string = (String) rel; >- String[] parts = string.split(" "); >- return parts[2]; >- } >- >- public Object[] getElements(Object input) { >- ArrayList listOfEdges = new ArrayList(); >- while (graph.hasMoreTokens()) { >- listOfEdges.add(graph.nextToken()); >- } >- return listOfEdges.toArray(); >- } >- >- public Object getSource(Object rel) { >- String string = (String) rel; >- String[] parts = string.split(" "); >- return parts[0]; >- } >- >- public double getWeight(Object connection) { >- return 0; >- } >- >- public void dispose() { >- >- } >- >- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { >- if (newInput != null) { >- graph = new StringTokenizer((String) newInput, "\n"); >- } >- } >- >- } >- >- public static void main(String[] args) throws IOException { >- Display display = new Display(); >- Shell shell = new Shell(display); >- shell.setText("Simple Graph File Format"); >- >- FileDialog dialog = new FileDialog(shell, SWT.OPEN); >- dialog.setFilterNames(new String[] { "Simple Graph Files (*.sgf)", "All Files (*.*)" }); >- dialog.setFilterExtensions(new String[] { "*.sgf", "*.*" }); //Windows wild cards >- >- String directory = System.getProperty("user.dir") + "/src/org/eclipse/zest/tests/jface/SimpleGraph.sgf"; //eclipse/zest/examples/jface/"; >- System.out.println(directory); >- dialog.setFilterPath(directory); >- //dialog.setFilterPath(System.getProperty("user.dir") + "src/org/eclipse/zest/examples/jface/"); //Windows path >- >- shell.setLayout(new FillLayout(SWT.VERTICAL)); >- shell.setSize(400, 400); >- GraphViewer viewer = null; >- >- viewer = new GraphViewer(shell, SWT.NONE); >- viewer.setContentProvider(new SimpleGraphContentProvider()); >- viewer.setLabelProvider(new LabelProvider()); >- viewer.setLayoutAlgorithm(new RadialLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING)); >- >- shell.open(); >- String fileName = dialog.open(); >- >- if (fileName == null) { >- // use the sample graph >- viewer.setInput(graph); >- } else { >- FileReader fileReader = new FileReader(new File(fileName)); >- BufferedReader bufferedReader = new BufferedReader(fileReader); >- StringBuffer stringBuffer = new StringBuffer(); >- while (bufferedReader.ready()) { >- stringBuffer.append(bufferedReader.readLine() + "\n"); >- } >- viewer.setInput(stringBuffer.toString()); >- } >- >- while (!shell.isDisposed()) { >- if (!display.readAndDispatch()) { >- display.sleep(); >- } >- } >- display.dispose(); >- } >-} >Index: src/org/eclipse/zest/tests/jface/GraphJFaceSnippet1.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/test/org.eclipse.zest.tests/src/org/eclipse/zest/tests/jface/GraphJFaceSnippet1.java,v >retrieving revision 1.2 >diff -u -r1.2 GraphJFaceSnippet1.java >--- src/org/eclipse/zest/tests/jface/GraphJFaceSnippet1.java 12 Sep 2007 20:44:36 -0000 1.2 >+++ src/org/eclipse/zest/tests/jface/GraphJFaceSnippet1.java 28 Aug 2009 16:03:12 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,6 +7,7 @@ > * > * Contributors: > * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 > *******************************************************************************/ > package org.eclipse.zest.tests.jface; > >@@ -14,10 +15,6 @@ > import org.eclipse.jface.viewers.LabelProvider; > import org.eclipse.jface.viewers.SelectionChangedEvent; > import org.eclipse.jface.viewers.Viewer; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >-import org.eclipse.zest.core.viewers.GraphViewer; >-import org.eclipse.zest.core.viewers.IGraphEntityContentProvider; > import org.eclipse.swt.SWT; > import org.eclipse.swt.events.SelectionAdapter; > import org.eclipse.swt.events.SelectionEvent; >@@ -26,6 +23,9 @@ > import org.eclipse.swt.widgets.Button; > import org.eclipse.swt.widgets.Display; > import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.viewers.GraphViewer; >+import org.eclipse.zest.core.viewers.IGraphEntityContentProvider; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; > > /** > * This snippet shows how to use the IGraphEntityContentProvider to build a graph. >@@ -113,7 +113,7 @@ > > viewer.setContentProvider(new MyContentProvider()); > viewer.setLabelProvider(new MyLabelProvider()); >- viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING)); >+ viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm()); > viewer.addSelectionChangedListener(new ISelectionChangedListener() { > public void selectionChanged(SelectionChangedEvent event) { > System.out.println("Selection changed: " + (event.getSelection())); >Index: src/org/eclipse/zest/tests/jface/GraphJFaceSnippet7.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/jface/GraphJFaceSnippet7.java >diff -N src/org/eclipse/zest/tests/jface/GraphJFaceSnippet7.java >--- src/org/eclipse/zest/tests/jface/GraphJFaceSnippet7.java 31 Mar 2009 16:43:00 -0000 1.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,182 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.jface; >- >- >-import org.eclipse.draw2d.IFigure; >-import org.eclipse.draw2d.Label; >-import org.eclipse.jface.viewers.LabelProvider; >-import org.eclipse.jface.viewers.Viewer; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.events.SelectionEvent; >-import org.eclipse.swt.events.SelectionListener; >-import org.eclipse.swt.graphics.Font; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Button; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >-import org.eclipse.zest.core.viewers.EntityConnectionData; >-import org.eclipse.zest.core.viewers.GraphViewer; >-import org.eclipse.zest.core.viewers.IFigureProvider; >-import org.eclipse.zest.core.viewers.IGraphEntityContentProvider; >-import org.eclipse.zest.core.viewers.INestedContentProvider; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >-import org.eclipse.zest.tests.uml.UMLClassFigure; >- >-/** >- * This snippet shows how to use the INestedGraphContentProvider to create a graph >- * with Zest. In this example, getElements returns 3 edges: * Rock2Paper * >- * Paper2Scissors * Scissors2Rock >- * >- * And for each of these, the source and destination are returned in getSource >- * and getDestination. >- * >- * A label provider is also used to create the text and icons for the graph. >- * >- * @author Ian Bull >- * >- */ >-public class GraphJFaceSnippet7 { >- >- public static IFigure createClassFigure1(Font classFont, Image classImage, Image publicField, Image privateField) { >- Label classLabel1 = new Label("Table", classImage); >- classLabel1.setFont(classFont); >- >- UMLClassFigure classFigure = new UMLClassFigure(classLabel1); >- Label attribute1 = new Label("columns: Column[]", privateField); >- >- Label attribute2 = new Label("rows: Row[]", privateField); >- >- Label method1 = new Label("getColumns(): Column[]", publicField); >- Label method2 = new Label("getRows(): Row[]", publicField); >- classFigure.getAttributesCompartment().add(attribute1); >- classFigure.getAttributesCompartment().add(attribute2); >- classFigure.getMethodsCompartment().add(method1); >- classFigure.getMethodsCompartment().add(method2); >- classFigure.setSize(-1, -1); >- >- return classFigure; >- } >- >- static class MyContentProvider implements IGraphEntityContentProvider, INestedContentProvider { >- >- public Object[] getConnectedTo(Object entity) { >- if (entity.equals("First")) { >- return new Object[] { "Second" }; >- } >- if (entity.equals("Second")) { >- return new Object[] { "Third", "rock" }; >- } >- if (entity.equals("Third")) { >- return new Object[] { "First" }; >- } >- if ( entity.equals("rock")) { >- return new Object[] { "paper" }; >- } >- return null; >- } >- >- public Object[] getElements(Object inputElement) { >- return new String[] { "First", "Second", "Third" }; >- } >- >- public double getWeight(Object entity1, Object entity2) { >- return 0; >- } >- >- public void dispose() { >- >- } >- >- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { >- >- } >- >- public Object[] getChildren(Object element) { >- // TODO Auto-generated method stub >- return new Object[] {"rock", "paper", "scissors"}; >- } >- >- public boolean hasChildren(Object element) { >- // TODO Auto-generated method stub >- if ( element.equals("First")) return true; >- return false; >- } >- >- } >- >- >- >- static class MyLabelProvider extends LabelProvider implements IFigureProvider { >- final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >- >- public Image getImage(Object element) { >- if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) { >- return image; >- } >- return null; >- } >- >- public String getText(Object element) { >- if ( element instanceof EntityConnectionData ) return ""; >- return element.toString(); >- } >- >- public IFigure getFigure(Object element) { >- Font classFont = new Font(null, "Arial", 12, SWT.BOLD); >- Image classImage = new Image(Display.getDefault(), UMLClassFigure.class.getResourceAsStream("class_obj.gif")); >- Image privateField = new Image(Display.getDefault(), UMLClassFigure.class.getResourceAsStream("field_private_obj.gif")); >- Image publicField= new Image(Display.getDefault(), UMLClassFigure.class.getResourceAsStream("methpub_obj.gif")); >- return createClassFigure1(classFont, classImage, publicField, privateField); >- } >- >- } >- >- static GraphViewer viewer = null; >- >- /** >- * @param args >- */ >- public static void main(String[] args) { >- Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("GraphJFaceSnippet2"); >- shell.setLayout(new FillLayout(SWT.VERTICAL)); >- shell.setSize(400, 400); >- viewer = new GraphViewer(shell, SWT.NONE); >- viewer.setContentProvider(new MyContentProvider()); >- viewer.setLabelProvider(new MyLabelProvider()); >- viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING)); >- viewer.setInput(new Object()); >- >- Button button = new Button(shell, SWT.PUSH); >- button.setText("push"); >- button.addSelectionListener(new SelectionListener() { >- >- public void widgetDefaultSelected(SelectionEvent e) { >- } >- >- public void widgetSelected(SelectionEvent e) { >- viewer.setInput(new Object()); >- } >- >- }); >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- >- } >- >-} >Index: src/org/eclipse/zest/tests/jface/GraphJFaceSnippet5.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/jface/GraphJFaceSnippet5.java >diff -N src/org/eclipse/zest/tests/jface/GraphJFaceSnippet5.java >--- src/org/eclipse/zest/tests/jface/GraphJFaceSnippet5.java 12 Sep 2007 20:44:36 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,141 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.jface; >- >-import org.eclipse.jface.viewers.LabelProvider; >-import org.eclipse.jface.viewers.Viewer; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >-import org.eclipse.zest.core.viewers.GraphViewer; >-import org.eclipse.zest.core.viewers.IGraphContentProvider; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.events.SelectionAdapter; >-import org.eclipse.swt.events.SelectionEvent; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.layout.GridData; >-import org.eclipse.swt.layout.GridLayout; >-import org.eclipse.swt.widgets.Button; >-import org.eclipse.swt.widgets.Composite; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >- >-/** >- * This snippet shows how the refresh works on a Zest viewer. >- */ >-public class GraphJFaceSnippet5 { >- >- static class MyContentProvider implements IGraphContentProvider { >- >- Object[] elements = new Object[] { "Rock2Paper", "Paper2Scissors", "Scissors2Rock" }; >- >- public Object getDestination(Object rel) { >- if ("Rock2Paper".equals(rel)) { >- return "Rock"; >- } else if ("Paper2Scissors".equals(rel) || "Scissors2Paper".equals(rel)) { >- return "Paper"; >- } else if ("Scissors2Rock".equals(rel)) { >- return "Scissors"; >- } >- return null; >- } >- >- public Object[] getElements(Object input) { >- return elements; >- } >- >- public Object getSource(Object rel) { >- if ("Rock2Paper".equals(rel)) { >- return "Paper"; >- } else if ("Paper2Scissors".equals(rel) || "Scissors2Paper".equals(rel)) { >- return "Scissors"; >- } else if ("Scissors2Rock".equals(rel)) { >- return "Rock"; >- } >- return null; >- } >- >- public void setElements(Object[] elements) { >- this.elements = elements; >- } >- >- public double getWeight(Object connection) { >- return 0; >- } >- >- public void dispose() { >- } >- >- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { >- } >- >- } >- >- static class MyLabelProvider extends LabelProvider { >- final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >- >- public MyLabelProvider() { >- >- } >- >- public String getText(Object element) { >- return element.toString(); >- } >- >- public Image getImage(Object element) { >- return image; >- } >- } >- >- static GraphViewer viewer = null; >- private static MyContentProvider contentProvider; >- >- /** >- * @param args >- */ >- public static void main(String[] args) { >- Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("GraphJFaceSnippet2"); >- shell.setLayout(new FillLayout(SWT.VERTICAL)); >- shell.setSize(400, 400); >- Composite parent = new Composite(shell, SWT.NONE); >- parent.setLayout(new GridLayout(2, false)); >- buildViewer(parent); >- buildButton(parent); >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- >- } >- >- private static void buildButton(Composite parent) { >- Button button = new Button(parent, SWT.PUSH); >- button.setText("Refresh"); >- button.addSelectionListener(new SelectionAdapter() { >- public void widgetSelected(SelectionEvent e) { >- contentProvider.setElements(new Object[] { "Rock2Paper", "Scissors2Paper", "Scissors2Rock" }); >- viewer.refresh(); >- } >- }); >- } >- >- private static void buildViewer(Composite parent) { >- viewer = new GraphViewer(parent, SWT.NONE); >- viewer.getGraphControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); >- contentProvider = new MyContentProvider(); >- viewer.setContentProvider(contentProvider); >- viewer.setLabelProvider(new MyLabelProvider()); >- viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm()); >- viewer.setInput(new Object()); >- } >-} >Index: src/org/eclipse/zest/tests/jface/GraphJFaceSnippet2.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/test/org.eclipse.zest.tests/src/org/eclipse/zest/tests/jface/GraphJFaceSnippet2.java,v >retrieving revision 1.2 >diff -u -r1.2 GraphJFaceSnippet2.java >--- src/org/eclipse/zest/tests/jface/GraphJFaceSnippet2.java 12 Sep 2007 20:44:36 -0000 1.2 >+++ src/org/eclipse/zest/tests/jface/GraphJFaceSnippet2.java 28 Aug 2009 16:03:12 -0000 >@@ -1,17 +1,18 @@ > /******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, > * Canada. All rights reserved. This program and the accompanying materials are > * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html > * >- * Contributors: The Chisel Group, University of Victoria >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 > ******************************************************************************/ > package org.eclipse.zest.tests.jface; > > import org.eclipse.jface.viewers.LabelProvider; > import org.eclipse.jface.viewers.Viewer; >-import org.eclipse.zest.layouts.LayoutStyles; > import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; > import org.eclipse.zest.core.viewers.GraphViewer; > import org.eclipse.zest.core.viewers.IGraphContentProvider; >@@ -107,7 +108,7 @@ > viewer = new GraphViewer(shell, SWT.NONE); > viewer.setContentProvider(new MyContentProvider()); > viewer.setLabelProvider(new MyLabelProvider()); >- viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING)); >+ viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm()); > viewer.setInput(new Object()); > shell.open(); > while (!shell.isDisposed()) { >Index: src/org/eclipse/zest/tests/jface/GraphJFaceSnippet4.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/jface/GraphJFaceSnippet4.java >diff -N src/org/eclipse/zest/tests/jface/GraphJFaceSnippet4.java >--- src/org/eclipse/zest/tests/jface/GraphJFaceSnippet4.java 12 Sep 2007 20:44:36 -0000 1.2 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,133 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.jface; >- >-import java.util.Iterator; >- >-import org.eclipse.jface.viewers.ISelectionChangedListener; >-import org.eclipse.jface.viewers.LabelProvider; >-import org.eclipse.jface.viewers.SelectionChangedEvent; >-import org.eclipse.jface.viewers.StructuredSelection; >-import org.eclipse.jface.viewers.Viewer; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >-import org.eclipse.zest.core.viewers.GraphViewer; >-import org.eclipse.zest.core.viewers.IGraphContentProvider; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >- >-public class GraphJFaceSnippet4 { >- static class MyContentProvider implements IGraphContentProvider { >- >- public Object getDestination(Object rel) { >- if ("Rock2Paper".equals(rel)) { >- return "Rock"; >- } else if ("Paper2Scissors".equals(rel)) { >- return "Paper"; >- } else if ("Scissors2Rock".equals(rel)) { >- return "Scissors"; >- } >- return null; >- } >- >- public Object[] getElements(Object input) { >- return new Object[] { "Rock2Paper", "Paper2Scissors", "Scissors2Rock" }; >- } >- >- public Object getSource(Object rel) { >- if ("Rock2Paper".equals(rel)) { >- return "Paper"; >- } else if ("Paper2Scissors".equals(rel)) { >- return "Scissors"; >- } else if ("Scissors2Rock".equals(rel)) { >- return "Rock"; >- } >- return null; >- } >- >- public double getWeight(Object connection) { >- return 0; >- } >- >- public void dispose() { >- } >- >- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { >- } >- >- } >- >- static class MyLabelProvider extends LabelProvider { >- final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >- >- public Image getImage(Object element) { >- if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) { >- return image; >- } >- return null; >- } >- >- public String getText(Object element) { >- return element.toString(); >- } >- >- } >- >- static GraphViewer viewer = null; >- >- /** >- * @param args >- */ >- public static void main(String[] args) { >- Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("GraphJFaceSnippet2"); >- shell.setLayout(new FillLayout(SWT.VERTICAL)); >- shell.setSize(400, 400); >- viewer = new GraphViewer(shell, SWT.NONE); >- viewer.setContentProvider(new MyContentProvider()); >- viewer.setLabelProvider(new MyLabelProvider()); >- viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING)); >- viewer.setInput(new Object()); >- viewer.addSelectionChangedListener(new ISelectionChangedListener() { >- >- public void selectionChanged(SelectionChangedEvent event) { >- System.out.println("Selection Changed: " + selectionToString((StructuredSelection) event.getSelection())); >- } >- >- private String selectionToString(StructuredSelection selection) { >- StringBuffer stringBuffer = new StringBuffer(); >- Iterator iterator = selection.iterator(); >- boolean first = true; >- while (iterator.hasNext()) { >- if (first) { >- first = false; >- } else { >- stringBuffer.append(" : "); >- } >- stringBuffer.append(iterator.next()); >- } >- return stringBuffer.toString(); >- } >- >- }); >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- >- } >- >-} >Index: src/org/eclipse/zest/tests/jface/GraphJFaceSnippet6.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/jface/GraphJFaceSnippet6.java >diff -N src/org/eclipse/zest/tests/jface/GraphJFaceSnippet6.java >--- src/org/eclipse/zest/tests/jface/GraphJFaceSnippet6.java 20 Nov 2008 00:13:06 -0000 1.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,147 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.tests.jface; >- >- >-import org.eclipse.jface.viewers.LabelProvider; >-import org.eclipse.jface.viewers.Viewer; >-import org.eclipse.swt.SWT; >-import org.eclipse.swt.events.SelectionEvent; >-import org.eclipse.swt.events.SelectionListener; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.layout.FillLayout; >-import org.eclipse.swt.widgets.Button; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Shell; >-import org.eclipse.zest.core.viewers.EntityConnectionData; >-import org.eclipse.zest.core.viewers.GraphViewer; >-import org.eclipse.zest.core.viewers.IGraphEntityContentProvider; >-import org.eclipse.zest.core.viewers.INestedContentProvider; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >- >-/** >- * This snippet shows how to use the INestedGraphContentProvider to create a graph >- * with Zest. In this example, getElements returns 3 edges: * Rock2Paper * >- * Paper2Scissors * Scissors2Rock >- * >- * And for each of these, the source and destination are returned in getSource >- * and getDestination. >- * >- * A label provider is also used to create the text and icons for the graph. >- * >- * @author Ian Bull >- * >- */ >-public class GraphJFaceSnippet6 { >- >- static class MyContentProvider implements IGraphEntityContentProvider, INestedContentProvider { >- >- public Object[] getConnectedTo(Object entity) { >- if (entity.equals("First")) { >- return new Object[] { "Second" }; >- } >- if (entity.equals("Second")) { >- return new Object[] { "Third", "rock" }; >- } >- if (entity.equals("Third")) { >- return new Object[] { "First" }; >- } >- if ( entity.equals("rock")) { >- return new Object[] { "paper" }; >- } >- return null; >- } >- >- public Object[] getElements(Object inputElement) { >- return new String[] { "First", "Second", "Third" }; >- } >- >- public double getWeight(Object entity1, Object entity2) { >- return 0; >- } >- >- public void dispose() { >- >- } >- >- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { >- >- } >- >- public Object[] getChildren(Object element) { >- // TODO Auto-generated method stub >- return new Object[] {"rock", "paper", "scissors"}; >- } >- >- public boolean hasChildren(Object element) { >- // TODO Auto-generated method stub >- if ( element.equals("First")) return true; >- return false; >- } >- >- } >- >- static class MyLabelProvider extends LabelProvider { >- final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >- >- public Image getImage(Object element) { >- if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) { >- return image; >- } >- return null; >- } >- >- public String getText(Object element) { >- if ( element instanceof EntityConnectionData ) return ""; >- return element.toString(); >- } >- >- } >- >- static GraphViewer viewer = null; >- >- /** >- * @param args >- */ >- public static void main(String[] args) { >- Display d = new Display(); >- Shell shell = new Shell(d); >- shell.setText("GraphJFaceSnippet2"); >- shell.setLayout(new FillLayout(SWT.VERTICAL)); >- shell.setSize(400, 400); >- viewer = new GraphViewer(shell, SWT.NONE); >- viewer.setContentProvider(new MyContentProvider()); >- viewer.setLabelProvider(new MyLabelProvider()); >- viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING)); >- viewer.setInput(new Object()); >- >- Button button = new Button(shell, SWT.PUSH); >- button.setText("push"); >- button.addSelectionListener(new SelectionListener() { >- >- public void widgetDefaultSelected(SelectionEvent e) { >- } >- >- public void widgetSelected(SelectionEvent e) { >- viewer.setInput(new Object()); >- } >- >- }); >- shell.open(); >- while (!shell.isDisposed()) { >- while (!d.readAndDispatch()) { >- d.sleep(); >- } >- } >- >- } >- >-} >Index: src/org/eclipse/zest/tests/swt/TreeLayoutExample.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/TreeLayoutExample.java >diff -N src/org/eclipse/zest/tests/swt/TreeLayoutExample.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/TreeLayoutExample.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,160 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import java.util.List; >+ >+import org.eclipse.jface.action.Action; >+import org.eclipse.jface.action.MenuManager; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.SelectionAdapter; >+import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.layout.GridData; >+import org.eclipse.swt.layout.GridLayout; >+import org.eclipse.swt.widgets.Button; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.DAGExpandCollapseManager; >+import org.eclipse.zest.core.widgets.DefaultSubgraph; >+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; >+import org.eclipse.zest.core.widgets.ZestStyles; >+import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; >+ >+public class TreeLayoutExample { >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ // Create the shell >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("Tree Layout Example"); >+ GridLayout gridLayout = new GridLayout(); >+ gridLayout.numColumns = 10; >+ shell.setLayout(gridLayout); >+ shell.setSize(500, 500); >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ final TreeLayoutAlgorithm algorithm = new TreeLayoutAlgorithm(); >+ g >+ .setSubgraphFactory(new DefaultSubgraph.PrunedSuccessorsSubgraphFactory()); >+ g.setLayoutAlgorithm(algorithm, false); >+ g.setExpandCollapseManager(new DAGExpandCollapseManager()); >+ >+ >+ g.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 10, 10)); >+ g.setSize(500, 500); >+ >+ GraphNode root = new GraphNode(g, SWT.NONE, "Root"); >+ >+ GraphNode lastNode = null; >+ for (int i = 0; i < 3; i++) { >+ GraphNode n = new GraphNode(g, SWT.NONE, "1 - " + i); >+ if (lastNode != null) >+ new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, n, >+ lastNode); >+ for (int j = 0; j < 1; j++) { >+ GraphNode n2 = new GraphNode(g, SWT.NONE, "2 - " + j); >+ GraphConnection c = new GraphConnection(g, >+ ZestStyles.CONNECTIONS_DIRECTED, n, n2); >+ c.setWeight(-1); >+ c.setDirected(true); >+ lastNode = n2; >+ } >+ >+ new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, root, n); >+ } >+ >+ >+ hookMenu(g); >+ >+ final Button buttonTopDown = new Button(shell, SWT.FLAT); >+ buttonTopDown.setText("TOP_DOWN"); >+ >+ final Button buttonBottomUp = new Button(shell, SWT.FLAT); >+ buttonBottomUp.setText("BOTTOM_UP"); >+ buttonBottomUp.setLayoutData(new GridData()); >+ >+ final Button buttonLeftRight = new Button(shell, SWT.FLAT); >+ buttonLeftRight.setText("LEFT_RIGHT"); >+ >+ final Button buttonRightLeft = new Button(shell, SWT.FLAT); >+ buttonRightLeft.setText("RIGHT_LEFT"); >+ >+ SelectionAdapter buttonListener = new SelectionAdapter() { >+ public void widgetSelected(SelectionEvent e) { >+ if (e.widget == buttonTopDown) >+ algorithm.setDirection(TreeLayoutAlgorithm.TOP_DOWN); >+ if (e.widget == buttonBottomUp) >+ algorithm.setDirection(TreeLayoutAlgorithm.BOTTOM_UP); >+ if (e.widget == buttonLeftRight) >+ algorithm.setDirection(TreeLayoutAlgorithm.LEFT_RIGHT); >+ if (e.widget == buttonRightLeft) >+ algorithm.setDirection(TreeLayoutAlgorithm.RIGHT_LEFT); >+ >+ g.applyLayout(); >+ } >+ }; >+ buttonTopDown.addSelectionListener(buttonListener); >+ buttonBottomUp.addSelectionListener(buttonListener); >+ buttonLeftRight.addSelectionListener(buttonListener); >+ buttonRightLeft.addSelectionListener(buttonListener); >+ >+ final Button resizeButton = new Button(shell, SWT.CHECK); >+ resizeButton.setText("Resize"); >+ resizeButton.addSelectionListener(new SelectionAdapter() { >+ public void widgetSelected(SelectionEvent e) { >+ algorithm.setResizing(resizeButton.getSelection()); >+ } >+ }); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ } >+ >+ private static void hookMenu(final Graph g) { >+ MenuManager menuMgr = new MenuManager("#PopupMenu"); >+ >+ Action expandAction = new Action() { >+ public void run() { >+ List selection = g.getSelection(); >+ if (!selection.isEmpty()) { >+ GraphNode selected = (GraphNode) selection.get(0); >+ g.setExpanded((GraphNode) selected, true); >+ } >+ } >+ }; >+ expandAction.setText("expand"); >+ menuMgr.add(expandAction); >+ >+ Action collapseAction = new Action() { >+ public void run() { >+ List selection = g.getSelection(); >+ if (!selection.isEmpty()) { >+ GraphItem selected = (GraphItem) selection.get(0); >+ g.setExpanded((GraphNode) selected, false); >+ } >+ } >+ }; >+ collapseAction.setText("collapse"); >+ menuMgr.add(collapseAction); >+ >+ g.setMenu(menuMgr.createContextMenu(g)); >+ } >+} >Index: src/org/eclipse/zest/tests/swt/IconsGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/IconsGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/IconsGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/IconsGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,72 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.core.widgets.ZestStyles; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+ >+/** >+ * This snippet creates a very simple graph with an Icon and Label. >+ * >+ * This snippet shows how to use directed edges and self loops. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class IconsGraphSnippet { >+ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION); >+ Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >+ Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ Graph g = new Graph(shell, SWT.NONE); >+ g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED); >+ GraphNode n1 = new GraphNode(g, SWT.NONE); >+ n1.setText("Information"); >+ n1.setImage(image1); >+ GraphNode n2 = new GraphNode(g, SWT.NONE); >+ n2.setText("Warning"); >+ n2.setImage(image2); >+ GraphNode n3 = new GraphNode(g, SWT.NONE); >+ n3.setText("Error"); >+ n3.setImage(image3); >+ >+ new GraphConnection(g, SWT.NONE, n1, n2); >+ new GraphConnection(g, SWT.NONE, n2, n3); >+ new GraphConnection(g, SWT.NONE, n3, n3); >+ >+ g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ image1.dispose(); >+ image2.dispose(); >+ image3.dispose(); >+ } >+} >Index: .refactorings/2009/8/35/refactorings.index >=================================================================== >RCS file: .refactorings/2009/8/35/refactorings.index >diff -N .refactorings/2009/8/35/refactorings.index >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ .refactorings/2009/8/35/refactorings.index 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,5 @@ >+1251471945100 Delete element >+1251472688225 Delete element >+1251472860601 Delete elements >+1251472916946 Delete element >+1251473212253 Delete elements >Index: src/org/eclipse/zest/tests/swt/CurvedEdgeGraphSnippet2.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/CurvedEdgeGraphSnippet2.java >diff -N src/org/eclipse/zest/tests/swt/CurvedEdgeGraphSnippet2.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/CurvedEdgeGraphSnippet2.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,69 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.draw2d.ColorConstants; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.graphics.Color; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+ >+/** >+ * >+ * This snippet shows how to create a curved connection using Zest. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class CurvedEdgeGraphSnippet2 { >+ >+ >+ public static void createConnection( Graph g, GraphNode n1, GraphNode n2, Color color, int curve) { >+ GraphConnection connection = new GraphConnection(g, SWT.NONE, n1, n2); >+ connection.setLineColor(color); >+ connection.setCurveDepth(curve); >+ connection.setLineWidth(1); >+ } >+ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet11"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ GraphNode n = new GraphNode(g, SWT.NONE, "Node 1"); >+ GraphNode n2 = new GraphNode(g, SWT.NONE, "Node 2"); >+ createConnection(g, n, n2, ColorConstants.darkGreen, 20); >+ createConnection(g, n, n2, ColorConstants.darkGreen, -20); >+ createConnection(g, n, n2, ColorConstants.darkBlue, 40); >+ createConnection(g, n, n2, ColorConstants.darkBlue, -40); >+ createConnection(g, n, n2, ColorConstants.darkGray, 60); >+ createConnection(g, n, n2, ColorConstants.darkGray, -60); >+ createConnection(g, n, n2, ColorConstants.black, 0); >+ g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ } >+ >+} >Index: src/org/eclipse/zest/tests/swt/ContainerResizeGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/ContainerResizeGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/ContainerResizeGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/ContainerResizeGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,174 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.KeyEvent; >+import org.eclipse.swt.events.KeyListener; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+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.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.algorithms.CompositeLayoutAlgorithm; >+import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm; >+import org.eclipse.zest.layouts.algorithms.HorizontalShiftAlgorithm; >+import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm; >+import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; >+ >+public class ContainerResizeGraphSnippet { >+ >+ private static Image image1; >+ private static Image classImage; >+ >+ public static void createContainer(Graph g) { >+ GraphContainer a = new GraphContainer(g, SWT.NONE); >+ a.setText("SomeClass.java"); >+ a.setImage(classImage); >+ int r = (int) ((Math.random() * 3) + 1); >+ r = 2; >+ populateContainer(a, g, r, true); >+ for (int i = 0; i < 4; i++) { >+ GraphContainer b = new GraphContainer(g, SWT.NONE); >+ b.setText("SomeTestedClass.java"); >+ b.setImage(classImage); >+ r = (int) ((Math.random() * 3) + 1); >+ r = 2; >+ populateContainer(b, g, r, false); >+ new GraphConnection(g, SWT.NONE, a, b); >+ for (int j = 0; j < 4; j++) { >+ GraphContainer c = new GraphContainer(g, SWT.NONE); >+ c.setText("DefaultAction.java"); >+ c.setImage(classImage); >+ r = (int) ((Math.random() * 3) + 1); >+ r = 2; >+ populateContainer(c, g, r, true); >+ new GraphConnection(g, SWT.NONE, b, c); >+ } >+ } >+ } >+ >+ public static void populateContainer(GraphContainer c, Graph g, int number, boolean radial) { >+ GraphNode a = new GraphNode(c, ZestStyles.NODES_FISHEYE >+ | ZestStyles.NODES_HIDE_TEXT); >+ a.setText("SomeClass.java"); >+ a.setImage(classImage); >+ for (int i = 0; i < 4; i++) { >+ GraphNode b = new GraphNode(c, ZestStyles.NODES_FISHEYE >+ | ZestStyles.NODES_HIDE_TEXT); >+ b.setText("SomeNestedClass.java"); >+ b.setImage(classImage); >+ new GraphConnection(g, SWT.NONE, a, b); >+ for (int j = 0; j < 4; j++) { >+ GraphNode d = new GraphNode(c, ZestStyles.NODES_FISHEYE >+ | ZestStyles.NODES_HIDE_TEXT); >+ d.setText("DefaultAction.java"); >+ d.setImage(classImage); >+ new GraphConnection(g, SWT.NONE, b, d); >+ if (number > 2) { >+ for (int k = 0; k < 4; k++) { >+ GraphNode e = new GraphNode(c, ZestStyles.NODES_FISHEYE >+ | ZestStyles.NODES_HIDE_TEXT); >+ e.setText("LastAction(Hero).java"); >+ e.setImage(classImage); >+ new GraphConnection(g, SWT.NONE, d, e); >+ if (number > 3) { >+ for (int l = 0; l < 4; l++) { >+ GraphNode f = new GraphNode(c, >+ ZestStyles.NODES_FISHEYE >+ | ZestStyles.NODES_HIDE_TEXT); >+ f.setText("LastAction(Hero).java"); >+ f.setImage(classImage); >+ new GraphConnection(g, SWT.NONE, e, f); >+ } >+ } >+ } >+ } >+ } >+ } >+ if (number == 1) { >+ c.setScale(0.75); >+ } else if (number == 2) { >+ c.setScale(0.50); >+ } else { >+ c.setScale(0.25); >+ } >+ if (radial) { >+ c.setLayoutAlgorithm(new RadialLayoutAlgorithm(), true); >+ } else { >+ c.setLayoutAlgorithm(new TreeLayoutAlgorithm(), true); >+ } >+ } >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ // Create the shell >+ Display d = new Display(); >+ >+ image1 = new Image(Display.getDefault(), ContainerResizeGraphSnippet.class.getResourceAsStream("package_obj.gif")); >+ classImage = new Image(Display.getDefault(), ContainerResizeGraphSnippet.class.getResourceAsStream("class_obj.gif")); >+ >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet1"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(500, 800); >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ createContainer(g); >+ >+ CompositeLayoutAlgorithm compositeLayoutAlgorithm = new CompositeLayoutAlgorithm(new LayoutAlgorithm[] { new GridLayoutAlgorithm(), new HorizontalShiftAlgorithm() }); >+ //g.setLayoutAlgorithm(new GridLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true); >+ g.setLayoutAlgorithm(compositeLayoutAlgorithm, true); >+ >+ g.addKeyListener(new KeyListener() { >+ boolean flip = true; >+ >+ public void keyPressed(KeyEvent e) { >+ >+ if (g.getSelection().size() == 1) { >+ GraphNode item = (GraphNode) g.getSelection().get(0); >+ if (item.getItemType() == GraphItem.CONTAINER) { >+ if (flip) { >+ (item).setSize(500, 100); >+ } else { >+ (item).setSize(0, 0); >+ } >+ flip = !flip; >+ } >+ } >+ >+ } >+ >+ public void keyReleased(KeyEvent e) { >+ // TODO Auto-generated method stub >+ >+ } >+ >+ }); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ image1.dispose(); >+ } >+} >Index: src/org/eclipse/zest/tests/jface/NestedGraphJFaceSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/jface/NestedGraphJFaceSnippet.java >diff -N src/org/eclipse/zest/tests/jface/NestedGraphJFaceSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/jface/NestedGraphJFaceSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,148 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ >+package org.eclipse.zest.tests.jface; >+ >+ >+import org.eclipse.jface.viewers.LabelProvider; >+import org.eclipse.jface.viewers.Viewer; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.events.SelectionListener; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Button; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.viewers.EntityConnectionData; >+import org.eclipse.zest.core.viewers.GraphViewer; >+import org.eclipse.zest.core.viewers.IGraphEntityContentProvider; >+import org.eclipse.zest.core.viewers.INestedContentProvider; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+ >+/** >+ * This snippet shows how to use the INestedGraphContentProvider to create a graph >+ * with Zest. In this example, getElements returns 3 edges: * Rock2Paper * >+ * Paper2Scissors * Scissors2Rock >+ * >+ * And for each of these, the source and destination are returned in getSource >+ * and getDestination. >+ * >+ * A label provider is also used to create the text and icons for the graph. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class NestedGraphJFaceSnippet { >+ >+ static class MyContentProvider implements IGraphEntityContentProvider, INestedContentProvider { >+ >+ public Object[] getConnectedTo(Object entity) { >+ if (entity.equals("First")) { >+ return new Object[] { "Second" }; >+ } >+ if (entity.equals("Second")) { >+ return new Object[] { "Third", "rock" }; >+ } >+ if (entity.equals("Third")) { >+ return new Object[] { "First" }; >+ } >+ if ( entity.equals("rock")) { >+ return new Object[] { "paper" }; >+ } >+ return null; >+ } >+ >+ public Object[] getElements(Object inputElement) { >+ return new String[] { "First", "Second", "Third" }; >+ } >+ >+ public double getWeight(Object entity1, Object entity2) { >+ return 0; >+ } >+ >+ public void dispose() { >+ >+ } >+ >+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { >+ >+ } >+ >+ public Object[] getChildren(Object element) { >+ // TODO Auto-generated method stub >+ return new Object[] {"rock", "paper", "scissors"}; >+ } >+ >+ public boolean hasChildren(Object element) { >+ // TODO Auto-generated method stub >+ if ( element.equals("First")) return true; >+ return false; >+ } >+ >+ } >+ >+ static class MyLabelProvider extends LabelProvider { >+ final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >+ >+ public Image getImage(Object element) { >+ if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) { >+ return image; >+ } >+ return null; >+ } >+ >+ public String getText(Object element) { >+ if ( element instanceof EntityConnectionData ) return ""; >+ return element.toString(); >+ } >+ >+ } >+ >+ static GraphViewer viewer = null; >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphJFaceSnippet2"); >+ shell.setLayout(new FillLayout(SWT.VERTICAL)); >+ shell.setSize(400, 400); >+ viewer = new GraphViewer(shell, SWT.NONE); >+ viewer.setContentProvider(new MyContentProvider()); >+ viewer.setLabelProvider(new MyLabelProvider()); >+ viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm()); >+ viewer.setInput(new Object()); >+ >+ Button button = new Button(shell, SWT.PUSH); >+ button.setText("push"); >+ button.addSelectionListener(new SelectionListener() { >+ >+ public void widgetDefaultSelected(SelectionEvent e) { >+ } >+ >+ public void widgetSelected(SelectionEvent e) { >+ viewer.setInput(new Object()); >+ } >+ >+ }); >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ >+ } >+ >+} >Index: src/org/eclipse/zest/tests/swt/FilterGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/FilterGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/FilterGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/FilterGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,117 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.draw2d.ColorConstants; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+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; >+import org.eclipse.zest.core.widgets.LayoutFilter; >+import org.eclipse.zest.core.widgets.ZestStyles; >+import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; >+ >+/** >+ * This snippet shows how to filter elements in the layout. The Data on the tree >+ * connections are set to "False", meaning they won't be filtered. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class FilterGraphSnippet { >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ Display display = new Display(); >+ Shell shell = new Shell(display); >+ shell.setText("GraphSnippet8"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ final Graph graph = new Graph(shell, SWT.NONE); >+ >+ GraphNode a = new GraphNode(graph, SWT.NONE, "Root"); >+ GraphNode b = new GraphNode(graph, SWT.NONE, "B"); >+ GraphNode c = new GraphNode(graph, SWT.NONE, "C"); >+ GraphNode d = new GraphNode(graph, SWT.NONE, "D"); >+ GraphNode e = new GraphNode(graph, SWT.NONE, "E"); >+ GraphNode f = new GraphNode(graph, SWT.NONE, "F"); >+ GraphNode g = new GraphNode(graph, SWT.NONE, "G"); >+ GraphNode h = new GraphNode(graph, SWT.NONE, "H"); >+ GraphConnection connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, a, b); >+ connection.setData(Boolean.TRUE); >+ connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, a, c); >+ connection.setData(Boolean.TRUE); >+ connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, a, c); >+ connection.setData(Boolean.TRUE); >+ connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, a, d); >+ connection.setData(Boolean.TRUE); >+ connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, b, e); >+ connection.setData(Boolean.FALSE); >+ connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, b, f); >+ connection.setData(Boolean.FALSE); >+ connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, c, g); >+ connection.setData(Boolean.FALSE); >+ connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, d, h); >+ connection.setData(Boolean.FALSE); >+ >+ connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, b, c); >+ connection.setLineColor(ColorConstants.red); >+ connection.setLineWidth(3); >+ connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, c, d); >+ connection.setLineColor(ColorConstants.red); >+ connection.setLineWidth(3); >+ connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, e, f); >+ connection.setLineColor(ColorConstants.red); >+ connection.setLineWidth(3); >+ connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, f, g); >+ connection.setLineColor(ColorConstants.red); >+ connection.setLineWidth(3); >+ >+ connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, h, e); >+ connection.setLineColor(ColorConstants.red); >+ connection.setLineWidth(3); >+ >+ TreeLayoutAlgorithm treeLayoutAlgorithm = new TreeLayoutAlgorithm(); >+ LayoutFilter filter = new LayoutFilter() { >+ public boolean isObjectFiltered(GraphItem item) { >+ if (item instanceof GraphConnection ) { >+ GraphConnection connection = (GraphConnection) item; >+ Object data = connection.getData(); >+ if ( data != null && data instanceof Boolean ) { >+ // If the data is false, don't filter, otherwise, filter. >+ return ((Boolean) data).booleanValue(); >+ } >+ return true; >+ } >+ return false; >+ } >+ }; >+ graph.addLayoutFilter(filter); >+ graph.setLayoutAlgorithm(treeLayoutAlgorithm, true); >+ >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!display.readAndDispatch()) { >+ display.sleep(); >+ } >+ } >+ } >+ >+} >Index: src/org/eclipse/zest/tests/swt/RadialLayoutExample.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/RadialLayoutExample.java >diff -N src/org/eclipse/zest/tests/swt/RadialLayoutExample.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/RadialLayoutExample.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,55 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm; >+ >+public class RadialLayoutExample { >+ public static void main(String[] args) { >+ // Create the shell >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet1"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(500, 500); >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ g.setSize(500, 500); >+ GraphNode root = new GraphNode(g, SWT.NONE, "Root"); >+ for (int i = 0; i < 3; i++) { >+ GraphNode n = new GraphNode(g, SWT.NONE, "1 - " + i); >+ for (int j = 0; j < 3; j++) { >+ GraphNode n2 = new GraphNode(g, SWT.NONE, "2 - " + j); >+ new GraphConnection(g, SWT.NONE, n, n2).setWeight(-1); >+ } >+ new GraphConnection(g, SWT.NONE, root, n); >+ } >+ >+ final LayoutAlgorithm layoutAlgorithm = new RadialLayoutAlgorithm(); >+ >+ g.setLayoutAlgorithm(layoutAlgorithm, true); >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ } >+} >Index: src/org/eclipse/zest/tests/jface/CustomFigureGraphJFaceSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/jface/CustomFigureGraphJFaceSnippet.java >diff -N src/org/eclipse/zest/tests/jface/CustomFigureGraphJFaceSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/jface/CustomFigureGraphJFaceSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,177 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ >+package org.eclipse.zest.tests.jface; >+ >+ >+import org.eclipse.draw2d.IFigure; >+import org.eclipse.draw2d.Label; >+import org.eclipse.jface.viewers.LabelProvider; >+import org.eclipse.jface.viewers.Viewer; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.events.SelectionListener; >+import org.eclipse.swt.graphics.Font; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Button; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.viewers.EntityConnectionData; >+import org.eclipse.zest.core.viewers.GraphViewer; >+import org.eclipse.zest.core.viewers.IFigureProvider; >+import org.eclipse.zest.core.viewers.IGraphEntityContentProvider; >+import org.eclipse.zest.core.viewers.INestedContentProvider; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+import org.eclipse.zest.tests.uml.UMLClassFigure; >+ >+/** >+ * This snippet shows how to use Zest viewers with custom figures. >+ * It creates a figure containing UML representation of Table class. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class CustomFigureGraphJFaceSnippet { >+ >+ public static IFigure createClassFigure1(Font classFont, Image classImage, Image publicField, Image privateField) { >+ Label classLabel1 = new Label("Table", classImage); >+ classLabel1.setFont(classFont); >+ >+ UMLClassFigure classFigure = new UMLClassFigure(classLabel1); >+ Label attribute1 = new Label("columns: Column[]", privateField); >+ >+ Label attribute2 = new Label("rows: Row[]", privateField); >+ >+ Label method1 = new Label("getColumns(): Column[]", publicField); >+ Label method2 = new Label("getRows(): Row[]", publicField); >+ classFigure.getAttributesCompartment().add(attribute1); >+ classFigure.getAttributesCompartment().add(attribute2); >+ classFigure.getMethodsCompartment().add(method1); >+ classFigure.getMethodsCompartment().add(method2); >+ classFigure.setSize(-1, -1); >+ >+ return classFigure; >+ } >+ >+ static class MyContentProvider implements IGraphEntityContentProvider, INestedContentProvider { >+ >+ public Object[] getConnectedTo(Object entity) { >+ if (entity.equals("First")) { >+ return new Object[] { "Second" }; >+ } >+ if (entity.equals("Second")) { >+ return new Object[] { "Third", "rock" }; >+ } >+ if (entity.equals("Third")) { >+ return new Object[] { "First" }; >+ } >+ if ( entity.equals("rock")) { >+ return new Object[] { "paper" }; >+ } >+ return null; >+ } >+ >+ public Object[] getElements(Object inputElement) { >+ return new String[] { "First", "Second", "Third" }; >+ } >+ >+ public double getWeight(Object entity1, Object entity2) { >+ return 0; >+ } >+ >+ public void dispose() { >+ >+ } >+ >+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { >+ >+ } >+ >+ public Object[] getChildren(Object element) { >+ // TODO Auto-generated method stub >+ return new Object[] {"rock", "paper", "scissors"}; >+ } >+ >+ public boolean hasChildren(Object element) { >+ // TODO Auto-generated method stub >+ if ( element.equals("First")) return true; >+ return false; >+ } >+ >+ } >+ >+ >+ >+ static class MyLabelProvider extends LabelProvider implements IFigureProvider { >+ final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >+ >+ public Image getImage(Object element) { >+ if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) { >+ return image; >+ } >+ return null; >+ } >+ >+ public String getText(Object element) { >+ if ( element instanceof EntityConnectionData ) return ""; >+ return element.toString(); >+ } >+ >+ public IFigure getFigure(Object element) { >+ Font classFont = new Font(null, "Arial", 12, SWT.BOLD); >+ Image classImage = new Image(Display.getDefault(), UMLClassFigure.class.getResourceAsStream("class_obj.gif")); >+ Image privateField = new Image(Display.getDefault(), UMLClassFigure.class.getResourceAsStream("field_private_obj.gif")); >+ Image publicField= new Image(Display.getDefault(), UMLClassFigure.class.getResourceAsStream("methpub_obj.gif")); >+ return createClassFigure1(classFont, classImage, publicField, privateField); >+ } >+ >+ } >+ >+ static GraphViewer viewer = null; >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphJFaceSnippet2"); >+ shell.setLayout(new FillLayout(SWT.VERTICAL)); >+ shell.setSize(400, 400); >+ viewer = new GraphViewer(shell, SWT.NONE); >+ viewer.setContentProvider(new MyContentProvider()); >+ viewer.setLabelProvider(new MyLabelProvider()); >+ viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm()); >+ viewer.setInput(new Object()); >+ >+ Button button = new Button(shell, SWT.PUSH); >+ button.setText("push"); >+ button.addSelectionListener(new SelectionListener() { >+ >+ public void widgetDefaultSelected(SelectionEvent e) { >+ } >+ >+ public void widgetSelected(SelectionEvent e) { >+ viewer.setInput(new Object()); >+ } >+ >+ }); >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ >+ } >+ >+} >Index: src/org/eclipse/zest/tests/swt/SpringLayoutProgress.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/SpringLayoutProgress.java >diff -N src/org/eclipse/zest/tests/swt/SpringLayoutProgress.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/SpringLayoutProgress.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,103 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ * Ian Bull >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.SelectionAdapter; >+import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.layout.GridData; >+import org.eclipse.swt.layout.GridLayout; >+import org.eclipse.swt.widgets.Button; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Label; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+ >+/** >+ * >+ */ >+public class SpringLayoutProgress { >+ static Runnable r = null; >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ // Create the shell >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet1"); >+ GridLayout gridLayout = new GridLayout(); >+ gridLayout.numColumns = 5; >+ shell.setLayout(gridLayout); >+ shell.setSize(500, 500); >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ g.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 5, 5)); >+ g.setSize(500, 500); >+ GraphNode root = new GraphNode(g, SWT.NONE, "Root"); >+ for (int i = 0; i < 3; i++) { >+ GraphNode n = new GraphNode(g, SWT.NONE, "1 - " + i); >+ for (int j = 0; j < 3; j++) { >+ GraphNode n2 = new GraphNode(g, SWT.NONE, "2 - " + j); >+ new GraphConnection(g, SWT.NONE, n, n2).setWeight(-1); >+ } >+ new GraphConnection(g, SWT.NONE, root, n); >+ } >+ >+ >+ final SpringLayoutAlgorithm springLayoutAlgorithm = new SpringLayoutAlgorithm(); >+ >+ g.setLayoutAlgorithm(springLayoutAlgorithm, false); >+ >+ Button b = new Button(shell, SWT.FLAT); >+ b.setText("step"); >+ >+ final Label label = new Label(shell, SWT.LEFT); >+ label.setText("<--click"); >+ label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); >+ >+ b.addSelectionListener(new SelectionAdapter() { >+ int steps = 0; >+ public void widgetSelected(SelectionEvent e) { >+ >+ r = new Runnable() { >+ public void run() { >+ springLayoutAlgorithm.performOneIteration(); >+ g.redraw(); >+ label.setText("steps: " + ++steps); >+ try { >+ Thread.sleep(50); >+ } catch (InterruptedException e) { >+ e.printStackTrace(); >+ } >+ Display.getCurrent().asyncExec(r); >+ } >+ }; >+ Display.getCurrent().asyncExec(r); >+ >+ } >+ }); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ } >+ >+} >Index: .refactorings/2009/8/35/refactorings.history >=================================================================== >RCS file: .refactorings/2009/8/35/refactorings.history >diff -N .refactorings/2009/8/35/refactorings.history >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ .refactorings/2009/8/35/refactorings.history 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,3 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<session version="1.0">
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.tests'
- Original project: 'org.eclipse.zest.tests'
- Original element: 'org.eclipse.zest.tests.swt.LayoutExample.java'" description="Delete element" element1="/src<org.eclipse.zest.tests.swt{LayoutExample.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251471945100" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.tests'
- Original project: 'org.eclipse.zest.tests'
- Original element: 'org.eclipse.zest.tests.swt.ZoomSnippet.java'" description="Delete element" element1="/src<org.eclipse.zest.tests.swt{ZoomSnippet.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251472688225" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 12 element(s) from project 'org.eclipse.zest.tests'
- Original project: 'org.eclipse.zest.tests'
- Original elements:
 org.eclipse.zest.tests.swt.GraphSnippet1.java
 org.eclipse.zest.tests.swt.GraphSnippet10.java
 org.eclipse.zest.tests.swt.GraphSnippet11.java
 org.eclipse.zest.tests.swt.GraphSnippet12.java
 org.eclipse.zest.tests.swt.GraphSnippet13.java
 org.eclipse.zest.tests.swt.GraphSnippet2.java
 org.eclipse.zest.tests.swt.GraphSnippet3.java
 org.eclipse.zest.tests.swt.GraphSnippet4.java
 org.eclipse.zest.tests.swt.GraphSnippet5.java
 org.eclipse.zest.tests.swt.GraphSnippet6.java
 org.eclipse.zest.tests.swt.GraphSnippet7.java
 org.eclipse.zest.tests.swt.GraphSnippet8.java" description="Delete elements" element1="/src<org.eclipse.zest.tests.swt{GraphSnippet12.java" element10="/src<org.eclipse.zest.tests.swt{GraphSnippet8.java" element11="/src<org.eclipse.zest.tests.swt{GraphSnippet5.java" element12="/src<org.eclipse.zest.tests.swt{GraphSnippet11.java" element2="/src<org.eclipse.zest.tests.swt{GraphSnippet10.java" element3="/src<org.eclipse.zest.tests.swt{GraphSnippet7.java" element4="/src<org.eclipse.zest.tests.swt{GraphSnippet13.java" element5="/src<org.eclipse.zest.tests.swt{GraphSnippet4.java" element6="/src<org.eclipse.zest.tests.swt{GraphSnippet1.java" element7="/src<org.eclipse.zest.tests.swt{GraphSnippet2.java" element8="/src<org.eclipse.zest.tests.swt{GraphSnippet6.java" element9="/src<org.eclipse.zest.tests.swt{GraphSnippet3.java" elements="12" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251472860601" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.tests'
- Original project: 'org.eclipse.zest.tests'
- Original element: 'org.eclipse.zest.tests.swt.GraphSnippet9.java'" description="Delete element" element1="/src<org.eclipse.zest.tests.swt{GraphSnippet9.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251472916946" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 5 element(s) from project 'org.eclipse.zest.tests'
- Original project: 'org.eclipse.zest.tests'
- Original elements:
 org.eclipse.zest.tests.jface.GraphJFaceSnippet3.java
 org.eclipse.zest.tests.jface.GraphJFaceSnippet4.java
 org.eclipse.zest.tests.jface.GraphJFaceSnippet5.java
 org.eclipse.zest.tests.jface.GraphJFaceSnippet6.java
 org.eclipse.zest.tests.jface.GraphJFaceSnippet7.java" description="Delete elements" element1="/src<org.eclipse.zest.tests.jface{GraphJFaceSnippet5.java" element2="/src<org.eclipse.zest.tests.jface{GraphJFaceSnippet3.java" element3="/src<org.eclipse.zest.tests.jface{GraphJFaceSnippet4.java" element4="/src<org.eclipse.zest.tests.jface{GraphJFaceSnippet6.java" element5="/src<org.eclipse.zest.tests.jface{GraphJFaceSnippet7.java" elements="5" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251473212253" subPackages="false" version="1.0"/> >+</session> >\ No newline at end of file >Index: src/org/eclipse/zest/tests/swt/SelfLoopGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/SelfLoopGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/SelfLoopGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/SelfLoopGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,56 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.core.widgets.ZestStyles; >+ >+/** >+ * This snippet demonstrates a self loop with a label. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class SelfLoopGraphSnippet { >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ Display display = new Display(); >+ Shell shell = new Shell(display); >+ shell.setText("GraphSnippet9"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ final Graph graph = new Graph(shell, SWT.NONE); >+ >+ GraphNode a = new GraphNode(graph, ZestStyles.CONNECTIONS_DIRECTED, "Root"); >+ GraphConnection connection = new GraphConnection(graph, SWT.NONE, a, a); >+ connection.setText("A to A"); >+ a.setLocation(100, 100); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!display.readAndDispatch()) { >+ display.sleep(); >+ } >+ } >+ } >+ >+} >Index: src/org/eclipse/zest/tests/swt/DAGExample.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/DAGExample.java >diff -N src/org/eclipse/zest/tests/swt/DAGExample.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/DAGExample.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,145 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * Ian Bull >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import java.util.List; >+ >+import org.eclipse.jface.action.Action; >+import org.eclipse.jface.action.MenuManager; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.SelectionAdapter; >+import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.layout.GridData; >+import org.eclipse.swt.layout.GridLayout; >+import org.eclipse.swt.widgets.Button; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.DAGExpandCollapseManager; >+import org.eclipse.zest.core.widgets.DefaultSubgraph; >+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; >+import org.eclipse.zest.core.widgets.ZestStyles; >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.algorithms.DirectedGraphLayoutAlgorithm; >+ >+public class DAGExample { >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ // Create the shell >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet1"); >+ GridLayout gridLayout = new GridLayout(); >+ gridLayout.numColumns = 10; >+ shell.setLayout(gridLayout); >+ shell.setSize(500, 500); >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ // LayoutAlgorithm algorithm = new CompositeLayoutAlgorithm( >+ // new LayoutAlgorithm[] { new DirectedGraphLayoutAlgorithm(), >+ // new HorizontalShiftAlgorithm() }); >+ LayoutAlgorithm algorithm = new DirectedGraphLayoutAlgorithm(); >+ >+ g.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 10, 10)); >+ g.setSize(500, 500); >+ >+ g >+ .setSubgraphFactory(new DefaultSubgraph.PrunedSuccessorsSubgraphFactory()); >+ g.setLayoutAlgorithm(algorithm, false); >+ final DAGExpandCollapseManager dagExpandCollapseManager = new DAGExpandCollapseManager(); >+ g.setExpandCollapseManager(dagExpandCollapseManager); >+ >+ GraphNode root = new GraphNode(g, SWT.NONE, "Root"); >+ GraphNode a = new GraphNode(g, SWT.NONE, "A"); >+ GraphNode b = new GraphNode(g, SWT.NONE, "B"); >+ GraphNode c = new GraphNode(g, SWT.NONE, "C"); >+ GraphNode e = new GraphNode(g, SWT.NONE, "D"); >+ >+ GraphNode f = new GraphNode(g, SWT.NONE, "E"); >+ GraphNode h = new GraphNode(g, SWT.NONE, "F"); >+ >+ new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, root, a); >+ new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, root, b); >+ new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, root, c); >+ new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, a, c); >+ new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, c, e); >+ >+ new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, e, f); >+ new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, e, h); >+ new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, root, h); >+ >+ hookMenu(g); >+ >+ final Button buttonApply = new Button(shell, SWT.FLAT); >+ buttonApply.setText("Apply"); >+ >+ SelectionAdapter buttonListener = new SelectionAdapter() { >+ public void widgetSelected(SelectionEvent e) { >+ g.applyLayout(); >+ } >+ }; >+ buttonApply.addSelectionListener(buttonListener); >+ >+ final Button buttonHideAll = new Button(shell, SWT.CHECK); >+ buttonHideAll.setText("Hide all connections of collapsed nodes"); >+ >+ buttonListener = new SelectionAdapter() { >+ public void widgetSelected(SelectionEvent e) { >+ dagExpandCollapseManager.setHidingConnections(buttonHideAll >+ .getSelection()); >+ } >+ }; >+ buttonHideAll.addSelectionListener(buttonListener); >+ >+ >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ } >+ >+ private static void hookMenu(final Graph g) { >+ MenuManager menuMgr = new MenuManager("#PopupMenu"); >+ >+ Action expandAction = new Action() { >+ public void run() { >+ List selection = g.getSelection(); >+ if (!selection.isEmpty()) { >+ GraphNode selected = (GraphNode) selection.get(0); >+ g.setExpanded((GraphNode) selected, true); >+ } >+ } >+ }; >+ expandAction.setText("expand"); >+ menuMgr.add(expandAction); >+ >+ Action collapseAction = new Action() { >+ public void run() { >+ List selection = g.getSelection(); >+ if (!selection.isEmpty()) { >+ GraphItem selected = (GraphItem) selection.get(0); >+ g.setExpanded((GraphNode) selected, false); >+ } >+ } >+ }; >+ collapseAction.setText("collapse"); >+ menuMgr.add(collapseAction); >+ >+ g.setMenu(menuMgr.createContextMenu(g)); >+ } >+} >Index: src/org/mati/zest/examples/SpaceTreeBuilding.java >=================================================================== >RCS file: src/org/mati/zest/examples/SpaceTreeBuilding.java >diff -N src/org/mati/zest/examples/SpaceTreeBuilding.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/mati/zest/examples/SpaceTreeBuilding.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,120 @@ >+package org.mati.zest.examples; >+ >+import java.util.List; >+ >+import org.eclipse.jface.action.Action; >+import org.eclipse.jface.action.MenuManager; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.DefaultSubgraph; >+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; >+import org.eclipse.zest.layouts.algorithms.SpaceTreeLayoutAlgorithm; >+ >+/** >+ * This example shows how SpringLayoutAlgorithm reacts to graph structure >+ * related events, automatically rebuilding trees every time a new connection is >+ * added. >+ */ >+public class SpaceTreeBuilding { >+ private static GraphNode parentNode = null; >+ private static GraphNode childNode = null; >+ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet1"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ >+ hookMenu(g); >+ >+ SpaceTreeLayoutAlgorithm spaceTreeLayoutAlgorithm = new SpaceTreeLayoutAlgorithm(); >+ g.setLayoutAlgorithm(spaceTreeLayoutAlgorithm, false); >+ g.setExpandCollapseManager(spaceTreeLayoutAlgorithm >+ .getExpandCollapseManager()); >+ >+ g.setSubgraphFactory(new DefaultSubgraph.LabelSubgraphFactory()); >+ >+ for (int i = 0; i < 20; i++) { >+ GraphNode graphNode = new GraphNode(g, SWT.NONE); >+ graphNode.setText("" + i); >+ } >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ } >+ >+ private static void tryToAddConnection(Graph g) { >+ if (parentNode != null && childNode != null) { >+ new GraphConnection(g, SWT.NONE, parentNode, childNode); >+ parentNode = childNode = null; >+ } >+ } >+ >+ private static void hookMenu(final Graph g) { >+ MenuManager menuMgr = new MenuManager("#PopupMenu"); >+ >+ Action parentAction = new Action() { >+ public void run() { >+ List selection = g.getSelection(); >+ if (!selection.isEmpty()) { >+ GraphNode selected = (GraphNode) selection.get(0); >+ parentNode = selected; >+ tryToAddConnection(g); >+ } >+ } >+ }; >+ parentAction.setText("use as parent"); >+ menuMgr.add(parentAction); >+ >+ Action childAction = new Action() { >+ public void run() { >+ List selection = g.getSelection(); >+ if (!selection.isEmpty()) { >+ GraphNode selected = (GraphNode) selection.get(0); >+ childNode = selected; >+ tryToAddConnection(g); >+ } >+ } >+ }; >+ childAction.setText("use as child"); >+ menuMgr.add(childAction); >+ >+ Action expandAction = new Action() { >+ public void run() { >+ List selection = g.getSelection(); >+ if (!selection.isEmpty()) { >+ GraphNode selected = (GraphNode) selection.get(0); >+ g.setExpanded((GraphNode) selected, true); >+ } >+ } >+ }; >+ expandAction.setText("expand"); >+ menuMgr.add(expandAction); >+ >+ Action collapseAction = new Action() { >+ public void run() { >+ List selection = g.getSelection(); >+ if (!selection.isEmpty()) { >+ GraphItem selected = (GraphItem) selection.get(0); >+ g.setExpanded((GraphNode) selected, false); >+ } >+ } >+ }; >+ collapseAction.setText("collapse"); >+ menuMgr.add(collapseAction); >+ >+ g.setMenu(menuMgr.createContextMenu(g)); >+ } >+} >Index: src/org/eclipse/zest/tests/swt/ConnectionToolTipGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/ConnectionToolTipGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/ConnectionToolTipGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/ConnectionToolTipGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,110 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.draw2d.IFigure; >+import org.eclipse.draw2d.Label; >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.core.widgets.ZestStyles; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.graphics.GC; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+ >+/** >+ * This snippet shows how a custom figure can be used as a ToolTip for connections. >+ * Let your mouse hover over an edge to see the custom tooltip. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class ConnectionToolTipGraphSnippet { >+ >+ >+ /** >+ * Merges 2 images so they appear beside each other >+ * >+ * You must dispose this image! >+ * @param image1 >+ * @param image2 >+ * @param result >+ * @return >+ */ >+ public static Image mergeImages(Image image1, Image image2) { >+ Image mergedImage = new Image(Display.getDefault(), image1.getBounds().width + image2.getBounds().width, image1.getBounds().height); >+ GC gc = new GC(mergedImage); >+ gc.drawImage(image1, 0, 0); >+ gc.drawImage(image2, image1.getBounds().width, 0); >+ gc.dispose(); >+ return mergedImage; >+ } >+ >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("Graph Snippet 4"); >+ Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION); >+ Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >+ Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ Graph g = new Graph(shell, SWT.NONE); >+ g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED ); >+ GraphNode n1 = new GraphNode(g, SWT.NONE); >+ n1.setText("Information"); >+ n1.setImage(image1); >+ GraphNode n2 = new GraphNode(g, SWT.NONE); >+ n2.setText("Warning"); >+ n2.setImage(image2); >+ GraphNode n3 = new GraphNode(g, SWT.NONE); >+ n3.setText("Error"); >+ n3.setImage(image3); >+ >+ GraphConnection connection1 = new GraphConnection(g, SWT.NONE, n1, n2); >+ GraphConnection connection2 = new GraphConnection(g, SWT.NONE, n2, n3); >+ >+ Image information2warningImage = mergeImages(image1, image2); >+ Image warning2error = mergeImages(image2, image3); >+ IFigure tooltip1 = new Label("Information to Warning", information2warningImage); >+ IFigure tooltip2 = new Label("Warning to Error", warning2error); >+ connection1.setTooltip(tooltip1); >+ connection2.setTooltip(tooltip2); >+ >+ n1.setLocation(10, 10); >+ n2.setLocation(200, 10); >+ n3.setLocation(200, 200); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ >+ image1.dispose(); >+ image2.dispose(); >+ image3.dispose(); >+ >+ information2warningImage.dispose(); >+ warning2error.dispose(); >+ >+ } >+} >Index: src/org/eclipse/zest/tests/swt/SpringLayoutExample.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/SpringLayoutExample.java >diff -N src/org/eclipse/zest/tests/swt/SpringLayoutExample.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/SpringLayoutExample.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,60 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+ >+public class SpringLayoutExample { >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ // Create the shell >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet1"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(500, 500); >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ g.setSize(500, 500); >+ GraphNode root = new GraphNode(g, SWT.NONE, "Root"); >+ for (int i = 0; i < 3; i++) { >+ GraphNode n = new GraphNode(g, SWT.NONE, "1 - " + i); >+ for (int j = 0; j < 3; j++) { >+ GraphNode n2 = new GraphNode(g, SWT.NONE, "2 - " + j); >+ new GraphConnection(g, SWT.NONE, n, n2).setWeight(-1); >+ } >+ new GraphConnection(g, SWT.NONE, root, n); >+ } >+ >+ final LayoutAlgorithm layoutAlgorithm = new SpringLayoutAlgorithm(); >+ >+ g.setLayoutAlgorithm(layoutAlgorithm, true); >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ } >+ >+} >Index: src/org/eclipse/zest/tests/jface/SelectionListenerGraphJFaceSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/jface/SelectionListenerGraphJFaceSnippet.java >diff -N src/org/eclipse/zest/tests/jface/SelectionListenerGraphJFaceSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/jface/SelectionListenerGraphJFaceSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,134 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ >+package org.eclipse.zest.tests.jface; >+ >+import java.util.Iterator; >+ >+import org.eclipse.jface.viewers.ISelectionChangedListener; >+import org.eclipse.jface.viewers.LabelProvider; >+import org.eclipse.jface.viewers.SelectionChangedEvent; >+import org.eclipse.jface.viewers.StructuredSelection; >+import org.eclipse.jface.viewers.Viewer; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+import org.eclipse.zest.core.viewers.GraphViewer; >+import org.eclipse.zest.core.viewers.IGraphContentProvider; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+ >+public class SelectionListenerGraphJFaceSnippet { >+ static class MyContentProvider implements IGraphContentProvider { >+ >+ public Object getDestination(Object rel) { >+ if ("Rock2Paper".equals(rel)) { >+ return "Rock"; >+ } else if ("Paper2Scissors".equals(rel)) { >+ return "Paper"; >+ } else if ("Scissors2Rock".equals(rel)) { >+ return "Scissors"; >+ } >+ return null; >+ } >+ >+ public Object[] getElements(Object input) { >+ return new Object[] { "Rock2Paper", "Paper2Scissors", "Scissors2Rock" }; >+ } >+ >+ public Object getSource(Object rel) { >+ if ("Rock2Paper".equals(rel)) { >+ return "Paper"; >+ } else if ("Paper2Scissors".equals(rel)) { >+ return "Scissors"; >+ } else if ("Scissors2Rock".equals(rel)) { >+ return "Rock"; >+ } >+ return null; >+ } >+ >+ public double getWeight(Object connection) { >+ return 0; >+ } >+ >+ public void dispose() { >+ } >+ >+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { >+ } >+ >+ } >+ >+ static class MyLabelProvider extends LabelProvider { >+ final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >+ >+ public Image getImage(Object element) { >+ if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) { >+ return image; >+ } >+ return null; >+ } >+ >+ public String getText(Object element) { >+ return element.toString(); >+ } >+ >+ } >+ >+ static GraphViewer viewer = null; >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphJFaceSnippet2"); >+ shell.setLayout(new FillLayout(SWT.VERTICAL)); >+ shell.setSize(400, 400); >+ viewer = new GraphViewer(shell, SWT.NONE); >+ viewer.setContentProvider(new MyContentProvider()); >+ viewer.setLabelProvider(new MyLabelProvider()); >+ viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm()); >+ viewer.setInput(new Object()); >+ viewer.addSelectionChangedListener(new ISelectionChangedListener() { >+ >+ public void selectionChanged(SelectionChangedEvent event) { >+ System.out.println("Selection Changed: " + selectionToString((StructuredSelection) event.getSelection())); >+ } >+ >+ private String selectionToString(StructuredSelection selection) { >+ StringBuffer stringBuffer = new StringBuffer(); >+ Iterator iterator = selection.iterator(); >+ boolean first = true; >+ while (iterator.hasNext()) { >+ if (first) { >+ first = false; >+ } else { >+ stringBuffer.append(" : "); >+ } >+ stringBuffer.append(iterator.next()); >+ } >+ return stringBuffer.toString(); >+ } >+ >+ }); >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ >+ } >+ >+} >Index: src/org/eclipse/zest/tests/jface/FileProviderJFaceSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/jface/FileProviderJFaceSnippet.java >diff -N src/org/eclipse/zest/tests/jface/FileProviderJFaceSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/jface/FileProviderJFaceSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,136 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ >+package org.eclipse.zest.tests.jface; >+ >+import java.io.BufferedReader; >+import java.io.File; >+import java.io.FileReader; >+import java.io.IOException; >+import java.util.ArrayList; >+import java.util.StringTokenizer; >+ >+import org.eclipse.jface.viewers.LabelProvider; >+import org.eclipse.jface.viewers.Viewer; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.FileDialog; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.viewers.GraphViewer; >+import org.eclipse.zest.core.viewers.IGraphContentProvider; >+import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm; >+ >+/** >+ * This snippet uses a very simple file format to read a graph. Edges are listed >+ * on a new line in a file as such: >+ * a calls b >+ * b calls c >+ * c calld d >+ * >+ * The content provider creates an edge for each line in the file and names the >+ * sources and destination from the line. >+ * >+ * >+ * @author Ian Bull >+ * >+ */ >+public class FileProviderJFaceSnippet { >+ >+ public static final String graph = "a calls b\n" + "a calls c\n" + "b calld d\n" + "b calls e\n" + "c calls f\n" + "c calls g\n" + "d calls h\n" + "d calls i\n" + "e calls j\n" + "e calls k\n" + "f calls l\n" + "f calls m\n"; >+ >+ static class SimpleGraphContentProvider implements IGraphContentProvider { >+ >+ private StringTokenizer graph; >+ >+ public Object getDestination(Object rel) { >+ String string = (String) rel; >+ String[] parts = string.split(" "); >+ return parts[2]; >+ } >+ >+ public Object[] getElements(Object input) { >+ ArrayList listOfEdges = new ArrayList(); >+ while (graph.hasMoreTokens()) { >+ listOfEdges.add(graph.nextToken()); >+ } >+ return listOfEdges.toArray(); >+ } >+ >+ public Object getSource(Object rel) { >+ String string = (String) rel; >+ String[] parts = string.split(" "); >+ return parts[0]; >+ } >+ >+ public double getWeight(Object connection) { >+ return 0; >+ } >+ >+ public void dispose() { >+ >+ } >+ >+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { >+ if (newInput != null) { >+ graph = new StringTokenizer((String) newInput, "\n"); >+ } >+ } >+ >+ } >+ >+ public static void main(String[] args) throws IOException { >+ Display display = new Display(); >+ Shell shell = new Shell(display); >+ shell.setText("Simple Graph File Format"); >+ >+ FileDialog dialog = new FileDialog(shell, SWT.OPEN); >+ dialog.setFilterNames(new String[] { "Simple Graph Files (*.sgf)", "All Files (*.*)" }); >+ dialog.setFilterExtensions(new String[] { "*.sgf", "*.*" }); //Windows wild cards >+ >+ String directory = System.getProperty("user.dir") + "/src/org/eclipse/zest/tests/jface/SimpleGraph.sgf"; //eclipse/zest/examples/jface/"; >+ System.out.println(directory); >+ dialog.setFilterPath(directory); >+ //dialog.setFilterPath(System.getProperty("user.dir") + "src/org/eclipse/zest/examples/jface/"); //Windows path >+ >+ shell.setLayout(new FillLayout(SWT.VERTICAL)); >+ shell.setSize(400, 400); >+ GraphViewer viewer = null; >+ >+ viewer = new GraphViewer(shell, SWT.NONE); >+ viewer.setContentProvider(new SimpleGraphContentProvider()); >+ viewer.setLabelProvider(new LabelProvider()); >+ viewer.setLayoutAlgorithm(new RadialLayoutAlgorithm()); >+ >+ shell.open(); >+ String fileName = dialog.open(); >+ >+ if (fileName == null) { >+ // use the sample graph >+ viewer.setInput(graph); >+ } else { >+ FileReader fileReader = new FileReader(new File(fileName)); >+ BufferedReader bufferedReader = new BufferedReader(fileReader); >+ StringBuffer stringBuffer = new StringBuffer(); >+ while (bufferedReader.ready()) { >+ stringBuffer.append(bufferedReader.readLine() + "\n"); >+ } >+ viewer.setInput(stringBuffer.toString()); >+ } >+ >+ while (!shell.isDisposed()) { >+ if (!display.readAndDispatch()) { >+ display.sleep(); >+ } >+ } >+ display.dispose(); >+ } >+} >Index: src/org/eclipse/zest/tests/swt/SimpleGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/SimpleGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/SimpleGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/SimpleGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,61 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+ >+/** >+ * This snippet creates a very simple graph where Rock is connected to Paper >+ * which is connected to scissors which is connected to rock. >+ * >+ * The nodes a positioned using a SpringLayout Algorithm, and they can be moved >+ * around. >+ * >+ * >+ * @author Ian Bull >+ * >+ */ >+public class SimpleGraphSnippet { >+ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet1"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ Graph g = new Graph(shell, SWT.NONE); >+ >+ GraphNode n = new GraphNode(g, SWT.NONE, "Paper"); >+ GraphNode n2 = new GraphNode(g, SWT.NONE, "Rock"); >+ GraphNode n3 = new GraphNode(g, SWT.NONE, "Scissors"); >+ new GraphConnection(g, SWT.NONE, n, n2); >+ new GraphConnection(g, SWT.NONE, n2, n3); >+ new GraphConnection(g, SWT.NONE, n3, n); >+ g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ } >+ >+} >Index: src/org/eclipse/zest/tests/swt/FindFigureGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/FindFigureGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/FindFigureGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/FindFigureGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,72 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.MouseEvent; >+import org.eclipse.swt.events.MouseMoveListener; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+ >+/** >+ * This snippet shows how to use the findFigureAt to get the figure under the mouse >+ * >+ * @author Ian Bull >+ * >+ */ >+public class FindFigureGraphSnippet { >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet7"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ >+ GraphNode n = new GraphNode(g, SWT.NONE, "Paper"); >+ GraphNode n2 = new GraphNode(g, SWT.NONE, "Rock"); >+ GraphNode n3 = new GraphNode(g, SWT.NONE, "Scissors"); >+ new GraphConnection(g, SWT.NONE, n, n2); >+ new GraphConnection(g, SWT.NONE, n2, n3); >+ new GraphConnection(g, SWT.NONE, n3, n); >+ g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true); >+ >+ g.addMouseMoveListener(new MouseMoveListener() { >+ >+ public void mouseMove(MouseEvent e) { >+ // Get the figure at the current mouse location >+ Object o = g.getFigureAt(e.x, e.y); >+ if ( o != null ) { >+ System.out.println(o + " is at: (" + e.x + "," + e.y + ")"); >+ } >+ } >+ >+ }); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ } >+} >Index: src/org/eclipse/zest/tests/swt/FisheyeGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/FisheyeGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/FisheyeGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/FisheyeGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,77 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.core.widgets.ZestStyles; >+import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm; >+ >+/** >+ * This snippet creates a graph with 80*3 nodes (240 nodes). Only the icons are shown for the nodes, but if >+ * you mouse over the node you get the entire text. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class FisheyeGraphSnippet { >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet6"); >+ Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION); >+ Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >+ Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(800, 800); >+ >+ Graph g = new Graph(shell, SWT.NONE); >+ g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED); >+ for (int i = 0; i < 80; i++) { >+ GraphNode n1 = new GraphNode(g, ZestStyles.NODES_HIDE_TEXT >+ | ZestStyles.NODES_FISHEYE, "Information"); >+ n1.setImage(image1); >+ GraphNode n2 = new GraphNode(g, ZestStyles.NODES_HIDE_TEXT >+ | ZestStyles.NODES_FISHEYE, "Warning"); >+ n2.setImage(image2); >+ GraphNode n3 = new GraphNode(g, ZestStyles.NODES_HIDE_TEXT >+ | ZestStyles.NODES_FISHEYE, "Error"); >+ n3.setImage(image3); >+ new GraphConnection(g, SWT.NONE, n1, n2); >+ new GraphConnection(g, SWT.NONE, n2, n3); >+ new GraphConnection(g, SWT.NONE, n3, n3); >+ } >+ g.setLayoutAlgorithm(new GridLayoutAlgorithm(), true); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ image1.dispose(); >+ image2.dispose(); >+ image3.dispose(); >+ >+ } >+ >+} >Index: src/org/eclipse/zest/tests/swt/CustomFigureGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/CustomFigureGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/CustomFigureGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/CustomFigureGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,165 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import java.util.Iterator; >+ >+import org.eclipse.draw2d.ColorConstants; >+import org.eclipse.draw2d.Ellipse; >+import org.eclipse.draw2d.Figure; >+import org.eclipse.draw2d.FreeformLayout; >+import org.eclipse.draw2d.IFigure; >+import org.eclipse.draw2d.ImageFigure; >+import org.eclipse.draw2d.PolylineShape; >+import org.eclipse.draw2d.geometry.Point; >+import org.eclipse.draw2d.geometry.Rectangle; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.events.SelectionListener; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.core.widgets.custom.CGraphNode; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+ >+/** >+ * >+ * This snippet shows how to create a graph with custom figures as nodes. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class CustomFigureGraphSnippet { >+ >+ public static IFigure createPersonFigure(Image headImage) { >+ Figure person = new Figure(); >+ person.setLayoutManager(new FreeformLayout()); >+ IFigure head = null; >+ if ( headImage != null ) { >+ headImage = new Image(headImage.getDevice(), headImage.getImageData().scaledTo(40, 50)); >+ head = new ImageFigure(headImage); >+ } >+ else >+ head = new Ellipse(); >+ head.setSize(40, 50); >+ >+ PolylineShape body = new PolylineShape(); >+ body.setLineWidth(1); >+ body.setStart(new Point(20,40)); >+ body.setEnd(new Point(20,100)); >+ body.setBounds(new Rectangle(0,0,40,100)); >+ >+ PolylineShape leftLeg = new PolylineShape(); >+ leftLeg.setLineWidth(1); >+ leftLeg.setStart(new Point(20,100)); >+ leftLeg.setEnd(new Point(0,130)); >+ leftLeg.setBounds(new Rectangle(0,0,40,130)); >+ >+ PolylineShape rightLeg = new PolylineShape(); >+ rightLeg.setLineWidth(1); >+ rightLeg.setStart(new Point(20,100)); >+ rightLeg.setEnd(new Point(40,130)); >+ rightLeg.setBounds(new Rectangle(0,0,40,130)); >+ >+ PolylineShape leftArm = new PolylineShape(); >+ leftArm.setLineWidth(1); >+ leftArm.setStart(new Point(20,60)); >+ leftArm.setEnd(new Point(0,50)); >+ leftArm.setBounds(new Rectangle(0,0,40,130)); >+ >+ PolylineShape rightArm = new PolylineShape(); >+ rightArm.setLineWidth(1); >+ rightArm.setStart(new Point(20,60)); >+ rightArm.setEnd(new Point(40,50)); >+ rightArm.setBounds(new Rectangle(0,0,40,130)); >+ >+ person.add(head); >+ person.add(body); >+ person.add(leftLeg); >+ person.add(rightLeg); >+ person.add(leftArm); >+ person.add(rightArm); >+ person.setSize(40,130); >+ return person; >+ } >+ >+ public static void main(String[] args) { >+ final Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet11"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ g.addSelectionListener(new SelectionListener(){ >+ >+ public void widgetSelected(SelectionEvent e) { >+ Iterator iter = g.getSelection().iterator(); >+ while(iter.hasNext()) { >+ Object o = iter.next(); >+ if ( o instanceof CGraphNode) { >+ IFigure figure = ((CGraphNode)o).getFigure(); >+ figure.setBackgroundColor(ColorConstants.blue); >+ figure.setForegroundColor(ColorConstants.blue); >+ } >+ } >+ iter = g.getNodes().iterator(); >+ while ( iter.hasNext()) { >+ Object o = iter.next(); >+ if ( o instanceof CGraphNode) { >+ if ( !g.getSelection().contains(o)) { >+ ((CGraphNode)o).getFigure().setBackgroundColor(ColorConstants.black); >+ ((CGraphNode)o).getFigure().setForegroundColor(ColorConstants.black); >+ } >+ } >+ } >+ } >+ >+ public void widgetDefaultSelected(SelectionEvent e) { >+ // TODO Auto-generated method stub >+ >+ } >+ }); >+ >+ Image zx = new Image(d, "zx.png"); >+ Image ibull = new Image(d, "ibull.jpg"); >+ CGraphNode n = new CGraphNode(g, SWT.NONE, createPersonFigure(zx)); >+ CGraphNode n2 = new CGraphNode(g, SWT.NONE, createPersonFigure(ibull)); >+ GraphNode n3 = new GraphNode(g, SWT.NONE, "PDE"); >+ GraphNode n4 = new GraphNode(g, SWT.NONE, "Zest"); >+ GraphNode n5 = new GraphNode(g, SWT.NONE, "PDE Viz tool"); >+ >+ new GraphConnection(g, SWT.NONE, n, n2); >+ new GraphConnection(g, SWT.NONE, n, n3); >+ new GraphConnection(g, SWT.NONE, n2, n4); >+ new GraphConnection(g, SWT.NONE, n, n5); >+ new GraphConnection(g, SWT.NONE, n2, n5); >+ new GraphConnection(g, SWT.NONE, n3, n5); >+ new GraphConnection(g, SWT.NONE, n4, n5); >+ g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ zx.dispose(); >+ ibull.dispose(); >+ } >+ >+} >Index: src/org/eclipse/zest/tests/swt/CustomPaintingGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/CustomPaintingGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/CustomPaintingGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/CustomPaintingGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,145 @@ >+/******************************************************************************* >+ * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import java.util.ArrayList; >+import java.util.HashMap; >+import java.util.Iterator; >+import java.util.List; >+import java.util.Map; >+ >+import org.eclipse.draw2d.ColorConstants; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.KeyAdapter; >+import org.eclipse.swt.events.KeyEvent; >+import org.eclipse.swt.events.PaintEvent; >+import org.eclipse.swt.events.PaintListener; >+import org.eclipse.swt.graphics.Font; >+import org.eclipse.swt.graphics.FontData; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.graphics.Region; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+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; >+import org.eclipse.zest.core.widgets.ZestStyles; >+ >+/** >+ * This snippet shows how you can add a paint listener to a Zest graph to paint on top of >+ * the widget. This snippet allows you to type and it selects all the nodes that match >+ * what you type. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class CustomPaintingGraphSnippet { >+ public static final int BACKSPACE = 8; >+ public static final int ENTER = 13; >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ final Map figureListing = new HashMap(); >+ final StringBuffer stringBuffer = new StringBuffer(); >+ final Display d = new Display(); >+ FontData fontData = d.getSystemFont().getFontData()[0]; >+ fontData.height = 42; >+ >+ final Font font = new Font(d, fontData); >+ >+ Shell shell = new Shell(d); >+ shell.setText("Graph Snippet 5"); >+ Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION); >+ Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >+ Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED); >+ GraphNode n1 = new GraphNode(g, SWT.NONE); >+ n1.setText("org.eclipse.Information"); >+ n1.setImage(image1); >+ GraphNode n2 = new GraphNode(g, SWT.NONE); >+ n2.setText("org.eclipse.Warning"); >+ n2.setImage(image2); >+ GraphNode n3 = new GraphNode(g, SWT.NONE); >+ n3.setText("org.eclipse.Error"); >+ n3.setImage(image3); >+ figureListing.put(n1.getText().toLowerCase(), n1); >+ figureListing.put(n2.getText().toLowerCase(), n2); >+ figureListing.put(n3.getText().toLowerCase(), n3); >+ >+ new GraphConnection(g, SWT.NONE, n1, n2); >+ new GraphConnection(g, SWT.NONE, n2, n3); >+ n1.setLocation(10, 10); >+ n2.setLocation(200, 10); >+ n3.setLocation(200, 200); >+ >+ g.addKeyListener(new KeyAdapter() { >+ >+ public void keyPressed(KeyEvent e) { >+ boolean complete = false; >+ if (e.keyCode == BACKSPACE) { >+ if (stringBuffer.length() > 0) { >+ stringBuffer.deleteCharAt(stringBuffer.length() - 1); >+ } >+ } else if (e.keyCode == ENTER) { >+ complete = true; >+ } else if ((e.character >= 'a' && e.character <= 'z') || (e.character >= 'A' && e.character <= 'Z') || (e.character == '.') || (e.character >= '0' && e.character <= '9')) { >+ stringBuffer.append(e.character); >+ } >+ Iterator iterator = figureListing.keySet().iterator(); >+ List list = new ArrayList(); >+ if (stringBuffer.length() > 0) { >+ while (iterator.hasNext()) { >+ String string = (String) iterator.next(); >+ if (string.indexOf(stringBuffer.toString().toLowerCase()) >= 0) { >+ list.add(figureListing.get(string)); >+ } >+ } >+ } >+ g.setSelection((GraphItem[]) list.toArray(new GraphItem[list.size()])); >+ if (complete && stringBuffer.length() > 0) { >+ stringBuffer.delete(0, stringBuffer.length()); >+ } >+ >+ g.redraw(); >+ } >+ >+ }); >+ >+ g.addPaintListener(new PaintListener() { >+ public void paintControl(PaintEvent e) { >+ e.gc.setFont(font); >+ e.gc.setClipping((Region) null); >+ e.gc.setForeground(ColorConstants.black); >+ e.gc.drawText(stringBuffer.toString(), 50, 50, true); >+ } >+ }); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ image1.dispose(); >+ image2.dispose(); >+ image3.dispose(); >+ font.dispose(); >+ } >+} >Index: src/org/eclipse/zest/tests/swt/CurvedEdgeGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/CurvedEdgeGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/CurvedEdgeGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/CurvedEdgeGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,79 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.SelectionAdapter; >+import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Button; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+ >+/** >+ * >+ * This snippet shows how to create a curved connection using Zest. >+ * Each time the Button is clicked, the curve changes. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class CurvedEdgeGraphSnippet { >+ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet1"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ >+ GraphNode n = new GraphNode(g, SWT.NONE, "Paper"); >+ n.setBorderColor(org.eclipse.draw2d.ColorConstants.yellow); >+ n.setBorderWidth(3); >+ GraphNode n2 = new GraphNode(g, SWT.NONE, "Rock"); >+ GraphNode n3 = new GraphNode(g, SWT.NONE, "Scissors"); >+ final GraphConnection connection = new GraphConnection(g, SWT.NONE, n, n2); >+ connection.setLineWidth(3); >+ new GraphConnection(g, SWT.NONE, n2, n3); >+ new GraphConnection(g, SWT.NONE, n3, n); >+ g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true); >+ >+ Button button = new Button(shell, SWT.PUSH); >+ button.setText("Change Curve"); >+ button.addSelectionListener(new SelectionAdapter() { >+ int count = 0; >+ public void widgetSelected(SelectionEvent e) { >+ count = ++count % 16; >+ if ( count > 8 ) { >+ connection.setCurveDepth((-16 + count) * 10); >+ } >+ else { >+ connection.setCurveDepth(count * 10); >+ } >+ } >+ }); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ } >+ >+} >Index: src/org/eclipse/zest/tests/jface/RefreshGraphJFaceSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/jface/RefreshGraphJFaceSnippet.java >diff -N src/org/eclipse/zest/tests/jface/RefreshGraphJFaceSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/jface/RefreshGraphJFaceSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,143 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ >+package org.eclipse.zest.tests.jface; >+ >+import org.eclipse.jface.viewers.LabelProvider; >+import org.eclipse.jface.viewers.Viewer; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+import org.eclipse.zest.core.viewers.GraphViewer; >+import org.eclipse.zest.core.viewers.IGraphContentProvider; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.SelectionAdapter; >+import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.layout.GridData; >+import org.eclipse.swt.layout.GridLayout; >+import org.eclipse.swt.widgets.Button; >+import org.eclipse.swt.widgets.Composite; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+ >+/** >+ * This snippet shows how the refresh works on a Zest viewer. >+ */ >+public class RefreshGraphJFaceSnippet { >+ >+ static class MyContentProvider implements IGraphContentProvider { >+ >+ Object[] elements = new Object[] { "Rock2Paper", "Paper2Scissors", "Scissors2Rock" }; >+ >+ public Object getDestination(Object rel) { >+ if ("Rock2Paper".equals(rel)) { >+ return "Rock"; >+ } else if ("Paper2Scissors".equals(rel) || "Scissors2Paper".equals(rel)) { >+ return "Paper"; >+ } else if ("Scissors2Rock".equals(rel)) { >+ return "Scissors"; >+ } >+ return null; >+ } >+ >+ public Object[] getElements(Object input) { >+ return elements; >+ } >+ >+ public Object getSource(Object rel) { >+ if ("Rock2Paper".equals(rel)) { >+ return "Paper"; >+ } else if ("Paper2Scissors".equals(rel) || "Scissors2Paper".equals(rel)) { >+ return "Scissors"; >+ } else if ("Scissors2Rock".equals(rel)) { >+ return "Rock"; >+ } >+ return null; >+ } >+ >+ public void setElements(Object[] elements) { >+ this.elements = elements; >+ } >+ >+ public double getWeight(Object connection) { >+ return 0; >+ } >+ >+ public void dispose() { >+ } >+ >+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { >+ } >+ >+ } >+ >+ static class MyLabelProvider extends LabelProvider { >+ final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >+ >+ public MyLabelProvider() { >+ >+ } >+ >+ public String getText(Object element) { >+ return element.toString(); >+ } >+ >+ public Image getImage(Object element) { >+ return image; >+ } >+ } >+ >+ static GraphViewer viewer = null; >+ private static MyContentProvider contentProvider; >+ >+ /** >+ * @param args >+ */ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphJFaceSnippet2"); >+ shell.setLayout(new FillLayout(SWT.VERTICAL)); >+ shell.setSize(400, 400); >+ Composite parent = new Composite(shell, SWT.NONE); >+ parent.setLayout(new GridLayout(2, false)); >+ buildViewer(parent); >+ buildButton(parent); >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ >+ } >+ >+ private static void buildButton(Composite parent) { >+ Button button = new Button(parent, SWT.PUSH); >+ button.setText("Refresh"); >+ button.addSelectionListener(new SelectionAdapter() { >+ public void widgetSelected(SelectionEvent e) { >+ contentProvider.setElements(new Object[] { "Rock2Paper", "Scissors2Paper", "Scissors2Rock" }); >+ viewer.refresh(); >+ } >+ }); >+ } >+ >+ private static void buildViewer(Composite parent) { >+ viewer = new GraphViewer(parent, SWT.NONE); >+ viewer.getGraphControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); >+ contentProvider = new MyContentProvider(); >+ viewer.setContentProvider(contentProvider); >+ viewer.setLabelProvider(new MyLabelProvider()); >+ viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm()); >+ viewer.setInput(new Object()); >+ } >+} >Index: src/org/eclipse/zest/tests/swt/SelectionGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/SelectionGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/SelectionGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/SelectionGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,78 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.core.widgets.ZestStyles; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.SelectionAdapter; >+import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+ >+/** >+ * Adds a selection listener to the nodes to tell when a selection event has >+ * happened. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class SelectionGraphSnippet { >+ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION); >+ Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING); >+ Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ Graph g = new Graph(shell, SWT.NONE); >+ g.addSelectionListener(new SelectionAdapter() { >+ public void widgetSelected(SelectionEvent e) { >+ System.out.println(((Graph) e.widget).getSelection()); >+ } >+ }); >+ >+ g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED); >+ GraphNode n1 = new GraphNode(g, SWT.NONE); >+ n1.setText("Information"); >+ n1.setImage(image1); >+ GraphNode n2 = new GraphNode(g, SWT.NONE); >+ n2.setText("Warning"); >+ n2.setImage(image2); >+ GraphNode n3 = new GraphNode(g, SWT.NONE); >+ n3.setText("Error"); >+ n3.setImage(image3); >+ new GraphConnection(g, SWT.NONE, n1, n2); >+ new GraphConnection(g, SWT.NONE, n2, n3); >+ >+ g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ image1.dispose(); >+ image2.dispose(); >+ image3.dispose(); >+ >+ } >+} >Index: src/org/eclipse/zest/tests/swt/ContainersGraphSnippet.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/ContainersGraphSnippet.java >diff -N src/org/eclipse/zest/tests/swt/ContainersGraphSnippet.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/ContainersGraphSnippet.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,88 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import org.eclipse.draw2d.Figure; >+import org.eclipse.draw2d.FlowLayout; >+import org.eclipse.draw2d.IFigure; >+import org.eclipse.draw2d.ImageFigure; >+import org.eclipse.draw2d.Label; >+import org.eclipse.draw2d.MarginBorder; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+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.GraphNode; >+import org.eclipse.zest.core.widgets.ZestStyles; >+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm; >+ >+/** >+ * >+ * This snippet shows how to use graph containers. >+ * >+ * @author Ian Bull >+ * >+ */ >+public class ContainersGraphSnippet { >+ >+ public static void main(String[] args) { >+ final Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("GraphSnippet11"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ final Graph g = new Graph(shell, SWT.NONE); >+ >+ Image zx = new Image(d, "zxsnow.png"); >+ IFigure tooltip = new Figure(); >+ tooltip.setBorder(new MarginBorder(5,5,5,5)); >+ FlowLayout layout = new FlowLayout(false); >+ layout.setMajorSpacing(3); >+ layout.setMinorAlignment(3); >+ tooltip.setLayoutManager(new FlowLayout(false)); >+ tooltip.add(new ImageFigure(zx)); >+ tooltip.add(new Label("Name: Chris Aniszczyk")); >+ tooltip.add(new Label("Location: Austin, Texas")); >+ >+ GraphContainer c1 = new GraphContainer(g, SWT.NONE); >+ c1.setText("Canada"); >+ GraphContainer c2 = new GraphContainer(g, SWT.NONE); >+ c2.setText("USA"); >+ >+ GraphNode n1 = new GraphNode(c1, SWT.NONE, "Ian B."); >+ n1.setSize(200, 100); >+ GraphNode n2 = new GraphNode(c2, SWT.NONE, "Chris A."); >+ n2.setTooltip(tooltip); >+ >+ GraphConnection connection = new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, n1, n2); >+ connection.setCurveDepth(-30); >+ GraphConnection connection2 = new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, n2, n1); >+ connection2.setCurveDepth(-30); >+ >+ >+ g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ zx.dispose(); >+ } >+ >+} >Index: src/org/eclipse/zest/tests/swt/SpaceTreeExample.java >=================================================================== >RCS file: src/org/eclipse/zest/tests/swt/SpaceTreeExample.java >diff -N src/org/eclipse/zest/tests/swt/SpaceTreeExample.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/tests/swt/SpaceTreeExample.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,202 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ *******************************************************************************/ >+package org.eclipse.zest.tests.swt; >+ >+import java.util.List; >+ >+import org.eclipse.draw2d.ColorConstants; >+import org.eclipse.jface.action.Action; >+import org.eclipse.jface.action.IMenuListener; >+import org.eclipse.jface.action.IMenuManager; >+import org.eclipse.jface.action.MenuManager; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.layout.FillLayout; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.zest.core.widgets.DefaultSubgraph; >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphConnection; >+import org.eclipse.zest.core.widgets.GraphNode; >+import org.eclipse.zest.core.widgets.ZestStyles; >+import org.eclipse.zest.core.widgets.DefaultSubgraph.TriangleSubgraphFactory; >+import org.eclipse.zest.layouts.algorithms.SpaceTreeLayoutAlgorithm; >+ >+/** >+ * This example lets you play with TreeLayoutAlgorithm in many ways - expanding >+ * and collapsing nodes, moving them around, changing structure of the graph. >+ */ >+public class SpaceTreeExample { >+ >+ static Graph g; >+ >+ static GraphNode source; >+ >+ static GraphNode target; >+ >+ static boolean changesSeries = false; >+ >+ public static void main(String[] args) { >+ Display d = new Display(); >+ Shell shell = new Shell(d); >+ shell.setText("Space Tree Layout Example"); >+ shell.setLayout(new FillLayout()); >+ shell.setSize(400, 400); >+ >+ g = new Graph(shell, SWT.NONE); >+ g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED); >+ g.setNodeStyle(ZestStyles.NODES_FISHEYE); >+ >+ TriangleSubgraphFactory factory = new DefaultSubgraph.TriangleSubgraphFactory(); >+ factory.setColor(ColorConstants.green); >+ >+ g.setSubgraphFactory(factory); >+ SpaceTreeLayoutAlgorithm spaceTreeLayoutAlgorithm = new SpaceTreeLayoutAlgorithm(); >+ g.setExpandCollapseManager(spaceTreeLayoutAlgorithm >+ .getExpandCollapseManager()); >+ >+ g.setLayoutAlgorithm(spaceTreeLayoutAlgorithm, false); >+ >+ createTree(g, "!", 5, 5); >+ >+ >+ hookMenu(g); >+ >+ shell.open(); >+ while (!shell.isDisposed()) { >+ while (!d.readAndDispatch()) { >+ d.sleep(); >+ } >+ } >+ } >+ >+ private static GraphNode createTree(Graph g, String rootTitle, int depth, int breadth) { >+ GraphNode root = new GraphNode(g, SWT.NONE, rootTitle); >+ if (depth > 0) { >+ for (int i = 0; i < breadth; i++) { >+ GraphNode child = createTree(g, rootTitle + i, depth - 1 - i, >+ breadth - i); >+ new GraphConnection(g, SWT.NONE, root, child); >+ } >+ } >+ return root; >+ } >+ >+ private static void hookMenu(final Graph g) { >+ MenuManager menuMgr = new MenuManager("#PopupMenu"); >+ menuMgr.setRemoveAllWhenShown(true); >+ menuMgr.addMenuListener(new IMenuListener() { >+ public void menuAboutToShow(IMenuManager manager) { >+ fillContextMenu(manager); >+ } >+ }); >+ g.setMenu(menuMgr.createContextMenu(g)); >+ } >+ >+ private static void fillContextMenu(IMenuManager menuMgr) { >+ List selection = g.getSelection(); >+ if (selection.size() == 1) { >+ if (selection.get(0) instanceof GraphNode) { >+ final GraphNode node = (GraphNode) selection.get(0); >+ if (g.canExpand(node)) { >+ Action expandAction = new Action() { >+ public void run() { >+ g.setExpanded(node, true); >+ } >+ }; >+ expandAction.setText("expand"); >+ menuMgr.add(expandAction); >+ } >+ if (g.canCollapse(node)) { >+ Action collapseAction = new Action() { >+ public void run() { >+ g.setExpanded(node, false); >+ } >+ }; >+ collapseAction.setText("collapse"); >+ menuMgr.add(collapseAction); >+ } >+ Action disposeAction = new Action() { >+ public void run() { >+ node.dispose(); >+ } >+ }; >+ disposeAction.setText("dispose"); >+ menuMgr.add(disposeAction); >+ >+ Action asSourceAction = new Action() { >+ public void run() { >+ source = node; >+ addConnection(); >+ } >+ }; >+ asSourceAction.setText("use as source"); >+ menuMgr.add(asSourceAction); >+ >+ Action asTargetAction = new Action() { >+ public void run() { >+ target = node; >+ addConnection(); >+ } >+ }; >+ asTargetAction.setText("use as target"); >+ menuMgr.add(asTargetAction); >+ } >+ if (selection.get(0) instanceof GraphConnection) { >+ final GraphConnection connection = (GraphConnection) selection >+ .get(0); >+ Action removeAction = new Action() { >+ public void run() { >+ connection.dispose(); >+ } >+ }; >+ removeAction.setText("remove"); >+ menuMgr.add(removeAction); >+ } >+ } >+ if (selection.size() == 0) { >+ Action addNode = new Action() { >+ public void run() { >+ new GraphNode(g, SWT.NONE, "new!"); >+ } >+ }; >+ addNode.setText("add node"); >+ menuMgr.add(addNode); >+ >+ if (!changesSeries) { >+ Action startChangesSeries = new Action() { >+ public void run() { >+ g.setDynamicLayout(false); >+ changesSeries = true; >+ } >+ }; >+ startChangesSeries.setText("start changes"); >+ menuMgr.add(startChangesSeries); >+ } else { >+ Action endChangesSeries = new Action() { >+ public void run() { >+ g.setDynamicLayout(true); >+ changesSeries = false; >+ } >+ }; >+ endChangesSeries.setText("end changes"); >+ menuMgr.add(endChangesSeries); >+ } >+ } >+ } >+ >+ private static void addConnection() { >+ if (source != null && target != null) { >+ new GraphConnection(g, SWT.NONE, source, target); >+ source = target = null; >+ } >+ }; >+} >#P org.eclipse.zest.core >Index: src/org/eclipse/zest/core/viewers/IGraphEntityRelationshipContentProvider.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/IGraphEntityRelationshipContentProvider.java,v >retrieving revision 1.4 >diff -u -r1.4 IGraphEntityRelationshipContentProvider.java >--- src/org/eclipse/zest/core/viewers/IGraphEntityRelationshipContentProvider.java 12 Sep 2007 20:44:39 -0000 1.4 >+++ src/org/eclipse/zest/core/viewers/IGraphEntityRelationshipContentProvider.java 28 Aug 2009 16:03:16 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -14,18 +14,25 @@ > > /** > * 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. >+ * 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 { >+// @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. >+ * >+ * @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); > >Index: src/org/eclipse/zest/core/viewers/EntityConnectionData.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/EntityConnectionData.java,v >retrieving revision 1.6 >diff -u -r1.6 EntityConnectionData.java >--- src/org/eclipse/zest/core/viewers/EntityConnectionData.java 12 Sep 2007 20:44:39 -0000 1.6 >+++ src/org/eclipse/zest/core/viewers/EntityConnectionData.java 28 Aug 2009 16:03:15 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -11,8 +11,8 @@ > 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. >+ * 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 > * >@@ -23,23 +23,23 @@ > public final Object dest; > > /** >- * Creates a new entity connection data. The source and dest >- * are users nodes. >+ * 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"); >- } >- */ >+ * 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) >+ /* >+ * (non-Javadoc) >+ * > * @see java.lang.Object#equals(java.lang.Object) > */ > public boolean equals(Object obj) { >@@ -50,7 +50,9 @@ > return (this.source.equals(that.source) && this.dest.equals(that.dest)); > } > >- /* (non-Javadoc) >+ /* >+ * (non-Javadoc) >+ * > * @see java.lang.Object#hashCode() > */ > public int hashCode() { >Index: src/org/eclipse/zest/core/viewers/INestedContentProvider.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/INestedContentProvider.java,v >retrieving revision 1.1 >diff -u -r1.1 INestedContentProvider.java >--- src/org/eclipse/zest/core/viewers/INestedContentProvider.java 20 Nov 2008 00:09:54 -0000 1.1 >+++ src/org/eclipse/zest/core/viewers/INestedContentProvider.java 28 Aug 2009 16:03:16 -0000 >@@ -1,15 +1,14 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2008 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 >+ * Copyright (c) 2009 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: IBM Corporation - initial API and implementation Chisel Group, >- * University of Victoria >+ * 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 >@@ -22,20 +21,22 @@ > public interface INestedContentProvider { > > /** >- * Does the current node have children? If so, it will be rendered as a >+ * Does the current node have children? If so, it will be rendered as a > * container. > * >- * @param element The current node >+ * @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. >+ * 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. >+ * @param element >+ * The current node >+ * @return The list of children for this node. > */ > public Object[] getChildren(Object element); > } >Index: src/org/eclipse/zest/core/viewers/IEntityConnectionStyleProvider.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/IEntityConnectionStyleProvider.java,v >retrieving revision 1.5 >diff -u -r1.5 IEntityConnectionStyleProvider.java >--- src/org/eclipse/zest/core/viewers/IEntityConnectionStyleProvider.java 12 Sep 2007 20:44:39 -0000 1.5 >+++ src/org/eclipse/zest/core/viewers/IEntityConnectionStyleProvider.java 28 Aug 2009 16:03:16 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -15,53 +15,66 @@ > 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. >+ * 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 >+// @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 >+ * 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. >+ * >+ * @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. >+ * >+ * @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. >+ * >+ * @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. >+ * >+ * @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. >Index: src/org/eclipse/zest/core/viewers/IEntityConnectionStyleBezierExtension.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/IEntityConnectionStyleBezierExtension.java,v >retrieving revision 1.5 >diff -u -r1.5 IEntityConnectionStyleBezierExtension.java >--- src/org/eclipse/zest/core/viewers/IEntityConnectionStyleBezierExtension.java 12 Sep 2007 20:44:39 -0000 1.5 >+++ src/org/eclipse/zest/core/viewers/IEntityConnectionStyleBezierExtension.java 28 Aug 2009 16:03:16 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >Index: src/org/eclipse/zest/core/viewers/IGraphEntityContentProvider.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/IGraphEntityContentProvider.java,v >retrieving revision 1.5 >diff -u -r1.5 IGraphEntityContentProvider.java >--- src/org/eclipse/zest/core/viewers/IGraphEntityContentProvider.java 12 Sep 2007 20:44:39 -0000 1.5 >+++ src/org/eclipse/zest/core/viewers/IGraphEntityContentProvider.java 28 Aug 2009 16:03:16 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -15,7 +15,7 @@ > /** > * > * @author Ian Bull >- * >+ * > */ > public interface IGraphEntityContentProvider extends IStructuredContentProvider { > >@@ -23,6 +23,7 @@ > > /** > * Gets the elements this object is connected to >+ * > * @param entity > * @return > */ >Index: src/org/eclipse/zest/core/viewers/IConnectionStyleBezierExtension.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/IConnectionStyleBezierExtension.java,v >retrieving revision 1.3 >diff -u -r1.3 IConnectionStyleBezierExtension.java >--- src/org/eclipse/zest/core/viewers/IConnectionStyleBezierExtension.java 12 Sep 2007 20:44:39 -0000 1.3 >+++ src/org/eclipse/zest/core/viewers/IConnectionStyleBezierExtension.java 28 Aug 2009 16:03:16 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -16,51 +16,60 @@ > * > * 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. >+ * 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. >+// @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 >+ * 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. >+ * >+ * @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. >+ * 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. >+ * 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. >+ * 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); >Index: src/org/eclipse/zest/core/viewers/GraphViewer.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/GraphViewer.java,v >retrieving revision 1.7 >diff -u -r1.7 GraphViewer.java >--- src/org/eclipse/zest/core/viewers/GraphViewer.java 14 Oct 2008 19:57:32 -0000 1.7 >+++ src/org/eclipse/zest/core/viewers/GraphViewer.java 28 Aug 2009 16:03:15 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials are made > * available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at >@@ -27,26 +27,27 @@ > 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.AbstractStructuredGraphViewer; > 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.viewers.internal.ZoomManager; > 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 { >+public class GraphViewer extends AbstractStructuredGraphViewer implements >+ ISelectionProvider { > > protected Graph graph = null; > private IStylingGraphModelFactory modelFactory = null; >@@ -89,10 +90,12 @@ > Iterator iterator = selectionChangedListeners.iterator(); > > ISelection structuredSelection = getSelection(); >- SelectionChangedEvent event = new SelectionChangedEvent(GraphViewer.this, structuredSelection); >+ SelectionChangedEvent event = new SelectionChangedEvent( >+ GraphViewer.this, structuredSelection); > > while (iterator.hasNext()) { >- ISelectionChangedListener listener = (ISelectionChangedListener) iterator.next(); >+ ISelectionChangedListener listener = (ISelectionChangedListener) iterator >+ .next(); > listener.selectionChanged(event); > } > >@@ -103,7 +106,8 @@ > control.addMouseListener(new MouseListener() { > > public void mouseDoubleClick(MouseEvent e) { >- DoubleClickEvent doubleClickEvent = new DoubleClickEvent(GraphViewer.this, getSelection()); >+ DoubleClickEvent doubleClickEvent = new DoubleClickEvent( >+ GraphViewer.this, getSelection()); > fireDoubleClick(doubleClickEvent); > } > >@@ -118,6 +122,13 @@ > }); > } > >+ 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 > * >@@ -130,7 +141,8 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#getGraphControl() >+ * @seeorg.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer# >+ * getGraphControl() > */ > public Graph getGraphControl() { > return super.getGraphControl(); >@@ -151,7 +163,8 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#setLayoutAlgorithm(org.eclipse.zest.layouts.LayoutAlgorithm) >+ * @seeorg.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer# >+ * setLayoutAlgorithm(org.eclipse.zest.layouts.LayoutAlgorithm) > */ > public void setLayoutAlgorithm(LayoutAlgorithm algorithm) { > super.setLayoutAlgorithm(algorithm); >@@ -160,7 +173,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer#setNodeStyle(int) >+ * @see >+ * org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer#setNodeStyle >+ * (int) > */ > public void setNodeStyle(int nodeStyle) { > super.setNodeStyle(nodeStyle); >@@ -175,7 +190,8 @@ > } else if (contentProvider instanceof IGraphEntityRelationshipContentProvider) { > super.setContentProvider(contentProvider); > } else { >- throw new IllegalArgumentException("Invalid content provider, only IGraphContentProvider, IGraphEntityContentProvider, or IGraphEntityRelationshipContentProvider are supported."); >+ throw new IllegalArgumentException( >+ "Invalid content provider, only IGraphContentProvider, IGraphEntityContentProvider, or IGraphEntityRelationshipContentProvider are supported."); > } > } > >@@ -195,7 +211,8 @@ > */ > public GraphItem findGraphItem(Object element) { > Widget[] result = findItems(element); >- return (result.length == 0 || !(result[0] instanceof GraphItem)) ? null : (GraphItem) result[0]; >+ return (result.length == 0 || !(result[0] instanceof GraphItem)) ? null >+ : (GraphItem) result[0]; > } > > /** >@@ -225,7 +242,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#reveal(java.lang.Object) >+ * @see >+ * org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#reveal >+ * (java.lang.Object) > */ > public void reveal(Object element) { > super.reveal(element); >@@ -234,7 +253,8 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#setConnectionStyle(int) >+ * @seeorg.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer# >+ * setConnectionStyle(int) > */ > public void setConnectionStyle(int connectionStyle) { > super.setConnectionStyle(connectionStyle); >@@ -243,7 +263,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#unReveal(java.lang.Object) >+ * @see >+ * org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#unReveal >+ * (java.lang.Object) > */ > public void unReveal(Object element) { > super.unReveal(element); >@@ -255,25 +277,82 @@ > } > } > >- public void removeSelectionChangedListener(ISelectionChangedListener 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()); >+ 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) { >@@ -291,7 +370,8 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer#getLayoutAlgorithm() >+ * @seeorg.eclipse.zest.core.viewers.AbstractStructuredGraphViewer# >+ * getLayoutAlgorithm() > */ > protected LayoutAlgorithm getLayoutAlgorithm() { > return graph.getLayoutAlgorithm(); >Index: src/org/eclipse/zest/core/viewers/IEntityStyleProvider.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/IEntityStyleProvider.java,v >retrieving revision 1.9 >diff -u -r1.9 IEntityStyleProvider.java >--- src/org/eclipse/zest/core/viewers/IEntityStyleProvider.java 12 Sep 2007 20:44:39 -0000 1.9 >+++ src/org/eclipse/zest/core/viewers/IEntityStyleProvider.java 28 Aug 2009 16:03:16 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, > * Canada. All rights reserved. This program and the accompanying materials are > * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at >@@ -88,7 +88,7 @@ > * node is selected. > */ > // @tag ADJACENT : Removed highlight adjacent >- //public boolean highlightAdjacentEntities(Object entity); >+ // 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 >@@ -102,7 +102,7 @@ > * @see #dispose() > */ > // @tag ADJACENT : Removed highlight adjacent >- //public Color getAdjacentEntityHighlightColor(Object entity); >+ // 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 >Index: src/org/eclipse/zest/core/viewers/IFigureProvider.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/IFigureProvider.java,v >retrieving revision 1.1 >diff -u -r1.1 IFigureProvider.java >--- src/org/eclipse/zest/core/viewers/IFigureProvider.java 31 Mar 2009 16:39:23 -0000 1.1 >+++ src/org/eclipse/zest/core/viewers/IFigureProvider.java 28 Aug 2009 16:03:16 -0000 >@@ -1,11 +1,20 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 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()} >+ * 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 { > >Index: src/org/eclipse/zest/core/viewers/AbstractZoomableViewer.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/AbstractZoomableViewer.java,v >retrieving revision 1.5 >diff -u -r1.5 AbstractZoomableViewer.java >--- src/org/eclipse/zest/core/viewers/AbstractZoomableViewer.java 12 Sep 2007 20:44:39 -0000 1.5 >+++ src/org/eclipse/zest/core/viewers/AbstractZoomableViewer.java 28 Aug 2009 16:03:15 -0000 >@@ -1,8 +1,8 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html > * > * Contributors: >@@ -12,24 +12,29 @@ > > import org.eclipse.draw2d.geometry.Rectangle; > import org.eclipse.jface.viewers.StructuredViewer; >-import org.eclipse.zest.core.viewers.internal.ZoomManager; > > /** >- * A simple interface that provides zooming capabilites. Not intended to be subclassed by clients. >+ * 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 >+// @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. >+ * 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); >+ Rectangle r = new Rectangle(x, y, width, height); > if (r.isEmpty()) { > getZoomManager().setZoomAsText("100%"); > } else { >Index: src/org/eclipse/zest/core/viewers/ZoomContributionViewItem.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/ZoomContributionViewItem.java,v >retrieving revision 1.7 >diff -u -r1.7 ZoomContributionViewItem.java >--- src/org/eclipse/zest/core/viewers/ZoomContributionViewItem.java 17 Jun 2008 04:08:35 -0000 1.7 >+++ src/org/eclipse/zest/core/viewers/ZoomContributionViewItem.java 28 Aug 2009 16:03:17 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, > * Canada. All rights reserved. This program and the accompanying materials are > * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at >@@ -10,8 +10,6 @@ > package org.eclipse.zest.core.viewers; > > import org.eclipse.jface.action.ContributionItem; >-import org.eclipse.zest.core.viewers.internal.ZoomListener; >-import org.eclipse.zest.core.viewers.internal.ZoomManager; > import org.eclipse.swt.SWT; > import org.eclipse.swt.events.MenuAdapter; > import org.eclipse.swt.events.MenuEvent; >@@ -37,8 +35,10 @@ > * @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 { >+// @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. > */ >@@ -78,8 +78,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets.Menu, >- * int) >+ * @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) { >@@ -95,8 +96,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets.CoolBar, >- * int) >+ * @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); >@@ -107,8 +109,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets.ToolBar, >- * int) >+ * @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); >@@ -123,7 +126,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) >+ * @see >+ * org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse >+ * .swt.events.SelectionEvent) > */ > public void widgetSelected(SelectionEvent e) { > int selection = combo.getSelectionIndex(); >@@ -235,7 +240,8 @@ > if (fMenu != null) { > fMenu = null; > } >- // @tag zest.bug.159667-ZoomDispose : make sure that we no longer listen to the part service. >+ // @tag zest.bug.159667-ZoomDispose : make sure that we no longer listen >+ // to the part service. > super.dispose(); > } > } >Index: src/org/eclipse/zest/core/viewers/IGraphContentProvider.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/IGraphContentProvider.java,v >retrieving revision 1.6 >diff -u -r1.6 IGraphContentProvider.java >--- src/org/eclipse/zest/core/viewers/IGraphContentProvider.java 12 Sep 2007 20:44:39 -0000 1.6 >+++ src/org/eclipse/zest/core/viewers/IGraphContentProvider.java 28 Aug 2009 16:03:16 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -13,36 +13,43 @@ > import org.eclipse.jface.viewers.IStructuredContentProvider; > > /** >- * A graph content provider. >+ * 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. >+ * 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. >+ * 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. > */ >Index: src/org/eclipse/zest/core/viewers/IConnectionStyleProvider.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/IConnectionStyleProvider.java,v >retrieving revision 1.5 >diff -u -r1.5 IConnectionStyleProvider.java >--- src/org/eclipse/zest/core/viewers/IConnectionStyleProvider.java 12 Sep 2007 20:44:39 -0000 1.5 >+++ src/org/eclipse/zest/core/viewers/IConnectionStyleProvider.java 28 Aug 2009 16:03:16 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -15,46 +15,55 @@ > import org.eclipse.ui.services.IDisposable; > > /** >- * An extension to label providers, to supply styles for connections based upon >+ * 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 >+// @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 >+ * 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. >+ * >+ * @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. >+ * 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. >+ * 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. >+ * >+ * @param rel >+ * the relationship represented by this connection. > * @return the line width for the connection. -1 for default. > */ > public int getLineWidth(Object rel); >Index: src/org/eclipse/zest/core/viewers/IZoomableWorkbenchPart.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/IZoomableWorkbenchPart.java,v >retrieving revision 1.4 >diff -u -r1.4 IZoomableWorkbenchPart.java >--- src/org/eclipse/zest/core/viewers/IZoomableWorkbenchPart.java 12 Sep 2007 20:44:39 -0000 1.4 >+++ src/org/eclipse/zest/core/viewers/IZoomableWorkbenchPart.java 28 Aug 2009 16:03:17 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -10,17 +10,18 @@ > *******************************************************************************/ > package org.eclipse.zest.core.viewers; > >- > /** >- * An interface that can be added to IWorkbenchParts based on ZEST views so that zooming >- * is supported. >+ * 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 >+// @tag bug.156286-Zooming.fix : experimental > public interface IZoomableWorkbenchPart { > /** > * Returns the viewer that is zoomable. >+ * > * @return the viewer that is zoomable. > */ > AbstractZoomableViewer getZoomableViewer(); >Index: src/org/eclipse/zest/core/viewers/internal/GraphModelEntityFactory.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/internal/GraphModelEntityFactory.java,v >retrieving revision 1.8 >diff -u -r1.8 GraphModelEntityFactory.java >--- src/org/eclipse/zest/core/viewers/internal/GraphModelEntityFactory.java 31 Mar 2009 16:39:23 -0000 1.8 >+++ src/org/eclipse/zest/core/viewers/internal/GraphModelEntityFactory.java 28 Aug 2009 16:03:18 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials are made > * available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at >@@ -15,6 +15,7 @@ > 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; >@@ -39,7 +40,8 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#createGraphModel() >+ * @seeorg.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory# >+ * createGraphModel() > */ > public Graph createGraphModel(Graph model) { > doBuildGraph(model); >@@ -49,7 +51,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory#doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel) >+ * @see >+ * org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory >+ * #doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel) > */ > protected void doBuildGraph(Graph model) { > super.doBuildGraph(model); >@@ -73,8 +77,9 @@ > } > } > >- // We may have other entities (such as children of containers) >- Set keySet = ((AbstractStructuredGraphViewer) getViewer()).getNodesMap().keySet(); >+ // 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++) { >@@ -84,7 +89,8 @@ > if (filterElement(inputElement, data)) { > continue; > } >- Object[] related = ((IGraphEntityContentProvider) getContentProvider()).getConnectedTo(data); >+ Object[] related = ((IGraphEntityContentProvider) getContentProvider()) >+ .getConnectedTo(data); > > if (related != null) { > for (int j = 0; j < related.length; j++) { >@@ -93,7 +99,8 @@ > if (filterElement(inputElement, related[j])) { > continue; > } >- EntityConnectionData connectionData = new EntityConnectionData(data, related[j]); >+ EntityConnectionData connectionData = new EntityConnectionData( >+ data, related[j]); > if (filterElement(inputElement, connectionData)) { > continue; > } >@@ -106,8 +113,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh(org.eclipse.zest.core.internal.graphmodel.GraphModel, >- * java.lang.Object) >+ * @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) { >@@ -133,10 +141,12 @@ > > if (refreshLabels) { > update(node); >- for (Iterator it = node.getSourceConnections().iterator(); it.hasNext();) { >+ for (Iterator it = node.getSourceConnections().iterator(); it >+ .hasNext();) { > update((GraphItem) it.next()); > } >- for (Iterator it = node.getTargetConnections().iterator(); it.hasNext();) { >+ for (Iterator it = node.getTargetConnections().iterator(); it >+ .hasNext();) { > update((GraphItem) it.next()); > } > } >@@ -149,7 +159,8 @@ > */ > private void reconnect(Graph graph, Object element, boolean refreshLabels) { > GraphNode node = viewer.getGraphModelNode(element); >- Object[] related = ((IGraphEntityContentProvider) getContentProvider()).getConnectedTo(element); >+ Object[] related = ((IGraphEntityContentProvider) getContentProvider()) >+ .getConnectedTo(element); > List connections = node.getSourceConnections(); > LinkedList toAdd = new LinkedList(); > LinkedList toDelete = new LinkedList(); >@@ -157,10 +168,12 @@ > HashSet oldExternalConnections = new HashSet(); > HashSet newExternalConnections = new HashSet(); > for (Iterator it = connections.iterator(); it.hasNext();) { >- oldExternalConnections.add(((GraphConnection) it.next()).getExternalConnection()); >+ oldExternalConnections.add(((GraphConnection) it.next()) >+ .getExternalConnection()); > } > for (int i = 0; i < related.length; i++) { >- newExternalConnections.add(new EntityConnectionData(element, related[i])); >+ newExternalConnections.add(new EntityConnectionData(element, >+ related[i])); > } > for (Iterator it = oldExternalConnections.iterator(); it.hasNext();) { > Object next = it.next(); >@@ -204,8 +217,10 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh(org.eclipse.zest.core.internal.graphmodel.GraphModel, >- * java.lang.Object, boolean) >+ * @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); >Index: src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java,v >retrieving revision 1.13 >diff -u -r1.13 AbstractStylingModelFactory.java >--- src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java 24 Jul 2009 19:13:37 -0000 1.13 >+++ src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java 28 Aug 2009 16:03:17 -0000 >@@ -5,11 +5,12 @@ > * accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html > * >- * Contributors: The Chisel Group, University of Victoria >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 > ******************************************************************************/ > package org.eclipse.zest.core.viewers.internal; > >-import java.util.ArrayList; > import java.util.HashMap; > import java.util.Iterator; > import java.util.LinkedList; >@@ -22,15 +23,16 @@ > 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; >-import org.eclipse.zest.core.widgets.IContainer; > >-/* >+/** > * Base class that can be used for model factories. Offers facilities to style > * the items that have been created by the factory. > * >@@ -42,7 +44,6 @@ > private AbstractStructuredGraphViewer viewer; > private int connectionStyle; > private int nodeStyle; >- private List /* ConstraintAdapater */constraintAdapters = new ArrayList(); > > /** > * >@@ -51,9 +52,6 @@ > this.viewer = viewer; > this.connectionStyle = SWT.NONE; > this.nodeStyle = SWT.NONE; >- if (viewer instanceof AbstractStructuredGraphViewer) { >- this.constraintAdapters = (viewer).getConstraintAdapters(); >- } > } > > public void styleConnection(GraphConnection conn) { >@@ -208,10 +206,10 @@ > return node; > } > for (int i = 0; i < childNodes.length; i++) { >- GraphNode childNode = viewer.addGraphModelNode((IContainer) node, childNodes[i]); >+ GraphNode childNode = viewer.addGraphModelNode((GraphContainer) node, childNodes[i]); > styleItem(childNode); > } >- ((IContainer) node).applyLayout(); >+ ((GraphContainer) node).applyLayout(); > return node; > } > } >@@ -243,10 +241,6 @@ > this.nodeStyle = style; > } > >- public List /* ConstraintAdapter */getConstraintAdapters() { >- return this.constraintAdapters; >- } >- > /** > * @return the nodeStyle > */ >@@ -345,7 +339,6 @@ > clearGraph(model); > model.setConnectionStyle(getConnectionStyle()); > model.setNodeStyle(getNodeStyle()); >- model.setConstraintAdapters(getConstraintAdapters()); > } > > /** >Index: src/org/eclipse/zest/core/viewers/internal/IStylingGraphModelFactory.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/internal/IStylingGraphModelFactory.java,v >retrieving revision 1.6 >diff -u -r1.6 IStylingGraphModelFactory.java >--- src/org/eclipse/zest/core/viewers/internal/IStylingGraphModelFactory.java 12 Sep 2007 20:44:39 -0000 1.6 >+++ src/org/eclipse/zest/core/viewers/internal/IStylingGraphModelFactory.java 28 Aug 2009 16:03:19 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -93,7 +93,8 @@ > * 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); >+ public GraphConnection createConnection(Graph graph, Object element, >+ Object source, Object dest); > > /** > * Restyles the given graph items according to the label provider supplied >Index: src/org/eclipse/zest/core/viewers/internal/AbstractStructuredGraphViewer.java >=================================================================== >RCS file: src/org/eclipse/zest/core/viewers/internal/AbstractStructuredGraphViewer.java >diff -N src/org/eclipse/zest/core/viewers/internal/AbstractStructuredGraphViewer.java >--- src/org/eclipse/zest/core/viewers/internal/AbstractStructuredGraphViewer.java 4 May 2009 05:20:33 -0000 1.16 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,756 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.core.viewers.internal; >- >-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.AbstractZoomableViewer; >-import org.eclipse.zest.core.viewers.IGraphContentProvider; >-import org.eclipse.zest.core.widgets.CGraphNode; >-import org.eclipse.zest.core.widgets.ConstraintAdapter; >-import org.eclipse.zest.core.widgets.Graph; >-import org.eclipse.zest.core.widgets.GraphConnection; >-import org.eclipse.zest.core.widgets.GraphContainer; >-import org.eclipse.zest.core.widgets.GraphItem; >-import org.eclipse.zest.core.widgets.GraphNode; >-import org.eclipse.zest.core.widgets.IContainer; >-import org.eclipse.zest.core.widgets.ZestStyles; >-import org.eclipse.zest.layouts.LayoutAlgorithm; >- >-/* >- * Abstraction of graph viewers to implement functionality used by all of them. >- * Not intended to be implemented by clients. Use one of the provided children >- * instead. >- * >- * @author Del Myers >- */ >-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(); >- >- /** >- * The constraint adatpers >- */ >- private List constraintAdapters = new ArrayList(); >- >- /** >- * A simple graph comparator that orders graph elements based on thier type >- * (connection or node), and their unique object identification. >- */ >- 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; >- } >- >- /** >- * Adds a new constraint adapter to the list of constraints >- * >- * @param constraintAdapter >- */ >- public void addConstraintAdapter(ConstraintAdapter constraintAdapter) { >- this.constraintAdapters.add(constraintAdapter); >- } >- >- /** >- * Gets all the constraint adapters currently on the viewer >- * >- * @return >- */ >- public List getConstraintAdapters() { >- return this.constraintAdapters; >- } >- >- /** >- * Sets the layout algorithm for this viewer. Subclasses may place >- * restrictions on the algorithms that it accepts. >- * >- * @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(); >- } >- >- HashMap getNodesMap() { >- return this.nodesMap; >- } >- >- 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; >- } >- >- GraphNode addGraphModelNode(IContainer 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; >- } >- >- 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; >- } >- >- 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; >- >- } >- >- GraphConnection getGraphModelConnection(Object obj) { >- return (GraphConnection) this.connectionsMap.get(obj); >- } >- >- GraphNode getGraphModelNode(Object obj) { >- return (GraphNode) this.nodesMap.get(obj); >- } >- >- void removeGraphModelConnection(Object obj) { >- GraphConnection connection = (GraphConnection) connectionsMap.get(obj); >- if (connection != null) { >- connectionsMap.remove(obj); >- if (!connection.isDisposed()) { >- connection.dispose(); >- } >- } >- } >- >- 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); >- } >- } >- } >- >- applyLayout(); >- } >- >- /** >- * Returns the factory used to create the model. This must not be called >- * before the content provider is set. >- * >- * @return >- */ >- 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 layout algorithm >- if (getLayoutAlgorithm() != null) { >- getLayoutAlgorithm().removeRelationship(relationship.getLayoutRelationship()); >- } >- // 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 from the layout algorithm and all the connections >- if (getLayoutAlgorithm() != null) { >- getLayoutAlgorithm().removeEntity(node.getLayoutEntity()); >- getLayoutAlgorithm().removeRelationships(node.getSourceConnections()); >- getLayoutAlgorithm().removeRelationships(node.getTargetConnections()); >- } >- // remove the node and it's connections from the model >- node.dispose(); >- } >- } >- >- /** >- * 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; >- } >- >-} >Index: src/org/eclipse/zest/core/viewers/internal/ZoomManager.java >=================================================================== >RCS file: src/org/eclipse/zest/core/viewers/internal/ZoomManager.java >diff -N src/org/eclipse/zest/core/viewers/internal/ZoomManager.java >--- src/org/eclipse/zest/core/viewers/internal/ZoomManager.java 12 Sep 2007 20:44:39 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,598 +0,0 @@ >-/******************************************************************************* >- * Copyright (c) 2000, 2005 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; >- >-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; >- >-/** >- * 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 >- */ >-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()); >- } >- >-} >Index: src/org/eclipse/zest/core/viewers/internal/ZoomListener.java >=================================================================== >RCS file: src/org/eclipse/zest/core/viewers/internal/ZoomListener.java >diff -N src/org/eclipse/zest/core/viewers/internal/ZoomListener.java >--- src/org/eclipse/zest/core/viewers/internal/ZoomListener.java 12 Sep 2007 20:44:39 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,25 +0,0 @@ >-/******************************************************************************* >- * Copyright (c) 2000, 2005 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; >- >-/** >- * Listens to zoom level changes. >- * @author Eric Bordeau >- */ >-public interface ZoomListener { >- >-/** >- * Called whenever the ZoomManager's zoom level changes. >- * @param zoom the new zoom level. >- */ >-void zoomChanged(double zoom); >- >-} >Index: src/org/eclipse/zest/core/viewers/internal/SharedMessages.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/internal/SharedMessages.java,v >retrieving revision 1.3 >diff -u -r1.3 SharedMessages.java >--- src/org/eclipse/zest/core/viewers/internal/SharedMessages.java 12 Sep 2007 20:44:39 -0000 1.3 >+++ src/org/eclipse/zest/core/viewers/internal/SharedMessages.java 28 Aug 2009 16:03:19 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2003, 2005 IBM Corporation and others. All rights reserved. >+ * Copyright (c) 2003, 2005-2009 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 >@@ -19,14 +19,14 @@ > /** > * The string "Page". > */ >- public static String FitAllAction_Label = "Page"; //GEFMessages.FitAllAction_Label; >+ public static String FitAllAction_Label = "Page"; // GEFMessages.FitAllAction_Label; > /** > * The string "Width". > */ >- public static String FitWidthAction_Label = "Width"; //GEFMessages.FitWidthAction_Label; >+ public static String FitWidthAction_Label = "Width"; // GEFMessages.FitWidthAction_Label; > /** > * The string "Height". > */ >- public static String FitHeightAction_Label = "Height"; //GEFMessages.FitHeightAction_Label; >+ public static String FitHeightAction_Label = "Height"; // GEFMessages.FitHeightAction_Label; > > } >Index: src/org/eclipse/zest/core/viewers/internal/GraphModelFactory.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/internal/GraphModelFactory.java,v >retrieving revision 1.6 >diff -u -r1.6 GraphModelFactory.java >--- src/org/eclipse/zest/core/viewers/internal/GraphModelFactory.java 31 Mar 2009 16:39:23 -0000 1.6 >+++ src/org/eclipse/zest/core/viewers/internal/GraphModelFactory.java 28 Aug 2009 16:03:19 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials are made > * available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at >@@ -12,6 +12,7 @@ > 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; >@@ -46,12 +47,15 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory#doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel) >+ * @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()); >+ Object rels[] = getContentProvider() >+ .getElements(getViewer().getInput()); > if (rels != null) { > IFigureProvider figureProvider = null; > if (getLabelProvider() instanceof IFigureProvider) { >@@ -63,17 +67,20 @@ > 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; >+ 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; >+ 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)); >+ createNode(model, dest, figureProvider >+ .getFigure(dest)); > } else { > createNode(model, dest); > } >@@ -83,7 +90,8 @@ > // just create the node for the source > if (source != null) { > if (figureProvider != null) { >- createNode(model, source, figureProvider.getFigure(dest)); >+ createNode(model, source, figureProvider >+ .getFigure(dest)); > } else { > createNode(model, source); > } >@@ -92,8 +100,11 @@ > } > // 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])); >+ if (source != null && dest != null >+ && !filterElement(getViewer().getInput(), rels[i])) { >+ createConnection(model, rels[i], getCastedContent() >+ .getSource(rels[i]), getCastedContent() >+ .getDestination(rels[i])); > } > } > } >@@ -107,8 +118,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh(org.eclipse.zest.core.internal.graphmodel.GraphModel, >- * java.lang.Object) >+ * @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); >@@ -117,8 +129,10 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh(org.eclipse.zest.core.internal.graphmodel.GraphModel, >- * java.lang.Object, boolean) >+ * @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); >@@ -157,10 +171,6 @@ > } else if (updateLabels) { > styleItem(internalDest); > } >- >- // @tag TODO: Remove these lines >- // conn.disconnect(); >- // conn.reconnect(internalSource, internalDest); > if (updateLabels) { > styleItem(conn); > } >Index: src/org/eclipse/zest/core/viewers/internal/GraphModelEntityRelationshipFactory.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/internal/GraphModelEntityRelationshipFactory.java,v >retrieving revision 1.7 >diff -u -r1.7 GraphModelEntityRelationshipFactory.java >--- src/org/eclipse/zest/core/viewers/internal/GraphModelEntityRelationshipFactory.java 30 Jan 2009 22:25:48 -0000 1.7 >+++ src/org/eclipse/zest/core/viewers/internal/GraphModelEntityRelationshipFactory.java 28 Aug 2009 16:03:18 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, > * Canada. All rights reserved. This program and the accompanying materials are > * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at >@@ -12,6 +12,7 @@ > 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; >@@ -25,19 +26,24 @@ > // @tag bug.154580-Content.fix > // @tag bug.160367-Refreshing.fix : updated to use new > // AbstractStylingModelFactory >-public class GraphModelEntityRelationshipFactory extends AbstractStylingModelFactory { >+public class GraphModelEntityRelationshipFactory extends >+ AbstractStylingModelFactory { > >- public GraphModelEntityRelationshipFactory(AbstractStructuredGraphViewer viewer) { >+ public GraphModelEntityRelationshipFactory( >+ AbstractStructuredGraphViewer viewer) { > super(viewer); > if (!(viewer.getContentProvider() instanceof IGraphEntityRelationshipContentProvider)) { >- throw new IllegalArgumentException("Expected IGraphEntityRelationshipContentProvider"); >+ throw new IllegalArgumentException( >+ "Expected IGraphEntityRelationshipContentProvider"); > } > } > > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory#createGraphModel() >+ * @see >+ * org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory >+ * #createGraphModel() > */ > public Graph createGraphModel(Graph model) { > doBuildGraph(model); >@@ -47,11 +53,14 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory#doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel) >+ * @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()); >+ Object[] nodes = getContentProvider().getElements( >+ getViewer().getInput()); > nodes = filter(getViewer().getInput(), nodes); > createModelNodes(model, nodes); > createModelRelationships(model); >@@ -78,16 +87,19 @@ > listOfNodes.addAll(childNodes); > } > } >- modelNodes = (GraphNode[]) listOfNodes.toArray(new GraphNode[listOfNodes.size()]); >+ 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()); >+ 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()); >+ createConnection(model, rels[r], modelNodes[i] >+ .getData(), modelNodes[j].getData()); > } > } > } >@@ -111,8 +123,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh(org.eclipse.zest.core.internal.graphmodel.GraphModel, >- * java.lang.Object) >+ * @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); >@@ -121,8 +134,10 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh(org.eclipse.zest.core.internal.graphmodel.GraphModel, >- * java.lang.Object, boolean) >+ * @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 >Index: src/org/eclipse/zest/core/viewers/internal/GraphItemStyler.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/viewers/internal/GraphItemStyler.java,v >retrieving revision 1.12 >diff -u -r1.12 GraphItemStyler.java >--- src/org/eclipse/zest/core/viewers/internal/GraphItemStyler.java 4 May 2009 04:47:32 -0000 1.12 >+++ src/org/eclipse/zest/core/viewers/internal/GraphItemStyler.java 28 Aug 2009 16:03:18 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, > * Canada. All rights reserved. This program and the accompanying materials are > * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at >@@ -33,7 +33,8 @@ > */ > // @tag bug(151327-Styles) : created to help resolve this bug > public class GraphItemStyler { >- public static void styleItem(GraphItem item, final IBaseLabelProvider labelProvider) { >+ public static void styleItem(GraphItem item, >+ final IBaseLabelProvider labelProvider) { > > if (item instanceof GraphNode) { > GraphNode node = (GraphNode) item; >@@ -57,12 +58,15 @@ > node.setFont(fontProvider.getFont(entity)); > } > if (labelProvider instanceof ILabelProvider) { >- String text = ((ILabelProvider) labelProvider).getText(node.getData()); >+ String text = ((ILabelProvider) labelProvider).getText(node >+ .getData()); > node.setText((text != null) ? text : ""); >- node.setImage(((ILabelProvider) labelProvider).getImage(node.getData())); >+ node.setImage(((ILabelProvider) labelProvider).getImage(node >+ .getData())); > } > if (labelProvider instanceof ISelfStyleProvider) { >- ((ISelfStyleProvider) labelProvider).selfStyleNode(entity, node); >+ ((ISelfStyleProvider) labelProvider) >+ .selfStyleNode(entity, node); > } > } else if (item instanceof GraphConnection) { > GraphConnection conn = (GraphConnection) item; >@@ -75,19 +79,23 @@ > conn.setConnectionStyle(SWT.NONE); > } > if (labelProvider instanceof ILabelProvider) { >- String text = ((ILabelProvider) labelProvider).getText(conn.getExternalConnection()); >+ String text = ((ILabelProvider) labelProvider).getText(conn >+ .getExternalConnection()); > conn.setText((text != null) ? text : ""); >- conn.setImage(((ILabelProvider) labelProvider).getImage(conn.getExternalConnection())); >+ conn.setImage(((ILabelProvider) labelProvider).getImage(conn >+ .getExternalConnection())); > } > if (labelProvider instanceof IEntityConnectionStyleProvider) { >- styleEntityConnection(conn, (IEntityConnectionStyleProvider) labelProvider); >+ 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); >+ ((ISelfStyleProvider) labelProvider).selfStyleConnection(conn >+ .getData(), conn); > } > } > } >@@ -96,7 +104,8 @@ > * @param conn > * @param provider > */ >- private static void styleConnection(GraphConnection conn, IConnectionStyleProvider provider) { >+ private static void styleConnection(GraphConnection conn, >+ IConnectionStyleProvider provider) { > Object rel = conn.getExternalConnection(); > Color c; > int style = provider.getConnectionStyle(rel); >@@ -147,7 +156,8 @@ > * @param conn > * @param provider > */ >- private static void styleEntityConnection(GraphConnection conn, IEntityConnectionStyleProvider provider) { >+ private static void styleEntityConnection(GraphConnection conn, >+ IEntityConnectionStyleProvider provider) { > Object src = conn.getSource().getData(); > Object dest = conn.getDestination().getData(); > Color c; >@@ -159,7 +169,8 @@ > conn.setConnectionStyle(style); > } > // @tag bug(152530-Bezier(fisx)) >- // @tag TODO curved connections bezier : add back the bezier connection stuff >+ // @tag TODO curved connections bezier : add back the bezier connection >+ // stuff > // if (ZestStyles.checkStyle(conn.getConnectionStyle(), > // ZestStyles.CONNECTIONS_BEZIER) > // && provider instanceof IEntityConnectionStyleBezierExtension) { >@@ -205,17 +216,14 @@ > private static void styleNode(GraphNode node, IEntityStyleProvider provider) { > Object entity = node.getData(); > // @tag ADJACENT : Removed highlight adjacent >- //node.setHighlightAdjacentNodes(provider.highlightAdjacentEntities(entity)); >+ // 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); >- } >- } >- */ >+ * if (provider.highlightAdjacentEntities(entity)) { Color c = >+ * provider.getAdjacentEntityHighlightColor(entity); if (c != null) { >+ * node.setHighlightAdjacentColor(c); } } >+ */ > Color c; > IFigure figure; > int width = -1; >@@ -251,7 +259,9 @@ > * > */ > public static int getLineStyleForZestStyle(int style) { >- int lineStyles = ZestStyles.CONNECTIONS_DASH_DOT | ZestStyles.CONNECTIONS_DASH | ZestStyles.CONNECTIONS_DOT | ZestStyles.CONNECTIONS_SOLID; >+ 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; >Index: src/org/eclipse/zest/core/widgets/Graph.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/Graph.java,v >retrieving revision 1.41 >diff -u -r1.41 Graph.java >--- src/org/eclipse/zest/core/widgets/Graph.java 30 Jan 2009 01:14:33 -0000 1.41 >+++ src/org/eclipse/zest/core/widgets/Graph.java 28 Aug 2009 16:03:20 -0000 >@@ -1,22 +1,24 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials are made >- * available under the terms of the Eclipse Public License v1.0 which >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html > * >- * Contributors: The Chisel Group, University of Victoria >+ * Contributors: The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 > ******************************************************************************/ > package org.eclipse.zest.core.widgets; > > import java.util.ArrayList; > import java.util.HashMap; >+import java.util.HashSet; > import java.util.Iterator; >-import java.util.LinkedList; > import java.util.List; > > import org.eclipse.draw2d.Animation; > import org.eclipse.draw2d.ColorConstants; >+import org.eclipse.draw2d.CoordinateListener; > import org.eclipse.draw2d.FigureCanvas; > import org.eclipse.draw2d.FreeformLayer; > import org.eclipse.draw2d.FreeformLayout; >@@ -34,6 +36,8 @@ > import org.eclipse.draw2d.geometry.Point; > import org.eclipse.draw2d.geometry.Rectangle; > import org.eclipse.swt.SWT; >+import org.eclipse.swt.events.ControlEvent; >+import org.eclipse.swt.events.ControlListener; > import org.eclipse.swt.events.PaintEvent; > import org.eclipse.swt.events.PaintListener; > import org.eclipse.swt.events.SelectionAdapter; >@@ -41,27 +45,18 @@ > import org.eclipse.swt.events.SelectionListener; > import org.eclipse.swt.graphics.Color; > import org.eclipse.swt.widgets.Composite; >-import org.eclipse.swt.widgets.Control; > import org.eclipse.swt.widgets.Display; > import org.eclipse.swt.widgets.Event; > import org.eclipse.swt.widgets.Item; >+import org.eclipse.swt.widgets.Widget; > import org.eclipse.zest.core.widgets.internal.ContainerFigure; >-import org.eclipse.zest.core.widgets.internal.RevealListener; > import org.eclipse.zest.core.widgets.internal.ZestRootLayer; >-import org.eclipse.zest.layouts.InvalidLayoutConfiguration; > import org.eclipse.zest.layouts.LayoutAlgorithm; >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.LayoutRelationship; >-import org.eclipse.zest.layouts.LayoutStyles; >-import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; >-import org.eclipse.zest.layouts.constraints.LayoutConstraint; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >+import org.eclipse.zest.layouts.interfaces.ExpandCollapseManager; > >-/* >- * Holds the nodes and connections for the graph. >- * >- * @author Chris Callendar >- * >- * @author Ian Bull >+/** >+ * @since 1.0 > */ > public class Graph extends FigureCanvas implements IContainer { > >@@ -85,23 +80,23 @@ > * These are all the children of this graph. These lists contains all nodes > * and connections that have added themselves to this graph. > */ >- private final List nodes; >+ private List nodes; > protected List connections; >+ HashSet subgraphFigures; > private List selectedItems = null; >- IFigure fisheyedFigure = null; >- private List /* SelectionListener */selectionListeners = null; >+ private ArrayList fisheyeListeners = new ArrayList(); >+ private List selectionListeners = null; > > /** This maps all visible nodes to their model element. */ > private HashMap figure2ItemMap = null; > >- /** Maps user nodes to internal nodes */ > private int connectionStyle; > private int nodeStyle; >- private List constraintAdapters; >- private List revealListeners = null; >- > private ScalableFreeformLayeredPane fishEyeLayer = null; >- LayoutAlgorithm layoutAlgorithm = null; >+ private InternalLayoutContext layoutContext = null; >+ private volatile boolean shouldSheduleLayout; >+ private volatile Runnable scheduledLayoutRunnable = null; >+ private volatile boolean scheduledLayoutClean = false; > private Dimension preferredSize = null; > int style = 0; > >@@ -120,12 +115,6 @@ > this.style = style; > this.setBackground(ColorConstants.white); > >- LIGHT_BLUE = new Color(Display.getDefault(), 216, 228, 248); >- LIGHT_BLUE_CYAN = new Color(Display.getDefault(), 213, 243, 255); >- GREY_BLUE = new Color(Display.getDefault(), 139, 150, 171); >- DARK_BLUE = new Color(Display.getDefault(), 1, 70, 122); >- LIGHT_YELLOW = new Color(Display.getDefault(), 255, 255, 206); >- > this.setViewport(new FreeformViewport()); > > this.getVerticalBar().addSelectionListener(new SelectionAdapter() { >@@ -142,67 +131,69 @@ > > // @tag CGraph.workaround : this allows me to handle mouse events > // outside of the canvas >- this.getLightweightSystem().setEventDispatcher(new SWTEventDispatcher() { >- public void dispatchMouseMoved(org.eclipse.swt.events.MouseEvent me) { >- super.dispatchMouseMoved(me); >- >- // If the current event is null, return >- if (getCurrentEvent() == null) { >- return; >- } >+ this.getLightweightSystem().setEventDispatcher( >+ new SWTEventDispatcher() { >+ public void dispatchMouseMoved( >+ org.eclipse.swt.events.MouseEvent me) { >+ super.dispatchMouseMoved(me); >+ >+ // If the current event is null, return >+ if (getCurrentEvent() == null) { >+ return; >+ } > >- if (getMouseTarget() == null) { >- setMouseTarget(getRoot()); >- } >- if ((me.stateMask & SWT.BUTTON_MASK) != 0) { >- // Sometimes getCurrentEvent() returns null >- getMouseTarget().handleMouseDragged(getCurrentEvent()); >- } else { >- getMouseTarget().handleMouseMoved(getCurrentEvent()); >- } >- } >- }); >+ if (getMouseTarget() == null) { >+ setMouseTarget(getRoot()); >+ } >+ if ((me.stateMask & SWT.BUTTON_MASK) != 0) { >+ // Sometimes getCurrentEvent() returns null >+ getMouseTarget().handleMouseDragged( >+ getCurrentEvent()); >+ } else { >+ getMouseTarget() >+ .handleMouseMoved(getCurrentEvent()); >+ } >+ } >+ }); > > this.setContents(createLayers()); >- DragSupport dragSupport = new DragSupport(this); >- this.getLightweightSystem().getRootFigure().addMouseListener(dragSupport); >- this.getLightweightSystem().getRootFigure().addMouseMotionListener(dragSupport); >+ DragSupport dragSupport = new DragSupport(); >+ this.getLightweightSystem().getRootFigure().addMouseListener( >+ dragSupport); >+ this.getLightweightSystem().getRootFigure().addMouseMotionListener( >+ dragSupport); > > this.nodes = new ArrayList(); > this.preferredSize = new Dimension(-1, -1); > this.connectionStyle = ZestStyles.NONE; > this.nodeStyle = ZestStyles.NONE; > this.connections = new ArrayList(); >- this.constraintAdapters = new ArrayList(); >+ this.subgraphFigures = new HashSet(); > this.selectedItems = new ArrayList(); > this.selectionListeners = new ArrayList(); > this.figure2ItemMap = new HashMap(); > >- revealListeners = new ArrayList(1); > this.addPaintListener(new PaintListener() { > public void paintControl(PaintEvent e) { >- if (!revealListeners.isEmpty()) { >- // Go through the reveal list and let everyone know that the >- // view is now available. Remove the listeners so they are >- // only >- // called once! >- Iterator iterator = revealListeners.iterator(); >- while (iterator.hasNext()) { >- RevealListener reveallisetner = (RevealListener) iterator.next(); >- reveallisetner.revealed(Graph.this); >- iterator.remove(); >- } >- } >- /* >- Iterator iterator = getNodes().iterator(); >- while (iterator.hasNext()) { >- GraphNode node = (GraphNode) iterator.next(); >- node.paint(); >+ if (shouldSheduleLayout) { >+ applyLayoutInternal(true); >+ shouldSheduleLayout = false; > } >- */ > } > }); > >+ this.addControlListener(new ControlListener() { >+ >+ public void controlResized(ControlEvent e) { >+ if (preferredSize.width == -1 || preferredSize.height == -1) { >+ getLayoutContext().fireBoundsChangedEvent(); >+ } >+ } >+ >+ public void controlMoved(ControlEvent e) { >+ // do nothing >+ } >+ }); > } > > /** >@@ -235,23 +226,6 @@ > } > > /** >- * Adds a new constraint adapter to the list of constraint adapters >- * @param constraintAdapter >- */ >- public void addConstraintAdapter(ConstraintAdapter constraintAdapter) { >- this.constraintAdapters.add(constraintAdapter); >- } >- >- /** >- * Sets the constraint adapters on this model >- * >- * @param constraintAdapters >- */ >- public void setConstraintAdapters(List /* ConstraintAdapters */constraintAdapters) { >- this.constraintAdapters = constraintAdapters; >- } >- >- /** > * Gets the root layer for this graph > * > * @return >@@ -326,6 +300,7 @@ > } > } > } >+ // TODO shouldn't this method fire a selection event? > } > > public void selectAll() { >@@ -334,6 +309,7 @@ > selectedItems.add(nodes.get(i)); > ((GraphNode) nodes.get(i)).highlight(); > } >+ // TODO shouldn't this method fire a selection event? > } > > /** >@@ -351,16 +327,8 @@ > * @see org.eclipse.swt.widgets.Widget#toString() > */ > public String toString() { >- return "GraphModel {" + nodes.size() + " nodes, " + connections.size() + " connections}"; >- } >- >- /* >- * (non-Javadoc) >- * >- * @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphItem#getGraphModel() >- */ >- public Graph getGraphModel() { >- return this; >+ return "GraphModel {" + nodes.size() + " nodes, " + connections.size() >+ + " connections}"; > } > > /** >@@ -389,21 +357,70 @@ > } > > /** >- * Runs the layout on this graph. It uses the reveal listner to run the >- * layout only if the view is visible. Otherwise it will be deferred until >- * after the view is available. >+ * Runs the layout on this graph. If the view is not visible layout will be >+ * deferred until after the view is available. > */ > public void applyLayout() { >- this.addRevealListener(new RevealListener() { >- public void revealed(Control c) { >- Display.getDefault().asyncExec(new Runnable() { >+ scheduleLayoutOnReveal(true); >+ } > >- public void run() { >- applyLayoutInternal(); >- } >- }); >+ /** >+ * Enables or disables dynamic layout (that is layout algorithm performing >+ * layout in background or when certain events occur). Dynamic layout should >+ * be disabled before doing a long series of changes in the graph to make >+ * sure that layout algorithm won't interfere with these changes. >+ * >+ * Enabling dynamic layout causes the layout algorithm to be applied even if >+ * it's not actually a dynamic algorithm. >+ * >+ * @param enabled >+ * >+ * @since 2.0 >+ */ >+ public void setDynamicLayout(boolean enabled) { >+ if (getLayoutContext().isBackgroundLayoutEnabled() != enabled) { >+ layoutContext.setBackgroundLayoutEnabled(enabled); >+ if (enabled) { >+ scheduleLayoutOnReveal(false); > } >- }); >+ } >+ } >+ >+ /** >+ * >+ * @return true if dynamic layout is enabled (see >+ * {@link #setDynamicLayout(boolean)}) >+ * @since 2.0 >+ */ >+ public boolean isDynamicLayoutEnabled() { >+ return getLayoutContext().isBackgroundLayoutEnabled(); >+ } >+ >+ private void applyLayoutInternal(boolean clean) { >+ if (getLayoutContext().getLayoutAlgorithm() == null) { >+ return; >+ } >+ scheduledLayoutClean = scheduledLayoutClean || clean; >+ synchronized (this) { >+ if (scheduledLayoutRunnable == null) { >+ Display.getDefault().asyncExec( >+ scheduledLayoutRunnable = new Runnable() { >+ public void run() { >+ Animation.markBegin(); >+ getLayoutContext().applyLayout( >+ scheduledLayoutClean); >+ layoutContext.flushChanges(false); >+ Animation.run(ANIMATION_TIME); >+ getLightweightSystem().getUpdateManager() >+ .performUpdate(); >+ synchronized (Graph.this) { >+ scheduledLayoutRunnable = null; >+ scheduledLayoutClean = false; >+ } >+ } >+ }); >+ } >+ } > } > > /** >@@ -415,20 +432,106 @@ > */ > public void setPreferredSize(int width, int height) { > this.preferredSize = new Dimension(width, height); >+ getLayoutContext().fireBoundsChangedEvent(); >+ } >+ >+ /** >+ * @return the preferred size of the layout area. >+ * @since 2.0 >+ */ >+ public Dimension getPreferredSize() { >+ if (preferredSize.width < 0 || preferredSize.height < 0) { >+ org.eclipse.swt.graphics.Point size = getSize(); >+ double scale = getRootLayer().getScale(); >+ return new Dimension((int) (size.x / scale + 0.5), (int) (size.y >+ / scale + 0.5)); >+ } >+ return preferredSize; >+ } >+ >+ /** >+ * @noreference This method is not intended to be referenced by clients. >+ */ >+ public InternalLayoutContext getLayoutContext() { >+ if (layoutContext == null) { >+ layoutContext = new InternalLayoutContext(this); >+ } >+ return layoutContext; > } > > /** > * @param algorithm >+ * @since 2.0 > */ >- public void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean applyLayout) { >- this.layoutAlgorithm = algorithm; >+ public void setLayoutAlgorithm(LayoutAlgorithm algorithm, >+ boolean applyLayout) { >+ getLayoutContext().setLayoutAlgorithm(algorithm); > if (applyLayout) { > applyLayout(); > } > } > >+ /** >+ * @since 2.0 >+ */ > public LayoutAlgorithm getLayoutAlgorithm() { >- return this.layoutAlgorithm; >+ return getLayoutContext().getLayoutAlgorithm(); >+ } >+ >+ /** >+ * @since 2.0 >+ */ >+ public void setSubgraphFactory(SubgraphFactory factory) { >+ getLayoutContext().setSubgraphFactory(factory); >+ } >+ >+ /** >+ * @since 2.0 >+ */ >+ public SubgraphFactory getSubgraphFactory() { >+ return getLayoutContext().getSubgraphFactory(); >+ } >+ >+ /** >+ * @since 2.0 >+ */ >+ public void setExpandCollapseManager( >+ ExpandCollapseManager expandCollapseManager) { >+ getLayoutContext().setExpandCollapseManager(expandCollapseManager); >+ } >+ >+ /** >+ * @since 2.0 >+ */ >+ public ExpandCollapseManager getExpandCollapseManager() { >+ return getLayoutContext().getExpandCollapseManager(); >+ } >+ >+ /** >+ * Adds a filter used for hiding elements from layout algorithm. >+ * >+ * NOTE: If a node or subgraph if filtered out, all connections adjacent to >+ * it should also be filtered out. Otherwise layout algorithm may behave in >+ * an unexpected way. >+ * >+ * @param filter >+ * filter to add >+ * @since 2.0 >+ */ >+ public void addLayoutFilter(LayoutFilter filter) { >+ getLayoutContext().addFilter(filter); >+ } >+ >+ /** >+ * Removes given layout filter. If it had not been added to this graph, this >+ * method does nothing. >+ * >+ * @param filter >+ * filter to remove >+ * @since 2.0 >+ */ >+ public void removeLayoutFilter(LayoutFilter filter) { >+ getLayoutContext().removeFilter(filter); > } > > /** >@@ -437,112 +540,143 @@ > * This point should be translated to relative before calling findFigureAt > */ > public IFigure getFigureAt(int x, int y) { >- IFigure figureUnderMouse = this.getContents().findFigureAt(x, y, new TreeSearch() { >+ IFigure figureUnderMouse = this.getContents().findFigureAt(x, y, >+ new TreeSearch() { > >- public boolean accept(IFigure figure) { >- return true; >- } >- >- public boolean prune(IFigure figure) { >- IFigure parent = figure.getParent(); >- // @tag TODO Zest : change these to from getParent to their actual layer names >+ public boolean accept(IFigure figure) { >+ return true; >+ } > >- if (parent == fishEyeLayer) { >- // If it node is on the fish eye layer, don't worry about it. >- return true; >- } >- if (parent instanceof ContainerFigure && figure instanceof PolylineConnection) { >- return false; >- } >- if (parent == zestRootLayer || parent == zestRootLayer.getParent() || parent == zestRootLayer.getParent().getParent()) { >- return false; >- } >- GraphItem item = (GraphItem) figure2ItemMap.get(figure); >- if (item != null && item.getItemType() == GraphItem.CONTAINER) { >- return false; >- } else if (figure instanceof FreeformLayer || parent instanceof FreeformLayer || figure instanceof ScrollPane || parent instanceof ScrollPane || parent instanceof ScalableFreeformLayeredPane || figure instanceof ScalableFreeformLayeredPane || figure instanceof FreeformViewport || >- parent instanceof FreeformViewport) { >- return false; >- } >- return true; >- } >+ public boolean prune(IFigure figure) { >+ IFigure parent = figure.getParent(); >+ // @tag TODO Zest : change these to from getParent to >+ // their >+ // actual layer names >+ >+ if (parent == fishEyeLayer) { >+ // If it node is on the fish eye layer, don't worry >+ // about >+ // it. >+ return true; >+ } >+ if (parent instanceof ContainerFigure >+ && figure instanceof PolylineConnection) { >+ return false; >+ } >+ if (parent == zestRootLayer >+ || parent == zestRootLayer.getParent() >+ || parent == zestRootLayer.getParent() >+ .getParent()) { >+ return false; >+ } >+ GraphItem item = (GraphItem) figure2ItemMap.get(figure); >+ if (item != null >+ && item.getItemType() == GraphItem.CONTAINER) { >+ return false; >+ } else if (figure instanceof FreeformLayer >+ || parent instanceof FreeformLayer >+ || figure instanceof ScrollPane >+ || parent instanceof ScrollPane >+ || parent instanceof ScalableFreeformLayeredPane >+ || figure instanceof ScalableFreeformLayeredPane >+ || figure instanceof FreeformViewport >+ || parent instanceof FreeformViewport) { >+ return false; >+ } >+ return true; >+ } > >- }); >+ }); > return figureUnderMouse; > > } > >- // ///////////////////////////////////////////////////////////////////////////////// >- // PRIVATE METHODS. These are NON API >- // ///////////////////////////////////////////////////////////////////////////////// >- class DragSupport implements MouseMotionListener, org.eclipse.draw2d.MouseListener { >- /** >- * >- */ >- Graph graph = null; >- Point lastLocation = null; >+ private class DragSupport implements MouseMotionListener, >+ org.eclipse.draw2d.MouseListener { >+ >+ Point dragStartLocation = null; >+ IFigure draggedSubgraphFigure = null; >+ /** locations of dragged items relative to cursor position */ >+ ArrayList relativeLocations = new ArrayList(); > GraphItem fisheyedItem = null; > boolean isDragging = false; > >- DragSupport(Graph graph) { >- this.graph = graph; >- } >- > public void mouseDragged(org.eclipse.draw2d.MouseEvent me) { > if (!isDragging) { > return; > } >- Point mousePoint = new Point(me.x, me.y); >- Point tempPoint = mousePoint.getCopy(); >- if (selectedItems.size() > 0) { >- Iterator iterator = selectedItems.iterator(); >- while (iterator.hasNext()) { >- GraphItem item = (GraphItem) iterator.next(); >- if ((item.getItemType() == GraphItem.NODE) || (item.getItemType() == GraphItem.CONTAINER)) { >- // @tag Zest.selection Zest.move : This is where the node movement is tracked >- Point pointCopy = mousePoint.getCopy(); >+ if (selectedItems.isEmpty()) { >+ IFigure figureUnderMouse = getFigureAt(dragStartLocation.x, >+ dragStartLocation.y); >+ if (subgraphFigures.contains(figureUnderMouse)) { >+ draggedSubgraphFigure = figureUnderMouse; >+ } >+ } > >- Point tempLastLocation = lastLocation.getCopy(); >- item.getFigure().getParent().translateToRelative(tempLastLocation); >- item.getFigure().getParent().translateFromParent(tempLastLocation); >- >- item.getFigure().getParent().translateToRelative(pointCopy); >- item.getFigure().getParent().translateFromParent(pointCopy); >- Point delta = new Point(pointCopy.x - tempLastLocation.x, pointCopy.y - tempLastLocation.y); >- if (item.getItemType() == GraphItem.NODE || item.getItemType() == GraphItem.CONTAINER) { >- GraphNode node = (GraphNode) item; >- node.setLocation(node.getLocation().x + delta.x, node.getLocation().y + delta.y); >+ Point mousePoint = new Point(me.x, me.y); >+ if (!selectedItems.isEmpty() || draggedSubgraphFigure != null) { > >+ if (relativeLocations.isEmpty()) { >+ for (Iterator iterator = selectedItems.iterator(); iterator >+ .hasNext();) { >+ GraphItem item = (GraphItem) iterator.next(); >+ if ((item.getItemType() == GraphItem.NODE) >+ || (item.getItemType() == GraphItem.CONTAINER)) { >+ relativeLocations.add(getRelativeLocation(item >+ .getFigure())); > } >- /* >- else if (item.getItemType() == GraphItem.CONTAINER) { >- GraphContainer container = (GraphContainer) item; >- container.setLocation(container.getLocation().x + delta.x, container.getLocation().y + delta.y); >- } >- */ >+ } >+ if (draggedSubgraphFigure != null) { >+ relativeLocations >+ .add(getRelativeLocation(draggedSubgraphFigure)); >+ } >+ } >+ >+ Iterator locationsIterator = relativeLocations.iterator(); >+ for (Iterator selectionIterator = selectedItems.iterator(); selectionIterator >+ .hasNext();) { >+ GraphItem item = (GraphItem) selectionIterator.next(); >+ if ((item.getItemType() == GraphItem.NODE) >+ || (item.getItemType() == GraphItem.CONTAINER)) { >+ Point pointCopy = mousePoint.getCopy(); >+ Point relativeLocation = (Point) locationsIterator >+ .next(); >+ >+ item.getFigure().getParent().translateToRelative( >+ pointCopy); >+ item.getFigure().getParent().translateFromParent( >+ pointCopy); >+ >+ ((GraphNode) item) >+ .setLocation(relativeLocation.x + pointCopy.x, >+ relativeLocation.y + pointCopy.y); > } else { > // There is no movement for connection > } > } >- if (fisheyedFigure != null) { >+ if (draggedSubgraphFigure != null) { > Point pointCopy = mousePoint.getCopy(); >- >- Point tempLastLocation = lastLocation.getCopy(); >- fisheyedFigure.translateToRelative(tempLastLocation); >- fisheyedFigure.translateFromParent(tempLastLocation); >- >- fisheyedFigure.translateToRelative(pointCopy); >- fisheyedFigure.translateFromParent(pointCopy); >- Point delta = new Point(pointCopy.x - tempLastLocation.x, pointCopy.y - tempLastLocation.y); >- Point point = new Point(fisheyedFigure.getBounds().x + delta.x, fisheyedFigure.getBounds().y + delta.y); >- fishEyeLayer.setConstraint(fisheyedFigure, new Rectangle(point, fisheyedFigure.getSize())); >- fishEyeLayer.getUpdateManager().performUpdate(); >- //fisheyedFigure.setBounds(new Rectangle(point2, fisheyedFigure.getSize())); >- //fisheyedFigure.setLocation(new Point(fisheyedFigure.getBounds().x + delta.x, fisheyedFigure.getBounds().y + delta.y)); >+ draggedSubgraphFigure.getParent().translateToRelative( >+ pointCopy); >+ draggedSubgraphFigure.getParent().translateFromParent( >+ pointCopy); >+ Point relativeLocation = (Point) locationsIterator.next(); >+ pointCopy.x += relativeLocation.x; >+ pointCopy.y += relativeLocation.y; >+ >+ draggedSubgraphFigure.setLocation(pointCopy); > } > } >- lastLocation = tempPoint; >- //oldLocation = mousePoint; >+ } >+ >+ private Point getRelativeLocation(IFigure figure) { >+ Point location = figure.getBounds().getTopLeft(); >+ Point mousePointCopy = dragStartLocation.getCopy(); >+ figure.getParent().translateToRelative(mousePointCopy); >+ figure.getParent().translateFromParent(mousePointCopy); >+ location.x -= mousePointCopy.x; >+ location.y -= mousePointCopy.y; >+ return location; > } > > public void mouseEntered(org.eclipse.draw2d.MouseEvent me) { >@@ -559,7 +693,7 @@ > > /** > * This tracks whenever a mouse moves. The only thing we care about is >- * fisheye(ing) nodes. This means whenever the mouse moves we check if >+ * fisheye(ing) nodes. This means whenever the mouse moves we check if > * we need to fisheye on a node or not. > */ > public void mouseMoved(org.eclipse.draw2d.MouseEvent me) { >@@ -569,27 +703,31 @@ > > if (figureUnderMouse != null) { > // There is a figure under this mouse >- GraphItem itemUnderMouse = (GraphItem) figure2ItemMap.get(figureUnderMouse); >+ GraphItem itemUnderMouse = (GraphItem) figure2ItemMap >+ .get(figureUnderMouse); > if (itemUnderMouse == fisheyedItem) { >- >- } else if (itemUnderMouse != null && itemUnderMouse.getItemType() == GraphItem.NODE) { >+ return; >+ } >+ if (fisheyedItem != null) { >+ ((GraphNode) fisheyedItem).fishEye(false, true); >+ fisheyedItem = null; >+ } >+ if (itemUnderMouse != null >+ && itemUnderMouse.getItemType() == GraphItem.NODE) { > fisheyedItem = itemUnderMouse; >- fisheyedFigure = ((GraphNode) itemUnderMouse).fishEye(true, true); >+ IFigure fisheyedFigure = ((GraphNode) itemUnderMouse) >+ .fishEye(true, true); > if (fisheyedFigure == null) { >- // If there is no fisheye figure (this means that the node does not support a fish eye) >+ // If there is no fisheye figure (this means that the >+ // node does not support a fish eye) > // then remove the fisheyed item > fisheyedItem = null; > } >- } else if (fisheyedItem != null) { >- ((GraphNode) fisheyedItem).fishEye(false, true); >- fisheyedItem = null; >- fisheyedFigure = null; > } > } else { > if (fisheyedItem != null) { > ((GraphNode) fisheyedItem).fishEye(false, true); > fisheyedItem = null; >- fisheyedFigure = null; > } > } > } >@@ -601,7 +739,7 @@ > public void mousePressed(org.eclipse.draw2d.MouseEvent me) { > isDragging = true; > Point mousePoint = new Point(me.x, me.y); >- lastLocation = mousePoint.getCopy(); >+ dragStartLocation = mousePoint.getCopy(); > > getRootLayer().translateToRelative(mousePoint); > >@@ -610,10 +748,11 @@ > scale *= 1.05; > getRootLayer().setScale(scale); > Point newMousePoint = mousePoint.getCopy().scale(1.05); >- Point delta = new Point(newMousePoint.x - mousePoint.x, newMousePoint.y - mousePoint.y); >- Point newViewLocation = getViewport().getViewLocation().getCopy().translate(delta); >+ Point delta = new Point(newMousePoint.x - mousePoint.x, >+ newMousePoint.y - mousePoint.y); >+ Point newViewLocation = getViewport().getViewLocation() >+ .getCopy().translate(delta); > getViewport().setViewLocation(newViewLocation); >- lastLocation.scale(scale); > > clearSelection(); > return; >@@ -623,22 +762,27 @@ > getRootLayer().setScale(scale); > > Point newMousePoint = mousePoint.getCopy().scale(1 / 1.05); >- Point delta = new Point(newMousePoint.x - mousePoint.x, newMousePoint.y - mousePoint.y); >- Point newViewLocation = getViewport().getViewLocation().getCopy().translate(delta); >+ Point delta = new Point(newMousePoint.x - mousePoint.x, >+ newMousePoint.y - mousePoint.y); >+ Point newViewLocation = getViewport().getViewLocation() >+ .getCopy().translate(delta); > getViewport().setViewLocation(newViewLocation); > clearSelection(); > return; > } else { > boolean hasSelection = selectedItems.size() > 0; >- IFigure figureUnderMouse = getFigureAt(mousePoint.x, mousePoint.y); >+ IFigure figureUnderMouse = getFigureAt(mousePoint.x, >+ mousePoint.y); > getRootLayer().translateFromParent(mousePoint); > > if (figureUnderMouse != null) { >- figureUnderMouse.getParent().translateFromParent(mousePoint); >+ figureUnderMouse.getParent() >+ .translateFromParent(mousePoint); > } >- // If the figure under the mouse is the canvas, and CTRL is not being held down, then select >+ // If the figure under the mouse is the canvas, and CTRL is not >+ // being held down, then select > // nothing >- if (figureUnderMouse == null || figureUnderMouse == graph) { >+ if (figureUnderMouse == null || figureUnderMouse == Graph.this) { > if (me.getState() != org.eclipse.draw2d.MouseEvent.CONTROL) { > clearSelection(); > if (hasSelection) { >@@ -649,7 +793,8 @@ > return; > } > >- GraphItem itemUnderMouse = (GraphItem) figure2ItemMap.get(figureUnderMouse); >+ GraphItem itemUnderMouse = (GraphItem) figure2ItemMap >+ .get(figureUnderMouse); > if (itemUnderMouse == null) { > if (me.getState() != org.eclipse.draw2d.MouseEvent.CONTROL) { > clearSelection(); >@@ -661,8 +806,10 @@ > return; > } > if (selectedItems.contains(itemUnderMouse)) { >- // We have already selected this node, and CTRL is being held down, remove this selection >- // @tag Zest.selection : This deselects when you have CTRL pressed >+ // We have already selected this node, and CTRL is being >+ // held down, remove this selection >+ // @tag Zest.selection : This deselects when you have CTRL >+ // pressed > if (me.getState() == org.eclipse.draw2d.MouseEvent.CONTROL) { > selectedItems.remove(itemUnderMouse); > (itemUnderMouse).unhighlight(); >@@ -676,7 +823,8 @@ > } > > if (itemUnderMouse.getItemType() == GraphItem.NODE) { >- // @tag Zest.selection : This is where the nodes are selected >+ // @tag Zest.selection : This is where the nodes are >+ // selected > selectedItems.add(itemUnderMouse); > ((GraphNode) itemUnderMouse).highlight(); > fireWidgetSelectedEvent(itemUnderMouse); >@@ -696,7 +844,8 @@ > > public void mouseReleased(org.eclipse.draw2d.MouseEvent me) { > isDragging = false; >- >+ relativeLocations.clear(); >+ draggedSubgraphFigure = null; > } > > } >@@ -715,7 +864,8 @@ > private void fireWidgetSelectedEvent(Item item) { > Iterator iterator = selectionListeners.iterator(); > while (iterator.hasNext()) { >- SelectionListener selectionListener = (SelectionListener) iterator.next(); >+ SelectionListener selectionListener = (SelectionListener) iterator >+ .next(); > Event swtEvent = new Event(); > swtEvent.item = item; > swtEvent.widget = this; >@@ -726,79 +876,6 @@ > } > > /** >- * Moves the edge to the highlight layer. This moves the edge above the >- * nodes >- * >- * @param connection >- */ >- void highlightEdge(GraphConnection connection) { >- IFigure figure = connection.getConnectionFigure(); >- if (figure != null && !connection.isHighlighted()) { >- zestRootLayer.highlightConnection(figure); >- } >- } >- >- /** >- * Moves the edge from the edge feedback layer back to the edge layer >- * >- * @param graphConnection >- */ >- void unhighlightEdge(GraphConnection connection) { >- IFigure figure = connection.getConnectionFigure(); >- if (figure != null && connection.isHighlighted()) { >- zestRootLayer.unHighlightConnection(figure); >- } >- } >- >- /** >- * Moves the node onto the node feedback layer >- * >- * @param node >- */ >- void highlightNode(GraphNode node) { >- IFigure figure = node.getNodeFigure(); >- if (figure != null && !node.isHighlighted()) { >- zestRootLayer.highlightNode(figure); >- } >- } >- >- /** >- * Moves the node onto the node feedback layer >- * >- * @param node >- */ >- void highlightNode(GraphContainer node) { >- IFigure figure = node.getNodeFigure(); >- if (figure != null && !node.isHighlighted()) { >- zestRootLayer.highlightNode(figure); >- } >- } >- >- /** >- * Moves the node off the node feedback layer >- * >- * @param node >- */ >- void unhighlightNode(GraphContainer node) { >- IFigure figure = node.getNodeFigure(); >- if (figure != null && node.isHighlighted()) { >- zestRootLayer.unHighlightNode(figure); >- } >- } >- >- /** >- * Moves the node off the node feedback layer >- * >- * @param node >- */ >- void unhighlightNode(GraphNode node) { >- IFigure figure = node.getNodeFigure(); >- if (figure != null && node.isHighlighted()) { >- zestRootLayer.unHighlightNode(figure); >- } >- } >- >- /** > * Converts the list of GraphModelConnection objects into an array and > * returns it. > * >@@ -810,62 +887,15 @@ > return connsArray; > } > >- LayoutRelationship[] getConnectionsToLayout(List nodesToLayout) { >- // @tag zest.bug.156528-Filters.follows : make sure not to layout >- // filtered connections, if the style says so. >- LayoutRelationship[] entities; >- if (ZestStyles.checkStyle(style, ZestStyles.IGNORE_INVISIBLE_LAYOUT)) { >- LinkedList connectionList = new LinkedList(); >- for (Iterator i = this.getConnections().iterator(); i.hasNext();) { >- GraphConnection next = (GraphConnection) i.next(); >- if (next.isVisible() && nodesToLayout.contains(next.getSource()) && nodesToLayout.contains(next.getDestination())) { >- connectionList.add(next.getLayoutRelationship()); >- } >- } >- entities = (LayoutRelationship[]) connectionList.toArray(new LayoutRelationship[] {}); >- } else { >- LinkedList nodeList = new LinkedList(); >- for (Iterator i = this.getConnections().iterator(); i.hasNext();) { >- GraphConnection next = (GraphConnection) i.next(); >- if (nodesToLayout.contains(next.getSource()) && nodesToLayout.contains(next.getDestination())) { >- nodeList.add(next.getLayoutRelationship()); >- } >- } >- entities = (LayoutRelationship[]) nodeList.toArray(new LayoutRelationship[] {}); >- } >- return entities; >- } >- >- LayoutEntity[] getNodesToLayout(List nodes) { >- // @tag zest.bug.156528-Filters.follows : make sure not to layout >- // filtered nodes, if the style says so. >- LayoutEntity[] entities; >- if (ZestStyles.checkStyle(style, ZestStyles.IGNORE_INVISIBLE_LAYOUT)) { >- LinkedList nodeList = new LinkedList(); >- for (Iterator i = nodes.iterator(); i.hasNext();) { >- GraphNode next = (GraphNode) i.next(); >- if (next.isVisible()) { >- nodeList.add(next.getLayoutEntity()); >- } >- } >- entities = (LayoutEntity[]) nodeList.toArray(new LayoutEntity[] {}); >- } else { >- LinkedList nodeList = new LinkedList(); >- for (Iterator i = nodes.iterator(); i.hasNext();) { >- GraphNode next = (GraphNode) i.next(); >- nodeList.add(next.getLayoutEntity()); >- } >- entities = (LayoutEntity[]) nodeList.toArray(new LayoutEntity[] {}); >- } >- return entities; >- } >- > void removeConnection(GraphConnection connection) { > IFigure figure = connection.getConnectionFigure(); >- PolylineConnection sourceContainerConnectionFigure = connection.getSourceContainerConnectionFigure(); >- PolylineConnection targetContainerConnectionFigure = connection.getTargetContainerConnectionFigure(); >+ PolylineConnection sourceContainerConnectionFigure = connection >+ .getSourceContainerConnectionFigure(); >+ PolylineConnection targetContainerConnectionFigure = connection >+ .getTargetContainerConnectionFigure(); > connection.removeFigure(); > this.getConnections().remove(connection); >+ this.selectedItems.remove(connection); > figure2ItemMap.remove(figure); > if (sourceContainerConnectionFigure != null) { > figure2ItemMap.remove(sourceContainerConnectionFigure); >@@ -873,19 +903,18 @@ > if (targetContainerConnectionFigure != null) { > figure2ItemMap.remove(targetContainerConnectionFigure); > } >+ getLayoutContext().fireConnectionRemovedEvent(connection.getLayout()); > } > > void removeNode(GraphNode node) { > IFigure figure = node.getNodeFigure(); > if (figure.getParent() != null) { >- if (figure.getParent() instanceof ZestRootLayer) { >- ((ZestRootLayer) figure.getParent()).removeNode(figure); >- } else { >- figure.getParent().remove(figure); >- } >+ figure.getParent().remove(figure); > } > this.getNodes().remove(node); >+ this.selectedItems.remove(node); > figure2ItemMap.remove(figure); >+ node.getLayout().dispose(); > } > > void addConnection(GraphConnection connection, boolean addToEdgeLayer) { >@@ -893,44 +922,29 @@ > if (addToEdgeLayer) { > zestRootLayer.addConnection(connection.getFigure()); > } >+ getLayoutContext().fireConnectionAddedEvent(connection.getLayout()); > } > >- /* >- public void redraw() { >- >- Iterator iterator = this.getConnections().iterator(); >- while (iterator.hasNext()) { >- GraphConnection connection = (GraphConnection) iterator.next(); >- IFigure figure = connection.getFigure(); >- if (!zestRootLayer.getChildren().contains(figure)) { >- if (true || false || false) { >- zestRootLayer.addConnection(connection.getFigure()); >- } >- } >- } >- iterator = this.getNodes().iterator(); >- while (iterator.hasNext()) { >- GraphNode graphNode = (GraphNode) iterator.next(); >- IFigure figure = graphNode.getFigure(); >- if (!zestRootLayer.getChildren().contains(figure)) { >- zestRootLayer.addNode(graphNode.getFigure()); >- } >- } >- >- super.redraw(); >- >- } >- */ >- >- void addNode(GraphNode node) { >+ /** >+ * @noreference This method is not intended to be referenced by clients. >+ */ >+ public void addNode(GraphNode node) { > this.getNodes().add(node); > zestRootLayer.addNode(node.getFigure()); >+ getLayoutContext().fireNodeAddedEvent(node.getLayout()); > } > >- void addNode(GraphContainer graphContainer) { >- this.getNodes().add(graphContainer); >- zestRootLayer.addNode(graphContainer.getFigure()); >+ /** >+ * @noreference This method is not intended to be referenced by clients. >+ */ >+ public void addSubgraphFigure(IFigure figure) { >+ zestRootLayer.addSubgraph(figure); >+ subgraphFigures.add(figure); >+ } > >+ void removeSubgraphFigure(IFigure figure) { >+ subgraphFigures.remove(figure); >+ figure.getParent().remove(figure); > } > > void registerItem(GraphItem item) { >@@ -941,131 +955,41 @@ > IFigure figure = item.getFigure(); > figure2ItemMap.put(figure, item); > if (((GraphConnection) item).getSourceContainerConnectionFigure() != null) { >- figure2ItemMap.put(((GraphConnection) item).getSourceContainerConnectionFigure(), item); >+ figure2ItemMap.put(((GraphConnection) item) >+ .getSourceContainerConnectionFigure(), item); > } > if (((GraphConnection) item).getTargetContainerConnectionFigure() != null) { >- figure2ItemMap.put(((GraphConnection) item).getTargetContainerConnectionFigure(), item); >+ figure2ItemMap.put(((GraphConnection) item) >+ .getTargetContainerConnectionFigure(), item); > } > } else if (item.getItemType() == GraphItem.CONTAINER) { > IFigure figure = item.getFigure(); > figure2ItemMap.put(figure, item); > } else { >- throw new RuntimeException("Unknown item type: " + item.getItemType()); >- } >- } >- >- /* >- >- >- /** >- * Changes the figure for a particular node >- */ >- void changeNodeFigure(IFigure oldValue, IFigure newFigure, GraphNode graphItem) { >- if (zestRootLayer.getChildren().contains(oldValue)) { >- zestRootLayer.remove(oldValue); >- figure2ItemMap.remove(oldValue); >- } >- figure2ItemMap.put(newFigure, graphItem); >- zestRootLayer.add(newFigure); >- } >- >- /** >- * Invoke all the constraint adapaters for this constraints >- * >- * @param object >- * @param constraint >- */ >- void invokeConstraintAdapters(Object object, LayoutConstraint constraint) { >- if (constraintAdapters == null) { >- return; >+ throw new RuntimeException("Unknown item type: " >+ + item.getItemType()); > } >- Iterator iterator = this.constraintAdapters.iterator(); >- while (iterator.hasNext()) { >- ConstraintAdapter constraintAdapter = (ConstraintAdapter) iterator.next(); >- constraintAdapter.populateConstraint(object, constraint); >- } >- } >- >- private void applyLayoutInternal() { >- >- if ((this.getNodes().size() == 0)) { >- return; >- } >- >- int layoutStyle = 0; >- >- if ((nodeStyle & ZestStyles.NODES_NO_LAYOUT_RESIZE) > 0) { >- layoutStyle = LayoutStyles.NO_LAYOUT_NODE_RESIZING; >- } >- >- if (layoutAlgorithm == null) { >- layoutAlgorithm = new TreeLayoutAlgorithm(layoutStyle); >- } >- >- layoutAlgorithm.setStyle(layoutAlgorithm.getStyle() | layoutStyle); >- >- // calculate the size for the layout algorithm >- Dimension d = this.getViewport().getSize(); >- d.width = d.width - 10; >- d.height = d.height - 10; >- >- if (this.preferredSize.width >= 0) { >- d.width = preferredSize.width; >- } >- if (this.preferredSize.height >= 0) { >- d.height = preferredSize.height; >- } >- >- if (d.isEmpty()) { >- return; >- } >- LayoutRelationship[] connectionsToLayout = getConnectionsToLayout(nodes); >- LayoutEntity[] nodesToLayout = getNodesToLayout(getNodes()); >- >- try { >- Animation.markBegin(); >- layoutAlgorithm.applyLayout(nodesToLayout, connectionsToLayout, 0, 0, d.width, d.height, false, false); >- Animation.run(ANIMATION_TIME); >- getLightweightSystem().getUpdateManager().performUpdate(); >- >- } catch (InvalidLayoutConfiguration e) { >- e.printStackTrace(); >- } >- >- } >- >- interface MyRunnable extends Runnable { >- public boolean isVisible(); > } > > /** >- * Adds a reveal listener to the view. Note: A reveal listener will only >- * every be called ONCE!!! even if a view comes and goes. There is no remove >- * reveal listener. This is used to defer some events until after the view >- * is revealed. >+ * Schedules a layout to be performed after the view is revealed (or >+ * immediately, if the view is already revealed). > * >- * @param revealListener >+ * @param clean > */ >- private void addRevealListener(final RevealListener revealListener) { >- >- MyRunnable myRunnable = new MyRunnable() { >- boolean isVisible; >- >- public boolean isVisible() { >- return this.isVisible; >- } >+ private void scheduleLayoutOnReveal(final boolean clean) { > >+ final boolean[] isVisibleSync = new boolean[1]; >+ Display.getDefault().syncExec(new Runnable() { > public void run() { >- isVisible = Graph.this.isVisible(); >+ isVisibleSync[0] = isVisible(); > } >+ }); > >- }; >- Display.getDefault().syncExec(myRunnable); >- >- if (myRunnable.isVisible()) { >- revealListener.revealed(this); >+ if (isVisibleSync[0]) { >+ applyLayoutInternal(clean); > } else { >- revealListeners.add(revealListener); >+ shouldSheduleLayout = true; > } > } > >@@ -1084,18 +1008,30 @@ > > zestRootLayer.addLayoutListener(LayoutAnimator.getDefault()); > fishEyeLayer.addLayoutListener(LayoutAnimator.getDefault()); >+ >+ rootlayer.addCoordinateListener(new CoordinateListener() { >+ public void coordinateSystemChanged(IFigure source) { >+ if (preferredSize.width == -1 && preferredSize.height == -1) { >+ getLayoutContext().fireBoundsChangedEvent(); >+ } >+ } >+ }); >+ > return rootlayer; > } > > /** >- * This removes the fisheye from the graph. It uses an animation to make the fisheye >- * shrink, and then it finally clears the fisheye layer. This assumes that there >- * is ever only 1 node on the fisheye layer at any time. >- * >- * @param fishEyeFigure The fisheye figure >- * @param regularFigure The regular figure (i.e. the non fisheye version) >+ * This removes the fisheye from the graph. It uses an animation to make the >+ * fisheye shrink, and then it finally clears the fisheye layer. This >+ * assumes that there is ever only 1 node on the fisheye layer at any time. >+ * >+ * @param fishEyeFigure >+ * The fisheye figure >+ * @param regularFigure >+ * The regular figure (i.e. the non fisheye version) > */ >- void removeFishEye(final IFigure fishEyeFigure, final IFigure regularFigure, boolean animate) { >+ void removeFishEye(final IFigure fishEyeFigure, >+ final IFigure regularFigure, boolean animate) { > > if (!fishEyeLayer.getChildren().contains(fishEyeFigure)) { > return; >@@ -1114,17 +1050,23 @@ > > fishEyeLayer.setConstraint(fishEyeFigure, bounds); > >+ for (Iterator iterator = fisheyeListeners.iterator(); iterator >+ .hasNext();) { >+ FisheyeListener listener = (FisheyeListener) iterator.next(); >+ listener.fisheyeRemoved(this, regularFigure, fishEyeFigure); >+ } >+ > if (animate) { > Animation.run(FISHEYE_ANIMATION_TIME * 2); > } > this.getRootLayer().getUpdateManager().performUpdate(); > fishEyeLayer.removeAll(); >- this.fisheyedFigure = null; > > } > > /** > * Replaces the old fisheye figure with a new one. >+ * > * @param oldFigure > * @param newFigure > */ >@@ -1132,29 +1074,37 @@ > if (this.fishEyeLayer.getChildren().contains(oldFigure)) { > Rectangle bounds = oldFigure.getBounds(); > newFigure.setBounds(bounds); >- //this.fishEyeLayer.getChildren().remove(oldFigure); > this.fishEyeLayer.remove(oldFigure); > this.fishEyeLayer.add(newFigure); >- //this.fishEyeLayer.getChildren().add(newFigure); >- //this.fishEyeLayer.invalidate(); >- //this.fishEyeLayer.repaint(); >- this.fisheyedFigure = newFigure; >+ >+ for (Iterator iterator = fisheyeListeners.iterator(); iterator >+ .hasNext();) { >+ FisheyeListener listener = (FisheyeListener) iterator.next(); >+ listener.fisheyeReplaced(this, oldFigure, newFigure); >+ } >+ > return true; > } > return false; > } > > /** >- * Add a fisheye version of the node. This works by animating the change from the original node >- * to the fisheyed one, and then placing the fisheye node on the fisheye layer. >- * @param startFigure The original node >- * @param endFigure The fisheye figure >- * @param newBounds The final size of the fisheyed figure >+ * Add a fisheye version of the node. This works by animating the change >+ * from the original node to the fisheyed one, and then placing the fisheye >+ * node on the fisheye layer. >+ * >+ * @param startFigure >+ * The original node >+ * @param endFigure >+ * The fisheye figure >+ * @param newBounds >+ * The final size of the fisheyed figure > */ >- void fishEye(IFigure startFigure, IFigure endFigure, Rectangle newBounds, boolean animate) { >+ void fishEye(IFigure startFigure, IFigure endFigure, Rectangle newBounds, >+ boolean animate) { > > fishEyeLayer.removeAll(); >- fisheyedFigure = null; >+ > if (animate) { > Animation.markBegin(); > } >@@ -1167,7 +1117,7 @@ > > Rectangle bounds = startFigure.getBounds().getCopy(); > startFigure.translateToAbsolute(bounds); >- //startFigure.translateToRelative(bounds); >+ // startFigure.translateToRelative(bounds); > fishEyeLayer.translateToRelative(bounds); > fishEyeLayer.translateFromParent(bounds); > >@@ -1176,15 +1126,35 @@ > fishEyeLayer.add(endFigure); > fishEyeLayer.setConstraint(endFigure, newBounds); > >+ for (Iterator iterator = fisheyeListeners.iterator(); iterator >+ .hasNext();) { >+ FisheyeListener listener = (FisheyeListener) iterator.next(); >+ listener.fisheyeAdded(this, startFigure, endFigure); >+ } >+ > if (animate) { > Animation.run(FISHEYE_ANIMATION_TIME); > } > this.getRootLayer().getUpdateManager().performUpdate(); > } > >- public Graph getGraph() { >- // @tag refactor : Is this method really needed >- return this.getGraphModel(); >+ /** >+ * Adds a listener that will be notified when fisheyed figures change in >+ * this graph. >+ * >+ * @param listener >+ * listener to add >+ * @since 2.0 >+ */ >+ public void addFisheyeListener(FisheyeListener listener) { >+ fisheyeListeners.add(listener); >+ } >+ >+ /** >+ * @since 2.0 >+ */ >+ public void removeFisheyeListener(FisheyeListener listener) { >+ fisheyeListeners.remove(listener); > } > > public int getItemType() { >@@ -1195,4 +1165,45 @@ > return (GraphItem) figure2ItemMap.get(figure); > } > >+ /** >+ * @since 2.0 >+ */ >+ public void setExpanded(GraphNode node, boolean expanded) { >+ layoutContext.setExpanded(node.getLayout(), expanded); >+ rootlayer.invalidate(); >+ } >+ >+ /** >+ * @since 2.0 >+ */ >+ public boolean canExpand(GraphNode node) { >+ return layoutContext.canExpand(node.getLayout()); >+ } >+ >+ /** >+ * @since 2.0 >+ */ >+ public boolean canCollapse(GraphNode node) { >+ return layoutContext.canCollapse(node.getLayout()); >+ } >+ >+ public Graph getGraph() { >+ return this; >+ } >+ >+ /** >+ * @since 2.0 >+ */ >+ public Widget getItem() { >+ return this; >+ } >+ >+ /** >+ * @since 2.0 >+ */ >+ public DisplayIndependentRectangle getLayoutBounds() { >+ Dimension preferredSize = this.getPreferredSize(); >+ return new DisplayIndependentRectangle(0, 0, preferredSize.width, >+ preferredSize.height); >+ } > } >Index: src/org/eclipse/zest/core/widgets/GraphContainer.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/GraphContainer.java,v >retrieving revision 1.25 >diff -u -r1.25 GraphContainer.java >--- src/org/eclipse/zest/core/widgets/GraphContainer.java 31 Mar 2009 16:39:23 -0000 1.25 >+++ src/org/eclipse/zest/core/widgets/GraphContainer.java 28 Aug 2009 16:03:22 -0000 >@@ -1,11 +1,12 @@ > /******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, > * Canada. All rights reserved. This program and the accompanying materials are > * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html > * >- * Contributors: The Chisel Group, University of Victoria >+ * Contributors: The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 > ******************************************************************************/ > package org.eclipse.zest.core.widgets; > >@@ -14,33 +15,42 @@ > import java.util.LinkedList; > import java.util.List; > >+import org.eclipse.draw2d.ActionEvent; >+import org.eclipse.draw2d.ActionListener; > import org.eclipse.draw2d.Animation; >+import org.eclipse.draw2d.Clickable; > import org.eclipse.draw2d.ColorConstants; >+import org.eclipse.draw2d.Figure; > import org.eclipse.draw2d.FreeformLayout; > import org.eclipse.draw2d.FreeformViewport; >+import org.eclipse.draw2d.Graphics; > import org.eclipse.draw2d.IFigure; >+import org.eclipse.draw2d.Label; > import org.eclipse.draw2d.LayoutAnimator; > import org.eclipse.draw2d.LineBorder; >-import org.eclipse.draw2d.PolylineConnection; > import org.eclipse.draw2d.ScrollPane; >+import org.eclipse.draw2d.ToolbarLayout; >+import org.eclipse.draw2d.Triangle; > import org.eclipse.draw2d.Viewport; > import org.eclipse.draw2d.geometry.Dimension; > import org.eclipse.draw2d.geometry.Point; > import org.eclipse.draw2d.geometry.Rectangle; >+import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.events.SelectionListener; >+import org.eclipse.swt.graphics.Color; > import org.eclipse.swt.graphics.Image; >+import org.eclipse.swt.graphics.RGB; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.swt.widgets.Widget; > import org.eclipse.zest.core.widgets.internal.AspectRatioFreeformLayer; > import org.eclipse.zest.core.widgets.internal.ContainerFigure; >-import org.eclipse.zest.core.widgets.internal.ExpandGraphLabel; > import org.eclipse.zest.core.widgets.internal.ZestRootLayer; >-import org.eclipse.zest.layouts.InvalidLayoutConfiguration; > import org.eclipse.zest.layouts.LayoutAlgorithm; >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.LayoutRelationship; >-import org.eclipse.zest.layouts.LayoutStyles; > import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; > >-/* >- * A Container than can be added to a Graph. Nodes can be added to this >+/** >+ * A Container that can be added to a Graph. Nodes can be added to this > * container. The container supports collapsing and expanding and has the same > * properties as the nodes. Containers cannot have custom figures. > * >@@ -48,74 +58,260 @@ > */ > public class GraphContainer extends GraphNode implements IContainer { > >- //private static final double CONTAINER_SCALE = 0.75; >- private static final double scaledWidth = 300; >- private static final double scaledHeight = 200; >+ static class ExpandGraphLabel extends Figure implements ActionListener { >+ >+ private boolean isExpanded; >+ private Expander expander = new Expander(); >+ private Color darkerBackground; >+ >+ class Expander extends Clickable { >+ private Triangle triangle; >+ >+ public Expander() { >+ setStyle(Clickable.STYLE_TOGGLE); >+ triangle = new Triangle(); >+ triangle.setSize(10, 10); >+ triangle.setBackgroundColor(ColorConstants.black); >+ triangle.setForegroundColor(ColorConstants.black); >+ triangle.setFill(true); >+ triangle.setDirection(Triangle.EAST); >+ triangle.setLocation(new Point(5, 3)); >+ this.setLayoutManager(new FreeformLayout()); >+ this.add(triangle); >+ this.setPreferredSize(15, 15); >+ this.addActionListener(ExpandGraphLabel.this); >+ } >+ >+ public void open() { >+ triangle.setDirection(Triangle.SOUTH); >+ } >+ >+ public void close() { >+ triangle.setDirection(Triangle.EAST); >+ } >+ >+ } >+ >+ /** >+ * Sets the expander state (the little triangle) to >+ * ExpanderGraphLabel.OPEN or ExpanderGraphLabel.CLOSED >+ * >+ * @param state >+ */ >+ public void setExpandedState(boolean expanded) { >+ if (expanded) { >+ expander.open(); >+ } else { >+ expander.close(); >+ } >+ this.isExpanded = expanded; >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see >+ * org.eclipse.draw2d.ActionListener#actionPerformed(org.eclipse.draw2d >+ * .ActionEvent) >+ */ >+ public void actionPerformed(ActionEvent event) { >+ if (isExpanded) { >+ container.close(true); >+ } else { >+ container.open(true); >+ } >+ } >+ >+ private final int arcWidth = 8; >+ private final Label label; >+ private final GraphContainer container; >+ private final ToolbarLayout layout; >+ >+ public ExpandGraphLabel(GraphContainer container, String text, >+ Image image, boolean cacheLabel) { >+ this.label = new Label(text) { >+ >+ /** >+ * <b>This method is overwritten so that the text is not >+ * truncated.</b><br> >+ * >+ * {@inheritDoc} >+ * >+ */ >+ protected void paintFigure(Graphics graphics) { >+ if (isOpaque()) { >+ super.paintFigure(graphics); >+ } >+ Rectangle bounds = getBounds(); >+ graphics.translate(bounds.x, bounds.y); >+ if (getIcon() != null) { >+ graphics.drawImage(getIcon(), getIconLocation()); >+ } >+ if (!isEnabled()) { >+ graphics.translate(1, 1); >+ graphics >+ .setForegroundColor(ColorConstants.buttonLightest); >+ graphics >+ .drawText(getSubStringText(), getTextLocation()); >+ graphics.translate(-1, -1); >+ graphics >+ .setForegroundColor(ColorConstants.buttonDarker); >+ } >+ graphics.drawText(getText(), getTextLocation()); >+ graphics.translate(-bounds.x, -bounds.y); >+ } >+ }; >+ this.setText(text); >+ this.setImage(image); >+ this.container = container; >+ this.setFont(Display.getDefault().getSystemFont()); >+ layout = new ToolbarLayout(true); >+ layout.setSpacing(5); >+ layout.setMinorAlignment(ToolbarLayout.ALIGN_CENTER); >+ this.setLayoutManager(layout); >+ this.add(this.expander); >+ this.add(this.label); >+ } >+ >+ private Color getDarkerBackgroundColor() { >+ if (darkerBackground == null) { >+ Color baseColor = getBackgroundColor(); >+ int blue = (int) (baseColor.getBlue() * 0.8 + 0.5); >+ int red = (int) (baseColor.getRed() * 0.8 + 0.5); >+ int green = (int) (baseColor.getGreen() * 0.8 + 0.5); >+ darkerBackground = new Color(Display.getCurrent(), new RGB(red, >+ green, blue)); >+ } >+ return darkerBackground; >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see >+ * org.eclipse.draw2d.Label#paintFigure(org.eclipse.draw2d.Graphics) >+ */ >+ public void paint(Graphics graphics) { >+ >+ graphics.setForegroundColor(getDarkerBackgroundColor()); >+ graphics.setBackgroundColor(getBackgroundColor()); >+ >+ graphics.pushState(); >+ >+ // fill in the background >+ Rectangle bounds = getBounds().getCopy(); >+ Rectangle r = bounds.getCopy(); >+ r.y += arcWidth / 2; >+ r.height -= arcWidth; >+ >+ Rectangle top = bounds.getCopy(); >+ top.height /= 2; >+ graphics.setForegroundColor(getBackgroundColor()); >+ graphics.setBackgroundColor(getBackgroundColor()); >+ graphics.fillRoundRectangle(top, arcWidth, arcWidth); >+ >+ top.y = top.y + top.height; >+ graphics.setForegroundColor(darkerBackground); >+ graphics.setBackgroundColor(darkerBackground); >+ graphics.fillRoundRectangle(top, arcWidth, arcWidth); >+ >+ graphics.setBackgroundColor(darkerBackground); >+ graphics.setForegroundColor(getBackgroundColor()); >+ graphics.fillGradient(r, true); >+ >+ super.paint(graphics); >+ graphics.popState(); >+ graphics.setForegroundColor(darkerBackground); >+ graphics.setBackgroundColor(darkerBackground); >+ // paint the border >+ bounds.setSize(bounds.width - 1, bounds.height - 1); >+ graphics.drawRoundRectangle(bounds, arcWidth, arcWidth); >+ } >+ >+ public void setBackgroundColor(Color bg) { >+ super.setBackgroundColor(bg); >+ if (darkerBackground != null) { >+ darkerBackground.dispose(); >+ } >+ darkerBackground = null; >+ } >+ >+ public void setTextT(String string) { >+ this.setPreferredSize(null); >+ this.label.setText(string); >+ this.add(label); >+ this.layout.layout(this); >+ this.invalidate(); >+ this.revalidate(); >+ this.validate(); >+ } >+ >+ public void setText(String string) { >+ this.label.setText(string); >+ } >+ >+ public void setImage(Image image) { >+ this.label.setIcon(image); >+ } >+ >+ public void setFocus() { >+ expander.requestFocus(); >+ } >+ >+ } >+ >+ static final double SCALED_WIDTH = 250; >+ static final double SCALED_HEIGHT = 200; > private static final int CONTAINER_HEIGHT = 200; > private static final int MIN_WIDTH = 250; >+ private static final int MIN_HEIGHT = 30; > private static final int ANIMATION_TIME = 100; > private static final int SUBLAYER_OFFSET = 2; > >+ private static SelectionListener selectionListener; >+ > private ExpandGraphLabel expandGraphLabel; > >- //private FreeformLayer container; >- //private FreeformLayer edgeLayer; > private List childNodes = null; > private int childAreaHeight = CONTAINER_HEIGHT; > >- public ZestRootLayer zestLayer; >+ private ZestRootLayer zestLayer; > private ScrollPane scrollPane; > private LayoutAlgorithm layoutAlgorithm; > private boolean isExpanded = false; >- //private ScalableFreeformLayeredPane scalledLayer; >+ private boolean isLayoutScheduled = false; > private AspectRatioFreeformLayer scalledLayer; >+ private InternalLayoutContext layoutContext; > > /** >- * Creates a new GraphContainer. A GraphContainer may contain nodes, >- * and has many of the same properties as a graph node. >- * @param graph The graph that the container is being added to >- * @param style >+ * Creates a new GraphContainer. A GraphContainer may contain nodes, and has >+ * many of the same properties as a graph node. >+ * >+ * @param graph >+ * The graph that the container is being added to >+ * @param style >+ * >+ * @since 2.0 > */ >- public GraphContainer(IContainer graph, int style) { >- this(graph, style, ""); >- >- } >- >- public GraphContainer(IContainer graph, int style, String text) { >- this(graph, style, text, null); >- >- } >- >- public GraphContainer(IContainer graph, int style, String text, Image image) { >- super(graph, style, text, image); >- initModel(graph, text, image); >+ public GraphContainer(Graph graph, int style) { >+ super(graph, style, ""); >+ initModel(graph, "", null); > close(false); > childNodes = new ArrayList(); >+ registerToParent(graph); > } > > /** > * Custom figures cannot be set on a GraphContainer. > */ > public void setCustomFigure(IFigure nodeFigure) { >- throw new RuntimeException("Operation not supported: Containers cannot have custom figures"); >- } >- >- /* >- * (non-Javadoc) >- * @see org.eclipse.mylar.zest.core.widgets.GraphItem#getItemType() >- public int getItemType() { >- return GraphItem.CONTAINER; >- } >- >- /** >- * Gets the figure for this container. >- */ >- public IFigure getNodeFigure() { >- return this.nodeFigure; >+ throw new RuntimeException( >+ "Operation not supported: Containers cannot have custom figures"); > } > > /** > * Close this node. >+ * > * @param animate > */ > public void close(boolean animate) { >@@ -124,38 +320,40 @@ > } > isExpanded = false; > >- expandGraphLabel.setExpandedState(ExpandGraphLabel.CLOSED); >+ expandGraphLabel.setExpandedState(false); > Rectangle newBounds = scrollPane.getBounds().getCopy(); > newBounds.height = 0; > >- //this.nodeFigure.setConstraint(scrollPane, newBounds); >- //this.nodeFigure.revalidate(); > scrollPane.setSize(scrollPane.getSize().width, 0); > updateFigureForModel(this.zestLayer); > scrollPane.setVisible(false); >- //setSize(expandGraphLabel.getSize().width, expandGraphLabel.getSize().height); > List children = this.zestLayer.getChildren(); > for (Iterator iterator = children.iterator(); iterator.hasNext();) { > IFigure child = (IFigure) iterator.next(); > GraphItem item = getGraph().getGraphItem(child); > item.setVisible(false); > } >- Rectangle containerBounds = new Rectangle(this.getLocation(), new Dimension(this.getSize().width, CONTAINER_HEIGHT + this.expandGraphLabel.getSize().height)); >+ Rectangle containerBounds = new Rectangle(this.getLocation(), >+ new Dimension(this.getSize().width, CONTAINER_HEIGHT >+ + this.expandGraphLabel.getSize().height)); > moveNodesUp(containerBounds, this); > if (animate) { > Animation.run(ANIMATION_TIME); > } >- //this.nodeFigure.getUpdateManager().performUpdate(); > updateFigureForModel(nodeFigure); > } > >- private static void addNodeToOrderedList(List orderedNodeList, GraphNode node) { >+ private static void addNodeToOrderedList(List orderedNodeList, >+ GraphNode node) { > Iterator orderedNodeIterator = orderedNodeList.iterator(); > int counter = 0; > while (orderedNodeIterator.hasNext()) { >- // Look through the list of nodes below and find the right spot for this >+ // Look through the list of nodes below and find the right spot for >+ // this > GraphNode nextOrderedNode = (GraphNode) orderedNodeIterator.next(); >- if (nextOrderedNode.getLocation().y + nextOrderedNode.getBounds().height > node.getLocation().y + node.getBounds().height) { >+ if (nextOrderedNode.getLocation().y >+ + nextOrderedNode.getBounds().height > node.getLocation().y >+ + node.getBounds().height) { > break; > } > counter++; >@@ -165,12 +363,14 @@ > } > > /** >- * Gets all the nodes below the yValue. The nodes are returned in order. >+ * Gets all the nodes below the yValue. The nodes are returned in order. >+ * > * @param nodes > * @param yValue > * @return > */ >- private static List getOrderedNodesBelowY(List nodes, int yValue, GraphNode yValueNode) { >+ private static List getOrderedNodesBelowY(List nodes, int yValue, >+ GraphNode yValueNode) { > Iterator iterator = nodes.iterator(); > LinkedList orderedNode = new LinkedList(); > while (iterator.hasNext()) { >@@ -194,13 +394,15 @@ > > /** > * Checks if the node intersects the stripe between left and right >+ * > * @param left > * @param right > * @param node > * @return > */ > private static boolean nodeInStripe(int left, int right, GraphNode node) { >- return (node.getBounds().x < right && node.getBounds().x + node.getBounds().width > left); >+ return (node.getBounds().x < right && node.getBounds().x >+ + node.getBounds().width > left); > } > > void pack(Graph g) { >@@ -229,13 +431,15 @@ > > /** > * Move the nodes below this node up >+ * > * @param containerBounds > * @param graphContainer > */ > private void moveNodesUp(Rectangle containerBounds, GraphNode graphContainer) { > > // Get all nodes below this container, in order >- List orderedNodesBelowY = getOrderedNodesBelowY(parent.getNodes(), containerBounds.y, graphContainer); >+ List orderedNodesBelowY = getOrderedNodesBelowY(parent.getGraph() >+ .getNodes(), containerBounds.y, graphContainer); > int leftSide = containerBounds.x; > int rightSide = containerBounds.x + containerBounds.width; > List nodesToConsider = new LinkedList(); >@@ -248,8 +452,9 @@ > GraphNode node = (GraphNode) nodesToConsider.get(0); > if (nodeInStripe(leftSide, rightSide, node)) { > leftSide = Math.min(leftSide, node.getBounds().x); >- rightSide = Math.max(rightSide, node.getBounds().x + node.getBounds().width); >- // If this node is in the stripe, move it up >+ rightSide = Math.max(rightSide, node.getBounds().x >+ + node.getBounds().width); >+ // If this node is in the stripe, move it up > // the previous node > GraphNode previousNode = null; > int i = 0; >@@ -261,8 +466,9 @@ > int j = i - 1; > while (j >= 0) { > GraphNode pastNode = (GraphNode) orderedNodesBelowY.get(j); >- //if (nodeInStripe(leftSide, rightSide, pastNode)) { >- if (nodeInStripe(node.getBounds().x, node.getBounds().x + node.getBounds().width, pastNode)) { >+ // if (nodeInStripe(leftSide, rightSide, pastNode)) { >+ if (nodeInStripe(node.getBounds().x, node.getBounds().x >+ + node.getBounds().width, pastNode)) { > previousNode = pastNode; > break; > } >@@ -271,7 +477,8 @@ > if (previousNode == null) { > previousNode = graphContainer; > } >- int previousLocation = previousNode.getBounds().y + previousNode.getBounds().height + 2; >+ int previousLocation = previousNode.getBounds().y >+ + previousNode.getBounds().height + 2; > > orderedNodesBelowY.remove(i); > node.setLocation(node.getLocation().x, previousLocation); >@@ -283,20 +490,23 @@ > } > > /** >- * Open the container. This opens the graph container to >- * show the nodes within and update the twistie >+ * Open the container. This opens the graph container to show the nodes >+ * within and update the twistie > */ > public void open(boolean animate) { >+ if (isLayoutScheduled) { >+ internalApplyLayout(); >+ } >+ > if (animate) { > Animation.markBegin(); > } > isExpanded = true; > >- expandGraphLabel.setExpandedState(ExpandGraphLabel.OPEN); >+ expandGraphLabel.setExpandedState(true); > > scrollPane.setSize(computeChildArea()); > scrollPane.setVisible(true); >- //setSize(expandGraphLabel.getSize().width, expandGraphLabel.getSize().height + expandedHeight - SUBLAYER_OFFSET); > > List children = this.zestLayer.getChildren(); > for (Iterator iterator = children.iterator(); iterator.hasNext();) { >@@ -307,17 +517,15 @@ > > updateFigureForModel(nodeFigure); > >- Rectangle containerBounds = new Rectangle(this.getLocation(), new Dimension(this.getSize().width, CONTAINER_HEIGHT + this.expandGraphLabel.getSize().height)); >- //moveIntersectedNodes(containerBounds, this); >+ Rectangle containerBounds = new Rectangle(this.getLocation(), >+ new Dimension(this.getSize().width, CONTAINER_HEIGHT >+ + this.expandGraphLabel.getSize().height)); > moveNodesDown(containerBounds, this); > moveNodesUp(containerBounds, this); >- //pack(graph); > if (animate) { > Animation.run(ANIMATION_TIME); > } > this.getFigure().getUpdateManager().performValidation(); >- //this.nodeFigure.getUpdateManager().performUpdate(); >- > } > > /** >@@ -325,10 +533,12 @@ > * @param containerBounds > * @param graphContainer > */ >- private void moveNodesDown(Rectangle containerBounds, GraphContainer graphContainer) { >+ private void moveNodesDown(Rectangle containerBounds, >+ GraphContainer graphContainer) { > > // Find all nodes below here >- List nodesBelowHere = getOrderedNodesBelowY(parent.getNodes(), containerBounds.y, graphContainer); >+ List nodesBelowHere = getOrderedNodesBelowY(parent.getGraph() >+ .getNodes(), containerBounds.y, graphContainer); > Iterator nodesBelowHereIterator = nodesBelowHere.iterator(); > List nodesToMove = new LinkedList(); > int left = containerBounds.x; >@@ -338,10 +548,12 @@ > if (nodeInStripe(left, right, node)) { > nodesToMove.add(node); > left = Math.min(left, node.getBounds().x); >- right = Math.max(right, node.getBounds().x + node.getBounds().width); >+ right = Math.max(right, node.getBounds().x >+ + node.getBounds().width); > } > } >- List intersectingNodes = intersectingNodes(containerBounds, nodesToMove, graphContainer); >+ List intersectingNodes = intersectingNodes(containerBounds, >+ nodesToMove, graphContainer); > int delta = getMaxMovement(containerBounds, intersectingNodes); > if (delta > 0) { > shiftNodesDown(nodesToMove, delta); >@@ -349,50 +561,16 @@ > > } > >- void highlightNode(GraphNode node) { >- >- } >- >- void highlightEdge(GraphConnection connection) { >- } >- >- void highlightNode(GraphContainer container) { >- >- } >- >- void unhighlightNode(GraphNode node) { >- >- } >- >- void unhighlightNode(GraphContainer container) { >- >- } >- >-// /** >-// * Gets a list of nodes below the given node >-// * @param node >-// * @return >-// */ >-// private List getNodesBelow(int y, List nodes) { >-// Iterator allNodes = nodes.iterator(); >-// LinkedList result = new LinkedList(); >-// while (allNodes.hasNext()) { >-// GraphNode nextNode = (GraphNode) allNodes.next(); >-// int top = nextNode.getLocation().y; >-// if (top > y) { >-// result.add(nextNode); >-// } >-// } >-// return result; >-// } >- > /** >- * Checks all the nodes in the list of nodesToCheck to see if they intersect with the bounds set >+ * Checks all the nodes in the list of nodesToCheck to see if they intersect >+ * with the bounds set >+ * > * @param node > * @param nodesToCheck > * @return > */ >- private List intersectingNodes(Rectangle bounds, List nodesToCheck, GraphNode node) { >+ private List intersectingNodes(Rectangle bounds, List nodesToCheck, >+ GraphNode node) { > List result = new LinkedList(); > Iterator nodes = nodesToCheck.iterator(); > while (nodes.hasNext()) { >@@ -408,7 +586,9 @@ > } > > /** >- * Gets the max distance the intersecting nodes need to be shifted to make room for the expanding node >+ * Gets the max distance the intersecting nodes need to be shifted to make >+ * room for the expanding node >+ * > * @param bounds > * @param nodesToMove > * @return >@@ -427,6 +607,7 @@ > > /** > * Shifts a collection of nodes down. >+ * > * @param nodesToShift > * @param amount > */ >@@ -435,64 +616,23 @@ > while (iterator.hasNext()) { > GraphNode node = (GraphNode) iterator.next(); > >- node.setLocation(node.getLocation().x, node.getLocation().y + amount); >+ node.setLocation(node.getLocation().x, node.getLocation().y >+ + amount); > } > } > >-// /** >-// * This finds the highest Y Value of a set of nodes. >-// * @param nodes >-// * @return >-// */ >-// private int findSmallestYValue(List nodes) { >-// Iterator iterator = nodes.iterator(); >-// int lowestNode /*highest on the screen*/= Integer.MAX_VALUE - 100; // Subtract 100 so we don't overflow >-// while (iterator.hasNext()) { >-// GraphNode node = (GraphNode) iterator.next(); >-// int y = node.getLocation().y; >-// lowestNode = Math.min(lowestNode, y); >-// } >-// return lowestNode; >-// } >- >-// /** >-// * Clears the nodes that the container intersects as it expands >-// * @param containerBounds >-// * @param graphContainer >-// */ >-// private void moveIntersectedNodes(Rectangle containerBounds, GraphNode graphContainer) { >-// >-// List nodesBelowHere = getNodesBelow(this.getLocation().y, graphContainer.getGraphModel().getNodes()); >-// List intersectingNodes = intersectingNodes(containerBounds, nodesBelowHere, graphContainer); >-// int delta = getMaxMovement(containerBounds, intersectingNodes); >-// shiftNodesDown(intersectingNodes, delta); >-// >-// int lowestNode /*highest on the screen*/= findSmallestYValue(intersectingNodes); >-// nodesBelowHere = getNodesBelow(lowestNode, nodesBelowHere); >-// >-// while (nodesBelowHere.size() > 0) { >-// Iterator intersectingNodeIterator = intersectingNodes.iterator(); >-// List nodesMovedInLastIteration = new LinkedList(); >-// while (intersectingNodeIterator.hasNext()) { >-// GraphNode node = (GraphNode) intersectingNodeIterator.next(); >-// intersectingNodes = intersectingNodes(node.getBounds(), nodesBelowHere, node); >-// delta = getMaxMovement(node.getBounds(), intersectingNodes); >-// if (delta > 0) { >-// shiftNodesDown(intersectingNodes, delta); >-// nodesMovedInLastIteration.addAll(intersectingNodes); >-// } >-// } >-// lowestNode /*highest on the screen*/= findSmallestYValue(nodesMovedInLastIteration); >-// nodesBelowHere = getNodesBelow(lowestNode, nodesBelowHere); >-// intersectingNodes = nodesMovedInLastIteration; >-// } >-// } >- > /** > * Gets the graph that this container has been added to. > */ > public Graph getGraph() { >- return this.graph.getGraph(); >+ return this.graph; >+ } >+ >+ /** >+ * @since 2.0 >+ */ >+ public Widget getItem() { >+ return this; > } > > public int getItemType() { >@@ -500,66 +640,64 @@ > } > > /** >- * >+ * @since 2.0 > */ >- public void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean applyLayout) { >+ public void setLayoutAlgorithm(LayoutAlgorithm algorithm, >+ boolean applyLayout) { >+ if (this.layoutAlgorithm != null) { >+ this.layoutAlgorithm.setLayoutContext(null); >+ } >+ > this.layoutAlgorithm = algorithm; >+ this.layoutAlgorithm.setLayoutContext(getLayoutContext()); > if (applyLayout) { > applyLayout(); > } >- > } > >- public void applyLayout() { >- if ((this.getNodes().size() == 0)) { >- return; >+ /** >+ * @noreference This method is not intended to be referenced by clients. >+ */ >+ public InternalLayoutContext getLayoutContext() { >+ if (layoutContext == null) { >+ layoutContext = new InternalLayoutContext(this); > } >+ return layoutContext; >+ } > >- int layoutStyle = 0; >+ /** >+ * @since 2.0 >+ */ >+ public DisplayIndependentRectangle getLayoutBounds() { >+ double width = GraphContainer.SCALED_WIDTH; >+ double height = GraphContainer.SCALED_HEIGHT; >+ return new DisplayIndependentRectangle(0, 0, width, height); >+ } > >- if (checkStyle(ZestStyles.NODES_NO_LAYOUT_RESIZE)) { >- layoutStyle = LayoutStyles.NO_LAYOUT_NODE_RESIZING; >+ public void applyLayout() { >+ if (isExpanded) { >+ internalApplyLayout(); >+ } else { >+ isLayoutScheduled = true; > } >+ } > >+ private void internalApplyLayout() { >+ isLayoutScheduled = false; > if (layoutAlgorithm == null) { >- layoutAlgorithm = new TreeLayoutAlgorithm(layoutStyle); >- } >- >- layoutAlgorithm.setStyle(layoutAlgorithm.getStyle() | layoutStyle); >- >- // calculate the size for the layout algorithm >- //Dimension d = this.scalledLayer.getSize(); >- Dimension d = new Dimension(); >- d.width = (int) scaledWidth; >- d.height = (int) scaledHeight; >- >- d.width = d.width - 10; >- d.height = d.height - 10; >- //if (d.height <= 0) { >- //d.height = (CONTAINER_HEIGHT); >- //} >- //d.scale(1 / this.scalledLayer.getScale()); >- >- if (d.isEmpty()) { >- return; >- } >- LayoutRelationship[] connectionsToLayout = getGraph().getConnectionsToLayout(getNodes()); >- LayoutEntity[] nodesToLayout = getGraph().getNodesToLayout(getNodes()); >- >- try { >- Animation.markBegin(); >- layoutAlgorithm.applyLayout(nodesToLayout, connectionsToLayout, 25, 25, d.width - 50, d.height - 50, false, false); >- Animation.run(ANIMATION_TIME); >- getFigure().getUpdateManager().performUpdate(); >- >- } catch (InvalidLayoutConfiguration e) { >- e.printStackTrace(); >+ setLayoutAlgorithm(new TreeLayoutAlgorithm(), false); > } >- >+ Animation.markBegin(); >+ layoutAlgorithm.applyLayout(true); >+ layoutContext.flushChanges(false); >+ Animation.run(ANIMATION_TIME); >+ getFigure().getUpdateManager().performUpdate(); > } > > /** >- * Get the scale for this container. This is the scale applied to the children contained within >+ * Get the scale for this container. This is the scale applied to the >+ * children contained within >+ * > * @return > */ > public double getScale() { >@@ -567,7 +705,9 @@ > } > > /** >- * Set the scale for this container. This is the scale applied to the children contained within. >+ * Set the scale for this container. This is the scale applied to the >+ * children contained within. >+ * > * @param scale > */ > public void setScale(double scale) { >@@ -582,8 +722,8 @@ > } > > /** >- * This is a small class to help represent the size of the container. It should only be >- * used in the computeContainerSize method. >+ * This is a small class to help represent the size of the container. It >+ * should only be used in the computeContainerSize method. > */ > class ContainerDimension { > int width; >@@ -593,19 +733,22 @@ > > /** > * Computes size of the scroll pane that the child nodes will be placed in. >+ * > * @return > */ > private Dimension computeChildArea() { > ContainerDimension containerDimension = computeContainerSize(); > Dimension dimension = new Dimension(); > dimension.width = containerDimension.width; >- dimension.height = containerDimension.expandedHeight - containerDimension.labelHeight + SUBLAYER_OFFSET; >+ dimension.height = containerDimension.expandedHeight >+ - containerDimension.labelHeight + SUBLAYER_OFFSET; > return dimension; > } > > /** >- * Computes the desired size of the container. This method uses the >- * minimum size, label size and setSize to compute the size. >+ * Computes the desired size of the container. This method uses the minimum >+ * size, label size and setSize to compute the size. >+ * > * @return > */ > private ContainerDimension computeContainerSize() { >@@ -616,36 +759,24 @@ > labelWidth = MIN_WIDTH; > expandGraphLabel.setPreferredSize(labelWidth, labelHeight); > } >- if (labelHeight < 30) { >- labelHeight = 30; >- } > >- dimension.labelHeight = labelHeight; >- dimension.width = labelWidth; >- dimension.width = Math.max(dimension.width, this.size.width); >- dimension.expandedHeight = dimension.labelHeight + childAreaHeight - SUBLAYER_OFFSET; >- dimension.expandedHeight = Math.max(dimension.expandedHeight, this.size.height); >+ dimension.labelHeight = Math.max(labelHeight, MIN_HEIGHT); >+ dimension.width = Math.max(labelWidth, this.size.width); >+ dimension.expandedHeight = Math.max(dimension.labelHeight >+ + childAreaHeight - SUBLAYER_OFFSET, this.size.height); > > return dimension; > } > >- /* >- private double computeChildScale() { >- Dimension childArea = computeChildArea(); >- double widthScale = childArea.width / scaledWidth; >- double heightScale = childArea.height / scaledHeight; >- return Math.min(widthScale, heightScale); >- } >- */ > private double computeHeightScale() { > Dimension childArea = computeChildArea(); >- double heightScale = childArea.height / scaledHeight; >+ double heightScale = childArea.height / SCALED_HEIGHT; > return heightScale; > } > > private double computeWidthScale() { > Dimension childArea = computeChildArea(); >- double widthScale = childArea.width / scaledWidth; >+ double widthScale = childArea.width / SCALED_WIDTH; > return widthScale; > } > >@@ -657,7 +788,8 @@ > containerFigure.addLayoutListener(LayoutAnimator.getDefault()); > > containerFigure.setLayoutManager(new FreeformLayout()); >- expandGraphLabel = new ExpandGraphLabel(this, node.getText(), node.getImage(), false); >+ expandGraphLabel = new ExpandGraphLabel(this, node.getText(), node >+ .getImage(), false); > expandGraphLabel.setText(getText()); > expandGraphLabel.setImage(getImage()); > ContainerDimension containerDimension = computeContainerSize(); >@@ -666,53 +798,22 @@ > scrollPane.addLayoutListener(LayoutAnimator.getDefault()); > > Viewport viewport = new FreeformViewport(); >- /* >- * This is the code that helps remove the scroll bars moving when the nodes >- * are dragged. >- * >- viewport.setHorizontalRangeModel(new DefaultRangeModel() { >- public void setAll(int min, int ext, int max) { >- System.out.println("Max: " + max + " : current Max: " + getMaximum()); >- if (max < getMaximum()) { >- max = getMaximum(); >- } >- super.setAll(min, ext, max); >- } >- >- public void setMaximum(int maximum) { >- // TODO Auto-generated method stub >- System.out.println("Max: " + maximum + " : current Max: " + getMaximum()); >- if (maximum < getMaximum()) { >- return; >- } >- super.setMaximum(maximum); >- } >- }); >- */ > > scrollPane.setViewport(viewport); > viewport.addLayoutListener(LayoutAnimator.getDefault()); > scrollPane.setScrollBarVisibility(ScrollPane.AUTOMATIC); > >- //scalledLayer = new ScalableFreeformLayeredPane(); > scalledLayer = new AspectRatioFreeformLayer("debug label"); > scalledLayer.addLayoutListener(LayoutAnimator.getDefault()); >- //scalledLayer.setScale(computeChildScale()); > scalledLayer.setScale(computeWidthScale(), computeHeightScale()); >- //container = new FreeformLayer(); >- //edgeLayer = new FreeformLayer(); > zestLayer = new ZestRootLayer(); > zestLayer.addLayoutListener(LayoutAnimator.getDefault()); >- //container.addLayoutListener(LayoutAnimator.getDefault()); >- //edgeLayer.addLayoutListener(LayoutAnimator.getDefault()); >- //scalledLayer.add(edgeLayer); >- //scalledLayer.add(container); > scalledLayer.add(zestLayer); > >- //container.setLayoutManager(new FreeformLayout()); > zestLayer.setLayoutManager(new FreeformLayout()); > scrollPane.setSize(computeChildArea()); >- scrollPane.setLocation(new Point(0, containerDimension.labelHeight - SUBLAYER_OFFSET)); >+ scrollPane.setLocation(new Point(0, containerDimension.labelHeight >+ - SUBLAYER_OFFSET)); > scrollPane.setForegroundColor(ColorConstants.gray); > > expandGraphLabel.setBackgroundColor(getBackgroundColor()); >@@ -728,8 +829,37 @@ > return containerFigure; > } > >+ private void registerToParent(IContainer parent) { >+ if (parent.getItemType() == GRAPH) { >+ createSelectionListener(); >+ parent.getGraph().addSelectionListener(selectionListener); >+ } >+ } >+ >+ private void createSelectionListener() { >+ if (selectionListener == null) { >+ selectionListener = new SelectionListener() { >+ public void widgetSelected(SelectionEvent e) { >+ if (e.item instanceof GraphContainer) { >+ // set focus to expand label so that pressing space >+ // opens/closes the last selected container >+ ((GraphContainer) e.item).expandGraphLabel.setFocus(); >+ } >+ } >+ >+ public void widgetDefaultSelected(SelectionEvent e) { >+ // ignore >+ } >+ }; >+ >+ } >+ } >+ > protected void updateFigureForModel(IFigure currentFigure) { > >+ if (expandGraphLabel == null) { >+ initFigure(); >+ } > expandGraphLabel.setTextT(getText()); > expandGraphLabel.setImage(getImage()); > expandGraphLabel.setFont(getFont()); >@@ -737,47 +867,27 @@ > if (highlighted == HIGHLIGHT_ON) { > expandGraphLabel.setForegroundColor(getForegroundColor()); > expandGraphLabel.setBackgroundColor(getHighlightColor()); >- } >- // @tag ADJACENT : Removed highlight adjacent >- /* >- else if (highlighted == HIGHLIGHT_ADJACENT) { >- expandGraphLabel.setForegroundColor(getForegroundColor()); >- expandGraphLabel.setBackgroundColor(getHighlightAdjacentColor()); >- } >- */ >- else { >+ } else { > expandGraphLabel.setForegroundColor(getForegroundColor()); > expandGraphLabel.setBackgroundColor(getBackgroundColor()); > } > > ContainerDimension containerDimension = computeContainerSize(); > >- expandGraphLabel.setSize(containerDimension.width, containerDimension.labelHeight); >+ expandGraphLabel.setSize(containerDimension.width, >+ containerDimension.labelHeight); > if (isExpanded) { >- //setSize(expandGraphLabel.getSize().width, expandGraphLabel.getSize().height + expandedHeight - SUBLAYER_OFFSET); > setSize(containerDimension.width, containerDimension.expandedHeight); > } else { > setSize(containerDimension.width, containerDimension.labelHeight); > } >- scrollPane.setLocation(new Point(expandGraphLabel.getLocation().x, expandGraphLabel.getLocation().y + containerDimension.labelHeight - SUBLAYER_OFFSET)); >- //scrollPane.setLocation(new Point(0, labelHeight - SUBLAYER_OFFSET)); >- //Rectangle bounds = expandGraphLabel.getBounds().getCopy(); >- //Rectangle newBounds = new Rectangle(new Point(bounds.x, bounds.y + labelHeight - SUBLAYER_OFFSET), scrollPane.getSize()); >- //figure.setConstraint(scrollPane, newBounds); >- /* >- size.width = labelWidth; >- if (scrollPane.getSize().height > 0) { >- size.height = labelHeight + scrollPane.getSize().height - SUBLAYER_OFFSET; >- } else { >- size.height = labelHeight; >- } >- refreshLocation(); >- figure.getUpdateManager().performValidation(); >- */ >+ scrollPane.setLocation(new Point(expandGraphLabel.getLocation().x, >+ expandGraphLabel.getLocation().y >+ + containerDimension.labelHeight - SUBLAYER_OFFSET)); > > } > >- protected void refreshLocation() { >+ void refreshBounds() { > if (nodeFigure == null || nodeFigure.getParent() == null) { > return; // node figure has not been created yet > } >@@ -787,7 +897,8 @@ > ContainerDimension containerDimension = computeContainerSize(); > Dimension size = new Dimension(); > >- expandGraphLabel.setSize(containerDimension.width, containerDimension.labelHeight); >+ expandGraphLabel.setSize(containerDimension.width, >+ containerDimension.labelHeight); > this.childAreaHeight = computeChildArea().height; > if (isExpanded) { > size.width = containerDimension.width; >@@ -798,38 +909,55 @@ > } > Rectangle bounds = new Rectangle(loc, size); > nodeFigure.getParent().setConstraint(nodeFigure, bounds); >- scrollPane.setLocation(new Point(expandGraphLabel.getLocation().x, expandGraphLabel.getLocation().y + containerDimension.labelHeight - SUBLAYER_OFFSET)); >+ scrollPane.setLocation(new Point(expandGraphLabel.getLocation().x, >+ expandGraphLabel.getLocation().y >+ + containerDimension.labelHeight - SUBLAYER_OFFSET)); > scrollPane.setSize(computeChildArea()); > scalledLayer.setScale(computeWidthScale(), computeHeightScale()); > } > >- void addConnectionFigure(PolylineConnection connection) { >- nodeFigure.add(connection); >- //zestLayer.addConnection(connection); >+ /** >+ * @noreference This method is not intended to be referenced by clients. >+ */ >+ public void addSubgraphFigure(IFigure figure) { >+ zestLayer.addSubgraph(figure); >+ graph.subgraphFigures.add(figure); > } > >- void addNode(GraphNode node) { >- zestLayer.addNode(node.getNodeFigure()); >- this.childNodes.add(node); >- //container.add(node.getNodeFigure()); >- //graph.registerItem(node); >+ void addConnectionFigure(IFigure figure) { >+ nodeFigure.add(figure); > } > >- void addNode(GraphContainer container) { >- // Containers cannot be added to other containers (yet) >+ /** >+ * @noreference This method is not intended to be referenced by clients. >+ */ >+ public void addNode(GraphNode node) { >+ zestLayer.addNode(node.getNodeFigure()); >+ this.childNodes.add(node); >+ node.setVisible(isExpanded); > } > > public List getNodes() { > return this.childNodes; > } > >- void paint() { >- Iterator iterator = getNodes().iterator(); >+ /** >+ * @since 2.0 >+ */ >+ public List getConnections() { >+ return filterConnections(getGraph().getConnections()); > >- while (iterator.hasNext()) { >- GraphNode node = (GraphNode) iterator.next(); >- node.paint(); >- } > } > >+ private List filterConnections(List connections) { >+ List result = new ArrayList(); >+ for (Iterator iterator = connections.iterator(); iterator.hasNext();) { >+ GraphConnection connection = (GraphConnection) iterator.next(); >+ if (connection.getSource().getParent() == this >+ && connection.getDestination().getParent() == this) { >+ result.add(connection); >+ } >+ } >+ return result; >+ } > } >Index: src/org/eclipse/zest/core/widgets/GraphNode.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/GraphNode.java,v >retrieving revision 1.40 >diff -u -r1.40 GraphNode.java >--- src/org/eclipse/zest/core/widgets/GraphNode.java 23 Apr 2009 02:41:22 -0000 1.40 >+++ src/org/eclipse/zest/core/widgets/GraphNode.java 28 Aug 2009 16:03:23 -0000 >@@ -1,11 +1,12 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials are made >- * available under the terms of the Eclipse Public License v1.0 which >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html > * >- * Contributors: The Chisel Group, University of Victoria >+ * Contributors: The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 > ******************************************************************************/ > package org.eclipse.zest.core.widgets; > >@@ -13,7 +14,9 @@ > import java.util.Iterator; > import java.util.List; > >+import org.eclipse.draw2d.Animation; > import org.eclipse.draw2d.ColorConstants; >+import org.eclipse.draw2d.FigureListener; > import org.eclipse.draw2d.IFigure; > import org.eclipse.draw2d.Label; > import org.eclipse.draw2d.geometry.Dimension; >@@ -21,17 +24,14 @@ > import org.eclipse.draw2d.geometry.Point; > import org.eclipse.draw2d.geometry.PrecisionPoint; > import org.eclipse.draw2d.geometry.Rectangle; >-import org.eclipse.swt.SWT; > import org.eclipse.swt.graphics.Color; > import org.eclipse.swt.graphics.Font; >-import org.eclipse.swt.graphics.FontData; > import org.eclipse.swt.graphics.Image; > import org.eclipse.swt.widgets.Display; > import org.eclipse.zest.core.widgets.internal.GraphLabel; >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.constraints.LayoutConstraint; >+import org.eclipse.zest.core.widgets.internal.ZestRootLayer; > >-/* >+/** > * Simple node class which has the following properties: color, size, location, > * and a label. It also has a list of connections and anchors. > * >@@ -44,8 +44,6 @@ > public class GraphNode extends GraphItem { > public static final int HIGHLIGHT_NONE = 0; > public static final int HIGHLIGHT_ON = 1; >- // @tag ADJACENT : Removed highlight adjacent >- //public static final int HIGHLIGHT_ADJACENT = 2; > > private int nodeStyle; > >@@ -55,17 +53,14 @@ > private Color foreColor; > private Color backColor; > private Color highlightColor; >- // @tag ADJACENT : Removed highlight adjacent >- //private Color highlightAdjacentColor; > private Color borderColor; > private Color borderHighlightColor; > private int borderWidth; >- private Point currentLocation; >+ private PrecisionPoint currentLocation; > protected Dimension size; > private Font font; > private boolean cacheLabel; > private boolean visible = true; >- private LayoutEntity layoutEntity; > > protected Graph graph; > protected IContainer parent; >@@ -84,37 +79,23 @@ > this(graphModel, style, null); > } > >- public GraphNode(IContainer graphModel, int style, Object data) { >- this(graphModel.getGraph(), style, "" /*text*/, null /*image*/, data); >- } >- > public GraphNode(IContainer graphModel, int style, String text) { >- this(graphModel, style, text, null); >- } >- >- public GraphNode(IContainer graphModel, int style, String text, Object data) { >- this(graphModel.getGraph(), style, text, null /*image*/, data); >+ this(graphModel, style, text, null, null); > } > >- public GraphNode(IContainer graphModel, int style, String text, Image image) { >- this(graphModel, style, text, image, null); >+ public GraphNode(IContainer graphModel, int style, Object data) { >+ this(graphModel, style, "" /* text */, null /* image */, data); > } > >- public GraphNode(IContainer graphModel, int style, String text, Image image, Object data) { >+ private GraphNode(IContainer graphModel, int style, String text, >+ Image image, Object data) { > super(graphModel.getGraph(), style, data); > initModel(graphModel, text, image); > if (nodeFigure == null) { > initFigure(); > } > >- // This is a hack because JAVA sucks! >- // I don't want to expose addNode so I can't put it in the >- // IContainer interface. >- if (this.parent.getItemType() == GRAPH) { >- ((Graph) this.parent).addNode(this); >- } else if (this.parent.getItemType() == CONTAINER) { >- ((GraphContainer) this.parent).addNode(this); >- } >+ this.parent.addNode(this); > this.parent.getGraph().registerItem(this); > } > >@@ -124,27 +105,23 @@ > > static int count = 0; > >- protected void initModel(IContainer parent, String text, Image image) { >- this.nodeStyle |= parent.getGraph().getNodeStyle(); >- this.parent = parent; >+ protected void initModel(IContainer graphModel, String text, Image image) { >+ this.nodeStyle |= graphModel.getGraph().getNodeStyle(); >+ this.parent = graphModel; > this.sourceConnections = new ArrayList(); > this.targetConnections = new ArrayList(); >- this.foreColor = parent.getGraph().DARK_BLUE; >- this.backColor = parent.getGraph().LIGHT_BLUE; >- this.highlightColor = parent.getGraph().HIGHLIGHT_COLOR; >- // @tag ADJACENT : Removed highlight adjacent >- //this.highlightAdjacentColor = ColorConstants.orange; >- this.nodeStyle = SWT.NONE; >+ this.foreColor = graphModel.getGraph().DARK_BLUE; >+ this.backColor = graphModel.getGraph().LIGHT_BLUE; >+ this.highlightColor = graphModel.getGraph().HIGHLIGHT_COLOR; > this.borderColor = ColorConstants.lightGray; > this.borderHighlightColor = ColorConstants.blue; > this.borderWidth = 1; > this.currentLocation = new PrecisionPoint(0, 0); > this.size = new Dimension(-1, -1); > this.font = Display.getDefault().getSystemFont(); >- this.graph = parent.getGraph(); >+ this.graph = graphModel.getGraph(); > this.cacheLabel = false; > this.setText(text); >- this.layoutEntity = new LayoutGraphNode(); > if (image != null) { > this.setImage(image); > } >@@ -162,10 +139,6 @@ > return "GraphModelNode: " + getText(); > } > >- public LayoutEntity getLayoutEntity() { >- return layoutEntity; >- } >- > /* > * (non-Javadoc) > * >@@ -178,7 +151,8 @@ > super.dispose(); > this.isDisposed = true; > while (getSourceConnections().size() > 0) { >- GraphConnection connection = (GraphConnection) getSourceConnections().get(0); >+ GraphConnection connection = (GraphConnection) getSourceConnections() >+ .get(0); > if (!connection.isDisposed()) { > connection.dispose(); > } else { >@@ -186,7 +160,8 @@ > } > } > while (getTargetConnections().size() > 0) { >- GraphConnection connection = (GraphConnection) getTargetConnections().get(0); >+ GraphConnection connection = (GraphConnection) getTargetConnections() >+ .get(0); > if (!connection.isDisposed()) { > connection.dispose(); > } else { >@@ -206,8 +181,9 @@ > } > > /** >- * Determines if this node has a fixed size or if it is packed to the size of its contents. >- * To set a node to pack, set its size (-1, -1) >+ * Determines if this node has a fixed size or if it is packed to the size >+ * of its contents. To set a node to pack, set its size (-1, -1) >+ * > * @return > */ > public boolean isSizeFixed() { >@@ -256,7 +232,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#isSelected() >+ * @see >+ * org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#isSelected >+ * () > */ > public boolean isSelected() { > return selected; >@@ -266,9 +244,12 @@ > * Sets the current location for this node. > */ > public void setLocation(double x, double y) { >- currentLocation.x = (int) x; >- currentLocation.y = (int) y; >- refreshLocation(); >+ if (currentLocation.preciseX != x || currentLocation.preciseY != y) { >+ currentLocation.preciseX = x; >+ currentLocation.preciseY = y; >+ currentLocation.updateInts(); >+ refreshBounds(); >+ } > } > > /** >@@ -374,28 +355,6 @@ > } > > /** >- * Get the highlight adjacent colour for this node. This is the colour that >- * adjacent nodes will get >- */ >- // @tag ADJACENT : Removed highlight adjacent >- /* >- public Color getHighlightAdjacentColor() { >- return highlightAdjacentColor; >- } >- */ >- >- /** >- * Set the highlight adjacent colour for this node. This is the colour that >- * adjacent node will get. >- */ >- // @tag ADJACENT : Removed highlight adjacent >- /* >- public void setHighlightAdjacentColor(Color c) { >- this.highlightAdjacentColor = c; >- } >- */ >- >- /** > * Highlights the node changing the background color and border color. The > * source and destination connections are also highlighted, and the adjacent > * nodes are highlighted too in a different color. >@@ -404,25 +363,9 @@ > if (highlighted == HIGHLIGHT_ON) { > return; > } >- // @tag ADJACENT : Removed highlight adjacent >- /* >- if (ZestStyles.checkStyle(getNodeStyle(), ZestStyles.NODES_HIGHLIGHT_ADJACENT)) { >- for (Iterator iter = sourceConnections.iterator(); iter.hasNext();) { >- GraphConnection conn = (GraphConnection) iter.next(); >- conn.highlight(); >- conn.getDestination().highlightAdjacent(); >- } >- for (Iterator iter = targetConnections.iterator(); iter.hasNext();) { >- GraphConnection conn = (GraphConnection) iter.next(); >- conn.highlight(); >- conn.getSource().highlightAdjacent(); >- } >- } >- */ >- if (parent.getItemType() == GraphItem.CONTAINER) { >- ((GraphContainer) parent).highlightNode(this); >- } else { >- ((Graph) parent).highlightNode(this); >+ IFigure parentFigure = nodeFigure.getParent(); >+ if (parentFigure instanceof ZestRootLayer) { >+ ((ZestRootLayer) parentFigure).highlightNode(nodeFigure); > } > highlighted = HIGHLIGHT_ON; > updateFigureForModel(getNodeFigure()); >@@ -433,46 +376,21 @@ > */ > public void unhighlight() { > >- // @tag ADJACENT : Removed highlight adjacent >- //boolean highlightedAdjacently = (highlighted == HIGHLIGHT_ADJACENT); > if (highlighted == HIGHLIGHT_NONE) { > return; > } >- // @tag ADJACENT : Removed highlight adjacent >- /* >- if (!highlightedAdjacently) { >- // IF we are highlighted as an adjacent node, we don't need to deal >- // with our connections. >- if (ZestStyles.checkStyle(getNodeStyle(), ZestStyles.NODES_HIGHLIGHT_ADJACENT)) { >- // unhighlight the adjacent edges >- for (Iterator iter = sourceConnections.iterator(); iter.hasNext();) { >- GraphConnection conn = (GraphConnection) iter.next(); >- conn.unhighlight(); >- if (conn.getDestination() != this) { >- conn.getDestination().unhighlight(); >- } >- } >- for (Iterator iter = targetConnections.iterator(); iter.hasNext();) { >- GraphConnection conn = (GraphConnection) iter.next(); >- conn.unhighlight(); >- if (conn.getSource() != this) { >- conn.getSource().unhighlight(); >- } >- } >- } >- } >- */ >- if (parent.getItemType() == GraphItem.CONTAINER) { >- ((GraphContainer) parent).unhighlightNode(this); >- } else { >- ((Graph) parent).unhighlightNode(this); >+ >+ IFigure parentFigure = nodeFigure.getParent(); >+ if (parentFigure instanceof ZestRootLayer) { >+ ((ZestRootLayer) parentFigure).unHighlightNode(nodeFigure); > } >+ > highlighted = HIGHLIGHT_NONE; > updateFigureForModel(nodeFigure); > > } > >- protected void refreshLocation() { >+ void refreshBounds() { > Point loc = this.getLocation(); > Dimension size = this.getSize(); > Rectangle bounds = new Rectangle(loc, size); >@@ -480,64 +398,18 @@ > if (nodeFigure == null || nodeFigure.getParent() == null) { > return; // node figure has not been created yet > } >- //nodeFigure.setBounds(bounds); > nodeFigure.getParent().setConstraint(nodeFigure, bounds); >- } > >- /** >- * Highlights this node using the adjacent highlight color. This only does >- * something if highlighAdjacentNodes is set to true and if the node isn't >- * already highlighted. >- * >- * @see #setHighlightAdjacentNodes(boolean) >- */ >- // @tag ADJACENT : removed highlight adjacent >- /* >- public void highlightAdjacent() { >- if (highlighted > 0) { >- return; >- } >- highlighted = HIGHLIGHT_ADJACENT; >- updateFigureForModel(nodeFigure); >- if (parent.getItemType() == GraphItem.CONTAINER) { >- ((GraphContainer) parent).highlightNode(this); >- } else { >- ((Graph) parent).highlightNode(this); >- } >- } >- */ >- >- /** >- * Returns if the nodes adjacent to this node will be highlighted when this >- * node is selected. >- * >- * @return GraphModelNode >- */ >- // @tag ADJACENT : Removed highlight adjacent >- /* >- public boolean isHighlightAdjacentNodes() { >- return ZestStyles.checkStyle(nodeStyle, ZestStyles.NODES_HIGHLIGHT_ADJACENT); >- } >- */ >- >- /** >- * Sets if the adjacent nodes to this one should be highlighted when this >- * node is selected. >- * >- * @param highlightAdjacentNodes >- * The highlightAdjacentNodes to set. >- */ >- // @tag ADJACENT : Removed highlight adjacent >- /* >- public void setHighlightAdjacentNodes(boolean highlightAdjacentNodes) { >- if (!highlightAdjacentNodes) { >- this.nodeStyle |= ZestStyles.NODES_HIGHLIGHT_ADJACENT; >- this.nodeStyle ^= ZestStyles.NODES_HIGHLIGHT_ADJACENT; >- return; >+ if (isFisheyeEnabled) { >+ Rectangle fishEyeBounds = calculateFishEyeBounds(); >+ if (fishEyeBounds != null) { >+ fishEyeFigure.getParent().translateToRelative(fishEyeBounds); >+ fishEyeFigure.getParent().translateFromParent(fishEyeBounds); >+ fishEyeFigure.getParent().setConstraint(fishEyeFigure, >+ fishEyeBounds); >+ } > } >- this.nodeStyle |= ZestStyles.NODES_HIGHLIGHT_ADJACENT; > } >- */ > > public Color getBorderColor() { > return borderColor; >@@ -572,21 +444,18 @@ > } > super.setText(string); > >- if (nodeFigure != null) { >- updateFigureForModel(this.nodeFigure); >- } >+ updateFigureForModel(this.nodeFigure); > } > > /* > * (non-Javadoc) > * >- * @see org.eclipse.swt.widgets.Item#setImage(org.eclipse.swt.graphics.Image) >+ * @see >+ * org.eclipse.swt.widgets.Item#setImage(org.eclipse.swt.graphics.Image) > */ > public void setImage(Image image) { > super.setImage(image); >- if (nodeFigure != null) { >- updateFigureForModel(nodeFigure); >- } >+ updateFigureForModel(nodeFigure); > } > > /** >@@ -611,28 +480,18 @@ > */ > public void setNodeStyle(int nodeStyle) { > this.nodeStyle = nodeStyle; >- this.cacheLabel = ((this.nodeStyle & ZestStyles.NODES_CACHE_LABEL) > 0) ? true : false; >+ this.cacheLabel = ((this.nodeStyle & ZestStyles.NODES_CACHE_LABEL) > 0) ? true >+ : false; > } > >- /* >- * (non-Javadoc) >- * >- * @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setSize(double, >- * double) >- */ > public void setSize(double width, double height) { > if ((width != size.width) || (height != size.height)) { > size.width = (int) width; > size.height = (int) height; >- refreshLocation(); >+ refreshBounds(); > } > } > >- /* >- * (non-Javadoc) >- * >- * @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getBorderHighlightColor() >- */ > public Color getBorderHighlightColor() { > return borderHighlightColor; > } >@@ -645,27 +504,30 @@ > this.cacheLabel = cacheLabel; > } > >- public IFigure getNodeFigure() { >+ IFigure getNodeFigure() { > return this.nodeFigure; > } > > public void setVisible(boolean visible) { >- // graph.addRemoveFigure(this, visible); > this.visible = visible; > this.getFigure().setVisible(visible); >- List sConnections = (this).getSourceConnections(); >- List tConnections = (this).getTargetConnections(); >- for (Iterator iterator2 = sConnections.iterator(); iterator2.hasNext();) { >+ for (Iterator iterator2 = sourceConnections.iterator(); iterator2 >+ .hasNext();) { > GraphConnection connection = (GraphConnection) iterator2.next(); > connection.setVisible(visible); > } > >- for (Iterator iterator2 = tConnections.iterator(); iterator2.hasNext();) { >+ for (Iterator iterator2 = targetConnections.iterator(); iterator2 >+ .hasNext();) { > GraphConnection connection = (GraphConnection) iterator2.next(); > connection.setVisible(visible); > } > } > >+ public boolean isVisible() { >+ return visible; >+ } >+ > public int getStyle() { > return super.getStyle() | this.getNodeStyle(); > } >@@ -675,13 +537,12 @@ > **************************************************************************/ > > private IFigure fishEyeFigure = null; >- private Font fishEyeFont = null; > private boolean isFisheyeEnabled; > > protected IFigure fishEye(boolean enable, boolean animate) { > if (isDisposed) { > // If a fisheyed figure is still left on the canvas, we could get >- // called once more after the dispose is called. Since we cleaned >+ // called once more after the dispose is called. Since we cleaned > // up everything on dispose, we can just return null here. > return null; > } >@@ -692,42 +553,24 @@ > // Create the fish eye label > fishEyeFigure = createFishEyeFigure(); > >- // Get the current Bounds >- Rectangle rectangle = nodeFigure.getBounds().getCopy(); >+ Rectangle rectangle = calculateFishEyeBounds(); > >- // Calculate how much we have to expand the current bounds to get to the new bounds >- Dimension newSize = fishEyeFigure.getPreferredSize(); >- Rectangle currentSize = rectangle.getCopy(); >- nodeFigure.translateToAbsolute(currentSize); >- int expandedH = (newSize.height - currentSize.height) / 2 + 1; >- int expandedW = (newSize.width - currentSize.width) / 2 + 1; >- Dimension expandAmount = new Dimension(expandedW, expandedH); >- nodeFigure.translateToAbsolute(rectangle); >- rectangle.expand(new Insets(expandAmount.height, expandAmount.width, expandAmount.height, expandAmount.width)); >- if (expandedH <= 0 && expandedW <= 0) { >+ if (rectangle == null) { > return null; > } > >- FontData fontData = Display.getCurrent().getSystemFont().getFontData()[0]; >- fontData.height = 12; >- fishEyeFont = new Font(Display.getCurrent(), fontData); >- fishEyeFigure.setFont(fishEyeFont); >- >- //Add the fisheye >- this.getGraphModel().fishEye(nodeFigure, fishEyeFigure, rectangle, true); >+ // Add the fisheye >+ this.getGraphModel().fishEye(nodeFigure, fishEyeFigure, rectangle, >+ true); > if (fishEyeFigure != null) { > isFisheyeEnabled = true; > } > return fishEyeFigure; > > } else { >- // Remove the fisheye and dispose the font >- this.getGraphModel().removeFishEye(fishEyeFigure, nodeFigure, animate); >- if (fishEyeFont != null) { >- this.fishEyeFont.dispose(); >- this.fishEyeFont = null; >- } > isFisheyeEnabled = false; >+ this.getGraphModel().removeFishEye(fishEyeFigure, nodeFigure, >+ animate); > return null; > } > } >@@ -740,10 +583,6 @@ > return highlighted > 0; > } > >- void invokeLayoutListeners(LayoutConstraint constraint) { >- graph.invokeConstraintAdapters(this, constraint); >- } >- > protected void updateFigureForModel(IFigure currentFigure) { > if (currentFigure == null) { > return; >@@ -755,10 +594,13 @@ > GraphLabel figure = (GraphLabel) currentFigure; > IFigure toolTip; > >- if (!checkStyle(ZestStyles.NODES_HIDE_TEXT)) { >+ if (!checkStyle(ZestStyles.NODES_HIDE_TEXT) >+ && !figure.getText().equals(this.getText())) { > figure.setText(this.getText()); > } >- figure.setIcon(getImage()); >+ if (figure.getIcon() != getImage()) { >+ figure.setIcon(getImage()); >+ } > > if (highlighted == HIGHLIGHT_ON) { > figure.setForegroundColor(getForegroundColor()); >@@ -772,7 +614,9 @@ > > figure.setBorderWidth(getBorderWidth()); > >- figure.setFont(getFont()); >+ if (figure.getFont() != getFont()) { >+ figure.setFont(getFont()); >+ } > > if (this.getTooltip() == null && hasCustomTooltip == false) { > // if we have a custom tooltip, don't try and create our own. >@@ -783,54 +627,102 @@ > } > figure.setToolTip(toolTip); > >- refreshLocation(); >- > if (isFisheyeEnabled) { > IFigure newFisheyeFigure = createFishEyeFigure(); > if (graph.replaceFishFigure(this.fishEyeFigure, newFisheyeFigure)) { > this.fishEyeFigure = newFisheyeFigure; > } > } >+ refreshBounds(); > } > > protected IFigure createFigureForModel() { > GraphNode node = this; > boolean cacheLabel = (this).cacheLabel(); >- GraphLabel label = new GraphLabel(node.getText(), node.getImage(), cacheLabel); >+ final GraphLabel label = new GraphLabel(node.getText(), >+ node.getImage(), cacheLabel); > label.setFont(this.font); > if (checkStyle(ZestStyles.NODES_HIDE_TEXT)) { > label.setText(""); > } > updateFigureForModel(label); >+ label.addFigureListener(new FigureListener() { >+ private Dimension previousSize = label.getBounds().getSize(); >+ private PrecisionPoint previousLocation = new PrecisionPoint( >+ currentLocation); >+ >+ public void figureMoved(IFigure source) { >+ if (Animation.isAnimating() || getLayout().isMinimized()) { >+ return; >+ } >+ getLayout().refreshSize(); >+ getLayout().refreshLocation(); >+ >+ Rectangle newBounds = nodeFigure.getBounds(); >+ if (!newBounds.getSize().equals(previousSize)) { >+ previousSize = newBounds.getSize(); >+ if (size.width >= 0 && size.height >= 0) { >+ size = newBounds.getSize(); >+ } >+ currentLocation = new PrecisionPoint(nodeFigure.getBounds() >+ .getTopLeft()); >+ parent.getLayoutContext().fireEntityResizedEvent( >+ getLayout()); >+ } else if (previousLocation.x != newBounds.x >+ || previousLocation.y != newBounds.y) { >+ currentLocation = new PrecisionPoint(nodeFigure.getBounds() >+ .getTopLeft()); >+ previousLocation = new PrecisionPoint(currentLocation); >+ parent.getLayoutContext().fireEntityMovedEvent(getLayout()); >+ } >+ } >+ }); > return label; > } > > private IFigure createFishEyeFigure() { > GraphNode node = this; > boolean cacheLabel = this.cacheLabel(); >- GraphLabel label = new GraphLabel(node.getText(), node.getImage(), cacheLabel); >+ GraphLabel label = new GraphLabel(node.getText(), node.getImage(), >+ cacheLabel); > >- if (!checkStyle(ZestStyles.NODES_HIDE_TEXT)) { >- label.setText(this.getText()); >- } >- label.setIcon(getImage()); >- >- // @tag TODO: Add border and foreground colours to highlight >- // (this.borderColor) > if (highlighted == HIGHLIGHT_ON) { > label.setForegroundColor(getForegroundColor()); > label.setBackgroundColor(getHighlightColor()); >+ label.setBorderColor(getBorderHighlightColor()); > } else { > label.setForegroundColor(getForegroundColor()); > label.setBackgroundColor(getBackgroundColor()); >+ label.setBorderColor(getBorderColor()); > } > >+ label.setBorderWidth(getBorderWidth()); > label.setFont(getFont()); >+ > return label; > } > >- public boolean isVisible() { >- return visible; >+ private Rectangle calculateFishEyeBounds() { >+ // Get the current Bounds >+ Rectangle rectangle = nodeFigure.getBounds().getCopy(); >+ >+ // Calculate how much we have to expand the current bounds to get to the >+ // new bounds >+ Dimension newSize = fishEyeFigure.getPreferredSize(); >+ Rectangle currentSize = rectangle.getCopy(); >+ nodeFigure.translateToAbsolute(currentSize); >+ int expandedH = Math.max((newSize.height - currentSize.height) / 2 + 1, >+ 0); >+ int expandedW = Math >+ .max((newSize.width - currentSize.width) / 2 + 1, 0); >+ Dimension expandAmount = new Dimension(expandedW, expandedH); >+ nodeFigure.translateToAbsolute(rectangle); >+ rectangle.expand(new Insets(expandAmount.height, expandAmount.width, >+ expandAmount.height, expandAmount.width)); >+ if (expandedH <= 0 && expandedW <= 0) { >+ return null; >+ } >+ return rectangle; > } > > void addSourceConnection(GraphConnection connection) { >@@ -873,83 +765,31 @@ > return NODE; > } > >- class LayoutGraphNode implements LayoutEntity { >- Object layoutInformation = null; >- >- public double getHeightInLayout() { >- return getSize().height; >- } >- >- public Object getLayoutInformation() { >- return layoutInformation; >- } >- >- public String toString() { >- return getText(); >- } >- >- public double getWidthInLayout() { >- return getSize().width; >- } >- >- public double getXInLayout() { >- return getLocation().x; >- } >- >- public double getYInLayout() { >- return getLocation().y; >- } >- >- public void populateLayoutConstraint(LayoutConstraint constraint) { >- invokeLayoutListeners(constraint); >- } >- >- public void setLayoutInformation(Object internalEntity) { >- this.layoutInformation = internalEntity; >- >- } >- >- public void setLocationInLayout(double x, double y) { >- setLocation(x, y); >- } >- >- public void setSizeInLayout(double width, double height) { >- setSize(width, height); >- } >- >- /** >- * Compares two nodes. >- */ >- public int compareTo(Object otherNode) { >- int rv = 0; >- if (otherNode instanceof GraphNode) { >- GraphNode node = (GraphNode) otherNode; >- if (getText() != null) { >- rv = getText().compareTo(node.getText()); >- } >- } >- return rv; >- } >- >- public Object getGraphData() { >- return GraphNode.this; >- } >- >- public void setGraphData(Object o) { >- // TODO Auto-generated method stub >- >- } >- >- } >- >- IFigure getFigure() { >+ /** >+ * @noreference This method is not intended to be referenced by clients. >+ */ >+ public IFigure getFigure() { > if (this.nodeFigure == null) { > initFigure(); > } > return this.getNodeFigure(); > } > >- void paint() { >+ private InternalNodeLayout layout; >+ >+ /** >+ * @noreference This method is not intended to be referenced by clients. >+ */ >+ public InternalNodeLayout getLayout() { >+ if (layout == null) { >+ layout = new InternalNodeLayout(this); >+ } >+ return layout; >+ } > >+ void applyLayoutChanges() { >+ if (layout != null) { >+ layout.applyLayout(); >+ } > } > } >Index: src/org/eclipse/zest/core/widgets/ConstraintAdapter.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/ConstraintAdapter.java >diff -N src/org/eclipse/zest/core/widgets/ConstraintAdapter.java >--- src/org/eclipse/zest/core/widgets/ConstraintAdapter.java 12 Sep 2007 20:44:39 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,31 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >-package org.eclipse.zest.core.widgets; >- >-import org.eclipse.zest.layouts.constraints.LayoutConstraint; >- >-/** >- * >- * This interface is used to populate layout constraints on Zest nodes. >- * Constraint will be a instance of LayoutConstraint (look at the heirarchy for an up-to-date list). >- * >- * @author Ian Bull >- */ >-public interface ConstraintAdapter { >- >- /** >- * >- * @param object >- * @param constraint >- */ >- public void populateConstraint(Object object, LayoutConstraint constraint); >- >-} >Index: src/org/eclipse/zest/core/widgets/GraphConnection.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/GraphConnection.java,v >retrieving revision 1.23 >diff -u -r1.23 GraphConnection.java >--- src/org/eclipse/zest/core/widgets/GraphConnection.java 2 Apr 2009 22:49:10 -0000 1.23 >+++ src/org/eclipse/zest/core/widgets/GraphConnection.java 28 Aug 2009 16:03:21 -0000 >@@ -1,11 +1,12 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials are made >- * available under the terms of the Eclipse Public License v1.0 which >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html > * >- * Contributors: The Chisel Group, University of Victoria >+ * Contributors: The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 > ******************************************************************************/ > package org.eclipse.zest.core.widgets; > >@@ -28,10 +29,8 @@ > import org.eclipse.zest.core.widgets.internal.PolylineArcConnection; > import org.eclipse.zest.core.widgets.internal.RoundedChopboxAnchor; > import org.eclipse.zest.core.widgets.internal.ZestRootLayer; >-import org.eclipse.zest.layouts.LayoutBendPoint; >-import org.eclipse.zest.layouts.LayoutEntity; >-import org.eclipse.zest.layouts.LayoutRelationship; >-import org.eclipse.zest.layouts.constraints.LayoutConstraint; >+import org.eclipse.zest.layouts.interfaces.ConnectionLayout; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; > > /* > * This is the graph connection model which stores the source and destination >@@ -44,8 +43,8 @@ > public class GraphConnection extends GraphItem { > > private Font font; >- private GraphNode sourceNode; >- private GraphNode destinationNode; >+ private final GraphNode sourceNode; >+ private final GraphNode destinationNode; > > private double weight; > private Color color; >@@ -53,7 +52,7 @@ > private Color foreground; > private int lineWidth; > private int lineStyle; >- private final Graph graphModel; >+ private final Graph graph; > > private int connectionStyle; > private int curveDepth; >@@ -72,10 +71,10 @@ > private IFigure tooltip; > > private boolean highlighted; >- private GraphLayoutConnection layoutConnection = null; > private boolean hasCustomTooltip; > >- public GraphConnection(Graph graphModel, int style, GraphNode source, GraphNode destination) { >+ public GraphConnection(Graph graphModel, int style, GraphNode source, >+ GraphNode destination) { > super(graphModel, style); > > this.connectionStyle |= graphModel.getConnectionStyle(); >@@ -88,10 +87,9 @@ > this.highlightColor = graphModel.DARK_BLUE; > this.lineWidth = 1; > this.lineStyle = Graphics.LINE_SOLID; >- setWeight(weight); >- this.graphModel = graphModel; >+ this.weight = 1.0; >+ this.graph = graphModel; > this.curveDepth = 0; >- this.layoutConnection = new GraphLayoutConnection(); > this.font = Display.getDefault().getSystemFont(); > registerConnection(source, destination); > } >@@ -106,47 +104,50 @@ > (source).addSourceConnection(this); > (destination).addTargetConnection(this); > >- if (source.getParent().getItemType() == GraphItem.CONTAINER && destination.getParent().getItemType() == GraphItem.CONTAINER && (source.getParent() == destination.getParent())) { >- // 196189: Edges should not draw on the edge layer if both the src and dest are in the same container >+ if (source.getParent().getItemType() == GraphItem.CONTAINER >+ && destination.getParent().getItemType() == GraphItem.CONTAINER >+ && (source.getParent() == destination.getParent())) { >+ // 196189: Edges should not draw on the edge layer if both the src >+ // and dest are in the same container > // https://bugs.eclipse.org/bugs/show_bug.cgi?id=196189 >- graphModel.addConnection(this, ZestRootLayer.EDGES_ON_TOP); >+ graph.addConnection(this, false); > } else { >- graphModel.addConnection(this, true); >+ graph.addConnection(this, true); > } > > if ((source.getParent()).getItemType() == GraphItem.CONTAINER) { >- // If the container of the source is a container, we need to draw another >- // arc on that arc layer >+ // If the container of the source is a container, we need to draw >+ // another arc on that arc layer > sourceContainerConnectionFigure = doCreateFigure(); >- ((GraphContainer) source.getParent()).addConnectionFigure((PolylineConnection) sourceContainerConnectionFigure); >+ ((GraphContainer) source.getParent()) >+ .addConnectionFigure(sourceContainerConnectionFigure); > this.setVisible(false); > } > >- if ((destination.getParent()).getItemType() == GraphItem.CONTAINER) { //&& src_destSameContainer == false) { >- // If the container of the source is a container, we need to draw another >- // arc on that arc layer >+ if ((destination.getParent()).getItemType() == GraphItem.CONTAINER) { >+ // If the container of the source is a container, we need to draw >+ // another arc on that arc layer > targetContainerConnectionFigure = doCreateFigure(); >- ((GraphContainer) destination.getParent()).addConnectionFigure((PolylineConnection) targetContainerConnectionFigure); >+ ((GraphContainer) destination.getParent()) >+ .addConnectionFigure(targetContainerConnectionFigure); > this.setVisible(false); > } >- graphModel.getGraph().registerItem(this); >+ graph.registerItem(this); > } > > void removeFigure() { > if (connectionFigure.getParent() != null) { >- if (connectionFigure.getParent() instanceof ZestRootLayer) { >- ((ZestRootLayer) connectionFigure.getParent()).removeConnection(connectionFigure); >- } else { >- connectionFigure.getParent().remove(connectionFigure); >- } >+ connectionFigure.getParent().remove(connectionFigure); > } > connectionFigure = null; > if (sourceContainerConnectionFigure != null) { >- sourceContainerConnectionFigure.getParent().remove(sourceContainerConnectionFigure); >+ sourceContainerConnectionFigure.getParent().remove( >+ sourceContainerConnectionFigure); > sourceContainerConnectionFigure = null; > } > if (targetContainerConnectionFigure != null) { >- targetContainerConnectionFigure.getParent().remove(targetContainerConnectionFigure); >+ targetContainerConnectionFigure.getParent().remove( >+ targetContainerConnectionFigure); > targetContainerConnectionFigure = null; > } > >@@ -157,12 +158,14 @@ > this.isDisposed = true; > (getSource()).removeSourceConnection(this); > (getDestination()).removeTargetConnection(this); >- graphModel.removeConnection(this); >+ graph.removeConnection(this); > if (sourceContainerConnectionFigure != null) { >- sourceContainerConnectionFigure.getParent().remove(sourceContainerConnectionFigure); >+ sourceContainerConnectionFigure.getParent().remove( >+ sourceContainerConnectionFigure); > } > if (targetContainerConnectionFigure != null) { >- targetContainerConnectionFigure.getParent().remove(targetContainerConnectionFigure); >+ targetContainerConnectionFigure.getParent().remove( >+ targetContainerConnectionFigure); > } > } > >@@ -172,22 +175,12 @@ > > public Connection getConnectionFigure() { > if (connectionFigure == null) { >- connectionFigure = createFigure(); >+ connectionFigure = doCreateFigure(); > } > return connectionFigure; > } > > /** >- * Gets a proxy to this connection that can be used with the Zest layout >- * engine >- * >- * @return >- */ >- public LayoutRelationship getLayoutRelationship() { >- return this.layoutConnection; >- } >- >- /** > * Gets the external connection object. > * > * @return Object >@@ -202,11 +195,13 @@ > * @return String > */ > public String toString() { >- String arrow = (isBidirectionalInLayout() ? " <--> " : " --> "); >- String src = (sourceNode != null ? sourceNode.getText() : "null"); >- String dest = (destinationNode != null ? destinationNode.getText() : "null"); >- String weight = " (weight=" + getWeightInLayout() + ")"; >- return ("GraphModelConnection: " + src + arrow + dest + weight); >+ StringBuffer buffer = new StringBuffer("GraphModelConnection: "); >+ buffer.append(sourceNode != null ? sourceNode.getText() : "null"); >+ buffer.append(isDirected() ? " --> " : " --- "); >+ buffer.append(destinationNode != null ? destinationNode.getText() >+ : "null"); >+ buffer.append(" (weight=").append(getWeightInLayout()).append(")"); >+ return buffer.toString(); > } > > /** >@@ -228,8 +223,12 @@ > * @see #ZestStyles > */ > public void setConnectionStyle(int style) { >+ boolean directed = isDirected(); > this.connectionStyle = style; > updateFigure(this.connectionFigure); >+ if (directed != isDirected()) { >+ graph.getLayoutContext().fireConnectionDirectedChanged(getLayout()); >+ } > } > > /** >@@ -272,6 +271,7 @@ > * > */ > public void setWeight(double weight) { >+ double previousWeight = this.weight; > if (weight < 0) { > this.weight = -1; > } else if (weight > 1) { >@@ -279,6 +279,9 @@ > } else { > this.weight = weight; > } >+ if (previousWeight != this.weight) { >+ graph.getLayoutContext().fireConnectionWeightChanged(getLayout()); >+ } > } > > /** >@@ -413,9 +416,13 @@ > if (highlighted) { > return; > } >+ IFigure parentFigure = connectionFigure.getParent(); >+ if (parentFigure instanceof ZestRootLayer) { >+ ((ZestRootLayer) parentFigure) >+ .highlightConnection(connectionFigure); >+ } > highlighted = true; > updateFigure(connectionFigure); >- graphModel.highlightEdge(this); > } > > /** >@@ -425,9 +432,13 @@ > if (!highlighted) { > return; > } >+ IFigure parentFigure = connectionFigure.getParent(); >+ if (parentFigure instanceof ZestRootLayer) { >+ ((ZestRootLayer) parentFigure) >+ .unHighlightConnection(connectionFigure); >+ } > highlighted = false; > updateFigure(connectionFigure); >- graphModel.unhighlightEdge(this); > } > > /** >@@ -445,25 +456,28 @@ > * @return The graph model that this connection is contained in > */ > public Graph getGraphModel() { >- return this.graphModel; >+ return this.graph; > } > > /** >- * Sets the curve depth of the arc. The curve depth is defined as >- * the maximum distance from any point on the chord (i.e. a vector >- * normal to the chord with magnitude d). >+ * Sets the curve depth of the arc. The curve depth is defined as the >+ * maximum distance from any point on the chord (i.e. a vector normal to the >+ * chord with magnitude d). > * >- * If 0 is set, a Polyline Connection will be used, otherwise a >- * PolylineArcConnectoin will be used. Negative depths are also supported. >- * @param depth The depth of the curve >+ * If 0 is set, a Polyline Connection will be used, otherwise a >+ * PolylineArcConnectoin will be used. Negative depths are also supported. >+ * >+ * @param depth >+ * The depth of the curve > */ > public void setCurveDepth(int depth) { >- if (this.curveDepth == 0 && depth != 0 || this.curveDepth != 0 && depth == 0) { >+ if (this.curveDepth == 0 && depth != 0 || this.curveDepth != 0 >+ && depth == 0) { > // There is currently no curve, so we have to create > // a curved connection >- graphModel.removeConnection(this); >+ graph.removeConnection(this); > this.curveDepth = depth; >- this.connectionFigure = createFigure(); >+ this.connectionFigure = doCreateFigure(); > registerConnection(sourceNode, destinationNode); > updateFigure(this.connectionFigure); > } else { >@@ -484,10 +498,11 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.mylar.zest.core.internal.graphmodel.GraphItem#setVisible(boolean) >+ * @see >+ * org.eclipse.mylar.zest.core.internal.graphmodel.GraphItem#setVisible( >+ * boolean) > */ > public void setVisible(boolean visible) { >- //graphModel.addRemoveFigure(this, visible); > if (getSource().isVisible() && getDestination().isVisible() && visible) { > this.getFigure().setVisible(visible); > if (sourceContainerConnectionFigure != null) { >@@ -532,6 +547,27 @@ > } > } > >+ /** >+ * @since 2.0 >+ */ >+ public boolean isDirected() { >+ return ZestStyles.checkStyle(connectionStyle, >+ ZestStyles.CONNECTIONS_DIRECTED); >+ } >+ >+ /** >+ * @since 2.0 >+ */ >+ public void setDirected(boolean directed) { >+ if (directed) { >+ setConnectionStyle(connectionStyle >+ | ZestStyles.CONNECTIONS_DIRECTED); >+ } else { >+ setConnectionStyle(connectionStyle >+ & (-1 - ZestStyles.CONNECTIONS_DIRECTED)); >+ } >+ } >+ > PolylineConnection getSourceContainerConnectionFigure() { > return (PolylineConnection) sourceContainerConnectionFigure; > } >@@ -559,7 +595,6 @@ > connectionShape.setLineStyle(getLineStyle()); > > if (this.getText() != null || this.getImage() != null) { >- //Label l = new Label(this.getText(), this.getImage()); > if (this.getImage() != null) { > this.connectionLabel.setIcon(this.getImage()); > } >@@ -593,7 +628,8 @@ > } > > IFigure toolTip; >- if (this.getTooltip() == null && getText() != null && getText().length() > 0 && hasCustomTooltip == false) { >+ if (this.getTooltip() == null && getText() != null >+ && getText().length() > 0 && hasCustomTooltip == false) { > toolTip = new Label(); > ((Label) toolTip).setText(getText()); > } else { >@@ -602,24 +638,6 @@ > connection.setToolTip(toolTip); > } > >- private Connection createFigure() { >- /* >- if ((sourceNode.getParent()).getItemType() == GraphItem.CONTAINER) { >- GraphContainer container = (GraphContainer) sourceNode.getParent(); >- sourceContainerConnectionFigure = doCreateFigure(); >- container.addConnectionFigure((PolylineConnection) sourceContainerConnectionFigure); >- } >- if ((destinationNode.getParent()).getItemType() == GraphItem.CONTAINER) { >- GraphContainer container = (GraphContainer) destinationNode.getParent(); >- targetContainerConnectionFigure = doCreateFigure(); >- container.addConnectionFigure((PolylineConnection) targetContainerConnectionFigure); >- } >- */ >- >- return doCreateFigure(); >- >- } >- > private Connection doCreateFigure() { > Connection connectionFigure = null; > ChopboxAnchor sourceAnchor = null; >@@ -628,8 +646,8 @@ > Locator labelLocator = null; > > if (getSource() == getDestination()) { >- // If this is a self loop, create a looped arc and put the locator at the top >- // of the connection >+ // If this is a self loop, create a looped arc and put the locator >+ // at the top of the connection > connectionFigure = new PolylineArcConnection(); > sourceAnchor = new LoopAnchor(getSource().getNodeFigure()); > targetAnchor = new LoopAnchor(getDestination().getNodeFigure()); >@@ -637,19 +655,23 @@ > protected Point getReferencePoint() { > Point p = Point.SINGLETON; > p.x = getConnection().getPoints().getPoint(getIndex()).x; >- p.y = (int) (getConnection().getPoints().getPoint(getIndex()).y - (curveDepth * 1.5)); >+ p.y = (int) (getConnection().getPoints().getPoint( >+ getIndex()).y - (curveDepth * 1.5)); > return p; > } > }; > } else { > if (curveDepth != 0) { > connectionFigure = new PolylineArcConnection(); >- ((PolylineArcConnection) connectionFigure).setDepth(this.curveDepth); >+ ((PolylineArcConnection) connectionFigure) >+ .setDepth(this.curveDepth); > } else { > connectionFigure = new PolylineConnection(); > } >- sourceAnchor = new RoundedChopboxAnchor(getSource().getNodeFigure(), 8); >- targetAnchor = new RoundedChopboxAnchor(getDestination().getNodeFigure(), 8); >+ sourceAnchor = new RoundedChopboxAnchor( >+ getSource().getNodeFigure(), 8); >+ targetAnchor = new RoundedChopboxAnchor(getDestination() >+ .getNodeFigure(), 8); > labelLocator = new MidpointLocator(connectionFigure, 0); > } > >@@ -661,58 +683,58 @@ > return connectionFigure; > } > >- /* >- * (non-Javadoc) >- * >- * @see org.eclipse.mylar.zest.layouts.LayoutRelationship#isBidirectionalInLayout() >- */ >- private boolean isBidirectionalInLayout() { >- return !ZestStyles.checkStyle(connectionStyle, ZestStyles.CONNECTIONS_DIRECTED); >+ IFigure getFigure() { >+ return this.getConnectionFigure(); > } > >- class GraphLayoutConnection implements LayoutRelationship { >- >- Object layoutInformation = null; >+ private InternalConnectionLayout layout; > >- public void clearBendPoints() { >- // @tag TODO : add bendpoints >+ InternalConnectionLayout getLayout() { >+ if (layout == null) { >+ layout = new InternalConnectionLayout(); > } >+ return layout; >+ } > >- public LayoutEntity getDestinationInLayout() { >- return getDestination().getLayoutEntity(); >- } >+ class InternalConnectionLayout implements ConnectionLayout { >+ private boolean visible = GraphConnection.this.isVisible(); > >- public Object getLayoutInformation() { >- return layoutInformation; >+ public NodeLayout getSource() { >+ return sourceNode.getLayout(); > } > >- public LayoutEntity getSourceInLayout() { >- return getSource().getLayoutEntity(); >+ public NodeLayout getTarget() { >+ return destinationNode.getLayout(); > } > >- public void populateLayoutConstraint(LayoutConstraint constraint) { >- graphModel.invokeConstraintAdapters(GraphConnection.this, constraint); >+ public double getWeight() { >+ return GraphConnection.this.getWeightInLayout(); > } > >- public void setBendPoints(LayoutBendPoint[] bendPoints) { >- // @tag TODO : add bendpoints >+ public boolean isDirected() { >+ return ZestStyles.checkStyle(getConnectionStyle(), >+ ZestStyles.CONNECTIONS_DIRECTED); > } > >- public void setLayoutInformation(Object layoutInformation) { >- this.layoutInformation = layoutInformation; >+ public boolean isVisible() { >+ return visible; > } > >- public Object getGraphData() { >- return GraphConnection.this; >+ public void setVisible(boolean visible) { >+ graph.getLayoutContext().checkChangesAllowed(); >+ this.visible = visible; > } > >- public void setGraphData(Object o) { >- >+ void applyLayout() { >+ if (GraphConnection.this.isVisible() != this.visible) { >+ GraphConnection.this.setVisible(this.visible); >+ } > } >- > } > >- IFigure getFigure() { >- return this.getConnectionFigure(); >+ void applyLayoutChanges() { >+ if (layout != null) { >+ layout.applyLayout(); >+ } > } > } >Index: src/org/eclipse/zest/core/widgets/CGraphNode.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/CGraphNode.java >diff -N src/org/eclipse/zest/core/widgets/CGraphNode.java >--- src/org/eclipse/zest/core/widgets/CGraphNode.java 31 Mar 2009 16:39:23 -0000 1.1 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,51 +0,0 @@ >-package org.eclipse.zest.core.widgets; >- >-import org.eclipse.draw2d.IFigure; >-import org.eclipse.swt.graphics.Color; >-import org.eclipse.swt.graphics.Font; >- >-/** >- * A Custom Graph Node >- */ >-public class CGraphNode extends GraphNode { >- >- IFigure figure = null; >- >- public CGraphNode(IContainer graphModel, int style, IFigure figure) { >- super(graphModel, style, figure); >- } >- >- public IFigure getFigure() { >- return super.getFigure(); >- } >- >- protected IFigure createFigureForModel() { >- this.figure = (IFigure) this.getData(); >- return this.figure; >- } >- >- public void setBackgroundColor(Color c) { >- getFigure().setBackgroundColor(c); >- } >- >- public void setFont(Font font) { >- getFigure().setFont(font); >- } >- >- public Color getBackgroundColor() { >- return getFigure().getBackgroundColor(); >- } >- >- public Font getFont() { >- return getFigure().getFont(); >- } >- >- public Color getForegroundColor() { >- return getFigure().getForegroundColor(); >- } >- >- protected void updateFigureForModel(IFigure currentFigure) { >- // Undefined >- } >- >-} >Index: src/org/eclipse/zest/core/widgets/IContainer.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/IContainer.java,v >retrieving revision 1.2 >diff -u -r1.2 IContainer.java >--- src/org/eclipse/zest/core/widgets/IContainer.java 12 Sep 2007 20:44:39 -0000 1.2 >+++ src/org/eclipse/zest/core/widgets/IContainer.java 28 Aug 2009 16:03:23 -0000 >@@ -1,64 +1,74 @@ > /******************************************************************************* >- * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: >- * The Chisel Group, University of Victoria >- *******************************************************************************/ >+ * >+ * Contributors: The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ > package org.eclipse.zest.core.widgets; > > import java.util.List; > >+import org.eclipse.draw2d.IFigure; >+import org.eclipse.swt.widgets.Widget; > import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; > > /** >- * This interface describes all Zest components that are Containers. This is an internal interface >- * and thus should not be used outside of Zest. Implementors of this interface must include the >- * following two methods >- * o addNode(GraphNode) >- * o addNode(GraphContainer) >- * >- * These are not actually listed here because Java does not allow protected methods in >- * interfaces. >+ * @noimplement This interface is not intended to be implemented by clients. > * >- * @author Ian Bull > */ > public interface IContainer { > >- public Graph getGraph(); >- >- // All implementers must include this method >- /* protected void addNode(GraphNode node); */ >+ public abstract Graph getGraph(); > >- // All implementers must include this method >- /* protected void addNode(GraphContainer container); */ >+ /** >+ * @since 2.0 >+ */ >+ public Widget getItem(); > >- public int getItemType(); >+ public abstract List getNodes(); > > /** >- * Re-applies the current layout algorithm >+ * Returns list of connections laying inside this container. Only >+ * connections which both source and target nodes lay directly in this >+ * container are returned. >+ * >+ * @return >+ * @since 2.0 > */ >- public void applyLayout(); >+ public abstract List getConnections(); > > /** >- * Sets the LayoutAlgorithm for this container and optionally applies it. >- * >- * @param algorithm The layout algorithm to set >- * @param applyLayout >+ * @noreference This method is not intended to be referenced by clients. >+ * @param graphNode > */ >- public void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean applyLayout); >+ public abstract void addNode(GraphNode graphNode); > >- public List getNodes(); >+ /** >+ * @noreference This method is not intended to be referenced by clients. >+ * @param figure >+ */ >+ public abstract void addSubgraphFigure(IFigure figure); > >- /* protected void highlightNode(GraphNode node); */ >+ public abstract int getItemType(); > >- /* protected void highlightNode(GraphContainer container);*/ >+ /** >+ * @return >+ * @since 2.0 >+ */ >+ public abstract DisplayIndependentRectangle getLayoutBounds(); > >- /* protected void unhighlightNode(GraphNode node); */ >+ /** >+ * @noreference This method is not intended to be referenced by clients. >+ * @return >+ */ >+ public abstract InternalLayoutContext getLayoutContext(); > >- /* protected void unhighlightNode(GraphContainer container);*/ >+ public void applyLayout(); > >-} // end of IContainer >+ public void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean apply); >+} >Index: src/org/eclipse/zest/core/widgets/GraphItem.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/GraphItem.java,v >retrieving revision 1.9 >diff -u -r1.9 GraphItem.java >--- src/org/eclipse/zest/core/widgets/GraphItem.java 12 Sep 2007 20:44:39 -0000 1.9 >+++ src/org/eclipse/zest/core/widgets/GraphItem.java 28 Aug 2009 16:03:22 -0000 >@@ -1,11 +1,12 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >- * All rights reserved. This program and the accompanying materials are made >- * available under the terms of the Eclipse Public License v1.0 which >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html > * >- * Contributors: The Chisel Group, University of Victoria >+ * Contributors: The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 > ******************************************************************************/ > package org.eclipse.zest.core.widgets; > >@@ -89,15 +90,15 @@ > public abstract Graph getGraphModel(); > > /** >- * Highlights the current GraphItem. A graph item is either a graph node or >- * graph connection, and highlighting them will set the appropriate highlight >- * color. >+ * Highlights the current GraphItem. A graph item is either a graph node or >+ * graph connection, and highlighting them will set the appropriate >+ * highlight color. > */ > public abstract void highlight(); > > /** >- * Unhighlight sets the graphItem (either a graphNode or graphConnection) back >- * to the unhighlight figure or color. >+ * Unhighlight sets the graphItem (either a graphNode or graphConnection) >+ * back to the unhighlight figure or color. > */ > public abstract void unhighlight(); > >@@ -105,7 +106,9 @@ > > /** > * Checks a style to see if it is set on the given graph item >- * @param styleToCheck The style to check >+ * >+ * @param styleToCheck >+ * The style to check > * @return > */ > protected boolean checkStyle(int styleToCheck) { >Index: META-INF/MANIFEST.MF >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/META-INF/MANIFEST.MF,v >retrieving revision 1.30 >diff -u -r1.30 MANIFEST.MF >--- META-INF/MANIFEST.MF 24 Jul 2009 19:14:05 -0000 1.30 >+++ META-INF/MANIFEST.MF 28 Aug 2009 16:03:15 -0000 >@@ -1,15 +1,16 @@ >-Manifest-Version: 1.0 >-Bundle-ManifestVersion: 2 >-Bundle-Name: %Plugin.name >-Bundle-SymbolicName: org.eclipse.zest.core;singleton:=true >-Bundle-Vendor: %Plugin.providerName >-Bundle-Localization: plugin >-Bundle-Version: 1.2.0.qualifier >-Require-Bundle: org.eclipse.zest.layouts, >- org.eclipse.ui, >- org.eclipse.draw2d;visibility:=reexport >-Eclipse-LazyStart: false >-Export-Package: org.eclipse.zest.core.viewers, >- org.eclipse.zest.core.widgets >-Import-Package: com.ibm.icu.text;version="[3.8.1,5.0.0)" >-Bundle-RequiredExecutionEnvironment: J2SE-1.4 >+Manifest-Version: 1.0 >+Bundle-ManifestVersion: 2 >+Bundle-Name: %Plugin.name >+Bundle-SymbolicName: org.eclipse.zest.core;singleton:=true >+Bundle-Vendor: %Plugin.providerName >+Bundle-Localization: plugin >+Bundle-Version: 2.0.0.qualifier >+Require-Bundle: org.eclipse.zest.layouts, >+ org.eclipse.ui, >+ org.eclipse.draw2d;visibility:=reexport >+Eclipse-LazyStart: false >+Export-Package: org.eclipse.zest.core.viewers, >+ org.eclipse.zest.core.widgets, >+ org.eclipse.zest.core.widgets.custom >+Import-Package: com.ibm.icu.text;version="[3.8.1,5.0.0)" >+Bundle-RequiredExecutionEnvironment: J2SE-1.4 >Index: src/org/eclipse/zest/core/widgets/internal/AligningBendpointLocator.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/internal/AligningBendpointLocator.java,v >retrieving revision 1.3 >diff -u -r1.3 AligningBendpointLocator.java >--- src/org/eclipse/zest/core/widgets/internal/AligningBendpointLocator.java 12 Sep 2007 20:44:39 -0000 1.3 >+++ src/org/eclipse/zest/core/widgets/internal/AligningBendpointLocator.java 28 Aug 2009 16:03:24 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -20,15 +20,18 @@ > > /** > * A locator that finds the middle of a connection based on the bendpoints. >+ * > * @author Del Myers >- * >+ * > */ >-//@tag zest(bug(154391-ArcEnds(fix))) : use this locator to ensure that labels will be in the middle of connections. >-//@tag zest.bug.160368-ConnectionAlign : replaces MidBenpointLocator in order to have finer control over alignment. >+// @tag zest(bug(154391-ArcEnds(fix))) : use this locator to ensure that labels >+// will be in the middle of connections. >+// @tag zest.bug.160368-ConnectionAlign : replaces MidBenpointLocator in order >+// to have finer control over alignment. > public class AligningBendpointLocator extends AbstractLocator { > /** >- * "Vertical" alignment contstant. Figures should be placed in the middle >- * of the line. >+ * "Vertical" alignment contstant. Figures should be placed in the middle of >+ * the line. > */ > public static final int MIDDLE = 0; > /** >@@ -39,38 +42,38 @@ > * "Vertical" alignment constant. Figures should be placed below the line. > */ > public static final int BELOW = 2; >- >+ > /** > * "Horizontal" alignment constant. Figures should be placed in the center > * of the points on the line. > */ > public static final int CENTER = 0; >- >+ > /** >- * "Horizontal" alignment constant. Figures should be placed at the beginning >- * of the line. Figures will be anchored so that they have one end at the >- * beginning of the connection, not so that they are centered at the start >- * point. Which end of the figure is placed at that point will depend >+ * "Horizontal" alignment constant. Figures should be placed at the >+ * beginning of the line. Figures will be anchored so that they have one end >+ * at the beginning of the connection, not so that they are centered at the >+ * start point. Which end of the figure is placed at that point will depend > * on the direction of the first two points. > */ > public static final int BEGINNING = 1; >- >+ > /** > * "Horizontal" alignment constant. Figures should be placed at the end of > * the line. Figures will be anchored so that they have one end at the > * beginning of the connection, not so that they are centered at the end >- * point. Which end of the figure is placed at that point will depend >- * on the direction of the last two points. >+ * point. Which end of the figure is placed at that point will depend on the >+ * direction of the last two points. > */ > public static final int END = 2; >- >+ > /** > * "Horizontal" alignment constant. Figures should be centered between the >- * first two points on the connection. For connections with only two points, >+ * first two points on the connection. For connections with only two points, > * this will behave the same as CENTER. > */ > public static final int CENTER_BEGINNING = 3; >- >+ > /** > * "Horizontal" alignment constant. Figures should be centered between the > * last two points on the connection. For connections with only two points, >@@ -80,20 +83,24 @@ > private int horizontal; > private int vertical; > private Connection connection; >+ > /** > * @param connection > */ > public AligningBendpointLocator(Connection connection) { > this(connection, CENTER, MIDDLE); > } >- >- public AligningBendpointLocator(Connection connection, int horizontal, int vertical) { >+ >+ public AligningBendpointLocator(Connection connection, int horizontal, >+ int vertical) { > this.connection = connection; > this.horizontal = horizontal; > this.vertical = vertical; > } >- >- /* (non-Javadoc) >+ >+ /* >+ * (non-Javadoc) >+ * > * @see org.eclipse.draw2d.ConnectionLocator#getReferencePoint() > */ > protected Point getReferencePoint() { >@@ -116,7 +123,7 @@ > tempPoints = new PointList(); > int s = points.size(); > tempPoints.addPoint(points.getLastPoint().getCopy()); >- tempPoints.addPoint(points.getPoint(s-2).getCopy()); >+ tempPoints.addPoint(points.getPoint(s - 2).getCopy()); > p = tempPoints.getMidpoint().getCopy(); > case CENTER: > default: >@@ -124,47 +131,56 @@ > } > return p; > } >+ > /** > * Recalculates the position of the figure and returns the updated bounds. >- * @param target The figure to relocate >+ * >+ * @param target >+ * The figure to relocate > */ > public void relocate(IFigure target) { > Dimension prefSize = target.getPreferredSize(); > Point center = getReferencePoint(); > calculatePosition(); >- //@tag zest(bug(GEFProblem)) : there seems to be a bug in GEF that if the following is done, then labels get printed in the wrong location >- //target.translateToRelative(center); >+ // @tag zest(bug(GEFProblem)) : there seems to be a bug in GEF that if >+ // the following is done, then labels get printed in the wrong location >+ // target.translateToRelative(center); > target.setBounds(getNewBounds(prefSize, center)); > } >- >+ > /** > * Translates the center point depending on the horizontal and veritical > * alignments based on the given bounds. >+ * > * @param center > */ > private void calculatePosition() { > PointList points = getConnection().getPoints(); > int position = 0; >- switch(horizontal) { >+ switch (horizontal) { > case BEGINNING: > Point first = points.getFirstPoint(); > Point next = points.getPoint(1); >- if (first.x <= next.x) >+ if (first.x <= next.x) { > position |= PositionConstants.EAST; >- else >+ } else { > position |= PositionConstants.WEST; >+ } > break; > case END: > Point last = points.getLastPoint(); > int s = points.size(); >- Point before = points.getPoint(s-1); >- if (last.x <= before.x) >+ Point before = points.getPoint(s - 1); >+ if (last.x <= before.x) { > position |= PositionConstants.EAST; >- else >+ } else { > position |= PositionConstants.WEST; >+ } > break; > } >- if (position == 0) position = PositionConstants.CENTER; >+ if (position == 0) { >+ position = PositionConstants.CENTER; >+ } > switch (vertical) { > case ABOVE: > position |= PositionConstants.NORTH; >@@ -176,7 +192,7 @@ > position |= PositionConstants.MIDDLE; > } > setRelativePosition(position); >- >+ > } > > /** >@@ -185,30 +201,31 @@ > public int getHorizontalAlignment() { > return horizontal; > } >- >+ > /** >- * @param horizontal the horizontal alignment to set. One of CENTER, >- * BEGINNING, END, CENTER_BEGINNING, or CENTER_END. >+ * @param horizontal >+ * the horizontal alignment to set. One of CENTER, BEGINNING, >+ * END, CENTER_BEGINNING, or CENTER_END. > */ > public void setHorizontalAlignment(int horizontal) { > this.horizontal = horizontal; > } >- >+ > /** >- * @param vertical the vertical alignment to set. One of ABOVE, MIDDLE, or >- * BELOW. >+ * @param vertical >+ * the vertical alignment to set. One of ABOVE, MIDDLE, or BELOW. > */ > public void setVerticalAlginment(int vertical) { > this.vertical = vertical; > } >- >+ > /** > * @return the vertical alginment. > */ > public int getVerticalAlignment() { > return vertical; > } >- >+ > /** > * @return the connection > */ >Index: src/org/eclipse/zest/core/widgets/internal/GraphLabel.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/internal/GraphLabel.java,v >retrieving revision 1.14 >diff -u -r1.14 GraphLabel.java >--- src/org/eclipse/zest/core/widgets/internal/GraphLabel.java 25 Apr 2009 06:08:58 -0000 1.14 >+++ src/org/eclipse/zest/core/widgets/internal/GraphLabel.java 28 Aug 2009 16:03:25 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials are made > * available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at >@@ -58,7 +58,7 @@ > * faster, but the > */ > public GraphLabel(String text, boolean cacheLabel) { >- this("", null, cacheLabel); >+ this(text, null, cacheLabel); > } > > /** >@@ -127,11 +127,14 @@ > if (font != null) { > Dimension minSize = FigureUtilities.getTextExtents(text, font); > if (getIcon() != null) { >- org.eclipse.swt.graphics.Rectangle imageRect = getIcon().getBounds(); >- int expandHeight = Math.max(imageRect.height - minSize.height, 0); >+ org.eclipse.swt.graphics.Rectangle imageRect = getIcon() >+ .getBounds(); >+ int expandHeight = Math.max(imageRect.height >+ - minSize.height, 0); > minSize.expand(imageRect.width + 4, expandHeight); > } >- minSize.expand(10 + (2 * safeBorderWidth), 4 + (2 * safeBorderWidth)); >+ minSize.expand(10 + (2 * safeBorderWidth), >+ 4 + (2 * safeBorderWidth)); > setBounds(new Rectangle(getLocation(), minSize)); > } > } >@@ -155,7 +158,8 @@ > green = (int) (green - (green * 0.20)); > green = green > 0 ? green : 0; > >- Color lightenColor = new Color(Display.getCurrent(), new RGB(red, green, blue)); >+ Color lightenColor = new Color(Display.getCurrent(), new RGB(red, >+ green, blue)); > graphics.setForegroundColor(lightenColor); > graphics.setBackgroundColor(getBackgroundColor()); > >@@ -166,19 +170,22 @@ > if (graphics instanceof ScaledGraphics) { > scale = ((ScaledGraphics) graphics).getAbsoluteScale(); > } >- // Top part inside the border (as fillGradient does not allow to fill a rectangle with round corners). >+ // Top part inside the border (as fillGradient does not allow to fill a >+ // rectangle with round corners). > Rectangle rect = getBounds().getCopy(); > rect.height /= 2; > graphics.setForegroundColor(getBackgroundColor()); > graphics.setBackgroundColor(getBackgroundColor()); >- graphics.fillRoundRectangle(rect, arcWidth * safeBorderWidth, arcWidth * 2 * safeBorderWidth); >+ graphics.fillRoundRectangle(rect, arcWidth * safeBorderWidth, arcWidth >+ * 2 * safeBorderWidth); > > // Bottom part inside the border. > rect.y = rect.y + rect.height; > rect.height += 1; // Not sure why it is needed, but it is needed ;-) > graphics.setForegroundColor(lightenColor); > graphics.setBackgroundColor(lightenColor); >- graphics.fillRoundRectangle(rect, arcWidth * safeBorderWidth, arcWidth * 2 * safeBorderWidth); >+ graphics.fillRoundRectangle(rect, arcWidth * safeBorderWidth, arcWidth >+ * 2 * safeBorderWidth); > > // Now fill the middle part of top and bottom part with a gradient. > rect = bounds.getCopy(); >@@ -235,12 +242,7 @@ > * @see org.eclipse.draw2d.Label#setText(java.lang.String) > */ > public void setText(String s) { >- if (!s.equals("")) { >- super.setText(s); >- >- } else { >- super.setText(""); >- } >+ super.setText(s); > adjustBoundsToFit(); > } > >@@ -251,7 +253,7 @@ > */ > public void setIcon(Image image) { > super.setIcon(image); >- //adjustBoundsToFit(); >+ adjustBoundsToFit(); > } > > public Color getBorderColor() { >@@ -277,10 +279,4 @@ > public void setArcWidth(int arcWidth) { > this.arcWidth = arcWidth; > } >- >- public void setBounds(Rectangle rect) { >- // TODO Auto-generated method stub >- super.setBounds(rect); >- } >- > } >Index: src/org/eclipse/zest/core/widgets/internal/XYScaledGraphics.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/internal/XYScaledGraphics.java,v >retrieving revision 1.5 >diff -u -r1.5 XYScaledGraphics.java >--- src/org/eclipse/zest/core/widgets/internal/XYScaledGraphics.java 12 Sep 2007 20:44:39 -0000 1.5 >+++ src/org/eclipse/zest/core/widgets/internal/XYScaledGraphics.java 28 Aug 2009 16:03:26 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2005 IBM Corporation and others. All rights reserved. >+ * Copyright (c) 2005-2009 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 >@@ -39,7 +39,9 @@ > */ > public class XYScaledGraphics extends ScaledGraphics { > >- public static final double MAX_TEXT_SIZE = 0.45; // MAX size, when to stop zooming text >+ public static final double MAX_TEXT_SIZE = 0.45; // MAX size, when to stop >+ >+ // zooming text > > private static class FontHeightCache { > Font font; >@@ -80,7 +82,7 @@ > private double appliedY; > private Font font; > private int lineWidth; >- //private double zoom; // This has been replaced with xZoom and yZoom >+ // private double zoom; // This has been replaced with xZoom and yZoom > private double xZoom; > private double yZoom; > >@@ -105,7 +107,8 @@ > * @param lineWidth > * the line width > */ >- protected State(double xZoom, double yZoom, double x, double y, Font font, int lineWidth) { >+ protected State(double xZoom, double yZoom, double x, double y, >+ Font font, int lineWidth) { > this.xZoom = xZoom; > this.yZoom = yZoom; > this.appliedX = x; >@@ -128,7 +131,8 @@ > * @param lineWidth > * the line width > */ >- protected void setValues(double xZoom, double yZoom, double x, double y, Font font, int lineWidth) { >+ protected void setValues(double xZoom, double yZoom, double x, >+ double y, Font font, int lineWidth) { > this.xZoom = xZoom; > this.yZoom = yZoom; > this.appliedX = x; >@@ -148,7 +152,7 @@ > } > > private boolean allowText = true; >- // private static final Point PT = new Point(); >+ // private static final Point PT = new Point(); > private Map fontCache = new HashMap(); > private Map fontDataCache = new HashMap(); > private FontKey fontKey = new FontKey(); >@@ -189,12 +193,12 @@ > > /** @see Graphics#dispose() */ > public void dispose() { >- //Remove all states from the stack >+ // Remove all states from the stack > while (stackPointer > 0) { > popState(); > } > >- //Dispose fonts >+ // Dispose fonts > Iterator iter = fontCache.values().iterator(); > while (iter.hasNext()) { > Font font = ((Font) iter.next()); >@@ -221,22 +225,31 @@ > public void drawImage(Image srcImage, int x, int y) { > org.eclipse.swt.graphics.Rectangle size = srcImage.getBounds(); > double imageZoom = Math.min(xZoom, yZoom); >- graphics.drawImage(srcImage, 0, 0, size.width, size.height, (int) (Math.floor((x * xZoom + fractionalX))), (int) (Math.floor((y * yZoom + fractionalY))), (int) (Math.floor((size.width * imageZoom + fractionalX))), (int) (Math.floor((size.height * imageZoom + fractionalY)))); >+ graphics.drawImage(srcImage, 0, 0, size.width, size.height, (int) (Math >+ .floor((x * xZoom + fractionalX))), (int) (Math.floor((y >+ * yZoom + fractionalY))), (int) (Math.floor((size.width >+ * imageZoom + fractionalX))), (int) (Math.floor((size.height >+ * imageZoom + fractionalY)))); > } > > /** @see Graphics#drawImage(Image, int, int, int, int, int, int, int, int) */ >- public void drawImage(Image srcImage, int sx, int sy, int sw, int sh, int tx, int ty, int tw, int th) { >- //"t" == target rectangle, "s" = source >+ public void drawImage(Image srcImage, int sx, int sy, int sw, int sh, >+ int tx, int ty, int tw, int th) { >+ // "t" == target rectangle, "s" = source > > Rectangle t = zoomRect(tx, ty, tw, th); > if (!t.isEmpty()) { >- graphics.drawImage(srcImage, sx, sy, sw, sh, t.x, t.y, t.width, t.height); >+ graphics.drawImage(srcImage, sx, sy, sw, sh, t.x, t.y, t.width, >+ t.height); > } > } > > /** @see Graphics#drawLine(int, int, int, int) */ > public void drawLine(int x1, int y1, int x2, int y2) { >- graphics.drawLine((int) (Math.floor((x1 * xZoom + fractionalX))), (int) (Math.floor((y1 * yZoom + fractionalY))), (int) (Math.floor((x2 * xZoom + fractionalX))), (int) (Math.floor((y2 * yZoom + fractionalY)))); >+ graphics.drawLine((int) (Math.floor((x1 * xZoom + fractionalX))), >+ (int) (Math.floor((y1 * yZoom + fractionalY))), (int) (Math >+ .floor((x2 * xZoom + fractionalX))), (int) (Math >+ .floor((y2 * yZoom + fractionalY)))); > } > > /** @see Graphics#drawOval(int, int, int, int) */ >@@ -246,7 +259,8 @@ > > /** @see Graphics#drawPoint(int, int) */ > public void drawPoint(int x, int y) { >- graphics.drawPoint((int) Math.floor(x * xZoom + fractionalX), (int) Math.floor(y * yZoom + fractionalY)); >+ graphics.drawPoint((int) Math.floor(x * xZoom + fractionalX), >+ (int) Math.floor(y * yZoom + fractionalY)); > } > > /** >@@ -280,7 +294,8 @@ > > /** @see Graphics#drawRoundRectangle(Rectangle, int, int) */ > public void drawRoundRectangle(Rectangle r, int arcWidth, int arcHeight) { >- graphics.drawRoundRectangle(zoomRect(r.x, r.y, r.width, r.height), (int) (arcWidth * xZoom), (int) (arcHeight * yZoom)); >+ graphics.drawRoundRectangle(zoomRect(r.x, r.y, r.width, r.height), >+ (int) (arcWidth * xZoom), (int) (arcHeight * yZoom)); > } > > /** @see Graphics#drawString(String, int, int) */ >@@ -310,9 +325,14 @@ > * @see Graphics#drawTextLayout(TextLayout, int, int, int, int, Color, > * Color) > */ >- public void drawTextLayout(TextLayout layout, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground) { >+ public void drawTextLayout(TextLayout layout, int x, int y, >+ int selectionStart, int selectionEnd, Color selectionForeground, >+ Color selectionBackground) { > TextLayout scaled = zoomTextLayout(layout); >- graphics.drawTextLayout(scaled, (int) Math.floor(x * xZoom + fractionalX), (int) Math.floor(y * yZoom + fractionalY), selectionStart, selectionEnd, selectionBackground, selectionForeground); >+ graphics.drawTextLayout(scaled, (int) Math.floor(x * xZoom >+ + fractionalX), (int) Math.floor(y * yZoom + fractionalY), >+ selectionStart, selectionEnd, selectionBackground, >+ selectionForeground); > scaled.dispose(); > } > >@@ -354,7 +374,8 @@ > > /** @see Graphics#fillRoundRectangle(Rectangle, int, int) */ > public void fillRoundRectangle(Rectangle r, int arcWidth, int arcHeight) { >- graphics.fillRoundRectangle(zoomFillRect(r.x, r.y, r.width, r.height), (int) (arcWidth * xZoom), (int) (arcHeight * yZoom)); >+ graphics.fillRoundRectangle(zoomFillRect(r.x, r.y, r.width, r.height), >+ (int) (arcWidth * xZoom), (int) (arcHeight * yZoom)); > } > > /** @see Graphics#fillString(String, int, int) */ >@@ -524,9 +545,11 @@ > State s; > if (stack.size() > stackPointer) { > s = (State) stack.get(stackPointer); >- s.setValues(xZoom, yZoom, fractionalX, fractionalY, getLocalFont(), localLineWidth); >+ s.setValues(xZoom, yZoom, fractionalX, fractionalY, getLocalFont(), >+ localLineWidth); > } else { >- stack.add(new State(xZoom, yZoom, fractionalX, fractionalY, getLocalFont(), localLineWidth)); >+ stack.add(new State(xZoom, yZoom, fractionalX, fractionalY, >+ getLocalFont(), localLineWidth)); > } > stackPointer++; > >@@ -554,7 +577,7 @@ > > /** @see Graphics#scale(double) */ > public void scale(double amount) { >- //setScale(zoom * amount); >+ // setScale(zoom * amount); > throw new RuntimeException("Operation not supported, use scale(x, y)"); > } > >@@ -681,28 +704,36 @@ > > /** @see Graphics#translate(int, int) */ > public void translate(int dx, int dy) { >- // fractionalX/Y is the fractional part left over from previous >+ // fractionalX/Y is the fractional part left over from previous > // translates that gets lost in the integer approximation. > double dxFloat = dx * xZoom + fractionalX; > double dyFloat = dy * yZoom + fractionalY; > fractionalX = dxFloat - Math.floor(dxFloat); > fractionalY = dyFloat - Math.floor(dyFloat); >- graphics.translate((int) Math.floor(dxFloat), (int) Math.floor(dyFloat)); >+ graphics >+ .translate((int) Math.floor(dxFloat), (int) Math.floor(dyFloat)); > } > > private Rectangle zoomClipRect(Rectangle r) { > tempRECT.x = (int) (Math.floor(r.x * xZoom + fractionalX)); > tempRECT.y = (int) (Math.floor(r.y * yZoom + fractionalY)); >- tempRECT.width = (int) (Math.ceil(((r.x + r.width) * xZoom + fractionalX))) - tempRECT.x; >- tempRECT.height = (int) (Math.ceil(((r.y + r.height) * yZoom + fractionalY))) - tempRECT.y; >+ tempRECT.width = (int) (Math >+ .ceil(((r.x + r.width) * xZoom + fractionalX))) >+ - tempRECT.x; >+ tempRECT.height = (int) (Math >+ .ceil(((r.y + r.height) * yZoom + fractionalY))) >+ - tempRECT.y; > return tempRECT; > } > > private Rectangle zoomFillRect(int x, int y, int w, int h) { > tempRECT.x = (int) (Math.floor((x * xZoom + fractionalX))); > tempRECT.y = (int) (Math.floor((y * yZoom + fractionalY))); >- tempRECT.width = (int) (Math.floor(((x + w - 1) * xZoom + fractionalX))) - tempRECT.x + 1; >- tempRECT.height = (int) (Math.floor(((y + h - 1) * yZoom + fractionalY))) - tempRECT.y + 1; >+ tempRECT.width = (int) (Math.floor(((x + w - 1) * xZoom + fractionalX))) >+ - tempRECT.x + 1; >+ tempRECT.height = (int) (Math >+ .floor(((y + h - 1) * yZoom + fractionalY))) >+ - tempRECT.y + 1; > return tempRECT; > } > >@@ -756,7 +787,8 @@ > // Scale the points > for (int i = 0; (i + 1) < points.length; i += 2) { > scaled[i] = (int) (Math.floor((points[i] * xZoom + fractionalX))); >- scaled[i + 1] = (int) (Math.floor((points[i + 1] * yZoom + fractionalY))); >+ scaled[i + 1] = (int) (Math >+ .floor((points[i + 1] * yZoom + fractionalY))); > } > return scaled; > } >@@ -764,8 +796,10 @@ > private Rectangle zoomRect(int x, int y, int w, int h) { > tempRECT.x = (int) (Math.floor(x * xZoom + fractionalX)); > tempRECT.y = (int) (Math.floor(y * yZoom + fractionalY)); >- tempRECT.width = (int) (Math.floor(((x + w) * xZoom + fractionalX))) - tempRECT.x; >- tempRECT.height = (int) (Math.floor(((y + h) * yZoom + fractionalY))) - tempRECT.y; >+ tempRECT.width = (int) (Math.floor(((x + w) * xZoom + fractionalX))) >+ - tempRECT.x; >+ tempRECT.height = (int) (Math.floor(((y + h) * yZoom + fractionalY))) >+ - tempRECT.y; > return tempRECT; > } > >@@ -798,13 +832,16 @@ > int start = 0, offset = 1; > TextStyle style = null, lastStyle = layout.getStyle(0); > for (; offset <= length; offset++) { >- if (offset != length && (style = layout.getStyle(offset)) == lastStyle) { >+ if (offset != length >+ && (style = layout.getStyle(offset)) == lastStyle) { > continue; > } > int end = offset - 1; > > if (lastStyle != null) { >- TextStyle zoomedStyle = new TextStyle(zoomFont(lastStyle.font), lastStyle.foreground, lastStyle.background); >+ TextStyle zoomedStyle = new TextStyle( >+ zoomFont(lastStyle.font), lastStyle.foreground, >+ lastStyle.background); > zoomed.setStyle(zoomedStyle, start, end); > } > lastStyle = style; >@@ -816,7 +853,7 @@ > > private Point zoomTextPoint(int x, int y) { > if (localCache.font != localFont) { >- //Font is different, re-calculate its height >+ // Font is different, re-calculate its height > FontMetrics metric = FigureUtilities.getFontMetrics(localFont); > localCache.height = metric.getHeight() - metric.getDescent(); > localCache.font = localFont; >@@ -826,7 +863,9 @@ > targetCache.font = graphics.getFont(); > targetCache.height = metric.getHeight() - metric.getDescent(); > } >- return new Point(((int) (Math.floor((x * xZoom) + fractionalX))), (int) (Math.floor((y + localCache.height - 1) * yZoom - targetCache.height + 1 + fractionalY))); >+ return new Point(((int) (Math.floor((x * xZoom) + fractionalX))), >+ (int) (Math.floor((y + localCache.height - 1) * yZoom >+ - targetCache.height + 1 + fractionalY))); > } > > } >Index: src/org/eclipse/zest/core/widgets/internal/ZestRootLayer.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/internal/ZestRootLayer.java,v >retrieving revision 1.5 >diff -u -r1.5 ZestRootLayer.java >--- src/org/eclipse/zest/core/widgets/internal/ZestRootLayer.java 12 Sep 2007 20:44:39 -0000 1.5 >+++ src/org/eclipse/zest/core/widgets/internal/ZestRootLayer.java 28 Aug 2009 16:03:27 -0000 >@@ -1,189 +1,205 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2005 IBM Corporation and others. All rights reserved. >+ * Copyright (c) 2005-2009 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 Chisel Group, >- * University of Victoria - Adapted for XY Scaled Graphics >+ * Contributors: >+ * IBM Corporation - initial API and implementation Chisel Group, >+ * University of Victoria - Adapted for XY Scaled Graphics >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 > ******************************************************************************/ > package org.eclipse.zest.core.widgets.internal; > >+import java.util.ArrayList; >+import java.util.HashSet; >+import java.util.Iterator; >+ > import org.eclipse.draw2d.FreeformLayer; > import org.eclipse.draw2d.IFigure; > > /** >- * The root figure for Zest. The figure is broken up into four segments, >- * 1. The Connections >- * 2. The Nodes >- * 3. The Highlighted Connections >- * 4. The Highlighted Nodes >- * >- * @author Ian Bull >+ * The root figure for Zest. The figure is broken up into following segments: >+ * <ol> >+ * <li>The Connections</li> >+ * <li>The Subgraphs</li> >+ * <li>The Nodes</li> >+ * <li>The Highlighted Connections</li> >+ * <li>The Highlighted Nodes</li> >+ * </ol> > * > */ > public class ZestRootLayer extends FreeformLayer { > >- public static final boolean EDGES_ON_TOP = false; >- private int numberOfNodes = 0; >- private int numberOfConnections = 0; >- private int numberOfHighlightedNodes = 0; >- private int numberOfHighlightedConnections = 0; >+ public static final int CONNECTIONS_LAYER = 0; >+ >+ public static final int SUBGRAPHS_LAYER = 1; >+ >+ public static final int NODES_LAYER = 2; >+ >+ public static final int CONNECTIONS_HIGHLIGHTED_LAYER = 3; >+ >+ public static final int NODES_HIGHLIGHTED_LAYER = 4; >+ >+ public static final int TOP_LAYER = 5; >+ >+ public static final int NUMBER_OF_LAYERS = 6; >+ >+ private final int[] itemsInLayer = new int[NUMBER_OF_LAYERS]; > > /** >- * Adds a node to the ZestRootLayer >- * @param nodeFigure The figure representing the node >+ * Set of all figures that are decorations for other figures. A decoration >+ * figure is always put one position (or more if there's more than one >+ * decoration for the same figure) after the decorated figure in children >+ * list. > */ >- public void addNode(IFigure nodeFigure) { >- int nodePosition = getNodePosition(); >- numberOfNodes++; >- add(nodeFigure, nodePosition); >- } >+ private HashSet decoratingFigures = new HashSet(); >+ >+ /** >+ * If true, it indicates that a figure is added using a proper method and >+ * its layer is known. Otherwise, Figure#add() method was used and layer >+ * must be guessed >+ */ >+ private boolean isLayerKnown = false; > > /** >- * Removes a node from the layer >+ * Adds a node to the ZestRootLayer >+ * > * @param nodeFigure >+ * The figure representing the node > */ >- public void removeNode(IFigure nodeFigure) { >- if (!this.getChildren().contains(nodeFigure)) { >- throw new RuntimeException("Node not contained on the ZestRootLayer"); >- } >- int nodePosition = this.getChildren().indexOf(nodeFigure); >- if (nodePosition > getHighlightNodeStartPosition()) { >- // The node is in the highlight node area >- numberOfHighlightedNodes--; >- } else { >- // The node is in the node area >- numberOfNodes--; >- } >- this.remove(nodeFigure); >+ public void addNode(IFigure nodeFigure) { >+ addFigure(nodeFigure, NODES_LAYER); > } > >- public void removeConnection(IFigure connectionFigure) { >- int connectionPosition = this.getChildren().indexOf(connectionFigure); >- if (connectionPosition > getHighlightConnectionStartPosition()) { >- // The connection is in the highlight connection area >- numberOfHighlightedConnections--; >- } else { >- // The connection is in the connection area >- numberOfConnections--; >- } >- this.remove(connectionFigure); >+ public void addConnection(IFigure connectionFigure) { >+ addFigure(connectionFigure, CONNECTIONS_LAYER); > } > >- public void addConnection(IFigure connectionFigure) { >- int connectionPosition = getConnectionPosition(); >- numberOfConnections++; >- add(connectionFigure, connectionPosition); >+ public void addSubgraph(IFigure subgraphFigrue) { >+ addFigure(subgraphFigrue, SUBGRAPHS_LAYER); > } > > public void highlightNode(IFigure nodeFigure) { >- this.numberOfNodes--; >- int highlightNodePosition = getHighlightNodePosition(); >- this.numberOfHighlightedNodes++; >- this.getChildren().remove(nodeFigure); >- this.getChildren().add(highlightNodePosition, nodeFigure); >- this.invalidate(); >- this.repaint(); >+ changeFigureLayer(nodeFigure, NODES_HIGHLIGHTED_LAYER); > } > > public void highlightConnection(IFigure connectionFigure) { >- this.numberOfConnections--; >- int highlightConnectionPosition = getHighlightConnectionPosition(); >- this.numberOfHighlightedConnections++; >- this.getChildren().remove(connectionFigure); >- this.getChildren().add(highlightConnectionPosition, connectionFigure); >- this.invalidate(); >- this.repaint(); >+ changeFigureLayer(connectionFigure, CONNECTIONS_HIGHLIGHTED_LAYER); > } > > public void unHighlightNode(IFigure nodeFigure) { >- int nodePosition = this.getChildren().indexOf(nodeFigure); >- if (nodePosition > getHighlightNodePosition()) { >- //throw new RuntimeException("Node: " + nodeFigure + " not currently Highlighted"); >- return; >- } >- this.numberOfHighlightedNodes--; >- nodePosition = getNodePosition(); >- this.numberOfNodes++; >- this.getChildren().remove(nodeFigure); >- this.getChildren().add(nodePosition, nodeFigure); >- this.invalidate(); >- this.repaint(); >+ changeFigureLayer(nodeFigure, NODES_LAYER); > } > > public void unHighlightConnection(IFigure connectionFigure) { >- int connectionPosition = this.getChildren().indexOf(connectionFigure); >- if (connectionPosition > getHighlightConnectionPosition()) { >- //throw new RuntimeException("Connection: " + connectionFigure + " not currently Highlighted"); >- return; >- } >- this.numberOfHighlightedConnections--; >- this.numberOfConnections++; >- connectionPosition = getConnectionPosition(); >- this.getChildren().remove(connectionFigure); >- if (connectionPosition > this.getChildren().size()) { >- this.getChildren().add(connectionFigure); >- } else { >- this.getChildren().add(connectionPosition, connectionFigure); >- } >- this.invalidate(); >- this.repaint(); >+ changeFigureLayer(connectionFigure, CONNECTIONS_LAYER); > } > >- /* >- * Node position is at the end of the list of nodes >- */ >- private int getNodePosition() { >- if (EDGES_ON_TOP) { >- return numberOfNodes; >- } >- return numberOfConnections + numberOfNodes; >- } >+ private void changeFigureLayer(IFigure figure, int newLayer) { >+ ArrayList decorations = getDecorations(figure); >+ remove(figure); > >- /* >- * Connection position is at the end of the list of connections >- */ >- private int getConnectionPosition() { >- if (EDGES_ON_TOP) { >- return 0 + numberOfConnections + numberOfNodes; >+ addFigure(figure, newLayer); >+ for (Iterator iterator = decorations.iterator(); iterator.hasNext();) { >+ addDecoration(figure, (IFigure) iterator.next()); > } >- return 0 + numberOfConnections; >- } > >- /* >- * Highlight node position is at the end of the list of highlighted nodes >- */ >- private int getHighlightNodePosition() { >- if (EDGES_ON_TOP) { >- return numberOfConnections + numberOfNodes + numberOfHighlightedNodes; >- } >- return numberOfConnections + numberOfHighlightedConnections + numberOfNodes + numberOfHighlightedNodes; >+ this.invalidate(); >+ this.repaint(); > } > >- /* >- * Highlighted connection position is at the end of the list of highlighted connections >- */ >- private int getHighlightConnectionPosition() { >- if (EDGES_ON_TOP) { >- return numberOfNodes + +numberOfConnections + numberOfHighlightedNodes + numberOfHighlightedConnections; >+ private ArrayList getDecorations(IFigure figure) { >+ ArrayList result = new ArrayList(); >+ int index = getChildren().indexOf(figure); >+ if (index == -1) >+ return result; >+ for (index++; index < getChildren().size(); index++) { >+ Object nextFigure = getChildren().get(index); >+ if (decoratingFigures.contains(nextFigure)) { >+ result.add(nextFigure); >+ } else >+ break; > } >- return numberOfConnections + numberOfNodes + numberOfHighlightedConnections; >+ return result; > } > >- private int getHighlightConnectionStartPosition() { >- if (EDGES_ON_TOP) { >- return numberOfConnections + numberOfNodes + numberOfHighlightedNodes; >- >- } >- return numberOfConnections + numberOfNodes; >+ /** >+ * >+ * @param layer >+ * @return position after the last element in given layer >+ */ >+ private int getPosition(int layer) { >+ int result = 0; >+ for (int i = 0; i <= layer; i++) >+ result += itemsInLayer[i]; >+ return result; > } > >- private int getHighlightNodeStartPosition() { >- if (EDGES_ON_TOP) { >- return numberOfNodes + numberOfConnections; >+ /** >+ * >+ * @param position >+ * @return number of layer containing element at given position >+ */ >+ private int getLayer(int position) { >+ int layer = 0; >+ int positionInLayer = itemsInLayer[0]; >+ while (layer < NUMBER_OF_LAYERS - 1 && positionInLayer <= position) { >+ layer++; >+ positionInLayer += itemsInLayer[layer]; >+ } >+ return layer; >+ } >+ >+ public void addFigure(IFigure figure, int layer) { >+ int position = getPosition(layer); >+ itemsInLayer[layer]++; >+ isLayerKnown = true; >+ add(figure, position); >+ } >+ >+ public void add(IFigure child, Object constraint, int index) { >+ super.add(child, constraint, index); >+ if (!isLayerKnown) { >+ int layer = 0, positionInLayer = itemsInLayer[0]; >+ while (positionInLayer < index) { >+ layer++; >+ positionInLayer += itemsInLayer[layer]; >+ } >+ if (index == -1) >+ layer = NUMBER_OF_LAYERS - 1; >+ itemsInLayer[layer]++; >+ } >+ isLayerKnown = false; >+ } >+ >+ public void remove(IFigure child) { >+ int position = this.getChildren().indexOf(child); >+ if (position == -1) >+ throw new RuntimeException("Can't remove a figure that is not on this ZestRootLayer"); >+ itemsInLayer[getLayer(position)]--; >+ if (decoratingFigures.contains(child)) { >+ decoratingFigures.remove(child); >+ super.remove(child); >+ } else { >+ ArrayList decorations = getDecorations(child); >+ super.remove(child); >+ for (Iterator iterator = decorations.iterator(); iterator.hasNext();) { >+ remove((IFigure) iterator.next()); >+ } > } >- return numberOfConnections + numberOfHighlightedConnections + numberOfNodes; > } > >+ public void addDecoration(IFigure decorated, IFigure decorating) { >+ int position = this.getChildren().indexOf(decorated); >+ if (position == -1) >+ throw new RuntimeException("Can't add decoration for a figuer that is not on this ZestRootLayer"); >+ itemsInLayer[getLayer(position)]++; >+ isLayerKnown = true; >+ do { >+ position++; >+ } while (position < getChildren().size() && decoratingFigures.contains(getChildren().get(position))); >+ decoratingFigures.add(decorating); >+ add(decorating, position); >+ } > } >Index: src/org/eclipse/zest/core/widgets/internal/LoopAnchor.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/internal/LoopAnchor.java,v >retrieving revision 1.3 >diff -u -r1.3 LoopAnchor.java >--- src/org/eclipse/zest/core/widgets/internal/LoopAnchor.java 12 Sep 2007 20:44:39 -0000 1.3 >+++ src/org/eclipse/zest/core/widgets/internal/LoopAnchor.java 28 Aug 2009 16:03:25 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -18,17 +18,19 @@ > public LoopAnchor(IFigure owner) { > super(owner); > } >- >- /* (non-Javadoc) >+ >+ /* >+ * (non-Javadoc) >+ * > * @see org.eclipse.draw2d.ChopboxAnchor#getReferencePoint() > */ > public Point getReferencePoint() { >- //modification to getReferencePoint. Returns >- //a point on the outside of the owners box, rather than the >- //center. Only usefull for self-loops. >- if (getOwner() == null) >+ // modification to getReferencePoint. Returns >+ // a point on the outside of the owners box, rather than the >+ // center. Only usefull for self-loops. >+ if (getOwner() == null) { > return null; >- else { >+ } else { > Point ref = getOwner().getBounds().getCenter(); > ref.y = getOwner().getBounds().y; > getOwner().translateToAbsolute(ref); >Index: src/org/eclipse/zest/core/widgets/internal/ExpandGraphLabel.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/internal/ExpandGraphLabel.java >diff -N src/org/eclipse/zest/core/widgets/internal/ExpandGraphLabel.java >--- src/org/eclipse/zest/core/widgets/internal/ExpandGraphLabel.java 12 Sep 2007 20:44:39 -0000 1.5 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,283 +0,0 @@ >-/******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, >- * Canada. All rights reserved. This program and the accompanying materials are >- * made available under the terms of the Eclipse Public License v1.0 which >- * accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * Contributors: The Chisel Group, University of Victoria >- ******************************************************************************/ >-package org.eclipse.zest.core.widgets.internal; >- >-import org.eclipse.draw2d.ActionEvent; >-import org.eclipse.draw2d.ActionListener; >-import org.eclipse.draw2d.Clickable; >-import org.eclipse.draw2d.ColorConstants; >-import org.eclipse.draw2d.Figure; >-import org.eclipse.draw2d.FigureUtilities; >-import org.eclipse.draw2d.FreeformLayout; >-import org.eclipse.draw2d.Graphics; >-import org.eclipse.draw2d.Label; >-import org.eclipse.draw2d.ToolbarLayout; >-import org.eclipse.draw2d.Triangle; >-import org.eclipse.draw2d.geometry.Dimension; >-import org.eclipse.draw2d.geometry.Point; >-import org.eclipse.draw2d.geometry.Rectangle; >-import org.eclipse.zest.core.widgets.GraphContainer; >-import org.eclipse.swt.graphics.Color; >-import org.eclipse.swt.graphics.Font; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.graphics.RGB; >-import org.eclipse.swt.widgets.Display; >- >-public class ExpandGraphLabel extends Figure implements ActionListener { >- >- public static final int OPEN = 1; >- public static final int CLOSED = 2; >- private int state = CLOSED; >- private Expander expander = null; >- >- class Expander extends Clickable { >- private Triangle triangle; >- >- public Expander() { >- setStyle(Clickable.STYLE_TOGGLE); >- triangle = new Triangle(); >- triangle.setSize(10, 10); >- triangle.setBackgroundColor(ColorConstants.black); >- triangle.setForegroundColor(ColorConstants.black); >- triangle.setFill(true); >- triangle.setDirection(Triangle.EAST); >- triangle.setLocation(new Point(5, 3)); >- this.setLayoutManager(new FreeformLayout()); >- this.add(triangle); >- this.setPreferredSize(15, 15); >- this.addActionListener(ExpandGraphLabel.this); >- } >- >- public void open() { >- triangle.setDirection(Triangle.SOUTH); >- } >- >- public void close() { >- triangle.setDirection(Triangle.EAST); >- } >- >- } >- >- /** >- * Sets the expander state (the little triangle) to ExpanderGraphLabel.OPEN or ExpanderGraphLabel.CLOSED >- * @param state >- */ >- public void setExpandedState(int state) { >- if (state == OPEN) { >- expander.open(); >- } else { >- expander.close(); >- } >- this.state = state; >- } >- >- /* >- * (non-Javadoc) >- * @see org.eclipse.draw2d.ActionListener#actionPerformed(org.eclipse.draw2d.ActionEvent) >- */ >- public void actionPerformed(ActionEvent event) { >- if (state == OPEN) { >- container.close(true); >- >- } else { >- container.open(true); >- } >- } >- >- private int arcWidth; >- private Label label = null; >- private final GraphContainer container; >- private ToolbarLayout layout; >- >- public ExpandGraphLabel(GraphContainer container, boolean cacheLabel) { >- this(container, "", null, cacheLabel); >- } >- >- public ExpandGraphLabel(GraphContainer container, Image i, boolean cacheLabel) { >- this(container, "", i, cacheLabel); >- } >- >- public ExpandGraphLabel(GraphContainer container, String text, boolean cacheLabel) { >- this(container, text, null, cacheLabel); >- } >- >- public ExpandGraphLabel(GraphContainer container, String text, Image image, boolean cacheLabel) { >- this.label = new Label(text) { >- >- /* >- * This method is overwritten so that the text is not truncated. >- * (non-Javadoc) >- * @see org.eclipse.draw2d.Label#paintFigure(org.eclipse.draw2d.Graphics) >- */ >- protected void paintFigure(Graphics graphics) { >- if (isOpaque()) { >- super.paintFigure(graphics); >- } >- Rectangle bounds = getBounds(); >- graphics.translate(bounds.x, bounds.y); >- if (getIcon() != null) { >- graphics.drawImage(getIcon(), getIconLocation()); >- } >- if (!isEnabled()) { >- graphics.translate(1, 1); >- graphics.setForegroundColor(ColorConstants.buttonLightest); >- graphics.drawText(getSubStringText(), getTextLocation()); >- graphics.translate(-1, -1); >- graphics.setForegroundColor(ColorConstants.buttonDarker); >- } >- graphics.drawText(getText(), getTextLocation()); >- graphics.translate(-bounds.x, -bounds.y); >- } >- }; >- this.setText(text); >- this.setImage(image); >- this.container = container; >- this.expander = new Expander(); >- this.arcWidth = 8; >- this.setFont(Display.getDefault().getSystemFont()); >- layout = new ToolbarLayout(true); >- layout.setSpacing(5); >- layout.setMinorAlignment(ToolbarLayout.ALIGN_CENTER); >- this.setLayoutManager(layout); >- this.add(this.expander); >- this.add(this.label); >- //this.remove(this.label); >- } >- >- /** >- * Adjust the bounds to make the text fit without truncation. >- */ >- protected void adjustBoundsToFit() { >- String text = getText(); >- if ((text != null) && (text.length() > 0)) { >- Font font = getFont(); >- if (font != null) { >- Dimension minSize = FigureUtilities.getTextExtents(text, font); >- if (getIcon() != null) { >- org.eclipse.swt.graphics.Rectangle imageRect = getIcon().getBounds(); >- int expandHeight = Math.max(imageRect.height - minSize.height, 0); >- minSize.expand(imageRect.width + 4, expandHeight); >- } >- minSize.expand(10 + (2 * 1) + 100, 4 + (2 * 1)); >- label.setBounds(new Rectangle(getLocation(), minSize)); >- } >- } >- } >- >- private Image getIcon() { >- return this.label.getIcon(); >- } >- >- private String getText() { >- return this.label.getText(); >- } >- >- /* >- * (non-Javadoc) >- * >- * @see org.eclipse.draw2d.Label#paintFigure(org.eclipse.draw2d.Graphics) >- */ >- public void paint(Graphics graphics) { >- >- int blue = getBackgroundColor().getBlue(); >- blue = (int) (blue - (blue * 0.20)); >- blue = blue > 0 ? blue : 0; >- >- int red = getBackgroundColor().getRed(); >- red = (int) (red - (red * 0.20)); >- red = red > 0 ? red : 0; >- >- int green = getBackgroundColor().getGreen(); >- green = (int) (green - (green * 0.20)); >- green = green > 0 ? green : 0; >- >- Color lightenColor = new Color(Display.getCurrent(), new RGB(red, green, blue)); >- graphics.setForegroundColor(lightenColor); >- graphics.setBackgroundColor(getBackgroundColor()); >- >- graphics.pushState(); >- >- // fill in the background >- Rectangle bounds = getBounds().getCopy(); >- Rectangle r = bounds.getCopy(); >- //r.x += arcWidth / 2; >- r.y += arcWidth / 2; >- //r.width -= arcWidth; >- r.height -= arcWidth; >- >- Rectangle top = bounds.getCopy(); >- top.height /= 2; >- //graphics.setForegroundColor(lightenColor); >- //graphics.setBackgroundColor(lightenColor); >- graphics.setForegroundColor(getBackgroundColor()); >- graphics.setBackgroundColor(getBackgroundColor()); >- graphics.fillRoundRectangle(top, arcWidth, arcWidth); >- >- top.y = top.y + top.height; >- //graphics.setForegroundColor(getBackgroundColor()); >- //graphics.setBackgroundColor(getBackgroundColor()); >- graphics.setForegroundColor(lightenColor); >- graphics.setBackgroundColor(lightenColor); >- graphics.fillRoundRectangle(top, arcWidth, arcWidth); >- >- //graphics.setForegroundColor(lightenColor); >- //graphics.setBackgroundColor(getBackgroundColor()); >- graphics.setBackgroundColor(lightenColor); >- graphics.setForegroundColor(getBackgroundColor()); >- graphics.fillGradient(r, true); >- >- super.paint(graphics); >- graphics.popState(); >- graphics.setForegroundColor(lightenColor); >- graphics.setBackgroundColor(lightenColor); >- // paint the border >- bounds.setSize(bounds.width - 1, bounds.height - 1); >- graphics.drawRoundRectangle(bounds, arcWidth, arcWidth); >- lightenColor.dispose(); >- } >- >-// public Dimension getPreferredSize(int hint, int hint2) { >- // return this.label.getPreferredSize(); >- //} >- >- public void setTextT(String string) { >- this.setPreferredSize(null); >- this.label.setText(string); >- this.add(label); >- //System.out.println(this.label.getPreferredSize()); >- this.layout.layout(this); >- this.invalidate(); >- this.revalidate(); >- this.validate(); >- //this.remove(label); >- } >- >- public void setText(String string) { >- this.label.setText(string); >- //this.label.setPreferredSize(500, 30); >- //adjustBoundsToFit(); >- } >- >- public void setImage(Image image) { >- this.label.setIcon(image); >- //adjustBoundsToFit(); >- } >- >- public void setLocation(Point p) { >- // TODO Auto-generated method stub >- super.setLocation(p); >- } >- >- public void setBounds(Rectangle rect) { >- // TODO Auto-generated method stub >- super.setBounds(rect); >- } >- >-} >Index: src/org/eclipse/zest/core/widgets/internal/PolylineArcConnection.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/internal/PolylineArcConnection.java,v >retrieving revision 1.7 >diff -u -r1.7 PolylineArcConnection.java >--- src/org/eclipse/zest/core/widgets/internal/PolylineArcConnection.java 21 Nov 2008 17:02:38 -0000 1.7 >+++ src/org/eclipse/zest/core/widgets/internal/PolylineArcConnection.java 28 Aug 2009 16:03:25 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, > * Canada. All rights reserved. This program and the accompanying materials are > * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at >@@ -41,7 +41,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.draw2d.Polyline#setPoints(org.eclipse.draw2d.geometry.PointList) >+ * @see >+ * org.eclipse.draw2d.Polyline#setPoints(org.eclipse.draw2d.geometry.PointList >+ * ) > */ > public void setPoints(PointList points) { > updateArc(points); >@@ -111,7 +113,8 @@ > // the center of the chord > float cartChordX = (x2 + x1) / 2; > float cartChordY = (y2 + y1) / 2; >- float chordLength = (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); >+ float chordLength = (float) Math.sqrt((x1 - x2) * (x1 - x2) >+ + (y1 - y2) * (y1 - y2)); > if (Math.abs(depth) >= chordLength / 2) { > depth = (chordLength / 3) * (depth / Math.abs(depth)); > } >@@ -134,7 +137,8 @@ > > float th1; > if (Float.isNaN(chordNormal)) { >- cartCenterX = (y1 > y2) ? (cartChordX - r + (depth)) : (cartChordX + r - (depth)); >+ cartCenterX = (y1 > y2) ? (cartChordX - r + (depth)) >+ : (cartChordX + r - (depth)); > cartCenterY = cartChordY; > th1 = PI / 2; > } else if (Float.isInfinite(chordNormal)) { >@@ -144,9 +148,11 @@ > } else { > // assume that the center of the chord is on the origin. > th1 = (float) Math.atan(chordNormal); >- cartCenterX = (r - (depth)) * (float) Math.sin(th1) + cartChordX;// cartChordX+r >+ cartCenterX = (r - (depth)) * (float) Math.sin(th1) >+ + cartChordX;// cartChordX+r > // -depth; >- cartCenterY = (r - (depth)) * (float) Math.cos(th1) + cartChordY;// cartChordY+r-depth; >+ cartCenterY = (r - (depth)) * (float) Math.cos(th1) >+ + cartChordY;// cartChordY+r-depth; > > } > // figure out the new angles >Index: src/org/eclipse/zest/core/widgets/internal/RoundedChopboxAnchor.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/internal/RoundedChopboxAnchor.java,v >retrieving revision 1.3 >diff -u -r1.3 RoundedChopboxAnchor.java >--- src/org/eclipse/zest/core/widgets/internal/RoundedChopboxAnchor.java 12 Sep 2007 20:44:39 -0000 1.3 >+++ src/org/eclipse/zest/core/widgets/internal/RoundedChopboxAnchor.java 28 Aug 2009 16:03:25 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -16,7 +16,8 @@ > import org.eclipse.draw2d.geometry.Rectangle; > > /** >- * A slight modification to the ChopboxAnchor class to account for the rounded corners. >+ * A slight modification to the ChopboxAnchor class to account for the rounded >+ * corners. > * > * @author Chris Callendar > */ >@@ -24,48 +25,58 @@ > > private int arcRadius = 10; > private int shift = 7; >- >+ > public RoundedChopboxAnchor(int arcRadius) { > super(); > this.arcRadius = arcRadius; >- this.shift = arcRadius - (int)(0.707 * arcRadius); >+ this.shift = arcRadius - (int) (0.707 * arcRadius); > } > > public RoundedChopboxAnchor(IFigure owner, int arcRadius) { > super(owner); > this.arcRadius = arcRadius; >- this.shift = arcRadius - (int)(0.707 * arcRadius); >+ this.shift = arcRadius - (int) (0.707 * arcRadius); > } > > /** > * Modifies the point slightly for the rounded corners. >+ * > * @return Point > */ > public Point getLocation(Point reference) { > Point p = super.getLocation(reference); > Rectangle bounds = getBox(); >- >+ > boolean done = getTranslatedPoint(bounds.getTopLeft(), p, shift, shift); >- if (!done) >+ if (!done) { > done = getTranslatedPoint(bounds.getTopRight(), p, -shift, shift); >- if (!done) >+ } >+ if (!done) { > done = getTranslatedPoint(bounds.getBottomLeft(), p, shift, -shift); >- if (!done) >- done = getTranslatedPoint(bounds.getBottomRight(), p, -shift, -shift); >+ } >+ if (!done) { >+ done = getTranslatedPoint(bounds.getBottomRight(), p, -shift, >+ -shift); >+ } > return p; > } >- >+ > /** >- * Calculates the distance from the corner to the Point p. >- * If it is less than the minimum then it translates it and returns the new Point. >- * @param corner The corner Point. >- * @param p The point to translate if close to the corner. >- * @param dx The amount to translate in the x direcion. >- * @param dy The amount to translate in the y direcion. >- * @return boolean If the translation occured. >+ * Calculates the distance from the corner to the Point p. If it is less >+ * than the minimum then it translates it and returns the new Point. >+ * >+ * @param corner >+ * The corner Point. >+ * @param p >+ * The point to translate if close to the corner. >+ * @param dx >+ * The amount to translate in the x direcion. >+ * @param dy >+ * The amount to translate in the y direcion. >+ * @return boolean If the translation occured. > */ > private boolean getTranslatedPoint(Point corner, Point p, int dx, int dy) { >- int diff = (int)corner.getDistance(p); >+ int diff = (int) corner.getDistance(p); > if (diff < arcRadius) { > Point t = corner.getTranslated(dx, dy); > p.setLocation(t.x, t.y); >@@ -73,6 +84,5 @@ > } > return false; > } >- >- >+ > } >Index: src/org/eclipse/zest/core/widgets/internal/RevealListener.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/internal/RevealListener.java,v >retrieving revision 1.3 >diff -u -r1.3 RevealListener.java >--- src/org/eclipse/zest/core/widgets/internal/RevealListener.java 12 Sep 2007 20:44:39 -0000 1.3 >+++ src/org/eclipse/zest/core/widgets/internal/RevealListener.java 28 Aug 2009 16:03:25 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada. >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -15,11 +15,12 @@ > /** > * > * A Listener to indicate when a view has become visible. >+ * > * @author Ian Bull >- * >+ * > */ > public interface RevealListener { >- >- public void revealed( Control c ); >+ >+ public void revealed(Control c); > > } >Index: src/org/eclipse/zest/core/widgets/internal/CachedLabel.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/internal/CachedLabel.java,v >retrieving revision 1.5 >diff -u -r1.5 CachedLabel.java >--- src/org/eclipse/zest/core/widgets/internal/CachedLabel.java 12 Sep 2007 20:44:39 -0000 1.5 >+++ src/org/eclipse/zest/core/widgets/internal/CachedLabel.java 28 Aug 2009 16:03:24 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, > * Canada. All rights reserved. This program and the accompanying materials are > * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at >@@ -64,7 +64,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.draw2d.Figure#setForegroundColor(org.eclipse.swt.graphics.Color) >+ * @see >+ * org.eclipse.draw2d.Figure#setForegroundColor(org.eclipse.swt.graphics >+ * .Color) > */ > public void setForegroundColor(Color fg) { > updateInvalidation(); >@@ -74,7 +76,9 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.draw2d.Figure#setBackgroundColor(org.eclipse.swt.graphics.Color) >+ * @see >+ * org.eclipse.draw2d.Figure#setBackgroundColor(org.eclipse.swt.graphics >+ * .Color) > */ > public void setBackgroundColor(Color bg) { > updateInvalidation(); >@@ -118,10 +122,13 @@ > /* > * (non-Javadoc) > * >- * @see org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle) >+ * @see >+ * org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle >+ * ) > */ > public void setBounds(Rectangle rect) { >- boolean resize = (rect.width != bounds.width) || (rect.height != bounds.height); >+ boolean resize = (rect.width != bounds.width) >+ || (rect.height != bounds.height); > > if (resize && Animation.isAnimating()) { > updateInvalidation(); >@@ -197,7 +204,8 @@ > cachedImage = new Image(Display.getCurrent(), width, height); > > // @tag TODO : Dispose of the image properly >- //ZestPlugin.getDefault().addImage(cachedImage.toString(), cachedImage); >+ // ZestPlugin.getDefault().addImage(cachedImage.toString(), >+ // cachedImage); > > GC gc = new GC(cachedImage); > >@@ -205,7 +213,7 @@ > graphics2.setBackgroundColor(getBackgroundTextColor()); > graphics2.fillRectangle(0, 0, width, height); > graphics2.setForegroundColor(getForegroundColor()); >- //graphics2.drawText(getSubStringText(), new Point(0, 0)); >+ // graphics2.drawText(getSubStringText(), new Point(0, 0)); > graphics2.drawText(getText(), new Point(0, 0)); > gc.dispose(); > >@@ -239,7 +247,7 @@ > protected void cleanImage() { > if (cachedImage != null) { > >- //ZestPlugin.getDefault().removeImage(cachedImage.toString()); >+ // ZestPlugin.getDefault().removeImage(cachedImage.toString()); > cachedImage.dispose(); > cachedImage = null; > } >Index: src/org/eclipse/zest/core/widgets/internal/AspectRatioFreeformLayer.java >=================================================================== >RCS file: /cvsroot/tools/org.eclipse.gef/plugins/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/internal/AspectRatioFreeformLayer.java,v >retrieving revision 1.4 >diff -u -r1.4 AspectRatioFreeformLayer.java >--- src/org/eclipse/zest/core/widgets/internal/AspectRatioFreeformLayer.java 12 Sep 2007 20:44:39 -0000 1.4 >+++ src/org/eclipse/zest/core/widgets/internal/AspectRatioFreeformLayer.java 28 Aug 2009 16:03:24 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, > * Canada. All rights reserved. This program and the accompanying materials are > * made available under the terms of the Eclipse Public License v1.0 which > * accompanies this distribution, and is available at >@@ -8,8 +8,7 @@ > * Contributors: The Chisel Group, University of Victoria > ******************************************************************************/ > package org.eclipse.zest.core.widgets.internal; >- >-import org.eclipse.draw2d.FreeformFigure; >+ import org.eclipse.draw2d.FreeformFigure; > import org.eclipse.draw2d.FreeformLayer; > import org.eclipse.draw2d.FreeformLayout; > import org.eclipse.draw2d.Graphics; >@@ -25,8 +24,10 @@ > import org.eclipse.draw2d.geometry.Translatable; > import org.eclipse.draw2d.text.CaretInfo; > >+ > //@tag zest.bug.156286-Scaling.fix : make this implement scalable figure so that a zoom manager can be used on GraphEditParts. >-public class AspectRatioFreeformLayer extends FreeformLayer implements ScalableFigure, FreeformFigure { >+public class AspectRatioFreeformLayer extends FreeformLayer implements >+ ScalableFigure, FreeformFigure { > > private double widthScale = 1.0; > private double heigthScale = 1.0; >@@ -37,7 +38,7 @@ > setLayoutManager(new FreeformLayout()); > setBorder(new MarginBorder(5)); > >- //setOpaque(false); >+ // setOpaque(false); > } > > protected boolean isValidationRoot() { >@@ -58,28 +59,26 @@ > } > > /* >- public boolean isCoordinateSystem() { >- // TODO Auto-generated method stub >- return true; >- } >- */ >+ * public boolean isCoordinateSystem() { // TODO Auto-generated method stub >+ * return true; } >+ */ > > public double getScale() { > // TODO Auto-generated method stub > throw new RuntimeException("Operation not supported"); > // return this.widthScale; > >- //throw new RuntimeException("Operation Not supported"); >+ // throw new RuntimeException("Operation Not supported"); > } > > public void setScale(double scale) { >- //super.setScale( scale ); >+ // super.setScale( scale ); > this.widthScale = scale; > this.heigthScale = scale; > revalidate(); > repaint(); >- //System.out.println("Operation not supported"); >- //throw new RuntimeException("Operation not supported"); >+ // System.out.println("Operation not supported"); >+ // throw new RuntimeException("Operation not supported"); > } > > /** >@@ -87,7 +86,7 @@ > */ > > public Rectangle getClientArea(Rectangle rect) { >- //return super.getClientArea(rect); >+ // return super.getClientArea(rect); > > rect.width /= widthScale; > rect.height /= heigthScale; >@@ -100,12 +99,13 @@ > Dimension d = super.getPreferredSize(wHint, hHint); > int w = getInsets().getWidth(); > int h = getInsets().getHeight(); >- return d.getExpanded(-w, -h).scale(widthScale, heigthScale).expand(w, h); >+ return d.getExpanded(-w, -h).scale(widthScale, heigthScale) >+ .expand(w, h); > } > > public void translateFromParent(Translatable t) { > super.translateFromParent(t); >- //t.performScale(1/widthScale); >+ // t.performScale(1/widthScale); > > if (t instanceof PrecisionRectangle) { > PrecisionRectangle r = (PrecisionRectangle) t; >@@ -137,16 +137,18 @@ > Point p = (Point) t; > p.scale(1 / widthScale, 1 / heigthScale); > } else if (t instanceof PointList) { >- throw new RuntimeException("PointList not supported in AspectRatioScale"); >+ throw new RuntimeException( >+ "PointList not supported in AspectRatioScale"); > } else { >- throw new RuntimeException(t.toString() + " not supported in AspectRatioScale"); >+ throw new RuntimeException(t.toString() >+ + " not supported in AspectRatioScale"); > } > >- //t.performScale(1/widthScale); >+ // t.performScale(1/widthScale); > } > > public void translateToParent(Translatable t) { >- //t.performScale(widthScale); >+ // t.performScale(widthScale); > > if (t instanceof PrecisionRectangle) { > PrecisionRectangle r = (PrecisionRectangle) t; >@@ -157,7 +159,7 @@ > r.updateInts(); > } else if (t instanceof Rectangle) { > Rectangle r = (Rectangle) t; >- //r.performScale(widthScale); >+ // r.performScale(widthScale); > r.scale(widthScale, heigthScale); > } else if (t instanceof CaretInfo) { > CaretInfo c = (CaretInfo) t; >@@ -179,17 +181,19 @@ > Point p = (Point) t; > p.scale(widthScale, heigthScale); > } else if (t instanceof PointList) { >- throw new RuntimeException("PointList not supported in AspectRatioScale"); >+ throw new RuntimeException( >+ "PointList not supported in AspectRatioScale"); > } else { >- throw new RuntimeException(t.toString() + " not supported in AspectRatioScale"); >+ throw new RuntimeException(t.toString() >+ + " not supported in AspectRatioScale"); > } > > super.translateToParent(t); > } > >- //protected boolean useLocalCoordinates() { >- // return true; >- //} >+ // protected boolean useLocalCoordinates() { >+ // return true; >+ // } > > protected void paintClientArea(Graphics graphics) { > >@@ -211,13 +215,13 @@ > g.clipRect(getBounds().getCropped(getInsets())); > } > >- //g.translate((int)(getBounds().x + getInsets().left) , >- // (int)(getBounds().y + getInsets().top) ); >+ // g.translate((int)(getBounds().x + getInsets().left) , >+ // (int)(getBounds().y + getInsets().top) ); > > g.scale(widthScale, heigthScale); >- //g.scale(widthScale); >+ // g.scale(widthScale); > >- //g.scale(widthScale); >+ // g.scale(widthScale); > g.pushState(); > paintChildren(g); > g.popState(); >Index: src/org/eclipse/zest/core/widgets/SubgraphFactory.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/SubgraphFactory.java >diff -N src/org/eclipse/zest/core/widgets/SubgraphFactory.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/widgets/SubgraphFactory.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,25 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.core.widgets; >+ >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+import org.eclipse.zest.layouts.interfaces.SubgraphLayout; >+ >+/** >+ * Factory used by {@link Graph} to create subgraphs. One instance of >+ * SubgraphFactory can be used with multiple graphs unless explicitly stated >+ * otherwise. >+ * >+ * @since 2.0 >+ */ >+public interface SubgraphFactory { >+ SubgraphLayout createSubgraph(NodeLayout[] nodes, LayoutContext context); >+} >Index: src/org/eclipse/zest/core/widgets/FigureSubgraph.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/FigureSubgraph.java >diff -N src/org/eclipse/zest/core/widgets/FigureSubgraph.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/widgets/FigureSubgraph.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,199 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.core.widgets; >+ >+import java.util.Iterator; >+ >+import org.eclipse.draw2d.Animation; >+import org.eclipse.draw2d.FigureListener; >+import org.eclipse.draw2d.IFigure; >+import org.eclipse.draw2d.geometry.Dimension; >+import org.eclipse.draw2d.geometry.Point; >+import org.eclipse.draw2d.geometry.Rectangle; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint; >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+ >+/** >+ * A subgraph layout that represents a subgraph as a single figure. An entity >+ * representing subgraph is not resizable by layout algorithm unless proper >+ * methods are redefined in a subclass. >+ * >+ * @since 2.0 >+ */ >+public abstract class FigureSubgraph extends DefaultSubgraph { >+ >+ protected IFigure figure; >+ private DisplayIndependentPoint location; >+ private boolean isLayoutBeingApplied = false; >+ >+ /** >+ * Listens to changes in this subgraph's figure and fires proper event in >+ * its layout context. >+ */ >+ protected class SubgraphFigrueListener implements FigureListener { >+ private Rectangle previousBounds = figure.getBounds().getCopy(); >+ >+ public void figureMoved(IFigure source) { >+ if (Animation.isAnimating() || isLayoutBeingApplied) { >+ return; >+ } >+ refreshSize(); >+ refreshLocation(); >+ Rectangle newBounds = figure.getBounds(); >+ if (!newBounds.getSize().equals(previousBounds.getSize())) { >+ context.fireEntityResizedEvent(FigureSubgraph.this); >+ } else if (!newBounds.getLocation().equals( >+ previousBounds.getLocation())) { >+ context.fireEntityMovedEvent(FigureSubgraph.this); >+ } >+ previousBounds = newBounds.getCopy(); >+ } >+ }; >+ >+ /** >+ * Creates a figure for this subgraph and stores it in {@link #figure}. >+ * >+ * This method may not be called right after creation of the subgraph but >+ * later when the figure is actually needed (lazy initialization). >+ */ >+ protected abstract void createFigure(); >+ >+ /** >+ * Updates the figure stored in {@link #figure} depending on current nodes >+ * contained in this subgraph. If this method creates a new instance of >+ * IFigure, it should also add a {@link SubgraphFigrueListener} to it. >+ */ >+ protected abstract void updateFigure(); >+ >+ public IFigure getFigure() { >+ if (figure == null) { >+ createFigure(); >+ updateFigure(); >+ figure.addFigureListener(new SubgraphFigrueListener()); >+ context.container.addSubgraphFigure(figure); >+ } >+ return figure; >+ } >+ >+ protected FigureSubgraph(NodeLayout[] nodes, LayoutContext context) { >+ super(context); >+ addNodes(nodes); >+ } >+ >+ /** >+ * {@inheritDoc} >+ * >+ * All nodes added to this subgraph are moved to the center of the figure >+ * (so that collapsing and expanding animation looks cool). >+ */ >+ public void addNodes(NodeLayout[] nodes) { >+ int initialCount = this.nodes.size(); >+ super.addNodes(nodes); >+ if (this.nodes.size() > initialCount && figure != null) { >+ updateFigure(); >+ if (location != null) { >+ for (int i = 0; i < nodes.length; i++) { >+ nodes[i].setLocation(location.x, location.y); >+ } >+ } >+ } >+ } >+ >+ public void removeNodes(NodeLayout[] nodes) { >+ int initialCount = this.nodes.size(); >+ super.removeNodes(nodes); >+ if (this.nodes.size() < initialCount && figure != null && !disposed) { >+ updateFigure(); >+ } >+ } >+ >+ public EntityLayout[] getSuccessingEntities() { >+ // TODO Auto-generated method stub >+ return super.getSuccessingEntities(); >+ } >+ >+ public EntityLayout[] getPredecessingEntities() { >+ // TODO Auto-generated method stub >+ return super.getPredecessingEntities(); >+ } >+ >+ public DisplayIndependentDimension getSize() { >+ Dimension size = getFigure().getSize(); >+ return new DisplayIndependentDimension(size.width, size.height); >+ } >+ >+ public DisplayIndependentPoint getLocation() { >+ if (location == null) { >+ Point location2 = getFigure().getBounds().getLocation(); >+ Dimension size = getFigure().getSize(); >+ return new DisplayIndependentPoint(location2.x + size.width / 2, >+ location2.y + size.height / 2); >+ } >+ return new DisplayIndependentPoint(location); >+ } >+ >+ public void setLocation(double x, double y) { >+ super.setLocation(x, y); >+ for (Iterator iterator = nodes.iterator(); iterator.hasNext();) { >+ NodeLayout node = (NodeLayout) iterator.next(); >+ node.setLocation(x, y); >+ } >+ >+ if (location != null) { >+ location.x = x; >+ location.y = y; >+ } else { >+ location = new DisplayIndependentPoint(x, y); >+ // the first location change will be applied immediately >+ applyLayoutChanges(); >+ } >+ } >+ >+ protected void refreshLocation() { >+ Rectangle bounds = figure.getBounds(); >+ if (location == null) { >+ location = new DisplayIndependentPoint(0, 0); >+ } >+ location.x = bounds.x + bounds.width / 2; >+ location.y = bounds.y + bounds.height / 2; >+ } >+ >+ public boolean isGraphEntity() { >+ return true; >+ } >+ >+ public boolean isMovable() { >+ return true; >+ } >+ >+ protected void dispose() { >+ if (!disposed) { >+ super.dispose(); >+ if (figure != null) { >+ context.container.getGraph().removeSubgraphFigure(figure); >+ } >+ } >+ } >+ >+ protected void applyLayoutChanges() { >+ getFigure(); >+ if (location != null) { >+ isLayoutBeingApplied = true; >+ Dimension size = figure.getSize(); >+ figure.setLocation(new Point(location.x - size.width / 2, >+ location.y - size.height / 2)); >+ isLayoutBeingApplied = false; >+ } >+ } >+ >+} >Index: src/org/eclipse/zest/core/widgets/FisheyeListener.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/FisheyeListener.java >diff -N src/org/eclipse/zest/core/widgets/FisheyeListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/widgets/FisheyeListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,61 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.core.widgets; >+ >+import org.eclipse.draw2d.IFigure; >+ >+/** >+ * Interface for listener that can be added to {@link Graph} and receive >+ * notifications when fisheye figures are added, removed or replaced in it. >+ * >+ * @since 2.0 >+ */ >+public interface FisheyeListener { >+ >+ /** >+ * Called when a fisheye figure is added to an observed graph. >+ * >+ * @param graph >+ * observed graph >+ * @param originalFigure >+ * figure to be fisheyed >+ * @param fisheyeFigure >+ * the added fisheye figure >+ */ >+ public void fisheyeAdded(Graph graph, IFigure originalFigure, >+ IFigure fisheyeFigure); >+ >+ /** >+ * Called when a fisheye figure is removed form an observed graph. >+ * >+ * @param graph >+ * observed graph >+ * @param originalFigure >+ * figure that was fisheyed >+ * @param fisheyeFigure >+ * the removed fisheye figure >+ */ >+ public void fisheyeRemoved(Graph graph, IFigure originalFigure, >+ IFigure fisheyeFigure); >+ >+ /** >+ * Called when one fisheye figure is replaced by another in an observed >+ * graph. >+ * >+ * @param graph >+ * observed graph >+ * @param oldFisheyeFigure >+ * fisheye figure that is replaced >+ * @param newFisheyeFigure >+ * fisheye figure that replaces the old figure >+ */ >+ public void fisheyeReplaced(Graph graph, IFigure oldFisheyeFigure, >+ IFigure newFisheyeFigure); >+} >Index: src/org/eclipse/zest/core/viewers/ZoomManager.java >=================================================================== >RCS file: src/org/eclipse/zest/core/viewers/ZoomManager.java >diff -N src/org/eclipse/zest/core/viewers/ZoomManager.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/viewers/ZoomManager.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,612 @@ >+/******************************************************************************* >+ * Copyright (c) 2000, 2009 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()); >+ } >+ >+} >Index: .refactorings/2009/8/35/refactorings.index >=================================================================== >RCS file: .refactorings/2009/8/35/refactorings.index >diff -N .refactorings/2009/8/35/refactorings.index >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ .refactorings/2009/8/35/refactorings.index 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,5 @@ >+1251470760220 Delete element >+1251470800714 Delete elements >+1251470850904 Delete element >+1251470853786 Delete element >+1251470950914 Delete element >Index: src/org/eclipse/zest/core/widgets/custom/CGraphNode.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/custom/CGraphNode.java >diff -N src/org/eclipse/zest/core/widgets/custom/CGraphNode.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/widgets/custom/CGraphNode.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,76 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ >+package org.eclipse.zest.core.widgets.custom; >+ >+import org.eclipse.draw2d.IFigure; >+import org.eclipse.swt.graphics.Color; >+import org.eclipse.swt.graphics.Font; >+import org.eclipse.zest.core.widgets.Graph; >+import org.eclipse.zest.core.widgets.GraphContainer; >+import org.eclipse.zest.core.widgets.GraphNode; >+ >+/** >+ * A Custom Graph Node >+ * >+ * @since 2.0 >+ */ >+public class CGraphNode extends GraphNode { >+ >+ IFigure figure = null; >+ >+ /** >+ * @since 2.0 >+ */ >+ public CGraphNode(Graph graphModel, int style, IFigure figure) { >+ super(graphModel, style, figure); >+ } >+ >+ /** >+ * @since 2.0 >+ */ >+ public CGraphNode(GraphContainer graphModel, int style, IFigure figure) { >+ super(graphModel, style, figure); >+ } >+ >+ public IFigure getFigure() { >+ return super.getFigure(); >+ } >+ >+ protected IFigure createFigureForModel() { >+ this.figure = (IFigure) this.getData(); >+ return this.figure; >+ } >+ >+ public void setBackgroundColor(Color c) { >+ getFigure().setBackgroundColor(c); >+ } >+ >+ public void setFont(Font font) { >+ getFigure().setFont(font); >+ } >+ >+ public Color getBackgroundColor() { >+ return getFigure().getBackgroundColor(); >+ } >+ >+ public Font getFont() { >+ return getFigure().getFont(); >+ } >+ >+ public Color getForegroundColor() { >+ return getFigure().getForegroundColor(); >+ } >+ >+ protected void updateFigureForModel(IFigure currentFigure) { >+ // Undefined >+ } >+ >+} >Index: src/org/eclipse/zest/core/widgets/LayoutFilter.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/LayoutFilter.java >diff -N src/org/eclipse/zest/core/widgets/LayoutFilter.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/widgets/LayoutFilter.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,20 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: The Chisel Group, University of Victoria >+ * Mateusz Matela >+ ******************************************************************************/ >+package org.eclipse.zest.core.widgets; >+ >+/** >+ * @since 2.0 >+ */ >+public interface LayoutFilter { >+ >+ public boolean isObjectFiltered(GraphItem item); >+ >+} >Index: src/org/eclipse/zest/core/widgets/custom/LabelSubgraph.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/custom/LabelSubgraph.java >diff -N src/org/eclipse/zest/core/widgets/custom/LabelSubgraph.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/widgets/custom/LabelSubgraph.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,68 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.core.widgets.custom; >+ >+import org.eclipse.draw2d.Label; >+import org.eclipse.swt.graphics.Color; >+import org.eclipse.zest.core.widgets.FigureSubgraph; >+import org.eclipse.zest.core.widgets.internal.GraphLabel; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+ >+/** >+ * A subgraph layout that displays a label showing number of items pruned within >+ * it. >+ * >+ * @since 2.0 >+ */ >+public class LabelSubgraph extends FigureSubgraph { >+ >+ private Color backgroundColor; >+ private Color foregroundColor; >+ >+ /** >+ * Sets the foreground color of this subgraph (that is color of the text on >+ * the label). >+ * >+ * @param color >+ * color to set >+ */ >+ public void setForegroundColor(Color color) { >+ figure.setForegroundColor(color); >+ } >+ >+ /** >+ * Sets the background color of this subgraph's label. >+ * >+ * @param color >+ * color to set >+ */ >+ public void setBackgroundColor(Color color) { >+ figure.setBackgroundColor(color); >+ } >+ >+ protected void createFigure() { >+ figure = new GraphLabel(false); >+ figure.setForegroundColor(foregroundColor); >+ figure.setBackgroundColor(backgroundColor); >+ updateFigure(); >+ } >+ >+ protected void updateFigure() { >+ ((Label) figure).setText("" + nodes.size()); >+ } >+ >+ public LabelSubgraph(NodeLayout[] nodes, LayoutContext context, >+ Color foregroundColor, Color backgroundColor) { >+ super(nodes, context); >+ this.foregroundColor = foregroundColor; >+ this.backgroundColor = backgroundColor; >+ } >+} >\ No newline at end of file >Index: .refactorings/2009/8/35/refactorings.history >=================================================================== >RCS file: .refactorings/2009/8/35/refactorings.history >diff -N .refactorings/2009/8/35/refactorings.history >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ .refactorings/2009/8/35/refactorings.history 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,3 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<session version="1.0">
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.core'
- Original project: 'org.eclipse.zest.core'
- Original element: 'org.eclipse.zest.core.viewers.internal.AbstractStructuredGraphViewer.java'" description="Delete element" element1="/src<org.eclipse.zest.core.viewers.internal{AbstractStructuredGraphViewer.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470760220" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 2 element(s) from project 'org.eclipse.zest.core'
- Original project: 'org.eclipse.zest.core'
- Original elements:
 org.eclipse.zest.core.viewers.internal.ZoomListener.java
 org.eclipse.zest.core.viewers.internal.ZoomManager.java" description="Delete elements" element1="/src<org.eclipse.zest.core.viewers.internal{ZoomListener.java" element2="/src<org.eclipse.zest.core.viewers.internal{ZoomManager.java" elements="2" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470800714" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.core'
- Original project: 'org.eclipse.zest.core'
- Original element: 'org.eclipse.zest.core.widgets.CGraphNode.java'" description="Delete element" element1="/src<org.eclipse.zest.core.widgets{CGraphNode.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470850904" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.core'
- Original project: 'org.eclipse.zest.core'
- Original element: 'org.eclipse.zest.core.widgets.ConstraintAdapter.java'" description="Delete element" element1="/src<org.eclipse.zest.core.widgets{ConstraintAdapter.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470853786" subPackages="false" version="1.0"/>
<refactoring accessors="true" comment="Delete 1 element(s) from project 'org.eclipse.zest.core'
- Original project: 'org.eclipse.zest.core'
- Original element: 'org.eclipse.zest.core.widgets.internal.ExpandGraphLabel.java'" description="Delete element" element1="/src<org.eclipse.zest.core.widgets.internal{ExpandGraphLabel.java" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470950914" subPackages="false" version="1.0"/> >+</session> >\ No newline at end of file >Index: src/org/eclipse/zest/core/viewers/AbstractStructuredGraphViewer.java >=================================================================== >RCS file: src/org/eclipse/zest/core/viewers/AbstractStructuredGraphViewer.java >diff -N src/org/eclipse/zest/core/viewers/AbstractStructuredGraphViewer.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/viewers/AbstractStructuredGraphViewer.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,774 @@ >+/******************************************************************************* >+ * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, >+ * Canada. All rights reserved. This program and the accompanying materials are >+ * made available under the terms of the Eclipse Public License v1.0 which >+ * accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * The Chisel Group, University of Victoria >+ * Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534 >+ ******************************************************************************/ >+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; >+ } >+ >+} >Index: src/org/eclipse/zest/core/widgets/DefaultSubgraph.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/DefaultSubgraph.java >diff -N src/org/eclipse/zest/core/widgets/DefaultSubgraph.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/widgets/DefaultSubgraph.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,393 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.core.widgets; >+ >+import java.util.ArrayList; >+import java.util.HashMap; >+import java.util.HashSet; >+import java.util.Iterator; >+import java.util.Set; >+ >+import org.eclipse.draw2d.ColorConstants; >+import org.eclipse.swt.graphics.Color; >+import org.eclipse.zest.core.widgets.custom.LabelSubgraph; >+import org.eclipse.zest.core.widgets.custom.TriangleSubgraph; >+import org.eclipse.zest.core.widgets.custom.TriangleSubgraph.TriangleParameters; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >+import org.eclipse.zest.layouts.interfaces.ConnectionLayout; >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+import org.eclipse.zest.layouts.interfaces.SubgraphLayout; >+ >+/** >+ * Default implementation of {@link SubgraphLayout}. Every subgraph added to >+ * Zest {@link Graph} should inherit from this class. The default implementation >+ * is very simple. A node pruned to this subgraph is minimized and all >+ * connections adjacent to it are made invisible. No additional graphic elements >+ * are added to the graph, but subclasses may add them. >+ * >+ * @since 2.0 >+ */ >+public class DefaultSubgraph implements SubgraphLayout { >+ >+ /** >+ * Default factory for {@link DefaultSubgraph}. It creates one subgraph for >+ * a whole graph and throws every node into it. >+ */ >+ public static class DefaultSubgraphFactory implements SubgraphFactory { >+ private HashMap contextToSubgraph = new HashMap(); >+ >+ public SubgraphLayout createSubgraph(NodeLayout[] nodes, >+ LayoutContext context) { >+ DefaultSubgraph subgraph = (DefaultSubgraph) contextToSubgraph >+ .get(context); >+ if (subgraph == null) { >+ subgraph = new DefaultSubgraph(context); >+ contextToSubgraph.put(context, subgraph); >+ } >+ subgraph.addNodes(nodes); >+ return subgraph; >+ } >+ }; >+ >+ public static class LabelSubgraphFactory implements SubgraphFactory { >+ private Color defaultForegroundColor = ColorConstants.black; >+ private Color defaultBackgroundColor = ColorConstants.yellow; >+ >+ /** >+ * Changes the default foreground color for newly created subgraphs. >+ * >+ * @param c >+ * color to use >+ */ >+ public void setDefualtForegroundColor(Color c) { >+ defaultForegroundColor = c; >+ } >+ >+ /** >+ * Changes the default background color for newly created subgraphs. >+ * >+ * @param c >+ * color to use >+ */ >+ public void setDefaultBackgroundColor(Color c) { >+ defaultBackgroundColor = c; >+ } >+ >+ public SubgraphLayout createSubgraph(NodeLayout[] nodes, >+ LayoutContext context) { >+ return new LabelSubgraph(nodes, context, defaultForegroundColor, >+ defaultBackgroundColor); >+ } >+ }; >+ >+ public static class TriangleSubgraphFactory implements SubgraphFactory { >+ private TriangleParameters parameters = new TriangleParameters(); >+ >+ public SubgraphLayout createSubgraph(NodeLayout[] nodes, >+ LayoutContext context) { >+ return new TriangleSubgraph(nodes, context, >+ (TriangleParameters) parameters.clone()); >+ } >+ >+ /** >+ * >+ * @return initial color of triangles created with this factory >+ */ >+ public Color getColor() { >+ return parameters.color; >+ } >+ >+ /** >+ * Changes the default color for newly created subgraphs. >+ * >+ * @param color >+ * color to use >+ */ >+ public void setColor(Color color) { >+ parameters.color = color; >+ } >+ >+ /** >+ * >+ * @return initial direction of triangles created with this factory >+ */ >+ public int getDirection() { >+ return parameters.direction; >+ } >+ >+ /** >+ * Changes the default direction for newly cretaed subgraphs. >+ * >+ * @param direction >+ * direction to use, can be {@link SubgraphLayout#TOP_DOWN}, >+ * {@link SubgraphLayout#BOTTOM_UP}, >+ * {@link SubgraphLayout#LEFT_RIGHT}, or >+ * {@link SubgraphLayout#RIGHT_LEFT} >+ */ >+ public void setDirection(int direction) { >+ parameters.direction = direction; >+ } >+ >+ /** >+ * >+ * @return maximum height of triangles created with this factory >+ */ >+ public double getReferenceHeight() { >+ return parameters.referenceHeight; >+ } >+ >+ /** >+ * Sets the maximum height for the triangle visualizing this subgraph. >+ * >+ * @param referenceHeight >+ * height to use >+ */ >+ public void setReferenceHeight(double referenceHeight) { >+ parameters.referenceHeight = referenceHeight; >+ } >+ >+ /** >+ * >+ * @return maximum base length of triangles created with this factory >+ */ >+ public double getReferenceBase() { >+ return parameters.referenceBase; >+ } >+ >+ /** >+ * Sets the maximum base length for the triangle visualizing this >+ * subgraph. >+ * >+ * @param referenceBase >+ * base length to use >+ */ >+ >+ public void setReferenceBase(double referenceBase) { >+ parameters.referenceBase = referenceBase; >+ } >+ }; >+ >+ /** >+ * Factory for {@link PrunedSuccessorsSubgraph}. It creates one subgraph for >+ * a whole graph and throws every node into it. >+ */ >+ public static class PrunedSuccessorsSubgraphFactory implements >+ SubgraphFactory { >+ private HashMap contextToSubgraph = new HashMap(); >+ >+ public SubgraphLayout createSubgraph(NodeLayout[] nodes, >+ LayoutContext context) { >+ PrunedSuccessorsSubgraph subgraph = (PrunedSuccessorsSubgraph) contextToSubgraph >+ .get(context); >+ if (subgraph == null) { >+ subgraph = new PrunedSuccessorsSubgraph(context); >+ contextToSubgraph.put(context, subgraph); >+ } >+ subgraph.addNodes(nodes); >+ return subgraph; >+ } >+ >+ /** >+ * Updates a label for given node (creates the label if necessary). >+ * >+ * @param node >+ * node to update >+ */ >+ public void updateLabelForNode(InternalNodeLayout node) { >+ InternalLayoutContext context = node.getOwnerLayoutContext(); >+ PrunedSuccessorsSubgraph subgraph = (PrunedSuccessorsSubgraph) contextToSubgraph >+ .get(context); >+ if (subgraph == null) { >+ subgraph = new PrunedSuccessorsSubgraph(context); >+ contextToSubgraph.put(context, subgraph); >+ } >+ subgraph.updateNodeLabel(node); >+ } >+ >+ }; >+ >+ protected final InternalLayoutContext context; >+ >+ protected final Set nodes = new HashSet(); >+ >+ protected boolean disposed = false; >+ >+ protected DefaultSubgraph(LayoutContext context2) { >+ if (context2 instanceof InternalLayoutContext) { >+ this.context = (InternalLayoutContext) context2; >+ } else { >+ throw new RuntimeException( >+ "This subgraph can be only created with LayoutContext provided by Zest Graph"); >+ } >+ } >+ >+ public boolean isGraphEntity() { >+ return false; >+ } >+ >+ public void setSize(double width, double height) { >+ // do nothing >+ context.checkChangesAllowed(); >+ } >+ >+ public void setLocation(double x, double y) { >+ // do nothing >+ context.checkChangesAllowed(); >+ } >+ >+ public boolean isResizable() { >+ return false; >+ } >+ >+ public boolean isMovable() { >+ return false; >+ } >+ >+ public EntityLayout[] getSuccessingEntities() { >+ return new EntityLayout[0]; >+ } >+ >+ public DisplayIndependentDimension getSize() { >+ DisplayIndependentRectangle bounds = context.getBounds(); >+ return new DisplayIndependentDimension(bounds.width, bounds.height); >+ } >+ >+ public double getPreferredAspectRatio() { >+ return 0; >+ } >+ >+ public EntityLayout[] getPredecessingEntities() { >+ return new EntityLayout[0]; >+ } >+ >+ public DisplayIndependentPoint getLocation() { >+ DisplayIndependentRectangle bounds = context.getBounds(); >+ return new DisplayIndependentPoint(bounds.x + bounds.width / 2, >+ bounds.y + bounds.height / 2); >+ } >+ >+ public boolean isDirectionDependant() { >+ return false; >+ } >+ >+ public void setDirection(int direction) { >+ context.checkChangesAllowed(); >+ // do nothing >+ } >+ >+ public void removeNodes(NodeLayout[] nodes) { >+ context.checkChangesAllowed(); >+ ArrayList removedNodes = new ArrayList(); >+ for (int i = 0; i < nodes.length; i++) { >+ if (this.nodes.remove(nodes[i])) { >+ nodes[i].prune(null); >+ nodes[i].setMinimized(false); >+ refreshConnectionsVisibility(nodes[i].getIncomingConnections()); >+ refreshConnectionsVisibility(nodes[i].getOutgoingConnections()); >+ removedNodes.add(nodes[i]); >+ } >+ } >+ if (!removedNodes.isEmpty()) { >+ context.fireNodesPrunedEvent((NodeLayout[]) removedNodes >+ .toArray(new NodeLayout[removedNodes.size()])); >+ } >+ if (this.nodes.isEmpty()) { >+ dispose(); >+ } >+ } >+ >+ public void removeDisposedNodes() { >+ for (Iterator iterator = nodes.iterator(); iterator.hasNext();) { >+ InternalNodeLayout node = (InternalNodeLayout) iterator.next(); >+ if (node.isDisposed()) { >+ iterator.remove(); >+ } >+ } >+ } >+ >+ public NodeLayout[] getNodes() { >+ InternalNodeLayout[] result = new InternalNodeLayout[nodes.size()]; >+ int i = 0; >+ for (Iterator iterator = nodes.iterator(); iterator.hasNext();) { >+ result[i] = (InternalNodeLayout) iterator.next(); >+ if (!context.isLayoutItemFiltered(result[i].getNode())) { >+ i++; >+ } >+ } >+ if (i == nodes.size()) { >+ return result; >+ } >+ >+ NodeLayout[] result2 = new NodeLayout[i]; >+ System.arraycopy(result, 0, result2, 0, i); >+ return result2; >+ } >+ >+ public int countNodes() { >+ return nodes.size(); >+ } >+ >+ public void addNodes(NodeLayout[] nodes) { >+ context.checkChangesAllowed(); >+ ArrayList addedNodes = new ArrayList(); >+ for (int i = 0; i < nodes.length; i++) { >+ if (this.nodes.add(nodes[i])) { >+ nodes[i].prune(this); >+ nodes[i].setMinimized(true); >+ refreshConnectionsVisibility(nodes[i].getIncomingConnections()); >+ refreshConnectionsVisibility(nodes[i].getOutgoingConnections()); >+ addedNodes.add(nodes[i]); >+ } >+ } >+ if (!addedNodes.isEmpty()) { >+ context.fireNodesPrunedEvent((NodeLayout[]) addedNodes >+ .toArray(new NodeLayout[addedNodes.size()])); >+ } >+ } >+ >+ protected void refreshConnectionsVisibility(ConnectionLayout[] connections) { >+ for (int i = 0; i < connections.length; i++) { >+ connections[i].setVisible(!connections[i].getSource().isPruned() >+ && !connections[i].getTarget().isPruned()); >+ } >+ } >+ >+ /** >+ * Makes sure that value returned by {@link #getLocation()} will be equal to >+ * current location of this subgraph. >+ */ >+ protected void refreshLocation() { >+ // do nothing, to be reimplemented in subclasses >+ } >+ >+ /** >+ * Makes sure that value returned by {@link #getSize()} will be equal to >+ * current size of this subgraph. >+ */ >+ protected void refreshSize() { >+ // do nothing, to be reimplemented in subclasses >+ } >+ >+ protected void applyLayoutChanges() { >+ // do nothing >+ } >+ >+ protected void dispose() { >+ if (!disposed) { >+ context.removeSubgrah(this); >+ disposed = true; >+ } >+ } >+ >+}; >\ No newline at end of file >Index: src/org/eclipse/zest/core/widgets/InternalNodeLayout.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/InternalNodeLayout.java >diff -N src/org/eclipse/zest/core/widgets/InternalNodeLayout.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/widgets/InternalNodeLayout.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,327 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.core.widgets; >+ >+import java.util.ArrayList; >+import java.util.HashMap; >+import java.util.HashSet; >+import java.util.Iterator; >+ >+import org.eclipse.draw2d.FigureListener; >+import org.eclipse.draw2d.IFigure; >+import org.eclipse.draw2d.geometry.Dimension; >+import org.eclipse.draw2d.geometry.Point; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint; >+import org.eclipse.zest.layouts.interfaces.ConnectionLayout; >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+import org.eclipse.zest.layouts.interfaces.SubgraphLayout; >+ >+class InternalNodeLayout implements NodeLayout { >+ >+ /** >+ * This listener is added to nodes' figures as a workaround for the problem >+ * of minimized nodes leaving single on the graph pixels when zoomed out >+ */ >+ private final static FigureListener figureListener = new FigureListener() { >+ public void figureMoved(IFigure source) { >+ // hide figures of minimized nodes >+ GraphNode node = (GraphNode) figureToNode.get(source); >+ if (node.getLayout().isMinimized() && source.getSize().equals(0, 0)) { >+ source.setVisible(false); >+ } else { >+ source.setVisible(node.isVisible()); >+ } >+ } >+ }; >+ private final static HashMap figureToNode = new HashMap(); >+ >+ private DisplayIndependentPoint location; >+ private DisplayIndependentDimension size; >+ private boolean minimized = false; >+ private final GraphNode node; >+ private final InternalLayoutContext ownerLayoutContext; >+ private DefaultSubgraph subgraph; >+ private boolean isDisposed = false; >+ >+ public InternalNodeLayout(GraphNode graphNode) { >+ this.node = graphNode; >+ this.ownerLayoutContext = node.parent.getLayoutContext(); >+ graphNode.nodeFigure.addFigureListener(figureListener); >+ figureToNode.put(graphNode.nodeFigure, graphNode); >+ } >+ >+ public DisplayIndependentPoint getLocation() { >+ if (location == null) { >+ refreshLocation(); >+ } >+ return new DisplayIndependentPoint(location); >+ } >+ >+ public DisplayIndependentDimension getSize() { >+ if (size == null) { >+ refreshSize(); >+ } >+ return new DisplayIndependentDimension(size); >+ } >+ >+ public SubgraphLayout getSubgraph() { >+ return subgraph; >+ } >+ >+ public boolean isMovable() { >+ return true; >+ } >+ >+ public boolean isPrunable() { >+ return ownerLayoutContext.isPruningEnabled(); >+ } >+ >+ public boolean isPruned() { >+ return subgraph != null; >+ } >+ >+ public boolean isResizable() { >+ return (node.parent.getItem().getStyle() & ZestStyles.NODES_NO_LAYOUT_RESIZE) == 0; >+ } >+ >+ public void prune(SubgraphLayout subgraph) { >+ if (subgraph != null && !(subgraph instanceof DefaultSubgraph)) { >+ throw new RuntimeException( >+ "InternalNodeLayout can be pruned only to instance of DefaultSubgraph."); >+ } >+ ownerLayoutContext.checkChangesAllowed(); >+ if (subgraph == this.subgraph) { >+ return; >+ } >+ if (this.subgraph != null) { >+ SubgraphLayout subgraph2 = this.subgraph; >+ this.subgraph = null; >+ subgraph2.removeNodes(new NodeLayout[] { this }); >+ } >+ if (subgraph != null) { >+ this.subgraph = (DefaultSubgraph) subgraph; >+ subgraph.addNodes(new NodeLayout[] { this }); >+ } >+ } >+ >+ public void setLocation(double x, double y) { >+ ownerLayoutContext.checkChangesAllowed(); >+ internalSetLocation(x, y); >+ } >+ >+ private void internalSetLocation(double x, double y) { >+ if (location != null) { >+ location.x = x; >+ location.y = y; >+ } else { >+ location = new DisplayIndependentPoint(x, y); >+ } >+ } >+ >+ public void setSize(double width, double height) { >+ ownerLayoutContext.checkChangesAllowed(); >+ internalSetSize(width, height); >+ } >+ >+ private void internalSetSize(double width, double height) { >+ if (size != null) { >+ size.width = width; >+ size.height = height; >+ } else { >+ size = new DisplayIndependentDimension(width, height); >+ } >+ } >+ >+ public void setMinimized(boolean minimized) { >+ ownerLayoutContext.checkChangesAllowed(); >+ getSize(); >+ this.minimized = minimized; >+ } >+ >+ public boolean isMinimized() { >+ return minimized; >+ } >+ >+ public NodeLayout[] getPredecessingNodes() { >+ ConnectionLayout[] connections = getIncomingConnections(); >+ NodeLayout[] result = new NodeLayout[connections.length]; >+ for (int i = 0; i < connections.length; i++) { >+ result[i] = connections[i].getSource(); >+ if (result[i] == this) { >+ result[i] = connections[i].getTarget(); >+ } >+ } >+ return result; >+ } >+ >+ public NodeLayout[] getSuccessingNodes() { >+ ConnectionLayout[] connections = getOutgoingConnections(); >+ NodeLayout[] result = new NodeLayout[connections.length]; >+ for (int i = 0; i < connections.length; i++) { >+ result[i] = connections[i].getTarget(); >+ if (result[i] == this) { >+ result[i] = connections[i].getSource(); >+ } >+ } >+ return result; >+ } >+ >+ public EntityLayout[] getSuccessingEntities() { >+ if (isPruned()) { >+ return new NodeLayout[0]; >+ } >+ ArrayList result = new ArrayList(); >+ HashSet addedSubgraphs = new HashSet(); >+ NodeLayout[] successingNodes = getSuccessingNodes(); >+ for (int i = 0; i < successingNodes.length; i++) { >+ if (!successingNodes[i].isPruned()) { >+ result.add(successingNodes[i]); >+ } else { >+ SubgraphLayout successingSubgraph = successingNodes[i] >+ .getSubgraph(); >+ if (successingSubgraph.isGraphEntity() >+ && !addedSubgraphs.contains(successingSubgraph)) { >+ result.add(successingSubgraph); >+ addedSubgraphs.add(successingSubgraph); >+ } >+ } >+ } >+ return (EntityLayout[]) result.toArray(new EntityLayout[result.size()]); >+ } >+ >+ public EntityLayout[] getPredecessingEntities() { >+ if (isPruned()) { >+ return new NodeLayout[0]; >+ } >+ ArrayList result = new ArrayList(); >+ HashSet addedSubgraphs = new HashSet(); >+ NodeLayout[] predecessingNodes = getPredecessingNodes(); >+ for (int i = 0; i < predecessingNodes.length; i++) { >+ if (!predecessingNodes[i].isPruned()) { >+ result.add(predecessingNodes[i]); >+ } else { >+ SubgraphLayout predecessingSubgraph = predecessingNodes[i] >+ .getSubgraph(); >+ if (predecessingSubgraph.isGraphEntity() >+ && !addedSubgraphs.contains(predecessingSubgraph)) { >+ result.add(predecessingSubgraph); >+ addedSubgraphs.add(predecessingSubgraph); >+ } >+ } >+ } >+ return (EntityLayout[]) result.toArray(new EntityLayout[result.size()]); >+ } >+ >+ public ConnectionLayout[] getIncomingConnections() { >+ ArrayList result = new ArrayList(); >+ for (Iterator iterator = node.getTargetConnections().iterator(); iterator >+ .hasNext();) { >+ GraphConnection connection = (GraphConnection) iterator.next(); >+ if (!ownerLayoutContext.isLayoutItemFiltered(connection)) { >+ result.add(connection.getLayout()); >+ } >+ } >+ for (Iterator iterator = node.getSourceConnections().iterator(); iterator >+ .hasNext();) { >+ GraphConnection connection = (GraphConnection) iterator.next(); >+ if (!connection.isDirected() >+ && !ownerLayoutContext.isLayoutItemFiltered(connection)) { >+ result.add(connection.getLayout()); >+ } >+ } >+ return (ConnectionLayout[]) result.toArray(new ConnectionLayout[result >+ .size()]); >+ } >+ >+ public ConnectionLayout[] getOutgoingConnections() { >+ ArrayList result = new ArrayList(); >+ for (Iterator iterator = node.getSourceConnections().iterator(); iterator >+ .hasNext();) { >+ GraphConnection connection = (GraphConnection) iterator.next(); >+ if (!ownerLayoutContext.isLayoutItemFiltered(connection)) { >+ result.add(connection.getLayout()); >+ } >+ } >+ for (Iterator iterator = node.getTargetConnections().iterator(); iterator >+ .hasNext();) { >+ GraphConnection connection = (GraphConnection) iterator.next(); >+ if (!connection.isDirected() >+ && !ownerLayoutContext.isLayoutItemFiltered(connection)) { >+ result.add(connection.getLayout()); >+ } >+ } >+ return (ConnectionLayout[]) result.toArray(new ConnectionLayout[result >+ .size()]); >+ } >+ >+ public double getPreferredAspectRatio() { >+ return 0; >+ } >+ >+ GraphNode getNode() { >+ return node; >+ } >+ >+ void applyLayout() { >+ if (minimized) { >+ node.setSize(0, 0); >+ if (location != null) { >+ node.setLocation(location.x, location.y); >+ } >+ } else { >+ node.setSize(-1, -1); >+ if (location != null) { >+ node.setLocation(location.x - getSize().width / 2, location.y >+ - size.height / 2); >+ } >+ if (size != null) { >+ Dimension currentSize = node.getSize(); >+ if (size.width != currentSize.width >+ || size.height != currentSize.height) { >+ node.setSize(size.width, size.height); >+ } >+ } >+ } >+ } >+ >+ InternalLayoutContext getOwnerLayoutContext() { >+ return ownerLayoutContext; >+ } >+ >+ void refreshSize() { >+ Dimension size2 = node.getSize(); >+ internalSetSize(size2.width, size2.height); >+ } >+ >+ void refreshLocation() { >+ Point location2 = node.getLocation(); >+ internalSetLocation(location2.x + getSize().width / 2, location2.y >+ + size.height / 2); >+ } >+ >+ public String toString() { >+ return node.toString() + "(layout)"; >+ } >+ >+ void dispose() { >+ isDisposed = true; >+ if (subgraph != null) { >+ subgraph.removeDisposedNodes(); >+ } >+ ownerLayoutContext.fireNodeRemovedEvent(node.getLayout()); >+ figureToNode.remove(node.nodeFigure); >+ } >+ >+ boolean isDisposed() { >+ return isDisposed; >+ } >+} >\ No newline at end of file >Index: src/org/eclipse/zest/core/widgets/PrunedSuccessorsSubgraph.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/PrunedSuccessorsSubgraph.java >diff -N src/org/eclipse/zest/core/widgets/PrunedSuccessorsSubgraph.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/widgets/PrunedSuccessorsSubgraph.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,275 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.core.widgets; >+ >+import java.util.Arrays; >+import java.util.HashMap; >+import java.util.HashSet; >+import java.util.Iterator; >+ >+import org.eclipse.draw2d.AncestorListener; >+import org.eclipse.draw2d.ColorConstants; >+import org.eclipse.draw2d.FigureListener; >+import org.eclipse.draw2d.IFigure; >+import org.eclipse.draw2d.geometry.Dimension; >+import org.eclipse.draw2d.geometry.Point; >+import org.eclipse.draw2d.geometry.Rectangle; >+import org.eclipse.swt.graphics.Font; >+import org.eclipse.swt.graphics.FontData; >+import org.eclipse.swt.widgets.Display; >+import org.eclipse.zest.core.widgets.internal.GraphLabel; >+import org.eclipse.zest.core.widgets.internal.ZestRootLayer; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+ >+/** >+ * A subgraph that for each unexpanded node in a graph adds a label showing >+ * number of pruned successors (as unexpanded node is considered a node for >+ * which {@link Graph#canExpand(GraphNode)} returns true AND >+ * {@link Graph#canCollapse(GraphNode)} returns false). It doesn't matter which >+ * subgraph a node is pruned to, so the factory for this subgraph uses one >+ * instance for whole layout context. >+ */ >+class PrunedSuccessorsSubgraph extends DefaultSubgraph { >+ >+ private class LabelAncestorListener extends AncestorListener.Stub { >+ private final IFigure originalFigure; >+ private IFigure fisheyeFigure; >+ >+ public LabelAncestorListener(IFigure originalFigure, >+ IFigure fisheyeFigure) { >+ this.originalFigure = originalFigure; >+ this.fisheyeFigure = fisheyeFigure; >+ } >+ >+ public void ancestorRemoved(IFigure ancestor) { >+ if (fisheyeFigure != null) { >+ final GraphLabel label = (GraphLabel) nodeFigureToLabel >+ .get(fisheyeFigure); >+ if (label == null) { >+ return; >+ } >+ nodeFigureToLabel.remove(fisheyeFigure); >+ Display.getDefault().asyncExec(new Runnable() { >+ public void run() { >+ label >+ .removeAncestorListener(LabelAncestorListener.this); >+ } >+ }); >+ fisheyeFigure.removeFigureListener(nodeFigureListener); >+ originalFigure.addFigureListener(nodeFigureListener); >+ labelToAncestorListener.remove(label); >+ fisheyeFigure = null; >+ addLabelForFigure(originalFigure, label); >+ refreshLabelBounds(originalFigure, label); >+ } >+ } >+ } >+ >+ private final FigureListener nodeFigureListener = new FigureListener() { >+ public void figureMoved(IFigure source) { >+ GraphLabel label = (GraphLabel) nodeFigureToLabel.get(source); >+ if (label != null) { >+ refreshLabelBounds(source, label); >+ } >+ } >+ }; >+ >+ private final FisheyeListener fisheyeListener = new FisheyeListener() { >+ >+ public void fisheyeReplaced(Graph graph, IFigure oldFisheyeFigure, >+ IFigure newFisheyeFigure) { >+ oldFisheyeFigure.removeFigureListener(nodeFigureListener); >+ newFisheyeFigure.addFigureListener(nodeFigureListener); >+ GraphLabel label = (GraphLabel) nodeFigureToLabel >+ .remove(oldFisheyeFigure); >+ nodeFigureToLabel.put(newFisheyeFigure, label); >+ >+ LabelAncestorListener ancestorListener = (LabelAncestorListener) labelToAncestorListener >+ .get(label); >+ ancestorListener.fisheyeFigure = null; >+ addLabelForFigure(newFisheyeFigure, label); >+ ancestorListener.fisheyeFigure = newFisheyeFigure; >+ refreshLabelBounds(newFisheyeFigure, label); >+ } >+ >+ public void fisheyeRemoved(Graph graph, IFigure originalFigure, >+ IFigure fisheyeFigure) { >+ // do nothing - labelAncestorListener will take care of cleaning >+ // up >+ } >+ >+ public void fisheyeAdded(Graph graph, IFigure originalFigure, >+ IFigure fisheyeFigure) { >+ originalFigure.removeFigureListener(nodeFigureListener); >+ fisheyeFigure.addFigureListener(nodeFigureListener); >+ GraphLabel label = (GraphLabel) nodeFigureToLabel >+ .get(originalFigure); >+ if (label == null) { >+ return; >+ } >+ nodeFigureToLabel.put(fisheyeFigure, label); >+ refreshLabelBounds(fisheyeFigure, label); >+ addLabelForFigure(fisheyeFigure, label); >+ LabelAncestorListener labelAncestorListener = new LabelAncestorListener( >+ originalFigure, fisheyeFigure); >+ label.addAncestorListener(labelAncestorListener); >+ labelToAncestorListener.put(label, labelAncestorListener); >+ } >+ }; >+ >+ /** >+ * Maps from figures of nodes to labels showing number of nodes hidden >+ * successors >+ */ >+ private HashMap nodeFigureToLabel = new HashMap(); >+ >+ private HashMap labelToAncestorListener = new HashMap(); >+ >+ protected PrunedSuccessorsSubgraph(LayoutContext context2) { >+ super(context2); >+ context.container.getGraph().addFisheyeListener(fisheyeListener); >+ } >+ >+ public void addNodes(NodeLayout[] nodes) { >+ super.addNodes(nodes); >+ HashSet nodesToUpdate = new HashSet(); >+ for (int i = 0; i < nodes.length; i++) { >+ nodesToUpdate >+ .addAll(Arrays.asList(nodes[i].getPredecessingNodes())); >+ } >+ for (Iterator iterator = nodesToUpdate.iterator(); iterator.hasNext();) { >+ InternalNodeLayout nodeToUpdate = (InternalNodeLayout) iterator >+ .next(); >+ updateNodeLabel(nodeToUpdate); >+ } >+ >+ } >+ >+ public void removeNodes(NodeLayout[] nodes) { >+ super.removeNodes(nodes); >+ HashSet nodesToUpdate = new HashSet(); >+ for (int i = 0; i < nodes.length; i++) { >+ nodesToUpdate >+ .addAll(Arrays.asList(nodes[i].getPredecessingNodes())); >+ if (((InternalNodeLayout) nodes[i]).isDisposed()) { >+ removeFigureForNode((InternalNodeLayout) nodes[i]); >+ } else { >+ nodesToUpdate.add(nodes[i]); >+ } >+ } >+ for (Iterator iterator = nodesToUpdate.iterator(); iterator.hasNext();) { >+ InternalNodeLayout predecessor = (InternalNodeLayout) iterator >+ .next(); >+ updateNodeLabel(predecessor); >+ } >+ } >+ >+ private void addLabelForFigure(IFigure figure, GraphLabel label) { >+ IFigure parent = figure.getParent(); >+ if (parent instanceof ZestRootLayer) { >+ ((ZestRootLayer) parent).addDecoration(figure, label); >+ } else { >+ if (parent.getChildren().contains(label)) { >+ parent.remove(label); >+ } >+ int index = parent.getChildren().indexOf(figure); >+ parent.add(label, index + 1); >+ } >+ } >+ >+ private void refreshLabelBounds(IFigure figure, GraphLabel label) { >+ Rectangle figureBounds = figure.getBounds(); >+ if (figureBounds.width * figureBounds.height > 0) { >+ label.setText(label.getText()); // hack: resets label's size >+ Dimension labelSize = label.getSize(); >+ labelSize.expand(-6, -4); >+ Point anchorPoint = figure.getBounds().getBottomRight(); >+ anchorPoint.x -= labelSize.width / 2; >+ anchorPoint.y -= labelSize.height / 2; >+ Rectangle bounds = new Rectangle(anchorPoint, labelSize); >+ label.setBounds(bounds); >+ label.getParent().setConstraint(label, bounds); >+ } else { >+ label.getParent().setConstraint(label, >+ new Rectangle(figureBounds.x, figureBounds.y, 0, 0)); >+ label >+ .setBounds(new Rectangle(figureBounds.x, figureBounds.y, 0, >+ 0)); >+ } >+ } >+ >+ void updateNodeLabel(InternalNodeLayout internalNode) { >+ if (internalNode.isDisposed()) { >+ return; >+ } >+ IFigure figure = internalNode.getNode().getFigure(); >+ GraphLabel label = (GraphLabel) nodeFigureToLabel.get(figure); >+ IFigure fisheye = getFisheyeFigure(figure); >+ if (fisheye != null) { >+ figure = fisheye; >+ } >+ if (label == null) { >+ label = new GraphLabel(false); >+ label.setForegroundColor(ColorConstants.white); >+ label.setBackgroundColor(ColorConstants.red); >+ FontData fontData = Display.getDefault().getSystemFont() >+ .getFontData()[0]; >+ fontData.setHeight(6); >+ label.setFont(new Font(Display.getCurrent(), fontData)); >+ figure.addFigureListener(nodeFigureListener); >+ addLabelForFigure(figure, label); >+ nodeFigureToLabel.put(figure, label); >+ } >+ >+ GraphNode graphNode = internalNode.getNode(); >+ if (!graphNode.getGraphModel().canExpand(graphNode) >+ || graphNode.getGraphModel().canCollapse(graphNode) >+ || internalNode.isPruned()) { >+ label.setVisible(false); >+ } else { >+ NodeLayout[] successors = internalNode.getSuccessingNodes(); >+ int numberOfHiddenSuccessors = 0; >+ for (int i = 0; i < successors.length; i++) { >+ if (successors[i].isPruned()) { >+ numberOfHiddenSuccessors++; >+ } >+ } >+ String labelText = numberOfHiddenSuccessors > 0 ? "" >+ + numberOfHiddenSuccessors : ""; >+ if (!labelText.equals(label.getText())) { >+ label.setText(labelText); >+ } >+ label.setVisible(true); >+ } >+ >+ refreshLabelBounds(figure, label); >+ } >+ >+ private IFigure getFisheyeFigure(IFigure originalFigure) { >+ // a node has a fisheye if and only if its label has an AncestorListener >+ GraphLabel label = (GraphLabel) nodeFigureToLabel.get(originalFigure); >+ LabelAncestorListener ancestorListener = (LabelAncestorListener) labelToAncestorListener >+ .get(label); >+ if (ancestorListener != null) { >+ return ancestorListener.fisheyeFigure; >+ } >+ return null; >+ } >+ >+ private void removeFigureForNode(InternalNodeLayout internalNode) { >+ IFigure figure = internalNode.getNode().getFigure(); >+ GraphLabel label = (GraphLabel) nodeFigureToLabel.get(figure); >+ if (label != null && label.getParent() != null) { >+ label.getParent().remove(label); >+ } >+ nodeFigureToLabel.remove(figure); >+ } >+} >Index: src/org/eclipse/zest/core/widgets/InternalLayoutContext.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/InternalLayoutContext.java >diff -N src/org/eclipse/zest/core/widgets/InternalLayoutContext.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/widgets/InternalLayoutContext.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,561 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.core.widgets; >+ >+import java.util.ArrayList; >+import java.util.Arrays; >+import java.util.HashSet; >+import java.util.Iterator; >+import java.util.List; >+ >+import org.eclipse.draw2d.Animation; >+import org.eclipse.zest.layouts.LayoutAlgorithm; >+import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle; >+import org.eclipse.zest.layouts.interfaces.ConnectionLayout; >+import org.eclipse.zest.layouts.interfaces.ContextListener; >+import org.eclipse.zest.layouts.interfaces.EntityLayout; >+import org.eclipse.zest.layouts.interfaces.ExpandCollapseManager; >+import org.eclipse.zest.layouts.interfaces.GraphStructureListener; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+import org.eclipse.zest.layouts.interfaces.LayoutListener; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+import org.eclipse.zest.layouts.interfaces.PruningListener; >+import org.eclipse.zest.layouts.interfaces.SubgraphLayout; >+ >+class InternalLayoutContext implements LayoutContext { >+ >+ private final static int INSETS = 15; >+ >+ final IContainer container; >+ private final List filters = new ArrayList(); >+ private final List contextListeners = new ArrayList(); >+ private final List graphStructureListeners = new ArrayList(); >+ private final List layoutListeners = new ArrayList(); >+ private final List pruningListeners = new ArrayList(); >+ private LayoutAlgorithm mainAlgorithm; >+ private LayoutAlgorithm layoutAlgorithm; >+ private ExpandCollapseManager expandCollapseManager; >+ private SubgraphFactory subgraphFactory = new DefaultSubgraph.DefaultSubgraphFactory(); >+ private final HashSet subgraphs = new HashSet(); >+ private boolean eventsOn = true; >+ private boolean backgorundLayoutEnabled = true; >+ private boolean externalLayoutInvocation = false; >+ >+ /** >+ * @param graph >+ * the graph owning this context >+ */ >+ InternalLayoutContext(Graph graph) { >+ this.container = graph; >+ } >+ >+ InternalLayoutContext(GraphContainer container) { >+ this.container = container; >+ } >+ >+ public void addContextListener(ContextListener listener) { >+ contextListeners.add(listener); >+ } >+ >+ public void addGraphStructureListener(GraphStructureListener listener) { >+ graphStructureListeners.add(listener); >+ } >+ >+ public void addLayoutListener(LayoutListener listener) { >+ layoutListeners.add(listener); >+ } >+ >+ public void addPruningListener(PruningListener listener) { >+ pruningListeners.add(listener); >+ } >+ >+ public SubgraphLayout createSubgraph(NodeLayout[] nodes) { >+ checkChangesAllowed(); >+ InternalNodeLayout[] internalNodes = new InternalNodeLayout[nodes.length]; >+ for (int i = 0; i < nodes.length; i++) { >+ internalNodes[i] = (InternalNodeLayout) nodes[i]; >+ } >+ SubgraphLayout subgraph = subgraphFactory.createSubgraph(internalNodes, >+ this); >+ subgraphs.add(subgraph); >+ return subgraph; >+ } >+ >+ void removeSubgrah(DefaultSubgraph subgraph) { >+ subgraphs.remove(subgraph); >+ } >+ >+ public void flushChanges(boolean animationHint) { >+ // TODO support for asynchronous call >+ if (!container.getGraph().isVisible()) { >+ return; >+ } >+ eventsOn = false; >+ if (animationHint) { >+ Animation.markBegin(); >+ } >+ for (Iterator iterator = container.getNodes().iterator(); iterator >+ .hasNext();) { >+ GraphNode node = (GraphNode) iterator.next(); >+ node.applyLayoutChanges(); >+ } >+ for (Iterator iterator = container.getConnections().iterator(); iterator >+ .hasNext();) { >+ GraphConnection connection = (GraphConnection) iterator.next(); >+ connection.applyLayoutChanges(); >+ } >+ for (Iterator iterator = subgraphs.iterator(); iterator.hasNext();) { >+ DefaultSubgraph subgraph = (DefaultSubgraph) iterator.next(); >+ subgraph.applyLayoutChanges(); >+ } >+ if (animationHint) { >+ Animation.run(Graph.ANIMATION_TIME); >+ } >+ eventsOn = true; >+ } >+ >+ public DisplayIndependentRectangle getBounds() { >+ DisplayIndependentRectangle result = new DisplayIndependentRectangle( >+ container.getLayoutBounds()); >+ >+ result.x += INSETS; >+ result.y += INSETS; >+ result.width = Math.max(result.width - 2 * INSETS, 0); >+ result.height = Math.max(result.height - 2 * INSETS, 0); >+ return result; >+ } >+ >+ public LayoutAlgorithm getMainLayoutAlgorithm() { >+ return mainAlgorithm; >+ } >+ >+ public ExpandCollapseManager getExpandCollapseManager() { >+ return expandCollapseManager; >+ } >+ >+ public NodeLayout[] getNodes() { >+ ArrayList result = new ArrayList(); >+ for (Iterator iterator = this.container.getNodes().iterator(); iterator >+ .hasNext();) { >+ GraphNode node = (GraphNode) iterator.next(); >+ if (!isLayoutItemFiltered(node)) { >+ result.add(node.getLayout()); >+ } >+ } >+ return (NodeLayout[]) result.toArray(new NodeLayout[result.size()]); >+ } >+ >+ public EntityLayout[] getEntities() { >+ HashSet addedSubgraphs = new HashSet(); >+ ArrayList result = new ArrayList(); >+ for (Iterator iterator = this.container.getNodes().iterator(); iterator >+ .hasNext();) { >+ GraphNode node = (GraphNode) iterator.next(); >+ if (!isLayoutItemFiltered(node)) { >+ InternalNodeLayout nodeLayout = node.getLayout(); >+ if (!nodeLayout.isPruned()) { >+ result.add(nodeLayout); >+ } else { >+ SubgraphLayout subgraph = nodeLayout.getSubgraph(); >+ if (subgraph.isGraphEntity() >+ && !addedSubgraphs.contains(subgraph)) { >+ result.add(subgraph); >+ addedSubgraphs.add(subgraph); >+ } >+ } >+ } >+ } >+ return (EntityLayout[]) result.toArray(new EntityLayout[result.size()]); >+ } >+ >+ public SubgraphLayout[] getSubgraphs() { >+ SubgraphLayout[] result = new SubgraphLayout[subgraphs.size()]; >+ int subgraphCount = 0; >+ for (Iterator iterator = subgraphs.iterator(); iterator.hasNext();) { >+ SubgraphLayout subgraph = (SubgraphLayout) iterator.next(); >+ NodeLayout[] nodes = subgraph.getNodes(); >+ for (int i = 0; i < nodes.length; i++) { >+ if (!isLayoutItemFiltered(((InternalNodeLayout) nodes[i]) >+ .getNode())) { >+ result[subgraphCount++] = subgraph; >+ break; >+ } >+ } >+ } >+ if (subgraphCount == subgraphs.size()) { >+ return result; >+ } else { >+ SubgraphLayout[] result2 = new SubgraphLayout[subgraphCount]; >+ System.arraycopy(result, 0, result2, 0, subgraphCount); >+ return result2; >+ } >+ } >+ >+ public boolean isBoundsExpandable() { >+ return false; >+ } >+ >+ public boolean isBackgroundLayoutEnabled() { >+ return backgorundLayoutEnabled; >+ } >+ >+ void setBackgroundLayoutEnabled(boolean enabled) { >+ if (this.backgorundLayoutEnabled != enabled) { >+ this.backgorundLayoutEnabled = enabled; >+ fireBackgroundEnableChangedEvent(); >+ } >+ } >+ >+ public boolean isPruningEnabled() { >+ return expandCollapseManager != null; >+ } >+ >+ public void removeContextListener(ContextListener listener) { >+ contextListeners.remove(listener); >+ } >+ >+ public void removeGraphStructureListener(GraphStructureListener listener) { >+ graphStructureListeners.remove(listener); >+ } >+ >+ public void removeLayoutListener(LayoutListener listener) { >+ layoutListeners.remove(listener); >+ } >+ >+ public void removePruningListener(PruningListener listener) { >+ pruningListeners.remove(listener); >+ } >+ >+ public void setMainLayoutAlgorithm(LayoutAlgorithm algorithm) { >+ mainAlgorithm = algorithm; >+ } >+ >+ public void setExpandCollapseManager( >+ ExpandCollapseManager expandCollapseManager) { >+ this.expandCollapseManager = expandCollapseManager; >+ expandCollapseManager.initExpansion(this); >+ } >+ >+ public ConnectionLayout[] getConnections() { >+ List connections = container.getConnections(); >+ ConnectionLayout[] result = new ConnectionLayout[connections.size()]; >+ int i = 0; >+ for (Iterator iterator = connections.iterator(); iterator.hasNext();) { >+ GraphConnection connection = (GraphConnection) iterator.next(); >+ if (!isLayoutItemFiltered(connection)) { >+ result[i++] = connection.getLayout(); >+ } >+ } >+ if (i == result.length) { >+ return result; >+ } >+ ConnectionLayout[] result2 = new ConnectionLayout[i]; >+ System.arraycopy(result, 0, result2, 0, i); >+ return result2; >+ } >+ >+ public ConnectionLayout[] getConnections(EntityLayout source, >+ EntityLayout target) { >+ ArrayList result = new ArrayList(); >+ >+ ArrayList sourcesList = new ArrayList(); >+ if (source instanceof NodeLayout) { >+ sourcesList.add(source); >+ } >+ if (source instanceof SubgraphLayout) { >+ sourcesList.addAll(Arrays.asList(((SubgraphLayout) source) >+ .getNodes())); >+ } >+ >+ HashSet targets = new HashSet(); >+ if (target instanceof NodeLayout) { >+ targets.add(target); >+ } >+ if (target instanceof SubgraphLayout) { >+ targets.addAll(Arrays.asList(((SubgraphLayout) target).getNodes())); >+ } >+ >+ for (Iterator iterator = sourcesList.iterator(); iterator.hasNext();) { >+ NodeLayout source2 = (NodeLayout) iterator.next(); >+ ConnectionLayout[] outgoingConnections = source2 >+ .getOutgoingConnections(); >+ for (int i = 0; i < outgoingConnections.length; i++) { >+ ConnectionLayout connection = outgoingConnections[i]; >+ if ((connection.getSource() == source2 && targets >+ .contains(connection.getTarget())) >+ || (connection.getTarget() == source2 && targets >+ .contains(connection.getSource()))) { >+ result.add(connection); >+ } >+ } >+ >+ } >+ return (ConnectionLayout[]) result.toArray(new ConnectionLayout[result >+ .size()]); >+ } >+ >+ void addFilter(LayoutFilter filter) { >+ filters.add(filter); >+ } >+ >+ void removeFilter(LayoutFilter filter) { >+ filters.remove(filter); >+ } >+ >+ boolean isLayoutItemFiltered(GraphItem item) { >+ for (Iterator it = filters.iterator(); it.hasNext();) { >+ LayoutFilter filter = (LayoutFilter) it.next(); >+ if (filter.isObjectFiltered(item)) { >+ return true; >+ } >+ } >+ return false; >+ } >+ >+ void setExpanded(NodeLayout node, boolean expanded) { >+ externalLayoutInvocation = true; >+ if (expandCollapseManager != null) { >+ expandCollapseManager.setExpanded(this, node, expanded); >+ } >+ externalLayoutInvocation = false; >+ } >+ >+ boolean canExpand(NodeLayout node) { >+ return expandCollapseManager != null >+ && expandCollapseManager.canExpand(this, node); >+ } >+ >+ boolean canCollapse(NodeLayout node) { >+ return expandCollapseManager != null >+ && expandCollapseManager.canCollapse(this, node); >+ } >+ >+ void setSubgraphFactory(SubgraphFactory factory) { >+ subgraphFactory = factory; >+ } >+ >+ SubgraphFactory getSubgraphFactory() { >+ return subgraphFactory; >+ } >+ >+ void applyMainAlgorithm() { >+ if (backgorundLayoutEnabled && mainAlgorithm != null) { >+ mainAlgorithm.applyLayout(true); >+ flushChanges(false); >+ } >+ } >+ >+ /** >+ * Sets layout algorithm for this context. It differs from >+ * {@link #setMainLayoutAlgorithm(LayoutAlgorithm) main algorithm} in that >+ * it's always used when {@link #applyLayoutAlgorithm(boolean)} and not >+ * after firing of events. >+ */ >+ void setLayoutAlgorithm(LayoutAlgorithm algorithm) { >+ if (this.layoutAlgorithm != null) { >+ this.layoutAlgorithm.setLayoutContext(null); >+ } >+ this.layoutAlgorithm = algorithm; >+ this.layoutAlgorithm.setLayoutContext(this); >+ } >+ >+ LayoutAlgorithm getLayoutAlgorithm() { >+ return layoutAlgorithm; >+ } >+ >+ void applyLayout(boolean clean) { >+ if (layoutAlgorithm != null) { >+ externalLayoutInvocation = true; >+ layoutAlgorithm.applyLayout(clean); >+ externalLayoutInvocation = false; >+ } >+ } >+ >+ void checkChangesAllowed() { >+ if (!backgorundLayoutEnabled && !externalLayoutInvocation) { >+ throw new RuntimeException( >+ "Layout not allowed to perform changes in layout context!"); >+ } >+ } >+ >+ void fireNodeAddedEvent(NodeLayout node) { >+ boolean intercepted = !eventsOn; >+ GraphStructureListener[] listeners = (GraphStructureListener[]) graphStructureListeners >+ .toArray(new GraphStructureListener[graphStructureListeners >+ .size()]); >+ for (int i = 0; i < listeners.length && !intercepted; i++) { >+ intercepted = listeners[i].nodeAdded(this, node); >+ } >+ if (!intercepted) { >+ applyMainAlgorithm(); >+ } >+ } >+ >+ void fireNodeRemovedEvent(NodeLayout node) { >+ boolean intercepted = !eventsOn; >+ GraphStructureListener[] listeners = (GraphStructureListener[]) graphStructureListeners >+ .toArray(new GraphStructureListener[graphStructureListeners >+ .size()]); >+ for (int i = 0; i < listeners.length && !intercepted; i++) { >+ intercepted = listeners[i].nodeRemoved(this, node); >+ } >+ if (!intercepted) { >+ applyMainAlgorithm(); >+ } >+ } >+ >+ void fireConnectionAddedEvent(ConnectionLayout connection) { >+ InternalLayoutContext sourceContext = ((InternalNodeLayout) connection >+ .getSource()).getOwnerLayoutContext(); >+ InternalLayoutContext targetContext = ((InternalNodeLayout) connection >+ .getTarget()).getOwnerLayoutContext(); >+ if (sourceContext != targetContext) { >+ // connection between nodes in different containers is not >+ // interesting for layout algorithms >+ return; >+ } >+ if (sourceContext == this) { >+ boolean intercepted = !eventsOn; >+ GraphStructureListener[] listeners = (GraphStructureListener[]) graphStructureListeners >+ .toArray(new GraphStructureListener[graphStructureListeners >+ .size()]); >+ for (int i = 0; i < listeners.length && !intercepted; i++) { >+ intercepted = listeners[i].connectionAdded(this, connection); >+ } >+ if (!intercepted) { >+ applyMainAlgorithm(); >+ } >+ } else { >+ sourceContext.fireConnectionAddedEvent(connection); >+ } >+ } >+ >+ void fireConnectionRemovedEvent(ConnectionLayout connection) { >+ InternalLayoutContext sourceContext = ((InternalNodeLayout) connection >+ .getSource()).getOwnerLayoutContext(); >+ InternalLayoutContext targetContext = ((InternalNodeLayout) connection >+ .getTarget()).getOwnerLayoutContext(); >+ if (sourceContext != targetContext) { >+ // connection between nodes in different containers is not >+ // interesting for layout algorithms >+ return; >+ } >+ if (sourceContext == this) { >+ boolean intercepted = !eventsOn; >+ GraphStructureListener[] listeners = (GraphStructureListener[]) graphStructureListeners >+ .toArray(new GraphStructureListener[graphStructureListeners >+ .size()]); >+ for (int i = 0; i < listeners.length && !intercepted; i++) { >+ intercepted = listeners[i].connectionRemoved(this, connection); >+ } >+ if (!intercepted) { >+ applyMainAlgorithm(); >+ } >+ } else { >+ sourceContext.fireConnectionAddedEvent(connection); >+ } >+ } >+ >+ void fireConnectionWeightChanged(ConnectionLayout connection) { >+ boolean intercepted = !eventsOn; >+ GraphStructureListener[] listeners = (GraphStructureListener[]) graphStructureListeners >+ .toArray(new GraphStructureListener[graphStructureListeners >+ .size()]); >+ for (int i = 0; i < listeners.length && !intercepted; i++) { >+ intercepted = listeners[i] >+ .connectionWeightChanged(this, connection); >+ } >+ if (!intercepted) { >+ applyMainAlgorithm(); >+ } >+ } >+ >+ void fireConnectionDirectedChanged(ConnectionLayout connection) { >+ boolean intercepted = !eventsOn; >+ GraphStructureListener[] listeners = (GraphStructureListener[]) graphStructureListeners >+ .toArray(new GraphStructureListener[graphStructureListeners >+ .size()]); >+ for (int i = 0; i < listeners.length && !intercepted; i++) { >+ intercepted = listeners[i].connectionDirectedChanged(this, >+ connection); >+ } >+ if (!intercepted) { >+ applyMainAlgorithm(); >+ } >+ } >+ >+ void fireBoundsChangedEvent() { >+ boolean intercepted = !eventsOn; >+ ContextListener[] listeners = (ContextListener[]) contextListeners >+ .toArray(new ContextListener[contextListeners.size()]); >+ for (int i = 0; i < listeners.length && !intercepted; i++) { >+ intercepted = listeners[i].boundsChanged(this); >+ } >+ if (!intercepted) { >+ applyMainAlgorithm(); >+ } >+ } >+ >+ void fireBackgroundEnableChangedEvent() { >+ ContextListener[] listeners = (ContextListener[]) contextListeners >+ .toArray(new ContextListener[contextListeners.size()]); >+ for (int i = 0; i < listeners.length; i++) { >+ listeners[i].backgroundEnableChanged(this); >+ } >+ } >+ >+ void fireEntityMovedEvent(EntityLayout entity) { >+ boolean intercepted = !eventsOn; >+ LayoutListener[] listeners = (LayoutListener[]) layoutListeners >+ .toArray(new LayoutListener[layoutListeners.size()]); >+ for (int i = 0; i < listeners.length && !intercepted; i++) { >+ intercepted = listeners[i].entityMoved(this, entity); >+ } >+ if (!intercepted) { >+ applyMainAlgorithm(); >+ } >+ } >+ >+ void fireEntityResizedEvent(EntityLayout entity) { >+ boolean intercepted = !eventsOn; >+ LayoutListener[] listeners = (LayoutListener[]) layoutListeners >+ .toArray(new LayoutListener[layoutListeners.size()]); >+ for (int i = 0; i < listeners.length && !intercepted; i++) { >+ intercepted = listeners[i].entityResized(this, entity); >+ } >+ if (!intercepted) { >+ applyMainAlgorithm(); >+ } >+ } >+ >+ void fireNodesPrunedEvent(NodeLayout[] nodes) { >+ boolean intercepted = !eventsOn; >+ PruningListener[] listeners = (PruningListener[]) pruningListeners >+ .toArray(new PruningListener[pruningListeners.size()]); >+ for (int i = 0; i < listeners.length && !intercepted; i++) { >+ intercepted = listeners[i].nodesPruned(this, nodes); >+ } >+ if (!intercepted) { >+ applyMainAlgorithm(); >+ } >+ } >+ >+ void fireNodesUnprunedEvent(NodeLayout[] nodes, SubgraphLayout subgraph) { >+ boolean intercepted = !eventsOn; >+ PruningListener[] listeners = (PruningListener[]) pruningListeners >+ .toArray(new PruningListener[pruningListeners.size()]); >+ for (int i = 0; i < listeners.length && !intercepted; i++) { >+ intercepted = listeners[i].nodesUnpruned(this, nodes, subgraph); >+ } >+ if (!intercepted) { >+ applyMainAlgorithm(); >+ } >+ } >+} >\ No newline at end of file >Index: src/org/eclipse/zest/core/widgets/custom/TriangleSubgraph.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/custom/TriangleSubgraph.java >diff -N src/org/eclipse/zest/core/widgets/custom/TriangleSubgraph.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/widgets/custom/TriangleSubgraph.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,255 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.core.widgets.custom; >+ >+import java.util.HashMap; >+ >+import org.eclipse.draw2d.ColorConstants; >+import org.eclipse.draw2d.Graphics; >+import org.eclipse.draw2d.Shape; >+import org.eclipse.draw2d.geometry.PointList; >+import org.eclipse.draw2d.geometry.Rectangle; >+import org.eclipse.swt.graphics.Color; >+import org.eclipse.zest.core.widgets.FigureSubgraph; >+import org.eclipse.zest.layouts.algorithms.TreeLayoutObserver; >+import org.eclipse.zest.layouts.algorithms.TreeLayoutObserver.TreeListener; >+import org.eclipse.zest.layouts.algorithms.TreeLayoutObserver.TreeNode; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+import org.eclipse.zest.layouts.interfaces.SubgraphLayout; >+ >+/** >+ * A subgraph that is visualized in a graph as a triangle. It assumes that nodes >+ * in context that uses them are arranged in a tree structure and the nodes >+ * added to the subgraph are a subtree (except for the subtree's root, which >+ * should not be added). >+ * >+ * The triangle has three features that show the properties of a subtree >+ * contained within it: >+ * <ul> >+ * <li><b>Height of the triangle</b> is proportional to the height of the >+ * subtree. If the subtree contains the whole tree, the triangle's height will >+ * be equal to value provided with >+ * {@link TriangleSubgraph#setReferenceHeight(double)} (default is 50).</li> >+ * <li><b>Length of the triangle's base</b> depends on the number of leaves in >+ * the subtree. More precisely, it is proportional to the logarithm of the >+ * percent that the subtree's leaves make of the whole context's leaves. The >+ * proportion factor is adjusted so that for a subtree containing all the leaves >+ * the base has length provided with {@link TriangleSubgraph} >+ * {@link #setReferenceBase(double)} (default is 50) and for a subtree >+ * containing only one leaf the base has length 1.</li> >+ * <li><b>Background color of the triangle</b> depends on average number of >+ * children for nodes in the subtree. The less is this value, the more bright is >+ * the color (up to white for a subtree with average number of children equal to >+ * 1). The average value is calculated only for nodes that have at least one >+ * child. The root of the subtree (which is not directly added to this subgraph) >+ * is also accounted.</li> >+ * </ul> >+ * >+ * When the first subgraph of this class is created for a layout context, a >+ * {@link TreeLayoutObserver} is created for the context. It must keep track of >+ * changes in the graph structure, so events related to it should not be >+ * intercepted by other listeners before they reach the subgraph's observer. >+ * >+ * @since 2.0 >+ */ >+public class TriangleSubgraph extends FigureSubgraph { >+ >+ public static class TriangleParameters implements Cloneable { >+ public Color color = ColorConstants.black; >+ >+ public int direction = TOP_DOWN; >+ >+ public double referenceHeight = 50; >+ >+ public double referenceBase = 50; >+ >+ public Object clone() { >+ TriangleParameters result = new TriangleParameters(); >+ result.color = color; >+ result.direction = direction; >+ result.referenceHeight = referenceHeight; >+ result.referenceBase = referenceBase; >+ return result; >+ } >+ } >+ >+ private class IsoscelesTriangle extends Shape { >+ >+ private PointList points = new PointList(3); >+ >+ protected void fillShape(Graphics graphics) { >+ graphics.fillPolygon(points); >+ } >+ >+ protected void outlineShape(Graphics graphics) { >+ graphics.drawPolygon(points); >+ } >+ >+ protected void primTranslate(int dx, int dy) { >+ super.primTranslate(dx, dy); >+ points.translate(dx, dy); >+ } >+ >+ public void validate() { >+ super.validate(); >+ Rectangle r = new Rectangle(); >+ r.setBounds(getBounds()); >+ r.crop(getInsets()); >+ points.removeAllPoints(); >+ switch (parameters.direction) { >+ case TOP_DOWN: >+ points.addPoint(r.x + r.width / 2, r.y); >+ points.addPoint(r.x, r.y + r.height); >+ points.addPoint(r.x + r.width, r.y + r.height); >+ break; >+ case BOTTOM_UP: >+ points.addPoint(r.x + r.width / 2, r.y + r.height); >+ points.addPoint(r.x, r.y); >+ points.addPoint(r.x + r.width, r.y); >+ break; >+ case LEFT_RIGHT: >+ points.addPoint(r.x, r.y + r.height / 2); >+ points.addPoint(r.x + r.width, r.y); >+ points.addPoint(r.x + r.width, r.y + r.height); >+ break; >+ case RIGHT_LEFT: >+ points.addPoint(r.x + r.width, r.y + r.height / 2); >+ points.addPoint(r.x, r.y); >+ points.addPoint(r.x, r.y + r.height); >+ break; >+ } >+ } >+ } >+ >+ private static HashMap contextToTree = new HashMap(); >+ >+ private TriangleParameters parameters; >+ >+ public TriangleSubgraph(NodeLayout[] nodes, LayoutContext context, >+ TriangleParameters triangleParameters) { >+ super(nodes, context); >+ this.parameters = triangleParameters; >+ if (contextToTree.get(context) == null) { >+ TreeLayoutObserver treeLayoutObserver = new TreeLayoutObserver( >+ context, null); >+ treeLayoutObserver.addTreeListener(new TreeListener() { >+ protected void defaultHandle(TreeNode changedNode) { >+ SubgraphLayout subgraph = changedNode.getNode() >+ .getSubgraph(); >+ if (subgraph instanceof TriangleSubgraph) { >+ ((TriangleSubgraph) subgraph).updateFigure(); >+ } >+ } >+ }); >+ contextToTree.put(context, treeLayoutObserver); >+ } >+ } >+ >+ protected void createFigure() { >+ figure = new IsoscelesTriangle(); >+ figure.setBackgroundColor(parameters.color); >+ figure.setForegroundColor(parameters.color); >+ } >+ >+ private double log(double value, double base) { >+ return Math.log(value) / Math.log(base); >+ } >+ >+ protected void updateFigure() { >+ TreeLayoutObserver tree = (TreeLayoutObserver) contextToTree >+ .get(context); >+ TreeNode subgraphRoot = tree.getTreeNode((NodeLayout) nodes.iterator() >+ .next()); >+ if (subgraphRoot == null) { >+ return; >+ } >+ while (nodes.contains(subgraphRoot.getNode())) { >+ subgraphRoot = subgraphRoot.getParent(); >+ } >+ >+ TreeNode superRoot = tree.getSuperRoot(); >+ double triangleHeight = parameters.referenceHeight >+ * subgraphRoot.getHeight() / superRoot.getHeight(); >+ >+ int numOfNodes = superRoot.getNumOfDescendants(); >+ int numOfNodesWithChildren = numOfNodes - superRoot.getNumOfLeaves() >+ + 1; >+ double logBase = (numOfNodesWithChildren > 0) ? (double) numOfNodes >+ / numOfNodesWithChildren : 1; >+ // logarithm base is the average number of children for whole context >+ double triangleBaseModifier = (parameters.referenceBase - 1) >+ / log(superRoot.getNumOfLeaves(), logBase); >+ double triangleBase = parameters.referenceBase >+ + triangleBaseModifier >+ * log((double) subgraphRoot.getNumOfLeaves() >+ / superRoot.getNumOfLeaves(), logBase); >+ >+ if (parameters.direction == 0) { >+ parameters.direction = parameters.direction; >+ } >+ if (parameters.direction == TOP_DOWN >+ || parameters.direction == BOTTOM_UP) { >+ figure.setSize((int) (triangleBase + 0.5), >+ (int) (triangleHeight + 0.5)); >+ } else { >+ figure.setSize((int) (triangleHeight + 0.5), >+ (int) (triangleBase + 0.5)); >+ } >+ >+ int numOfNodesWithChildrenInSubgraph = nodes.size() >+ - subgraphRoot.getNumOfLeaves() + 1; >+ double avgNumOfChildrenInSugbraph = (numOfNodesWithChildrenInSubgraph > 0) ? (double) nodes >+ .size() >+ / numOfNodesWithChildrenInSubgraph >+ : 1; >+ int r = (int) (parameters.color.getRed() + ((double) 255 - parameters.color >+ .getRed()) >+ / avgNumOfChildrenInSugbraph); >+ int g = (int) (parameters.color.getGreen() + ((double) 255 - parameters.color >+ .getGreen()) >+ / avgNumOfChildrenInSugbraph); >+ int b = (int) (parameters.color.getBlue() + ((double) 255 - parameters.color >+ .getBlue()) >+ / avgNumOfChildrenInSugbraph); >+ figure.setBackgroundColor(new Color(parameters.color.getDevice(), r, g, >+ b)); >+ figure.setForegroundColor(parameters.color); >+ } >+ >+ public boolean isDirectionDependant() { >+ return true; >+ } >+ >+ public void setDirection(int direction) { >+ super.setDirection(direction); >+ if (parameters.direction == direction) { >+ return; >+ } >+ if (direction == TOP_DOWN || direction == BOTTOM_UP >+ || direction == LEFT_RIGHT || direction == RIGHT_LEFT) { >+ parameters.direction = direction; >+ updateFigure(); >+ } else { >+ throw new IllegalArgumentException("invalid direction"); >+ } >+ } >+ >+ /** >+ * Changes the color of the triangle visualizing this subgraph. >+ * >+ * @param color >+ * color to use >+ */ >+ public void setColor(Color color) { >+ parameters.color = color; >+ updateFigure(); >+ } >+} >Index: src/org/eclipse/zest/core/viewers/ZoomListener.java >=================================================================== >RCS file: src/org/eclipse/zest/core/viewers/ZoomListener.java >diff -N src/org/eclipse/zest/core/viewers/ZoomListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/viewers/ZoomListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,28 @@ >+/******************************************************************************* >+ * Copyright (c) 2000, 2009 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); >+ >+} >Index: src/org/eclipse/zest/core/widgets/DAGExpandCollapseManager.java >=================================================================== >RCS file: src/org/eclipse/zest/core/widgets/DAGExpandCollapseManager.java >diff -N src/org/eclipse/zest/core/widgets/DAGExpandCollapseManager.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/zest/core/widgets/DAGExpandCollapseManager.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,356 @@ >+/******************************************************************************* >+ * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This >+ * program and the accompanying materials are made available under the terms of >+ * the Eclipse Public License v1.0 which accompanies this distribution, and is >+ * available at http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: Mateusz Matela - initial API and implementation >+ * Ian Bull >+ ******************************************************************************/ >+package org.eclipse.zest.core.widgets; >+ >+import java.util.HashMap; >+import java.util.HashSet; >+import java.util.Iterator; >+import java.util.Map; >+ >+import org.eclipse.zest.layouts.interfaces.ConnectionLayout; >+import org.eclipse.zest.layouts.interfaces.ContextListener; >+import org.eclipse.zest.layouts.interfaces.ExpandCollapseManager; >+import org.eclipse.zest.layouts.interfaces.GraphStructureListener; >+import org.eclipse.zest.layouts.interfaces.LayoutContext; >+import org.eclipse.zest.layouts.interfaces.NodeLayout; >+ >+/** >+ * <p> >+ * An {@link ExpandCollapseManager} specialized for Directed Acyclic Graphs. It >+ * works correctly only when all connections are directed (and of course nodes >+ * form an acyclic graph). It's supposed to be used with >+ * {@link InternalLayoutContext}. >+ * </p> >+ * <p> >+ * When a node is collapsed, all its outgoing connections are hidden and these >+ * successors that have no visible incoming nodes are pruned. When a node is >+ * expanded, all its successors are unpruned and connections pointing to them >+ * are shown. >+ * </p> >+ * </p> >+ * <p> >+ * <b>NOTE:</b> A <code>Graph</code> using this manger should use >+ * {@link DefaultSubgraph}, which doesn't show any information about subgraphs >+ * in the graph. That's because for this manager it doesn't matter which >+ * subgraph a node belongs to (each pruning creates a new subgraph). Also, this >+ * manager adds a label to each collapsed node showing number of its successors. >+ * </p> >+ * One instance of this class can serve only one instance of <code>Graph</code>. >+ * >+ * @since 2.0 >+ */ >+public class DAGExpandCollapseManager implements ExpandCollapseManager { >+ >+ private InternalLayoutContext context; >+ >+ private HashSet expandedNodes = new HashSet(); >+ >+ private HashSet nodesToPrune = new HashSet(); >+ >+ private HashSet nodesToUnprune = new HashSet(); >+ >+ private HashSet nodesToUpdate = new HashSet(); >+ >+ private HashMap connectionsToChangeVisibility = new HashMap(); >+ >+ private boolean cleanLayoutScheduled = false; >+ >+ private boolean hidingConnections = false; >+ >+ public void initExpansion(final LayoutContext context2) { >+ if (!(context2 instanceof InternalLayoutContext)) { >+ throw new RuntimeException( >+ "This manager works only with org.eclipse.zest.core.widgets.InternalLayoutContext"); >+ } >+ context = (InternalLayoutContext) context2; >+ >+ context.addGraphStructureListener(new GraphStructureListener.Stub() { >+ public boolean nodeRemoved(LayoutContext context, NodeLayout node) { >+ if (isExpanded(node)) { >+ collapse(node); >+ } >+ flushChanges(false, true); >+ return false; >+ } >+ >+ public boolean nodeAdded(LayoutContext context, NodeLayout node) { >+ resetState(node); >+ flushChanges(false, true); >+ return false; >+ } >+ >+ public boolean connectionRemoved(LayoutContext context, >+ ConnectionLayout connection) { >+ NodeLayout target = connection.getTarget(); >+ if (!isExpanded(target) >+ && target.getIncomingConnections().length == 0) { >+ expand(target); >+ } >+ flushChanges(false, true); >+ return false; >+ } >+ >+ public boolean connectionAdded(LayoutContext context, >+ ConnectionLayout connection) { >+ if (!connection.isDirected()) { >+ throw new RuntimeException( >+ "Only directed connections can be used with DAGExpandCollapseManager"); >+ } >+ resetState(connection.getTarget()); >+ updateNodeLabel(connection.getSource()); >+ refreshConnectionsVisibility(connection.getSource()); >+ flushChanges(false, true); >+ return false; >+ } >+ >+ }); >+ >+ context.addContextListener(new ContextListener.Stub() { >+ public void backgroundEnableChanged(LayoutContext context) { >+ flushChanges(false, false); >+ } >+ }); >+ } >+ >+ public boolean canCollapse(LayoutContext context, NodeLayout node) { >+ return isExpanded(node) && !node.isPruned() >+ && node.getOutgoingConnections().length > 0; >+ } >+ >+ public boolean canExpand(LayoutContext context, NodeLayout node) { >+ return !isExpanded(node) && !node.isPruned() >+ && node.getOutgoingConnections().length > 0; >+ } >+ >+ public void setExpanded(LayoutContext context, NodeLayout node, >+ boolean expanded) { >+ >+ if (isExpanded(node) == expanded) { >+ return; >+ } >+ if (expanded) { >+ if (canExpand(context, node)) { >+ expand(node); >+ } >+ } else { >+ if (canCollapse(context, node)) { >+ collapse(node); >+ } >+ } >+ refreshConnectionsVisibility(node); >+ flushChanges(true, true); >+ } >+ >+ /** >+ * Returns true if this collapse manager hides all outgoing connections of >+ * collapsed nodes. Returns false if connections pointing to a node that is >+ * not pruned (because it as predecessing node which is expanded) stay >+ * visible. >+ * >+ * @return whether or not all connections going out of collapsed nodes are >+ * hidden. >+ */ >+ public boolean isHidingConnections() { >+ return hidingConnections; >+ } >+ >+ /** >+ * Changes the way connections outgoing from collapsed nodes are hidden. If >+ * set to true, all such connections are always hidden. If set to false, a >+ * connection is visible if a node it points to is not pruned (which means >+ * that node has another predecessing node which is expanded). >+ * >+ * Default is false. >+ * >+ * @param hidingConnections >+ * true if all outgoing connections of collapsed nodes should be >+ * hidden. >+ */ >+ public void setHidingConnections(boolean hidingConnections) { >+ this.hidingConnections = hidingConnections; >+ NodeLayout[] nodes = context.getNodes(); >+ for (int i = 0; i < nodes.length; i++) { >+ refreshConnectionsVisibility(nodes[i]); >+ } >+ flushChanges(false, false); >+ } >+ >+ private void refreshConnectionsVisibility(NodeLayout node) { >+ ConnectionLayout[] outgoingConnections = node.getOutgoingConnections(); >+ for (int i = 0; i < outgoingConnections.length; i++) { >+ setConnectionVisible( >+ outgoingConnections[i], >+ isExpanded(node) >+ || (!hidingConnections && !isPruned(node) && !isPruned(outgoingConnections[i] >+ .getTarget()))); >+ } >+ } >+ >+ private void expand(NodeLayout node) { >+ setExpanded(node, true); >+ NodeLayout[] successingNodes = node.getSuccessingNodes(); >+ for (int i = 0; i < successingNodes.length; i++) { >+ unpruneNode(successingNodes[i]); >+ } >+ updateNodeLabel(node); >+ } >+ >+ private void collapse(NodeLayout node) { >+ if (isExpanded(node)) { >+ setExpanded(node, false); >+ } else { >+ return; >+ } >+ NodeLayout[] successors = node.getSuccessingNodes(); >+ for (int i = 0; i < successors.length; i++) { >+ checkPruning(successors[i]); >+ if (isPruned(successors[i])) { >+ collapse(successors[i]); >+ } >+ } >+ updateNodeLabel(node); >+ } >+ >+ private void checkPruning(NodeLayout node) { >+ boolean prune = true; >+ NodeLayout[] predecessors = node.getPredecessingNodes(); >+ for (int j = 0; j < predecessors.length; j++) { >+ if (isExpanded(predecessors[j])) { >+ prune = false; >+ break; >+ } >+ } >+ if (prune) { >+ pruneNode(node); >+ } else { >+ unpruneNode(node); >+ } >+ } >+ >+ /** >+ * By default nodes at the top (having no predecessors) are expanded. The >+ * rest are collapsed and pruned if they don't have any expanded >+ * predecessors >+ * >+ * @param target >+ */ >+ private void resetState(NodeLayout node) { >+ NodeLayout[] predecessors = node.getPredecessingNodes(); >+ if (predecessors.length == 0) { >+ expand(node); >+ } else { >+ collapse(node); >+ checkPruning(node); >+ } >+ } >+ >+ /** >+ * If given node belongs to a layout context using >+ * {@link PrunedSuccessorsSubgraph}, update of the nodes's label is forced. >+ * >+ * @param node >+ * node to update >+ */ >+ private void updateNodeLabel(NodeLayout node) { >+ nodesToUpdate.add(node); >+ } >+ >+ private void updateNodeLabel2(InternalNodeLayout node) { >+ SubgraphFactory subgraphFactory = node.getOwnerLayoutContext() >+ .getSubgraphFactory(); >+ if (subgraphFactory instanceof DefaultSubgraph.PrunedSuccessorsSubgraphFactory) { >+ ((DefaultSubgraph.PrunedSuccessorsSubgraphFactory) subgraphFactory) >+ .updateLabelForNode(node); >+ } >+ } >+ >+ private void pruneNode(NodeLayout node) { >+ if (isPruned(node)) { >+ return; >+ } >+ nodesToUnprune.remove(node); >+ nodesToPrune.add(node); >+ } >+ >+ private void unpruneNode(NodeLayout node) { >+ if (!isPruned(node)) { >+ return; >+ } >+ nodesToPrune.remove(node); >+ nodesToUnprune.add(node); >+ } >+ >+ private void setConnectionVisible(ConnectionLayout connection, >+ boolean visible) { >+ if (connection.isVisible() == visible) { >+ return; >+ } >+ connectionsToChangeVisibility.put(connection, new Boolean(visible)); >+ } >+ >+ private boolean isPruned(NodeLayout node) { >+ if (nodesToUnprune.contains(node)) { >+ return false; >+ } >+ if (nodesToPrune.contains(node)) { >+ return true; >+ } >+ return node.isPruned(); >+ } >+ >+ private void flushChanges(boolean force, boolean clean) { >+ cleanLayoutScheduled = cleanLayoutScheduled || clean; >+ if (!force && !context.isBackgroundLayoutEnabled()) { >+ return; >+ } >+ >+ for (Iterator iterator = nodesToUnprune.iterator(); iterator.hasNext();) { >+ NodeLayout node = (NodeLayout) iterator.next(); >+ node.prune(null); >+ } >+ nodesToUnprune.clear(); >+ >+ if (!nodesToPrune.isEmpty()) { >+ context.createSubgraph((NodeLayout[]) nodesToPrune >+ .toArray(new NodeLayout[nodesToPrune.size()])); >+ nodesToPrune.clear(); >+ } >+ >+ for (Iterator iterator = nodesToUpdate.iterator(); iterator.hasNext();) { >+ InternalNodeLayout node = (InternalNodeLayout) iterator.next(); >+ updateNodeLabel2(node); >+ } >+ nodesToUpdate.clear(); >+ >+ for (Iterator iterator = connectionsToChangeVisibility.entrySet() >+ .iterator(); iterator.hasNext();) { >+ Map.Entry entry = (Map.Entry) iterator.next(); >+ ConnectionLayout connection = (ConnectionLayout) entry.getKey(); >+ Boolean visible = (Boolean) entry.getValue(); >+ connection.setVisible(visible.booleanValue()); >+ } >+ >+ context.applyLayout(cleanLayoutScheduled); >+ cleanLayoutScheduled = false; >+ context.flushChanges(true); >+ } >+ >+ private boolean isExpanded(NodeLayout node) { >+ return expandedNodes.contains(node); >+ } >+ >+ private void setExpanded(NodeLayout node, boolean expanded) { >+ if (expanded) { >+ expandedNodes.add(node); >+ } else { >+ expandedNodes.remove(node); >+ } >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
mateusz.matela
:
review?
Actions:
View
|
Diff
Attachments on
bug 277534
: 145959 |
162001