Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 277534 | Differences between
and this patch

Collapse All | Expand All

(-)META-INF/MANIFEST.MF (-1 / +1 lines)
Lines 2-6 Link Here
2
Bundle-ManifestVersion: 2
2
Bundle-ManifestVersion: 2
3
Bundle-Name: Zest Plug-in
3
Bundle-Name: Zest Plug-in
4
Bundle-SymbolicName: org.eclipse.zest
4
Bundle-SymbolicName: org.eclipse.zest
5
Bundle-Version: 1.0.0
5
Bundle-Version: 2.0.0
6
Bundle-RequiredExecutionEnvironment: J2SE-1.4
6
Bundle-RequiredExecutionEnvironment: J2SE-1.4
(-)src/org/eclipse/zest/layouts/algorithms/ContinuousLayoutAlgorithm.java (-102 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
12
13
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
14
import org.eclipse.zest.layouts.dataStructures.InternalNode;
15
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;
16
17
/**
18
 * 
19
 * @author Ian Bull
20
 * 
21
 * Used to represent algorithms that can continuously run.  
22
 *
23
 */
24
public abstract class ContinuousLayoutAlgorithm extends AbstractLayoutAlgorithm {
25
26
	double x, y, widht, height;
27
28
	public ContinuousLayoutAlgorithm(int styles) {
29
		super(styles);
30
	}
31
32
	/**
33
	 * The logic to determine if a layout should continue running or not
34
	 */
35
	protected abstract boolean performAnotherNonContinuousIteration();
36
37
	/**
38
	 * Computes a single iteration of the layout algorithm
39
	 * @return
40
	 */
41
	protected abstract void computeOneIteration(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height);
42
43
	private boolean continueRunning() {
44
		if (layoutStopped) {
45
			return false;
46
		} else if (this.internalContinuous && !layoutStopped) {
47
			return true;
48
		} else if (performAnotherNonContinuousIteration()) {
49
			return true;
50
		} else {
51
			return false;
52
		}
53
	}
54
55
	public void setLayoutArea(double x, double y, double width, double height) {
56
		this.setBounds(x, y, width, height);
57
58
	}
59
60
	public synchronized DisplayIndependentRectangle getBounds() {
61
		return new DisplayIndependentRectangle(this.x, this.y, this.widht, this.height);
62
	}
63
64
	public synchronized void setBounds(double x, double y, double width, double height) {
65
		this.x = x;
66
		this.y = y;
67
		this.widht = width;
68
		this.height = height;
69
	}
70
71
	/**
72
	 * Calculates and applies the positions of the given entities based on a
73
	 * spring layout using the given relationships.
74
	 */
75
	protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) {
76
77
		this.setBounds(x, y, width, height);
78
79
		while (continueRunning()) {
80
			// check for entities and relationships to add or remove 
81
			entitiesToLayout = updateEntities(entitiesToLayout);
82
			relationshipsToConsider = updateRelationships(relationshipsToConsider);
83
			DisplayIndependentRectangle bounds = this.getBounds();
84
			double localX = bounds.x;
85
			double localY = bounds.y;
86
			double localWidth = bounds.width;
87
			double localHeight = bounds.height;
88
89
			computeOneIteration(entitiesToLayout, relationshipsToConsider, localX, localY, localWidth, localHeight);
90
91
			updateLayoutLocations(entitiesToLayout);
92
93
			if (this.internalContinuous) {
94
				fireProgressEvent(1, 1);
95
			} else {
96
				fireProgressEvent(getCurrentLayoutStep(), getTotalNumberOfLayoutSteps());
97
			}
98
99
		}
100
	}
101
102
}
(-)src/org/eclipse/zest/layouts/algorithms/GridLayoutAlgorithm.java (-124 / +113 lines)
Lines 1-20 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright (c) 2005-2009 The Chisel Group and others. All rights reserved. This
3
 * All rights reserved. This program and the accompanying materials
3
 * program and the accompanying materials are made available under the terms of
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * which accompanies this distribution, and is available at
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 *
7
 * Contributors: The Chisel Group - initial API and implementation
8
 * Contributors:
8
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 *     The Chisel Group, University of Victoria
9
 *               Ian Bull
10
 *******************************************************************************/
10
 ******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
11
package org.eclipse.zest.layouts.algorithms;
12
12
13
import java.util.Arrays;
13
import org.eclipse.zest.layouts.LayoutAlgorithm;
14
14
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension;
15
import org.eclipse.zest.layouts.LayoutStyles;
15
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
16
import org.eclipse.zest.layouts.dataStructures.InternalNode;
16
import org.eclipse.zest.layouts.interfaces.EntityLayout;
17
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;
17
import org.eclipse.zest.layouts.interfaces.LayoutContext;
18
18
19
19
20
/**
20
/**
Lines 22-148 Link Here
22
 * @author Ian Bull
22
 * @author Ian Bull
23
 * @author Casey Best and Rob Lintern
23
 * @author Casey Best and Rob Lintern
24
 */
24
 */
25
public class GridLayoutAlgorithm extends AbstractLayoutAlgorithm {
25
public class GridLayoutAlgorithm implements LayoutAlgorithm {
26
	
26
	
27
	private static final double PADDING_PERCENTAGE = 0.95;
27
	private static final double PADDING_PERCENTAGE = 0.95;
28
	private static final int MIN_ENTITY_SIZE = 5;
28
29
30
	protected double aspectRatio = 1.0;
29
	protected int rowPadding = 0;
31
	protected int rowPadding = 0;
30
	
32
	private boolean resize = false;
31
	public void setLayoutArea(double x, double y, double width, double height) {
33
	protected int rows, cols, numChildren;
32
		throw new RuntimeException("Operation not implemented");
34
	protected double colWidth, rowHeight, offsetX, offsetY;
35
	protected double childrenHeight, childrenWidth;
36
37
	private LayoutContext context;
38
39
40
	public void setLayoutContext(LayoutContext context) {
41
		this.context = context;
33
	}
42
	}
34
	
35
    int rows, cols, numChildren; 
36
    double colWidth, rowHeight, offsetX, offsetY;
37
    int totalProgress;
38
    double h, w;
39
    
43
    
40
    /**
44
	public void applyLayout(boolean clean) {
41
     * Initializes the grid layout.
45
		if (!clean)
42
     * @param styles
46
			return;
43
     * @see LayoutStyles
47
		DisplayIndependentRectangle bounds = context.getBounds();
44
     */
48
		calculateGrid(bounds);
45
	public GridLayoutAlgorithm(int styles) {
49
		applyLayoutInternal(context.getEntities(), bounds);
46
		super(styles);
47
	}
50
	}
48
	
51
49
	/**
52
	/**
50
	 * Inititalizes the grid layout with no style.
53
	 * Calculates all the dimensions of grid that layout entities will be fit
54
	 * in. The following fields are set by this method: {@link #numChildren},
55
	 * {@link #rows}, {@link #cols}, {@link #colWidth}, {@link #rowHeight},
56
	 * {@link #offsetX}, {@link #offsetY}
57
	 * 
58
	 * @param bounds
51
	 */
59
	 */
52
	public GridLayoutAlgorithm() {
60
    protected void calculateGrid(DisplayIndependentRectangle bounds) {
53
		this(LayoutStyles.NONE);
61
		numChildren = context.getNodes().length;
54
	}
62
		int[] result = calculateNumberOfRowsAndCols(numChildren, bounds.x, bounds.y, bounds.width, bounds.height);
55
63
		cols = result[0];
56
    
64
		rows = result[1];
57
    protected int getCurrentLayoutStep() {
58
    	// TODO: This isn't right
59
    	return 0;
60
    }
61
    
62
    protected int getTotalNumberOfLayoutSteps() {
63
    	return totalProgress;
64
    }
65
66
    /**
67
     * 
68
     */
69
	protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) {
70
		
65
		
71
		// TODO: Filter unwanted entities and relationships
66
		colWidth = bounds.width / cols;
72
		//super.applyLayout (entitiesToLayout, relationshipsToConsider, boundsX, boundsY, boundsWidth, boundsHeight);
67
		rowHeight = bounds.height / rows;
73
		// now begin
74
		numChildren = entitiesToLayout.length;
75
		if (numChildren < 1) return;
76
		
68
		
77
		int[] colsAndRows = calculateNumberOfRowsAndCols(numChildren, x, y, width, height);
78
		cols = colsAndRows[0];
79
		rows = colsAndRows[1];
80
81
		totalProgress = rows + 2;
82
		fireProgressEvent (1, totalProgress);
83
84
		// sort the entities
85
		if (comparator != null) {
86
            Arrays.sort(entitiesToLayout, comparator);
87
		} else {
88
			Arrays.sort(entitiesToLayout);
89
		}
90
		fireProgressEvent (2, totalProgress);
91
92
		// Calculate row height and column width
93
		colWidth = width/cols;	
94
		rowHeight = height/rows;	
95
96
		// Calculate amount to scale children
97
		double [] nodeSize = calculateNodeSize (colWidth, rowHeight);
69
		double [] nodeSize = calculateNodeSize (colWidth, rowHeight);
98
		w = nodeSize[0];
70
		childrenWidth = nodeSize[0];
99
		h = nodeSize[1];
71
		childrenHeight = nodeSize[1];
100
		offsetX = (colWidth - w)/2.0; // half of the space between columns
72
		offsetX = (colWidth - childrenWidth) / 2.0; // half of the space between
101
		offsetY = (rowHeight - h)/2.0; // half of the space between rows
73
													// columns
74
		offsetY = (rowHeight - childrenHeight) / 2.0; // half of the space
75
														// between rows
102
	}
76
	}
103
	
77
104
	/**
78
	/**
105
	 * Use this algorithm to layout the given entities, using the given relationships and bounds.
79
	 * Use this algorithm to layout the given entities and bounds. The entities
106
	 * The entities will be placed in the same order as they are passed in, unless a comparator
80
	 * will be placed in the same order as they are passed in, unless a
107
	 * is supplied.  
81
	 * comparator is supplied.
108
	 * 
82
	 * 
109
	 * @param entitiesToLayout Apply the algorithm to these entities
83
	 * @param entitiesToLayout
110
	 * @param relationshipsToConsider Only consider these relationships when applying the algorithm.
84
	 *            apply the algorithm to these entities
111
	 * @param boundsX The left side of the bounds in which the layout can place the entities.
85
	 * @param bounds
112
	 * @param boundsY The top side of the bounds in which the layout can place the entities.
86
	 *            the bounds in which the layout can place the entities.
113
	 * @param boundsWidth The width of the bounds in which the layout can place the entities.
114
	 * @param boundsHeight The height of the bounds in which the layout can place the entities.
115
	 * @throws RuntimeException Thrown if entitiesToLayout doesn't contain all of the endpoints for each relationship in relationshipsToConsider
116
	 */
87
	 */
117
	protected synchronized void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY, double boundsWidth, double boundsHeight) {
88
	protected synchronized void applyLayoutInternal(EntityLayout[] entitiesToLayout, DisplayIndependentRectangle bounds) {
118
		
89
		
119
		int index = 0;
90
		int index = 0;
120
		for( int i = 0; i < rows; i++ ) {
91
		for( int i = 0; i < rows; i++ ) {
121
			for( int j = 0; j < cols; j++ ) {
92
			for( int j = 0; j < cols; j++ ) {
122
				if( (i*cols + j) < numChildren ) {
93
				if( (i*cols + j) < numChildren ) {
123
					// find new position for child
94
					EntityLayout node = entitiesToLayout[index++];
124
					double xmove = boundsX + j * colWidth + offsetX;
95
					if (resize && node.isResizable())
125
					double ymove = boundsY + i * rowHeight + offsetY;
96
						node.setSize(Math.max(childrenWidth, MIN_ENTITY_SIZE), Math.max(childrenHeight, MIN_ENTITY_SIZE));
126
					InternalNode sn = entitiesToLayout[index++];
97
					DisplayIndependentDimension size = node.getSize();
127
					sn.setInternalLocation( xmove, ymove );
98
					double xmove = bounds.x + j * colWidth + offsetX + size.width / 2;
128
					sn.setInternalSize( Math.max(w, MIN_ENTITY_SIZE), Math.max(h, MIN_ENTITY_SIZE) );
99
					double ymove = bounds.y + i * rowHeight + offsetY + size.height / 2;
100
					if (node.isMovable())
101
						node.setLocation(xmove, ymove);
129
				}
102
				}
130
			}
103
			}
131
			fireProgressEvent (2 + i, totalProgress);
104
		}
132
		}	
133
		updateLayoutLocations(entitiesToLayout);
134
		fireProgressEvent (totalProgress, totalProgress);
135
	}
136
	
137
	protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) {
138
		
139
	}
105
	}
140
106
141
	/**
107
	/**
142
	 * Calculates and returns an array containing the number of columns, followed by the number of rows
108
	 * Calculates and returns an array containing the number of columns, followed by the number of rows
143
	 */
109
	 */
144
	protected int[] calculateNumberOfRowsAndCols (int numChildren, double boundX, double boundY, double boundWidth, double boundHeight) {
110
	protected int[] calculateNumberOfRowsAndCols(int numChildren, double boundX, double boundY, double boundWidth, double boundHeight) {
145
		if (getEntityAspectRatio() == 1.0) {
111
		if (aspectRatio == 1.0) {
146
			return calculateNumberOfRowsAndCols_square (numChildren, boundX, boundY, boundWidth, boundHeight);
112
			return calculateNumberOfRowsAndCols_square (numChildren, boundX, boundY, boundWidth, boundHeight);
147
		} else {
113
		} else {
148
			return calculateNumberOfRowsAndCols_rectangular (numChildren);
114
			return calculateNumberOfRowsAndCols_rectangular (numChildren);
Lines 201-233 Link Here
201
		double childW = Math.max (MIN_ENTITY_SIZE, PADDING_PERCENTAGE*colWidth);	
167
		double childW = Math.max (MIN_ENTITY_SIZE, PADDING_PERCENTAGE*colWidth);	
202
		double childH = Math.max (MIN_ENTITY_SIZE, PADDING_PERCENTAGE*(rowHeight - rowPadding));	
168
		double childH = Math.max (MIN_ENTITY_SIZE, PADDING_PERCENTAGE*(rowHeight - rowPadding));	
203
		double whRatio = colWidth/rowHeight;
169
		double whRatio = colWidth/rowHeight;
204
		if (whRatio < getEntityAspectRatio()) {
170
		if (whRatio < aspectRatio) {
205
			childH = childW/getEntityAspectRatio();		
171
			childH = childW / aspectRatio;
206
		} else {
172
		} else {
207
			childW = childH*getEntityAspectRatio();
173
			childW = childH * aspectRatio;
208
		}
174
		}
209
		double [] result = {childW, childH};
175
		double [] result = {childW, childH};
210
		return result;
176
		return result;
211
	}
177
	}
212
	
178
213
	/**
179
	/**
214
	 * Increases the padding between rows in the grid
180
	 * Sets the padding between rows in the grid
215
	 * @param rowPadding Value will not be set if less than 0.
181
	 * 
182
	 * @param rowPadding
183
	 *            padding - should be greater than or equal to 0
216
	 */
184
	 */
217
    public void setRowPadding(int rowPadding) {
185
    public void setRowPadding(int rowPadding) {
218
        if (rowPadding < 0 ) {
186
		if (rowPadding >= 0) {
219
            return;
187
			this.rowPadding = rowPadding;
220
        }
188
        }
221
        this.rowPadding = rowPadding;
222
    }
189
    }
223
190
224
	protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) {
191
	/**
225
		if ( asynchronous && continueous ) return false;
192
	 * Sets the preferred aspect ratio for layout entities. The default aspect
226
		else if ( asynchronous && !continueous ) return true;
193
	 * ratio is 1.
227
		else if ( !asynchronous && continueous ) return false;
194
	 * 
228
		else if ( !asynchronous && !continueous ) return true;
195
	 * @param aspectRatio
229
		
196
	 *            aspect ratio - should be greater than 0
230
		return false;
197
	 */
198
	public void setAspectRatio(double aspectRatio) {
199
		if (aspectRatio > 0) {
200
			this.aspectRatio = aspectRatio;
201
		}
202
	}
203
204
	/**
205
	 * 
206
	 * @return true if this algorithm is set to resize elements
207
	 */
208
	public boolean isResizing() {
209
		return resize;
210
	}
211
212
	/**
213
	 * 
214
	 * @param resizing
215
	 *            true if this algorithm should resize elements (default is
216
	 *            false)
217
	 */
218
	public void setResizing(boolean resizing) {
219
		resize = resizing;
231
	}
220
	}
232
221
233
}
222
}
(-)src/org/eclipse/zest/layouts/algorithms/HorizontalTreeLayoutAlgorithm.java (-68 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
12
13
import org.eclipse.zest.layouts.LayoutStyles;
14
import org.eclipse.zest.layouts.dataStructures.InternalNode;
15
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;
16
17
18
19
20
/**
21
 * A simple algorithm to arrange graph nodes in a layered horizontal tree-like layout. 
22
 * @see TreeLayoutAlgorithm
23
 * 
24
 * @version  1.0
25
 * @author   Rob Lintern
26
 */
27
public class HorizontalTreeLayoutAlgorithm extends TreeLayoutAlgorithm {
28
29
	
30
	/**
31
	 * Creates a horizontal tree layout with no style
32
	 */
33
	public HorizontalTreeLayoutAlgorithm() {
34
		this( LayoutStyles.NONE );
35
	}
36
	
37
    /**
38
     * 
39
     */
40
    public HorizontalTreeLayoutAlgorithm( int styles ) {
41
        super( styles );
42
    }
43
    
44
    protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) {
45
        // NOTE: width and height are swtiched here when calling super method
46
        super.preLayoutAlgorithm(entitiesToLayout, relationshipsToConsider, x, y, height, width); 
47
    }
48
    
49
    protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) {
50
        // swap x->y and width->height
51
        for (int i = 0; i < entitiesToLayout.length; i++) {
52
            InternalNode entity = entitiesToLayout[i];
53
			entity.setInternalLocation(entity.getInternalY(), entity.getInternalX() );
54
			entity.setInternalSize( entity.getInternalWidth(), entity.getInternalHeight() );
55
        }
56
    	super.postLayoutAlgorithm(entitiesToLayout, relationshipsToConsider);
57
    }
58
    
59
    protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) {
60
		if ( asynchronous && continueous ) return false;
61
		else if ( asynchronous && !continueous ) return true;
62
		else if ( !asynchronous && continueous ) return false;
63
		else if ( !asynchronous && !continueous ) return true;
64
		
65
		return false;
66
    }
67
68
}
(-)src/org/eclipse/zest/layouts/algorithms/SpringLayoutAlgorithm.java (-480 / +277 lines)
Lines 1-23 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright (c) 2005-2009 The Chisel Group and others. All rights reserved. This
3
 * All rights reserved. This program and the accompanying materials
3
 * program and the accompanying materials are made available under the terms of
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * which accompanies this distribution, and is available at
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 *
7
 * Contributors: The Chisel Group - initial API and implementation
8
 * Contributors:
8
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 *     The Chisel Group, University of Victoria
9
 *               Ian Bull
10
 *******************************************************************************/
10
 ******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
11
package org.eclipse.zest.layouts.algorithms;
12
12
13
import java.util.Date;
14
import java.util.HashMap;
13
import java.util.HashMap;
15
import java.util.Map;
16
14
17
import org.eclipse.zest.layouts.LayoutStyles;
15
import org.eclipse.zest.layouts.LayoutAlgorithm;
16
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension;
17
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint;
18
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
18
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
19
import org.eclipse.zest.layouts.dataStructures.InternalNode;
19
import org.eclipse.zest.layouts.interfaces.ConnectionLayout;
20
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;
20
import org.eclipse.zest.layouts.interfaces.EntityLayout;
21
import org.eclipse.zest.layouts.interfaces.LayoutContext;
22
import org.eclipse.zest.layouts.interfaces.LayoutListener;
23
import org.eclipse.zest.layouts.interfaces.NodeLayout;
24
import org.eclipse.zest.layouts.interfaces.SubgraphLayout;
21
25
22
/**
26
/**
23
 * The SpringLayoutAlgorithm has its own data repository and relation
27
 * The SpringLayoutAlgorithm has its own data repository and relation
Lines 37-45 Link Here
37
 * @author Ian Bull
41
 * @author Ian Bull
38
 * @author Casey Best (version 1.0 by Jingwei Wu/Rob Lintern)
42
 * @author Casey Best (version 1.0 by Jingwei Wu/Rob Lintern)
39
 */
43
 */
40
public class SpringLayoutAlgorithm extends ContinuousLayoutAlgorithm {
44
public class SpringLayoutAlgorithm implements LayoutAlgorithm {
41
42
    private final static boolean DEFAULT_ANCHOR = false;
43
45
44
    /**
46
    /**
45
     * The default value for the spring layout number of interations.
47
     * The default value for the spring layout number of interations.
Lines 57-72 Link Here
57
    public static final boolean DEFAULT_SPRING_RANDOM = true;
59
    public static final boolean DEFAULT_SPRING_RANDOM = true;
58
60
59
    /**
61
    /**
60
     * The default value for ignoring unconnected nodes.
61
     */
62
    public static final boolean DEFAULT_SPRING_IGNORE_UNCON = true;
63
64
    /**
65
     * The default value for separating connected components.
66
     */
67
    public static final boolean DEFAULT_SPRING_SEPARATE_COMPONENTS = true;
68
69
    /**
70
     * The default value for the spring layout move-control.
62
     * The default value for the spring layout move-control.
71
     */
63
     */
72
    public static final double DEFAULT_SPRING_MOVE = 1.0f;
64
    public static final double DEFAULT_SPRING_MOVE = 1.0f;
Lines 74-80 Link Here
74
    /**
66
    /**
75
     * The default value for the spring layout strain-control.
67
     * The default value for the spring layout strain-control.
76
     */
68
     */
77
    public static final double DEFAULT_SPRING_STRAIN = 1.0f;
69
	public static final double DEFAULT_SPRING_STRAIN = 1.0f;
78
70
79
    /**
71
    /**
80
     * The default value for the spring layout length-control.
72
     * The default value for the spring layout length-control.
Lines 84-212 Link Here
84
    /**
76
    /**
85
     * The default value for the spring layout gravitation-control.
77
     * The default value for the spring layout gravitation-control.
86
     */
78
     */
87
    public static final double DEFAULT_SPRING_GRAVITATION = 1.0f;
79
	public static final double DEFAULT_SPRING_GRAVITATION = 1.0f;
88
80
89
    /**
81
	/**
90
     * The variable can be customized to set the number of iterations used.
82
	 * Minimum distance considered between nodes
91
     */
83
	 */
92
    private static int sprIterations = DEFAULT_SPRING_ITERATIONS;
84
	protected static final double MIN_DISTANCE = 0.001d;
85
86
	/**
87
	 * An arbitrarily small value in mathematics.
88
	 */
89
	protected static final double EPSILON = 0.001d;
90
91
	/**
92
	 * The variable can be customized to set the number of iterations used.
93
	 */
94
	private int sprIterations = DEFAULT_SPRING_ITERATIONS;
93
95
94
    /**
96
    /**
95
     * This variable can be customized to set the max number of MS the algorithm
97
     * This variable can be customized to set the max number of MS the algorithm
96
     * should run
98
     * should run
97
     */
99
     */
98
    private static long maxTimeMS = MAX_SPRING_TIME;
100
	private long maxTimeMS = MAX_SPRING_TIME;
99
101
100
    /**
102
    /**
101
     * The variable can be customized to set whether or not the spring layout
103
     * The variable can be customized to set whether or not the spring layout
102
     * nodes are positioned randomly before beginning iterations.
104
     * nodes are positioned randomly before beginning iterations.
103
     */
105
     */
104
    private static boolean sprRandom = DEFAULT_SPRING_RANDOM;
106
	private boolean sprRandom = DEFAULT_SPRING_RANDOM;
105
106
    /**
107
     * Minimum distance considered between nodes
108
     */
109
    protected static final double MIN_DISTANCE = 0.001d;
110
111
    /**
112
     * An arbitrarily small value in mathematics.
113
     */
114
    protected static final double EPSILON = 0.001d;
115
107
116
    /**
108
	/**
117
     * The variable can be customerized to set the spring layout move-control.
109
	 * The variable can be customized to set the spring layout move-control.
118
     */
110
	 */
119
    private static double sprMove = DEFAULT_SPRING_MOVE;
111
    private double sprMove = DEFAULT_SPRING_MOVE;
120
112
121
    /**
113
    /**
122
     * The variable can be customized to set the spring layout strain-control.
114
     * The variable can be customized to set the spring layout strain-control.
123
     */
115
     */
124
    private static double sprStrain = DEFAULT_SPRING_STRAIN;
116
	private double sprStrain = DEFAULT_SPRING_STRAIN;
125
117
126
    /**
118
    /**
127
     * The variable can be customized to set the spring layout length-control.
119
     * The variable can be customized to set the spring layout length-control.
128
     */
120
     */
129
    private static double sprLength = DEFAULT_SPRING_LENGTH;
121
	private double sprLength = DEFAULT_SPRING_LENGTH;
130
122
131
    /**
123
    /**
132
     * The variable can be customized to set the spring layout
124
     * The variable can be customized to set the spring layout
133
     * gravitation-control.
125
     * gravitation-control.
134
     */
126
     */
135
    private static double sprGravitation = DEFAULT_SPRING_GRAVITATION;
127
	private double sprGravitation = DEFAULT_SPRING_GRAVITATION;
136
128
137
    /**
129
	/**
138
     * The largest movement of all vertices that has occured in the most recent
130
	 * Variable indicating whether the algorithm should resize elements.
139
     * iteration.
131
	 */
140
     */
132
	private boolean resize = false;
141
    private double largestMovement = 0;
142
133
134
    private int iteration;
143
135
144
    /**
136
	private double[][] srcDestToSumOfWeights;
145
     * Maps a src and dest object to the number of relations between them. Key
146
     * is src.toString() + dest.toString(), value is an Integer
147
     */
148
    private Map srcDestToNumRelsMap;
149
137
150
    /**
138
	private EntityLayout[] entities;
151
     * Maps a src and dest object to the average weight of the relations between
152
     * them. Key is src.toString() + dest.toString(), value is a Double
153
     */
154
    private Map srcDestToRelsAvgWeightMap;
155
139
156
    /**
140
	private double[] forcesX, forcesY;
157
     * Maps a relationship type to a weight. Key is a string, value is a Double
158
     */
159
    private static Map relTypeToWeightMap = new HashMap();
160
141
161
    private int iteration;
142
	private double[] locationsX, locationsY;
162
143
163
    private int[][] srcDestToNumRels;
144
	private double[] sizeW, sizeH;
164
145
165
    private double[][] srcDestToRelsAvgWeight;
146
	private DisplayIndependentRectangle bounds;
166
147
167
    private double[] tempLocationsX;
148
	private double boundsScale = 0.2;
168
149
169
    private double[] tempLocationsY;
150
	private LayoutContext context;
170
151
171
    private double[] forcesX;
152
	private LayoutListener springLayoutListener = new LayoutListener() {
172
153
173
    private double[] forcesY;
154
		public boolean entityMoved(LayoutContext context, EntityLayout entity) {
155
			updateLocation(entity);
156
			return false;
157
		}
174
158
175
    private boolean[] anchors;
159
		public boolean entityResized(LayoutContext context, EntityLayout entity) {
176
    
160
			updateLocation(entity);
177
    private DisplayIndependentRectangle bounds = null;
161
			return false;
178
    
162
		}
179
    Date date = null;
180
163
181
    /**
164
		private void updateLocation(EntityLayout entity) {
182
     * Constructor.
165
			if (entities != null) {
183
     */
166
				for (int i = 0; i < entities.length; i++) {
184
    public SpringLayoutAlgorithm( int styles ) {
167
					if (entities[i] == entity) {
185
        super( styles );
168
						locationsX[i] = entities[i].getLocation().x;
186
        srcDestToNumRelsMap = new HashMap();
169
						locationsY[i] = entities[i].getLocation().y;
187
        srcDestToRelsAvgWeightMap = new HashMap();
170
					}
188
        date = new Date();
171
				}
189
    }
172
			}
173
		}
174
	};
190
175
191
    
176
	public void applyLayout(boolean clean) {
192
    /**
177
		if (!clean)
193
     * Creates a sprint layout algoirthm with no style
178
			return;
194
     *
179
195
     */
180
		initLayout();
196
    public SpringLayoutAlgorithm() {
181
		while (performAnotherNonContinuousIteration()) {
197
    	this( LayoutStyles.NONE );
182
			computeOneIteration();
183
		}
184
		saveLocations();
185
		if (resize)
186
			AlgorithmHelper.maximizeSizes(entities);
187
188
		DisplayIndependentRectangle bounds2 = new DisplayIndependentRectangle(bounds);
189
		AlgorithmHelper.fitWithinBounds(entities, bounds2, resize);
198
	}
190
	}
199
    
191
    
200
    public void setLayoutArea(double x, double y, double width, double height) {
192
	public void setLayoutContext(LayoutContext context) {
201
        bounds = new DisplayIndependentRectangle(x,y,width,height);
193
		if (this.context != null) {
202
    }
194
			this.context.removeLayoutListener(springLayoutListener);
195
		}
196
		this.context = context;
197
		this.context.addLayoutListener(springLayoutListener);
198
	}
203
199
204
    /**
200
	public void performOneIteration() {
205
     * Sets the spring layout move-control.
201
		if (entities == null) {
206
     * 
202
			initLayout();
207
     * @param move
203
		}
208
     *            The move-control value.
204
		bounds = context.getBounds();
209
     */
205
		computeOneIteration();
206
		saveLocations();
207
		context.flushChanges(false);
208
	}
209
210
	/**
211
	 * 
212
	 * @return true if this algorithm is set to resize elements
213
	 */
214
	public boolean isResizing() {
215
		return resize;
216
	}
217
218
	/**
219
	 * 
220
	 * @param resizing
221
	 *            true if this algorithm should resize elements (default is
222
	 *            false)
223
	 */
224
	public void setResizing(boolean resizing) {
225
		resize = resizing;
226
	}
227
228
	/**
229
	 * Sets the spring layout move-control.
230
	 * 
231
	 * @param move
232
	 *            The move-control value.
233
	 */
210
    public void setSpringMove(double move) {
234
    public void setSpringMove(double move) {
211
        sprMove = move;
235
        sprMove = move;
212
    }
236
    }
Lines 337-528 Link Here
337
        return sprRandom;
361
        return sprRandom;
338
    }
362
    }
339
363
340
    public void setWeight(String relType, double weight) {
341
        relTypeToWeightMap.put(relType, new Double(weight));
342
    }
343
344
    public double getWeight(String relType) {
345
        Double weight = (Double) relTypeToWeightMap.get(relType);
346
        return (weight == null) ? 1 : weight.doubleValue();
347
    }
348
349
    /**
350
     * Sets the default conditions.
351
     */
352
    public void setDefaultConditions() {
353
        // sprMove = DEFAULT_SPRING_MOVE;
354
        // sprStrain = DEFAULT_SPRING_STRAIN;
355
        // sprLength = DEFAULT_SPRING_LENGTH;
356
        // sprGravitation = DEFAULT_SPRING_GRAVITATION;
357
        // sprIterations = DEFAULT_SPRING_ITERATIONS;
358
    }
359
360
    /**
361
     * Clean up after done
362
     * 
363
     * @param entitiesToLayout
364
     */
365
    private void reset(InternalNode[] entitiesToLayout) {
366
        tempLocationsX = null;
367
        tempLocationsY = null;
368
        forcesX = null;
369
        forcesY = null;
370
        anchors = null;
371
        setDefaultConditions();
372
        srcDestToNumRelsMap = new HashMap();
373
        srcDestToRelsAvgWeightMap = new HashMap();
374
        relTypeToWeightMap = new HashMap();
375
    }
376
377
    private long startTime = 0;
364
    private long startTime = 0;
378
365
379
    protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) {
366
	private void initLayout() {
380
        // TODO: Filter out any non-wanted entities and relationships
367
		entities = context.getEntities();
381
        // super.applyLayout(entitiesToLayout, relationshipsToConsider, x, y,
368
		bounds = context.getBounds();
382
        // width, height);
369
		loadLocations();
383
        //InternalNode[] a_entitiesToLayout = (InternalNode[]) entitiesToLayout.toArray(new InternalNode[entitiesToLayout.size()]);
370
384
    	bounds = new DisplayIndependentRectangle(x,y,width,height);
371
		srcDestToSumOfWeights = new double[entities.length][entities.length];
385
        tempLocationsX = new double[entitiesToLayout.length];
372
		HashMap entityToPosition = new HashMap();
386
        tempLocationsY = new double[entitiesToLayout.length];
373
		for (int i = 0; i < entities.length; i++) {
387
        forcesX = new double[entitiesToLayout.length];
374
			entityToPosition.put(entities[i], new Integer(i));
388
        forcesY = new double[entitiesToLayout.length];
375
		}
389
        anchors = new boolean[entitiesToLayout.length];
376
390
        
377
		ConnectionLayout[] connections = context.getConnections();
391
        for (int i = 0; i < entitiesToLayout.length; i++) {
378
		for (int i = 0; i < connections.length; i++) {
392
            anchors[i] = DEFAULT_ANCHOR;
379
			ConnectionLayout connection = connections[i];
393
        }
380
			Integer source = (Integer) entityToPosition.get(getEntity(connection.getSource()));
394
        for (int i = 0; i < relationshipsToConsider.length; i++) {
381
			Integer target = (Integer) entityToPosition.get(getEntity(connection.getTarget()));
395
            InternalRelationship layoutRelationship = relationshipsToConsider[i];
382
			if (source == null || target == null)
396
            addRelation(layoutRelationship);
383
				continue;
397
        }
384
			double weight = connection.getWeight();
398
385
			weight = (weight <= 0 ? 0.1 : weight);
399
        // do the calculations
386
			srcDestToSumOfWeights[source.intValue()][target.intValue()] += weight;
400
        preCompute(entitiesToLayout);
387
			srcDestToSumOfWeights[target.intValue()][source.intValue()] += weight;
401
        startTime = date.getTime();
388
		}
402
    }
403
404
    protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) {
405
        reset(entitiesToLayout);
406
    }
407
408
    /**
409
     * Adds a simple relation between two nodes to the relation repository.
410
     * 
411
     * @param layoutRelationship
412
     *            The simple relation to be added
413
     * @throws java.lang.NullPointerExcetption
414
     *             If <code>sr</code> is null
415
     * @see SimpleRelation
416
     */
417
    private void addRelation(InternalRelationship layoutRelationship) {
418
        if (layoutRelationship == null) {
419
            throw new IllegalArgumentException("The arguments can not be null!");
420
        } else {
421
            double weight = layoutRelationship.getWeight();
422
            weight = (weight <= 0 ? 0.1 : weight);
423
            String key1 = layoutRelationship.getSource().toString() + layoutRelationship.getDestination().toString();
424
            String key2 = layoutRelationship.getDestination().toString() + layoutRelationship.getSource().toString();
425
            String[] keys = { key1, key2 };
426
            for (int i = 0; i < keys.length; i++) {
427
                String key = keys[i];
428
                Integer count = (Integer) srcDestToNumRelsMap.get(key);
429
                Double avgWeight = (Double) srcDestToRelsAvgWeightMap.get(key);
430
                if (count == null) {
431
                    count = new Integer(1);
432
                    avgWeight = new Double(weight);
433
                } else {
434
                    int newCount = count.intValue() + 1;
435
                    double newAverage = (avgWeight.doubleValue() * count.doubleValue() + weight) / newCount;
436
                    avgWeight = new Double(newAverage);
437
                    count = new Integer(newCount);
438
                }
439
                srcDestToNumRelsMap.put(key, count);
440
                srcDestToRelsAvgWeightMap.put(key, avgWeight);
441
            }
442
        }
443
    }
444
445
    private void preCompute(InternalNode [] entitiesToLayout) {
446
        // count number of relationships between all nodes and the average
447
        // weight between them
448
        srcDestToNumRels = new int[entitiesToLayout.length][entitiesToLayout.length];
449
        srcDestToRelsAvgWeight = new double[entitiesToLayout.length][entitiesToLayout.length];
450
451
        for (int i = 0; i < entitiesToLayout.length - 1; i++) {
452
            InternalNode layoutEntity1 = entitiesToLayout[i];
453
            for (int j = i + 1; j < entitiesToLayout.length; j++) {
454
                InternalNode layoutEntity2 = entitiesToLayout[j];
455
                srcDestToNumRels[i][j] = numRelations(layoutEntity1, layoutEntity2);
456
                srcDestToNumRels[i][j] += numRelations(layoutEntity2, layoutEntity1);
457
                srcDestToRelsAvgWeight[i][j] = avgWeight(layoutEntity1, layoutEntity2);
458
            }
459
        }
460
389
461
        if (sprRandom)
390
        if (sprRandom)
462
            placeRandomly(entitiesToLayout); // put vertices in random places
391
			placeRandomly(); // put vertices in random places
463
        else
464
            convertToUnitCoordinates(entitiesToLayout);
465
392
466
        iteration = 1;
393
        iteration = 1;
467
        largestMovement = Double.MAX_VALUE;
468
    }
469
394
470
    // TODO: This is a complete Clone! (and not in a good way)
395
		startTime = System.currentTimeMillis();
471
    protected DisplayIndependentRectangle getLayoutBoundsTemp(InternalNode [] entitiesToLayout, boolean includeNodeSize) {
472
        double rightSide = Double.MIN_VALUE;
473
        double bottomSide = Double.MIN_VALUE;
474
        double leftSide = Double.MAX_VALUE;
475
        double topSide = Double.MAX_VALUE;
476
        for (int i = 0; i < entitiesToLayout.length; i++) {
477
            double x = tempLocationsX[i];
478
            double y = tempLocationsY[i];
479
480
            leftSide = Math.min(x, leftSide);
481
            topSide = Math.min(y, topSide);
482
            rightSide = Math.max(x, rightSide);
483
            bottomSide = Math.max(y, bottomSide);
484
485
        }
486
        return new DisplayIndependentRectangle(leftSide, topSide, rightSide - leftSide, bottomSide - topSide);
487
    }
396
    }
488
397
489
    protected void convertNodePositionsBack(int i, InternalNode entityToConvert, double px, double py, double screenWidth, double screenHeight, DisplayIndependentRectangle layoutBounds) {
398
	private EntityLayout getEntity(NodeLayout node) {
490
    	
399
		if (!node.isPruned())
491
    	// If the node selected is outside the screen, map it to the boarder
400
			return node;
492
    	if ( px > screenWidth ) px = screenWidth;
401
		SubgraphLayout subgraph = node.getSubgraph();
493
    	if ( py > screenHeight ) py = screenHeight;
402
		if (subgraph.isGraphEntity())
494
    	
403
			return subgraph;
495
    	if ( px < 0 ) px = 1;
404
		return null;
496
    	if ( py < 0 ) py = 1;
405
	}
497
    	
498
        double x = (px / screenWidth) * layoutBounds.width + layoutBounds.x;
499
        double y = (py / screenHeight) * layoutBounds.height + layoutBounds.y;
500
        
501
        tempLocationsX[i] = x;
502
        tempLocationsY[i] = y;
503
        //setTempLocation(entityToConvert, new DisplayIndependentPoint(x, y));
504
505
        if (entityToConvert.getInternalX() < 0) {
506
            // System.out.println("We have nodes less than 0 here!");
507
        }
508
406
509
    }
407
    private void loadLocations() {
408
		if (locationsX == null || locationsX.length != entities.length) {
409
			int length = entities.length;
410
			locationsX = new double[length];
411
			locationsY = new double[length];
412
			sizeW = new double[length];
413
			sizeH = new double[length];
414
			forcesX = new double[length];
415
			forcesY = new double[length];
416
		}
417
		for (int i = 0; i < entities.length; i++) {
418
			DisplayIndependentPoint location = entities[i].getLocation();
419
			locationsX[i] = location.x;
420
			locationsY[i] = location.y;
421
			DisplayIndependentDimension size = entities[i].getSize();
422
			sizeW[i] = size.width;
423
			sizeH[i] = size.height;
424
		}
425
	}
510
426
511
    private void checkPreferredLocation(InternalNode [] entitiesToLayout, DisplayIndependentRectangle realBounds) {
427
	private void saveLocations() {
512
        // use 10% for the border - 5% on each side
428
		if (entities == null)
513
        double borderWidth = Math.min(realBounds.width, realBounds.height) / 10.0; 
429
			return;
514
        DisplayIndependentRectangle screenBounds = new DisplayIndependentRectangle(realBounds.x + borderWidth / 2.0, realBounds.y + borderWidth / 2.0, realBounds.width - borderWidth, realBounds.height - borderWidth);
430
		for (int i = 0; i < entities.length; i++) {
515
431
			entities[i].setLocation(locationsX[i], locationsY[i]);
516
        DisplayIndependentRectangle layoutBounds = getLayoutBoundsTemp(entitiesToLayout, false);
432
		}
517
        for (int i = 0; i < entitiesToLayout.length; i++) {
433
	}
518
            InternalNode layoutEntity = entitiesToLayout[i];
519
            if (layoutEntity.hasPreferredLocation()) {
520
                convertNodePositionsBack(i, layoutEntity, layoutEntity.getPreferredX(), layoutEntity.getPreferredY(), screenBounds.width, screenBounds.height, layoutBounds);
521
            }
522
        }
523
    }
524
434
525
    /**
435
	/**
526
     * Scales the current iteration counter based on how long the algorithm has
436
     * Scales the current iteration counter based on how long the algorithm has
527
     * been running for. You can set the MaxTime in maxTimeMS!
437
     * been running for. You can set the MaxTime in maxTimeMS!
528
     */
438
     */
Lines 530-536 Link Here
530
        if (maxTimeMS <= 0)
440
        if (maxTimeMS <= 0)
531
            return;
441
            return;
532
442
533
        long currentTime = date.getTime();
443
		long currentTime = System.currentTimeMillis();
534
        double fractionComplete = (double) ((double) (currentTime - startTime) / ((double) maxTimeMS));
444
        double fractionComplete = (double) ((double) (currentTime - startTime) / ((double) maxTimeMS));
535
        int currentIteration = (int) (fractionComplete * sprIterations);
445
        int currentIteration = (int) (fractionComplete * sprIterations);
536
        if (currentIteration > iteration) {
446
        if (currentIteration > iteration) {
Lines 541-550 Link Here
541
451
542
    protected boolean performAnotherNonContinuousIteration() {
452
    protected boolean performAnotherNonContinuousIteration() {
543
        setSprIterationsBasedOnTime();
453
        setSprIterationsBasedOnTime();
544
        if (iteration <= sprIterations && largestMovement >= sprMove)
454
		return (iteration <= sprIterations);
545
            return true;
546
        else
547
            return false;
548
    }
455
    }
549
456
550
    protected int getCurrentLayoutStep() {
457
    protected int getCurrentLayoutStep() {
Lines 554-599 Link Here
554
    protected int getTotalNumberOfLayoutSteps() {
461
    protected int getTotalNumberOfLayoutSteps() {
555
        return sprIterations;
462
        return sprIterations;
556
    }
463
    }
557
    
558
    protected void computeOneIteration(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) {
559
    	if ( bounds == null )
560
    		bounds = new DisplayIndependentRectangle(x,y,width,height);
561
        checkPreferredLocation(entitiesToLayout, bounds );
562
        computeForces(entitiesToLayout);
563
        largestMovement = Double.MAX_VALUE;
564
        computePositions(entitiesToLayout);
565
        
566
        for (int i = 0; i < entitiesToLayout.length; i++) {
567
            InternalNode layoutEntity = entitiesToLayout[i];
568
            layoutEntity.setInternalLocation(tempLocationsX[i], tempLocationsY[i]);
569
        }        
570
        
571
        defaultFitWithinBounds(entitiesToLayout, bounds);
572
464
465
	protected void computeOneIteration() {
466
		computeForces();
467
		computePositions();
468
		DisplayIndependentRectangle currentBounds = getLayoutBounds();
469
		improveBoundsScale(currentBounds);
470
		moveToCenter(currentBounds);
573
        iteration++;
471
        iteration++;
574
    }
472
    }
575
        
473
        
576
    /**
474
    /**
577
     * Puts vertices in random places, all between (0,0) and (1,1).
475
     * Puts vertices in random places, all between (0,0) and (1,1).
578
     */
476
     */
579
    public void placeRandomly(InternalNode[] entitiesToLayout) {
477
	public void placeRandomly() {
580
        // If only one node in the data repository, put it in the middle
478
        // If only one node in the data repository, put it in the middle
581
        if (entitiesToLayout.length == 1) {
479
		if (locationsX.length == 1) {
582
            // If only one node in the data repository, put it in the middle
480
            // If only one node in the data repository, put it in the middle
583
            tempLocationsX[0] = 0.5;
481
			locationsX[0] = bounds.x + 0.5 * bounds.width;
584
            tempLocationsY[0] = 0.5;
482
			locationsY[0] = bounds.y + 0.5 * bounds.height;
585
        } else {
483
        } else {
586
            for (int i = 0; i < entitiesToLayout.length; i++) {
484
			locationsX[0] = bounds.x;
587
                if (i == 0) {
485
			locationsY[0] = bounds.y;
588
                    tempLocationsX[i] = 0.0;
486
			locationsX[1] = bounds.x + bounds.width;
589
                    tempLocationsY[i] = 0.0;
487
			locationsY[1] = bounds.y + bounds.height;
590
                } else if (i == 1) {
488
			for (int i = 2; i < locationsX.length; i++) {
591
                    tempLocationsX[i] = 1.0;
489
				locationsX[i] = bounds.x + Math.random() * bounds.width;
592
                    tempLocationsY[i] = 1.0;
490
				locationsY[i] = bounds.y + Math.random() * bounds.height;
593
                } else {
594
                    tempLocationsX[i] = Math.random();
595
                    tempLocationsY[i] = Math.random();
596
                }
597
            }
491
            }
598
        }
492
        }
599
    }
493
    }
Lines 606-684 Link Here
606
     * Computes the force for each node in this SpringLayoutAlgorithm. The
500
     * Computes the force for each node in this SpringLayoutAlgorithm. The
607
     * computed force will be stored in the data repository
501
     * computed force will be stored in the data repository
608
     */
502
     */
609
    protected void computeForces(InternalNode[] entitiesToLayout) {
503
	protected void computeForces() {
610
504
611
        // initialize all forces to zero
505
        // initialize all forces to zero
612
        for (int i = 0; i < entitiesToLayout.length; i++) {
506
		for (int i = 0; i < forcesX.length; i++) {
613
            forcesX[i] = 0.0;
507
            forcesX[i] = 0.0;
614
            forcesY[i] = 0.0;
508
            forcesY[i] = 0.0;
615
        }
509
        }
616
617
        // TODO: Again really really slow!
510
        // TODO: Again really really slow!
618
511
619
        for (int i = 0; i < entitiesToLayout.length - 1; i++) {
512
		for (int i = 0; i < locationsX.length; i++) {
620
            InternalNode sourceEntity = entitiesToLayout[i];
513
621
            
514
			for (int j = i + 1; j < locationsX.length; j++) {
622
            double srcLocationX = tempLocationsX[i];
515
				double dx = (locationsX[i] - locationsX[j]) / bounds.width / boundsScale;
623
            double srcLocationY = tempLocationsY[i];
516
				double dy = (locationsY[i] - locationsY[j]) / bounds.height / boundsScale;
624
            double fx = forcesX[i]; // force in x direction
517
					double distance_sq = dx * dx + dy * dy;
625
            double fy = forcesY[i]; // force in y direction
518
					// make sure distance and distance squared not too small
626
            
519
					distance_sq = Math.max(MIN_DISTANCE * MIN_DISTANCE, distance_sq);
627
520
					double distance = Math.sqrt(distance_sq);
628
            for (int j = i + 1; j < entitiesToLayout.length; j++) {
629
                InternalNode destinationEntity = entitiesToLayout[j];
630
631
                if (!destinationEntity.equals(sourceEntity)) {
632
                    double destLocationX = tempLocationsX[j];
633
                    double destLocationY = tempLocationsY[j];
634
                    double dx = srcLocationX - destLocationX;
635
                    double dy = srcLocationY- destLocationY;
636
                    double distance = Math.sqrt(dx * dx + dy * dy);
637
                    double distance_sq = distance * distance;
638
                    // make sure distance and distance squared not too small
639
                    distance = Math.max(MIN_DISTANCE, distance);
640
521
641
                    // If there are relationships between srcObj and destObj
522
                    // If there are relationships between srcObj and destObj
642
                    // then decrease force on srcObj (a pull) in direction of destObj
523
                    // then decrease force on srcObj (a pull) in direction of destObj
643
                    // If no relation between srcObj and destObj then increase
524
                    // If no relation between srcObj and destObj then increase
644
                    // force on srcObj (a push) from direction of destObj.
525
                    // force on srcObj (a push) from direction of destObj.
645
                    int numRels = srcDestToNumRels[i][j];
526
					double sumOfWeights = srcDestToSumOfWeights[i][j];
646
                    double avgWeight = srcDestToRelsAvgWeight[i][j];
527
647
                    if (numRels > 0) {
528
					double f;
529
					if (sumOfWeights > 0) {
648
                        // nodes are pulled towards each other
530
                        // nodes are pulled towards each other
649
                        double f = sprStrain * Math.log(distance / sprLength) * numRels * avgWeight;
531
						f = -sprStrain * Math.log(distance / sprLength) * sumOfWeights;
650
                        
651
                        fx = fx - (f * dx / distance);
652
                        fy = fy - (f * dy / distance);
653
                        
654
                    } else {
532
                    } else {
655
                        // nodes are repelled from each other
533
                        // nodes are repelled from each other
656
                        //double f = Math.min(100, sprGravitation / (distance*distance));
534
						f = sprGravitation / (distance_sq);
657
                        double f = sprGravitation / (distance_sq);
658
                        fx = fx + (f * dx / distance);
659
                        fy = fy + (f * dy / distance);
660
                    }
535
                    }
536
					double dfx = f * dx / distance;
537
					double dfy = f * dy / distance;
661
538
662
                    // According to Newton, "for every action, there is an equal
539
					forcesX[i] += dfx;
663
                    // and opposite reaction."
540
					forcesY[i] += dfy;
664
                    // so give the dest an opposite force
665
                    forcesX[j] = forcesX[j] - fx;
666
                    forcesY[j] = forcesY[j] - fy;
667
                } 
668
            } 
669
670
            /*
671
             * //make sure forces aren't too big if (fx > 0 ) fx = Math.min(fx,
672
             * 10*sprMove); else fx = Math.max(fx, -10*sprMove); if (fy > 0) fy =
673
             * Math.min(fy, 10*sprMove); else fy = Math.max(fy, -10*sprMove);
674
             */
675
            forcesX[i] = fx;
676
            forcesY[i] = fy;
677
            // Remove the src object from the list of destinations since
678
            // we've already calculated the force from it on all other
679
            // objects.
680
            // dests.remove(srcObj);
681
541
542
					forcesX[j] -= dfx;
543
					forcesY[j] -= dfy;
544
			}
682
        }
545
        }
683
    }
546
    }
684
547
Lines 687-808 Link Here
687
     * The computed position will be stored in the data repository. position =
550
     * The computed position will be stored in the data repository. position =
688
     * position + sprMove * force
551
     * position + sprMove * force
689
     */
552
     */
690
    protected void computePositions(InternalNode[] entitiesToLayout) {
553
	protected void computePositions() {
691
        for (int i = 0; i < entitiesToLayout.length; i++) {
554
		for (int i = 0; i < entities.length; i++) {
692
            if (!anchors[i] || entitiesToLayout[i].hasPreferredLocation() ) {
555
			if (entities[i].isMovable()) {
693
                double oldX = tempLocationsX[i];
694
                double oldY = tempLocationsY[i];
695
                double deltaX = sprMove * forcesX[i];
556
                double deltaX = sprMove * forcesX[i];
696
                double deltaY = sprMove * forcesY[i];
557
                double deltaY = sprMove * forcesY[i];
697
558
698
                // constrain movement, so that nodes don't shoot way off to the edge
559
				// constrain movement, so that nodes don't shoot way off to the
699
                double maxMovement = 0.2d * sprMove;
560
				// edge
700
                if (deltaX >= 0) {
561
				double dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
701
                    deltaX = Math.min(deltaX, maxMovement);
562
				double maxMovement = 0.2d * sprMove;
702
                } else {
563
				if (dist > maxMovement) {
703
                    deltaX = Math.max(deltaX, -maxMovement);
564
					deltaX *= maxMovement / dist;
704
                }
565
					deltaY *= maxMovement / dist;
705
                if (deltaY >= 0) {
566
				}
706
                    deltaY = Math.min(deltaY, maxMovement);
707
                } else {
708
                    deltaY = Math.max(deltaY, -maxMovement);
709
                }
710
                
711
712
                largestMovement = Math.max(largestMovement, Math.abs(deltaX));
713
                largestMovement = Math.max(largestMovement, Math.abs(deltaY));
714
715
                double newX = oldX + deltaX;
716
                double newY = oldY + deltaY;
717
                tempLocationsX[i] = newX;
718
                tempLocationsY[i] = newY;
719
            }
720
            
721
        }
722
723
    }
724
725
    /**
726
     * Converts the position for each node in this SpringLayoutAlgorithm
727
     * to unit coordinates in double precision. The computed positions will be
728
     * still stored in the data repository.
729
     */
730
    protected void convertToUnitCoordinates(InternalNode[] entitiesToLayout) {
731
        double minX = Double.MAX_VALUE;
732
        double maxX = Double.MIN_VALUE;
733
        double minY = Double.MAX_VALUE;
734
        double maxY = Double.MIN_VALUE;
735
        for (int i = 0; i < entitiesToLayout.length; i++) {
736
            InternalNode layoutEntity = entitiesToLayout[i];
737
            minX = Math.min(minX, layoutEntity.getInternalX());
738
            minY = Math.min(minY, layoutEntity.getInternalY());
739
            maxX = Math.max(maxX, layoutEntity.getInternalX());
740
            maxY = Math.max(maxY, layoutEntity.getInternalY());
741
        }
742
567
743
        double spanX = maxX - minX;
568
				locationsX[i] += deltaX * bounds.width * boundsScale;
744
        double spanY = maxY - minY;
569
				locationsY[i] += deltaY * bounds.height * boundsScale;
745
        double maxSpan = Math.max(spanX, spanY);
746
747
        if (maxSpan > EPSILON) {
748
            for (int i = 0; i < entitiesToLayout.length; i++) {
749
                InternalNode layoutEntity = entitiesToLayout[i];
750
                double x = (layoutEntity.getInternalX() - minX) / spanX;
751
                double y = (layoutEntity.getInternalY() - minY) / spanY;
752
                tempLocationsX[i] = x;
753
                tempLocationsY[i] = y;
754
            }
570
            }
755
        } else {
756
            placeRandomly(entitiesToLayout);
757
        }
571
        }
758
    }
572
	}
759
760
    /**
761
     * Examines the number of specified relation between the <code>src</code>
762
     * and the <code>dest</code> that exist in this
763
     * SpringLayoutAlgorithm's relation repository.
764
     * 
765
     * @param src
766
     *            The source part of the relaton to be examined.
767
     * @param dest
768
     *            The destination part of the relation to be examined.
769
     * @return The number of relations between src and dest.
770
     */
771
    private int numRelations(Object src, Object dest) {
772
        String key = src.toString() + dest.toString();
773
        Integer count = (Integer) srcDestToNumRelsMap.get(key);
774
        int intCount = (count == null) ? 0 : count.intValue();
775
        return intCount;
776
    }
777
778
    /**
779
     * Returns the average weight between a src and dest object.
780
     * 
781
     * @param src
782
     * @param dest
783
     * @return The average weight between the given src and dest nodes
784
     */
785
    private double avgWeight(Object src, Object dest) {
786
        String key = src.toString() + dest.toString();
787
        Double avgWeight = (Double) srcDestToRelsAvgWeightMap.get(key);
788
        double doubleWeight = (avgWeight == null) ? 1 : avgWeight.doubleValue();
789
        return doubleWeight;
790
    }
791
792
793
    protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) {
794
        if (asynchronous && continueous)
795
            return true;
796
        else if (asynchronous && !continueous)
797
            return true;
798
        else if (!asynchronous && continueous)
799
            return false;
800
        else if (!asynchronous && !continueous)
801
            return true;
802
573
803
        return false;
574
	private DisplayIndependentRectangle getLayoutBounds() {
804
    }
575
		double minX, maxX, minY, maxY;
576
		minX = minY = Double.POSITIVE_INFINITY;
577
		maxX = maxY = Double.NEGATIVE_INFINITY;
578
579
		for (int i = 0; i < locationsX.length; i++) {
580
			maxX = Math.max(maxX, locationsX[i] + sizeW[i] / 2);
581
			minX = Math.min(minX, locationsX[i] - sizeW[i] / 2);
582
			maxY = Math.max(maxY, locationsY[i] + sizeH[i] / 2);
583
			minY = Math.min(minY, locationsY[i] - sizeH[i] / 2);
584
		}
585
		return new DisplayIndependentRectangle(minX, minY, maxX - minX, maxY - minY);
586
	}
805
587
588
	private void improveBoundsScale(DisplayIndependentRectangle currentBounds) {
589
		double boundaryProportion = Math.max(currentBounds.width / bounds.width, currentBounds.height / bounds.height);
590
		if (boundaryProportion < 0.9)
591
			boundsScale *= 1.01;
592
		if (boundaryProportion > 1)
593
			boundsScale /= 1.01;
594
	}
806
595
596
	private void moveToCenter(DisplayIndependentRectangle currentBounds) {
597
		double moveX = (currentBounds.x + currentBounds.width / 2) - (bounds.x + bounds.width / 2);
598
		double moveY = (currentBounds.y + currentBounds.height / 2) - (bounds.y + bounds.height / 2);
599
		for (int i = 0; i < locationsX.length; i++) {
600
			locationsX[i] -= moveX;
601
			locationsY[i] -= moveY;
602
		}
603
	}
807
}
604
}
808
605
(-)src/org/eclipse/zest/layouts/algorithms/AbstractLayoutAlgorithm.java (-1035 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
12
package org.eclipse.zest.layouts.algorithms;
13
14
import java.util.ArrayList;
15
import java.util.Arrays;
16
import java.util.Calendar;
17
import java.util.Collection;
18
import java.util.Comparator;
19
import java.util.Iterator;
20
import java.util.List;
21
22
import org.eclipse.zest.layouts.Filter;
23
import org.eclipse.zest.layouts.InvalidLayoutConfiguration;
24
import org.eclipse.zest.layouts.LayoutAlgorithm;
25
import org.eclipse.zest.layouts.LayoutEntity;
26
import org.eclipse.zest.layouts.LayoutItem;
27
import org.eclipse.zest.layouts.LayoutRelationship;
28
import org.eclipse.zest.layouts.LayoutStyles;
29
import org.eclipse.zest.layouts.Stoppable;
30
import org.eclipse.zest.layouts.constraints.BasicEntityConstraint;
31
import org.eclipse.zest.layouts.dataStructures.BendPoint;
32
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension;
33
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint;
34
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
35
import org.eclipse.zest.layouts.dataStructures.InternalNode;
36
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;
37
import org.eclipse.zest.layouts.progress.ProgressEvent;
38
import org.eclipse.zest.layouts.progress.ProgressListener;
39
40
/**
41
 * Handles common elements in all layout algorithms
42
 * [irbull] Refactored into a template pattern.  ApplyLayout now delegates the
43
 * task to ApplyLayoutInternal
44
 * 
45
 * [irbull] Included asynchronous layouts
46
 * 
47
 * @version 1.0
48
 * @author Casey Best
49
 * @author Ian Bull
50
 * @author Chris Callendar
51
 * @author Rob Lintern
52
 * @author Chris Bennett
53
 */
54
public abstract class AbstractLayoutAlgorithm implements LayoutAlgorithm, Stoppable {
55
56
	public void removeRelationships(Collection collection) {
57
58
	}
59
60
	public final static int MIN_ENTITY_SIZE = 5;
61
	private final static int MIN_TIME_DELAY_BETWEEN_PROGRESS_EVENTS = 1;
62
63
	private Thread creationThread = null;
64
	protected Comparator comparator;
65
	protected Filter filter;
66
	private List progressListeners;
67
	private Calendar lastProgressEventFired;
68
	private double widthToHeightRatio;
69
70
	class InternalComparator implements Comparator {
71
		Comparator externalComparator = null;
72
73
		public InternalComparator(Comparator externalComparator) {
74
			this.externalComparator = externalComparator;
75
		}
76
77
		public int compare(Object o1, Object o2) {
78
			InternalNode internalNode1 = (InternalNode) o1;
79
			InternalNode internalNode2 = (InternalNode) o2;
80
81
			return this.externalComparator.compare(internalNode1.getLayoutEntity(), internalNode2.getLayoutEntity());
82
		}
83
84
	}
85
86
	/*
87
	 * Internal Nodes.   
88
	 */
89
	private InternalNode[] internalNodes;
90
	private InternalRelationship[] internalRelationships;
91
	private double internalX;
92
	private double internalY;
93
	private double internalWidth;
94
	private double internalHeight;
95
	protected boolean internalContinuous;
96
	protected boolean internalAsynchronous;
97
98
	/*
99
	 * A queue of entities and relationships to add or remove.  Each layout 
100
	 * algorithm should check these and update their internal lists.
101
	 */
102
103
	/** A list of LayoutEntity objects to be removed from the layout. */
104
	private List entitiesToRemove;
105
	/** A list of LayoutRelationship objects to be removed. */
106
	private List relationshipsToRemove;
107
	/** A list of LayoutEntity objects to be added to the layout. */
108
	private List entitiesToAdd;
109
	/** A list of LayoutRelationship objects to be added. */
110
	private List relationshipsToAdd;
111
112
	//protected boolean cancelled = false;
113
114
	protected boolean layoutStopped = true;
115
116
	protected int layout_styles = 0;
117
118
	// Child classes can set to false to retain node shapes and sizes
119
	protected boolean resizeEntitiesAfterLayout = true;
120
121
	/**
122
	 * Initializes the abstract layout algorithm.
123
	 * @see LayoutStyles
124
	 */
125
	public AbstractLayoutAlgorithm(int styles) {
126
		this.creationThread = Thread.currentThread();
127
		this.progressListeners = new ArrayList();
128
		this.lastProgressEventFired = Calendar.getInstance();
129
		this.widthToHeightRatio = 1.0;
130
131
		this.entitiesToRemove = new ArrayList();
132
		this.relationshipsToRemove = new ArrayList();
133
		this.entitiesToAdd = new ArrayList();
134
		this.relationshipsToAdd = new ArrayList();
135
		this.layout_styles = styles;
136
	}
137
138
	/**
139
	 * Queues up the given entity (if it isn't in the list) to be added to the algorithm.
140
	 * @param entity
141
	 */
142
	public void addEntity(LayoutEntity entity) {
143
		if ((entity != null) && !entitiesToAdd.contains(entity)) {
144
			entitiesToAdd.add(entity);
145
		}
146
	}
147
148
	/**
149
	 * Queues up the given relationshp (if it isn't in the list) to be added to the algorithm.
150
	 * @param relationship
151
	 */
152
	public void addRelationship(LayoutRelationship relationship) {
153
		if ((relationship != null) && !relationshipsToAdd.contains(relationship)) {
154
			relationshipsToAdd.add(relationship);
155
		}
156
	}
157
158
	/**
159
	 * Queues up the given entity to be removed from the algorithm next time it runs.
160
	 * @param entity The entity to remove
161
	 */
162
	public void removeEntity(LayoutEntity entity) {
163
		if ((entity != null) && !entitiesToRemove.contains(entity)) {
164
			entitiesToRemove.add(entity);
165
		}
166
	}
167
168
	/**
169
	 * Queues up the given relationship to be removed from the algorithm next time it runs.
170
	 * @param relationship	The relationship to remove.
171
	 */
172
	public void removeRelationship(LayoutRelationship relationship) {
173
		if ((relationship != null) && !relationshipsToRemove.contains(relationship)) {
174
			relationshipsToRemove.add(relationship);
175
		}
176
	}
177
178
	/**
179
	 * Queues up all the relationships in the list to be removed.
180
	 * @param relationships
181
	 */
182
	public void removeRelationships(List relationships) {
183
		// note we don't check if the relationshipsToRemove contains
184
		// any of the objects in relationships.
185
		relationshipsToRemove.addAll(relationships);
186
	}
187
188
	/**
189
	 * Sets the current layout style.  This overwrites all other layout styles.
190
	 * Use getStyle to get the current style.
191
	 * @param style
192
	 */
193
	public void setStyle(int style) {
194
		this.layout_styles = style;
195
	}
196
197
	/**
198
	 * Gets the current layout style
199
	 * @return
200
	 */
201
	public int getStyle() {
202
		return this.layout_styles;
203
	}
204
205
	public abstract void setLayoutArea(double x, double y, double width, double height);
206
207
	/**
208
	 * Determines if the configuration is valid for this layout
209
	 * @param asynchronous
210
	 * @param continuous
211
	 */
212
	protected abstract boolean isValidConfiguration(boolean asynchronous, boolean continuous);
213
214
	/**
215
	 * Apply the layout to the given entities.  The entities will be moved and resized based
216
	 * on the algorithm.
217
	 * 
218
	 * @param entitiesToLayout Apply the algorithm to these entities
219
	 * @param relationshipsToConsider Only consider these relationships when applying the algorithm.
220
	 * @param x The left side of the bounds in which the layout can place the entities.
221
	 * @param y The top side of the bounds in which the layout can place the entities.
222
	 * @param width The width of the bounds in which the layout can place the entities.
223
	 * @param height The height of the bounds in which the layout can place the entities.
224
	 */
225
	abstract protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY, double boundsWidth, double boundsHeight);
226
227
	/**
228
	 * Updates the given array of entities checking if any need to be removed or added.
229
	 * @param entities the current entities
230
	 * @return the updated entities array
231
	 */
232
	protected InternalNode[] updateEntities(InternalNode[] entities) {
233
		if ((entitiesToRemove.size() > 0) || (entitiesToAdd.size() > 0)) {
234
			List internalNodesList = new ArrayList(Arrays.asList(entities));
235
236
			// remove nodes
237
			for (Iterator iter = entitiesToRemove.iterator(); iter.hasNext();) {
238
				LayoutEntity entity = (LayoutEntity) iter.next();
239
				if (entity.getLayoutInformation() != null) {
240
					internalNodesList.remove(entity.getLayoutInformation());
241
				}
242
			}
243
244
			// Also remove from _internalNodes
245
			ArrayList updatedEntities = new ArrayList(internalNodes.length - entitiesToRemove.size() + entitiesToAdd.size());
246
			for (int i = 0; i < internalNodes.length; i++) {
247
				InternalNode node = internalNodes[i];
248
				if (entitiesToRemove.contains(node.getLayoutEntity())) {
249
					entitiesToRemove.remove(node.getLayoutEntity());
250
				} else {
251
					updatedEntities.add(node);
252
				}
253
			}
254
			entitiesToRemove.clear();
255
256
			// Add any new nodes
257
			LayoutEntity[] entitiesArray = new LayoutEntity[entitiesToAdd.size()];
258
			entitiesArray = (LayoutEntity[]) entitiesToAdd.toArray(entitiesArray);
259
			InternalNode[] newNodes = createInternalNodes(entitiesArray);
260
			for (int i = 0; i < newNodes.length; i++) {
261
				internalNodesList.add(newNodes[i]);
262
				updatedEntities.add(newNodes[i]);
263
			}
264
			entitiesToAdd.clear();
265
266
			entities = new InternalNode[internalNodesList.size()];
267
			entities = (InternalNode[]) internalNodesList.toArray(entities);
268
269
			internalNodes = new InternalNode[updatedEntities.size()];
270
			internalNodes = (InternalNode[]) updatedEntities.toArray(internalNodes);
271
		}
272
273
		return entities;
274
	}
275
276
	/**
277
	 * Updates the given array of relationships checking if any need to be removed or added.
278
	 * Also updates the original array of relationships.
279
	 * @param relationships the current relationships
280
	 * @return the update relationships array
281
	 */
282
	protected InternalRelationship[] updateRelationships(InternalRelationship[] relationships) {
283
		if ((relationshipsToRemove.size() > 0) || (relationshipsToAdd.size() > 0)) {
284
			List internalRelsList = new ArrayList(Arrays.asList(relationships));
285
286
			// remove relationships
287
			if (relationshipsToRemove.size() > 0) {
288
				for (Iterator iter = relationshipsToRemove.iterator(); iter.hasNext();) {
289
					LayoutRelationship relation = (LayoutRelationship) iter.next();
290
					if (relation.getLayoutInformation() != null) {
291
						internalRelsList.remove(relation.getLayoutInformation());
292
					}
293
				}
294
			}
295
296
			// Also remove from _internalRelationships
297
			ArrayList updatedRelationships = new ArrayList(internalRelationships.length - relationshipsToRemove.size() + relationshipsToAdd.size());
298
			for (int i = 0; i < internalRelationships.length; i++) {
299
				InternalRelationship relation = internalRelationships[i];
300
				if (relationshipsToRemove.contains(relation.getLayoutRelationship())) {
301
					relationshipsToRemove.remove(relation.getLayoutRelationship());
302
				} else {
303
					updatedRelationships.add(relation);
304
				}
305
			}
306
			relationshipsToRemove.clear();
307
308
			// add relationships
309
			if (relationshipsToAdd.size() > 0) {
310
				LayoutRelationship[] relsArray = new LayoutRelationship[relationshipsToAdd.size()];
311
				relsArray = (LayoutRelationship[]) relationshipsToAdd.toArray(relsArray);
312
				InternalRelationship[] newRelationships = createInternalRelationships(relsArray);
313
				for (int i = 0; i < newRelationships.length; i++) {
314
					internalRelsList.add(newRelationships[i]);
315
					updatedRelationships.add(newRelationships[i]);
316
				}
317
			}
318
			relationshipsToAdd.clear();
319
320
			relationships = new InternalRelationship[internalRelsList.size()];
321
			relationships = (InternalRelationship[]) internalRelsList.toArray(relationships);
322
323
			internalRelationships = new InternalRelationship[updatedRelationships.size()];
324
			internalRelationships = (InternalRelationship[]) updatedRelationships.toArray(internalRelationships);
325
		}
326
327
		return relationships;
328
	}
329
330
	/**
331
	 * Moves all the entities by the given amount.  
332
	 * @param dx	the amount to shift the entities in the x-direction 
333
	 * @param dy	the amount to shift the entities in the y-direction
334
	 */
335
	/*
336
	 public void moveAllEntities(double dx, double dy) {
337
	 if ((dx != 0) || (dy != 0)) {
338
	 synchronized (_internalNodes) {
339
	 for (int i = 0; i < _internalNodes.length; i++) {
340
	 InternalNode node = _internalNodes[i];
341
	 node.setInternalLocation(node.getInternalX()+dx, node.getInternalY()+dy);
342
	 node.setLocation(node.getX()+dx, node.getY()+dy);
343
	 }
344
	 }
345
	 }
346
	 }
347
	 */
348
349
	/**
350
	 * Returns true if the layout algorithm is running
351
	 * @return boolean if the layout algorithm is running
352
	 */
353
	public synchronized boolean isRunning() {
354
		return !layoutStopped;
355
	}
356
357
	/**
358
	 * Stops the current layout from running.
359
	 * All layout algorithms should constantly check isLayoutRunning
360
	 */
361
	public synchronized void stop() {
362
		layoutStopped = true;
363
		postLayoutAlgorithm(internalNodes, internalRelationships);
364
		fireProgressEnded(getTotalNumberOfLayoutSteps());
365
	}
366
367
	//	/**
368
	//	 * Sleeps while the algorithm is paused.
369
	//	 */
370
	//	protected void sleepWhilePaused() {
371
	//		// do nothing while the algorithm is paused
372
	//		boolean wasPaused = false;
373
	//		while (isPaused()) {
374
	//			try {
375
	//				Thread.sleep(200);
376
	//			} catch (InterruptedException e) {
377
	//			}
378
	//			wasPaused = true;
379
	//		}
380
	//		// update the node positions (they might have been moved while paused)
381
	//		if (wasPaused) {
382
	//			for (int i = 0; i < internalNodes.length; i++) {
383
	//				InternalNode node = internalNodes[i];
384
	//				node.setInternalLocation(node.getPreferredX(), node.getPreferredY());
385
	//			}
386
	//		}
387
	//	}
388
389
	private void setupLayout(LayoutEntity[] entitiesToLayout, LayoutRelationship[] relationshipsToConsider, double x, double y, double width, double height) {
390
		internalX = x;
391
		internalY = y;
392
		internalHeight = height;
393
		internalWidth = width;
394
		// Filter all the unwanted entities and relationships
395
		entitiesToLayout = (LayoutEntity[]) filterUnwantedObjects(entitiesToLayout);
396
		relationshipsToConsider = (LayoutRelationship[]) filterUnwantedObjects(relationshipsToConsider);
397
398
		// Check that the input is valid
399
		if (!verifyInput(entitiesToLayout, relationshipsToConsider)) {
400
			layoutStopped = true;
401
			throw new RuntimeException("The relationships in relationshipsToConsider don't contain the entities in entitiesToLayout");
402
		}
403
404
		// Create the internal nodes and relationship
405
		internalNodes = createInternalNodes(entitiesToLayout);
406
		internalRelationships = createInternalRelationships(relationshipsToConsider);
407
	}
408
409
	//	public synchronized Stoppable getLayoutThread(LayoutEntity[] entitiesToLayout, LayoutRelationship[] relationshipsToConsider, double x, double y, double width, double height, boolean continuous) {
410
	//		//setupLayout( entitiesToLayout, relationshipsToConsider, x, y, width, height );
411
	//		this.layoutStopped = false;
412
	//		this.runContinuously = continuous;
413
	//		setupLayout(entitiesToLayout, relationshipsToConsider, x, y, width, height);
414
	//		preLayoutAlgorithm(internalNodes, internalRelationships, internalX, internalY, internalWidth, internalHeight);
415
	//		fireProgressStarted(getTotalNumberOfLayoutSteps());
416
	//		return this;
417
	//	}
418
419
	/**
420
	 * Code called before the layout algorithm starts
421
	 */
422
	protected abstract void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height);
423
424
	/**
425
	 * Code called after the layout algorithm ends
426
	 */
427
	protected abstract void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider);
428
429
	/**
430
	 *  Gets the total number of steps in this layout
431
	 */
432
	protected abstract int getTotalNumberOfLayoutSteps();
433
434
	/**
435
	 * Gets the current layout step
436
	 * @return
437
	 */
438
	protected abstract int getCurrentLayoutStep();
439
440
	/**
441
	 * This actually applies the layout
442
	 */
443
	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 {
444
		checkThread();
445
		this.internalAsynchronous = asynchronous;
446
		this.internalContinuous = continuous;
447
448
		if (!isValidConfiguration(asynchronous, continuous)) {
449
			throw new InvalidLayoutConfiguration();
450
		}
451
452
		clearBendPoints(relationshipsToConsider);
453
454
		this.layoutStopped = false;
455
456
		// when an algorithm starts, reset the progress event
457
		lastProgressEventFired = Calendar.getInstance();
458
		if (asynchronous) {
459
460
			Thread thread = new Thread(new Runnable() {
461
462
				public void run() {
463
					setupLayout(entitiesToLayout, relationshipsToConsider, x, y, width, height);
464
					preLayoutAlgorithm(internalNodes, internalRelationships, internalX, internalY, internalWidth, internalHeight);
465
					fireProgressStarted(getTotalNumberOfLayoutSteps());
466
467
					applyLayoutInternal(internalNodes, internalRelationships, internalX, internalY, internalWidth, internalHeight);
468
					stop();
469
				}
470
471
			});
472
			thread.setPriority(Thread.MIN_PRIORITY);
473
			thread.start();
474
		} else {
475
476
			// If we are running synchronously then we have to stop this at some
477
			// point? right?
478
			setupLayout(entitiesToLayout, relationshipsToConsider, x, y, width, height);
479
			preLayoutAlgorithm(internalNodes, internalRelationships, internalX, internalY, internalWidth, internalHeight);
480
			fireProgressStarted(getTotalNumberOfLayoutSteps());
481
482
			applyLayoutInternal(internalNodes, internalRelationships, internalX, internalY, internalWidth, internalHeight);
483
			stop();
484
		}
485
486
	}
487
488
	/**
489
	 * Clear out all old bend points before doing a layout
490
	 */
491
	private void clearBendPoints(LayoutRelationship[] relationships) {
492
		for (int i = 0; i < relationships.length; i++) {
493
			LayoutRelationship rel = relationships[i];
494
			rel.clearBendPoints();
495
		}
496
	}
497
498
	/**
499
	 * Update external bend points from the internal bendpoints list. Save the 
500
	 * source and destination points for later use in scaling and translating
501
	 * @param relationshipsToConsider
502
	 */
503
	protected void updateBendPoints(InternalRelationship[] relationshipsToConsider) {
504
		for (int i = 0; i < relationshipsToConsider.length; i++) {
505
			InternalRelationship relationship = relationshipsToConsider[i];
506
			List bendPoints = relationship.getBendPoints();
507
			if (bendPoints.size() > 0) {
508
				// We will assume that source/dest coordinates are for center of node
509
				BendPoint[] externalBendPoints = new BendPoint[bendPoints.size() + 2];
510
				InternalNode sourceNode = relationship.getSource();
511
				externalBendPoints[0] = new BendPoint(sourceNode.getInternalX(), sourceNode.getInternalY());
512
				InternalNode destNode = relationship.getDestination();
513
				externalBendPoints[externalBendPoints.length - 1] = new BendPoint(destNode.getInternalX(), destNode.getInternalY());
514
515
				for (int j = 0; j < bendPoints.size(); j++) {
516
					BendPoint bp = (BendPoint) bendPoints.get(j);
517
					externalBendPoints[j + 1] = new BendPoint(bp.x, bp.y, bp.getIsControlPoint());
518
				}
519
				relationship.getLayoutRelationship().setBendPoints(externalBendPoints);
520
			}
521
		}
522
	}
523
524
	//	public void run() {
525
	//
526
	//		if (started == true) {
527
	//			throw new RuntimeException("Layout has already run!");
528
	//		}
529
	//		started = true;
530
	//		//layoutStopped = false;
531
	//		isLayoutPaused = false;
532
	//		applyLayoutInternal(internalNodes, internalRelationships, internalX, internalY, internalWidth, internalHeight);
533
	//		stop();
534
	//		layoutStopped = true;
535
	//		isLayoutPaused = false;
536
	//	}
537
538
	/**
539
	 * Creates a list of InternalNode objects from the list of LayoutEntity objects the user
540
	 * wants layed out. Sets the internal nodes' positions and sizes from the
541
	 * external entities.
542
	 */
543
	private InternalNode[] createInternalNodes(LayoutEntity[] nodes) {
544
		InternalNode[] internalNodes = new InternalNode[nodes.length];
545
		BasicEntityConstraint basicEntityConstraint = new BasicEntityConstraint();
546
		for (int i = 0; i < nodes.length; i++) {
547
			basicEntityConstraint.clear();
548
			LayoutEntity externalNode = nodes[i];
549
			InternalNode internalNode = new InternalNode(externalNode);
550
			externalNode.populateLayoutConstraint(basicEntityConstraint);
551
			internalNode.setInternalLocation(externalNode.getXInLayout(), externalNode.getYInLayout());
552
			internalNodes[i] = internalNode;
553
		} // end of for
554
		return internalNodes;
555
	}
556
557
	/**
558
	 * Creates a list of InternalRelationship objects from the given list of LayoutRelationship objects.
559
	 * @param rels
560
	 * @return List of internal relationships
561
	 */
562
	private InternalRelationship[] createInternalRelationships(LayoutRelationship[] rels) {
563
		ArrayList listOfInternalRelationships = new ArrayList(rels.length);
564
		for (int i = 0; i < rels.length; i++) {
565
			LayoutRelationship relation = rels[i];
566
			InternalNode src = (InternalNode) relation.getSourceInLayout().getLayoutInformation();
567
			InternalNode dest = (InternalNode) relation.getDestinationInLayout().getLayoutInformation();
568
			if ((src != null) && (dest != null)) {
569
				InternalRelationship internalRelationship = new InternalRelationship(relation, src, dest);
570
				listOfInternalRelationships.add(internalRelationship);
571
			} else {
572
				throw new RuntimeException("Error creating internal relationship, one of the nodes is null: src=" + src + ", dest=" + dest);
573
			}
574
		}
575
		InternalRelationship[] internalRelationships = new InternalRelationship[listOfInternalRelationships.size()];
576
		listOfInternalRelationships.toArray(internalRelationships);
577
		return internalRelationships;
578
	}
579
580
	/**
581
	 * Removes any objects that are currently filtered
582
	 */
583
	private Object[] filterUnwantedObjects(LayoutItem[] objects) {
584
		// first remove any entities or relationships that are filtered.
585
		List unfilteredObjsList = new ArrayList();
586
		if (filter != null) {
587
			for (int i = 0; i < objects.length; i++) {
588
				LayoutItem object = objects[i];
589
				if (!filter.isObjectFiltered(object)) {
590
					unfilteredObjsList.add(object);
591
				}
592
			}
593
			//@tag bug.156266-ClassCast.fix : use reflection to create the array.
594
			Object[] unfilteredObjs = (Object[]) java.lang.reflect.Array.newInstance(objects.getClass().getComponentType(), unfilteredObjsList.size());
595
			unfilteredObjsList.toArray(unfilteredObjs);
596
			return unfilteredObjs;
597
		}
598
		return objects;
599
	}
600
601
	/**
602
	 * Filters the entities and relationships to apply the layout on
603
	 */
604
	public void setFilter(Filter filter) {
605
		this.filter = filter;
606
	}
607
608
	/**
609
	 * Determines the order in which the objects should be displayed.
610
	 * Note: Some algorithms force a specific order.
611
	 */
612
	public void setComparator(Comparator comparator) {
613
		this.comparator = new InternalComparator(comparator);
614
	}
615
616
	/**
617
	 * Verifies the endpoints of the relationships are entities in the entitiesToLayout list.
618
	 * Allows other classes in this package to use this method to verify the input
619
	 */
620
	public static boolean verifyInput(LayoutEntity[] entitiesToLayout, LayoutRelationship[] relationshipsToConsider) {
621
		boolean stillValid = true;
622
		for (int i = 0; i < relationshipsToConsider.length; i++) {
623
			LayoutRelationship relationship = relationshipsToConsider[i];
624
			LayoutEntity source = relationship.getSourceInLayout();
625
			LayoutEntity destination = relationship.getDestinationInLayout();
626
			boolean containsSrc = false;
627
			boolean containsDest = false;
628
			int j = 0;
629
			while (j < entitiesToLayout.length && !(containsSrc && containsDest)) {
630
				if (entitiesToLayout[j].equals(source)) {
631
					containsSrc = true;
632
				}
633
				if (entitiesToLayout[j].equals(destination)) {
634
					containsDest = true;
635
				}
636
				j++;
637
			}
638
			stillValid = containsSrc && containsDest;
639
		}
640
		return stillValid;
641
	}
642
643
	/**
644
	 * Gets the location in the layout bounds for this node
645
	 * @param x
646
	 * @param y
647
	 * @return
648
	 */
649
	protected DisplayIndependentPoint getLocalLocation(InternalNode[] entitiesToLayout, double x, double y, DisplayIndependentRectangle realBounds) {
650
651
		double screenWidth = realBounds.width;
652
		double screenHeight = realBounds.height;
653
		DisplayIndependentRectangle layoutBounds = getLayoutBounds(entitiesToLayout, false);
654
		double localX = (x / screenWidth) * layoutBounds.width + layoutBounds.x;
655
		double localY = (y / screenHeight) * layoutBounds.height + layoutBounds.y;
656
		return new DisplayIndependentPoint(localX, localY);
657
	}
658
659
	/**
660
	 * Find an appropriate size for the given nodes, then fit them into the given bounds.
661
	 * The relative locations of the nodes to each other must be preserved.
662
	 * Child classes should set flag reresizeEntitiesAfterLayout to false if they 
663
	 * want to preserve node sizes.
664
	 */
665
	protected void defaultFitWithinBounds(InternalNode[] entitiesToLayout, DisplayIndependentRectangle realBounds) {
666
		defaultFitWithinBounds(entitiesToLayout, new InternalRelationship[0], realBounds);
667
	}
668
669
	/**
670
	 * Find an appropriate size for the given nodes, then fit them into the given bounds.
671
	 * The relative locations of the nodes to each other must be preserved.
672
	 * Child classes should set flag reresizeEntitiesAfterLayout to false if they 
673
	 * want to preserve node sizes.
674
	 */
675
	protected void defaultFitWithinBounds(InternalNode[] entitiesToLayout, InternalRelationship[] relationships, DisplayIndependentRectangle realBounds) {
676
677
		DisplayIndependentRectangle layoutBounds;
678
679
		if (resizeEntitiesAfterLayout) {
680
			layoutBounds = getLayoutBounds(entitiesToLayout, false);
681
682
			// Convert node x,y to be in percent rather than absolute coords
683
			convertPositionsToPercentage(entitiesToLayout, relationships, layoutBounds, false /*do not update size*/);
684
685
			// Resize and shift nodes
686
			resizeAndShiftNodes(entitiesToLayout);
687
		}
688
689
		// Recalculate layout, allowing for the node width, which we now know
690
		layoutBounds = getLayoutBounds(entitiesToLayout, true);
691
692
		// adjust node positions again, to the new coordinate system (still as a percentage)
693
		convertPositionsToPercentage(entitiesToLayout, relationships, layoutBounds, true /*update node size*/);
694
695
		DisplayIndependentRectangle screenBounds = calcScreenBounds(realBounds, layoutBounds);
696
697
		// Now convert to real screen coordinates
698
		convertPositionsToCoords(entitiesToLayout, relationships, screenBounds);
699
	}
700
701
	/**
702
	 * Calculate the screen bounds, maintaining the  
703
	 * @param realBounds
704
	 * @return
705
	 */
706
	private DisplayIndependentRectangle calcScreenBounds(DisplayIndependentRectangle realBounds, DisplayIndependentRectangle layoutBounds) {
707
		if (resizeEntitiesAfterLayout) { // OK to alter aspect ratio 
708
			double borderWidth = Math.min(realBounds.width, realBounds.height) / 10.0; // use 10% for the border - 5% on each side
709
			return new DisplayIndependentRectangle(realBounds.x + borderWidth / 2.0, realBounds.y + borderWidth / 2.0, realBounds.width - borderWidth, realBounds.height - borderWidth);
710
		} else { // retain layout aspect ratio 
711
			double heightAdjustment = realBounds.height / layoutBounds.height;
712
			double widthAdjustment = realBounds.width / layoutBounds.width;
713
			double ratio = Math.min(heightAdjustment, widthAdjustment);
714
			double adjustedHeight = layoutBounds.height * ratio;
715
			double adjustedWidth = layoutBounds.width * ratio;
716
			double adjustedX = realBounds.x + (realBounds.width - adjustedWidth) / 2.0;
717
			double adjustedY = realBounds.y + (realBounds.height - adjustedHeight) / 2.0;
718
			double borderWidth = Math.min(adjustedWidth, adjustedHeight) / 10.0; // use 10% for the border - 5% on each side
719
			return new DisplayIndependentRectangle(adjustedX + borderWidth / 2.0, adjustedY + borderWidth / 2.0, adjustedWidth - borderWidth, adjustedHeight - borderWidth);
720
		}
721
	}
722
723
	/**
724
	 * Find and set the node size - shift the nodes to the right and down to make 
725
	 * room for the width and height. 
726
	 * @param entitiesToLayout
727
	 * @param relationships
728
	 */
729
	private void resizeAndShiftNodes(InternalNode[] entitiesToLayout) {
730
		// get maximum node size as percent of screen dimmensions
731
		double nodeSize = getNodeSize(entitiesToLayout);
732
		double halfNodeSize = nodeSize / 2;
733
734
		// Resize and shift nodes
735
		for (int i = 0; i < entitiesToLayout.length; i++) {
736
			InternalNode node = entitiesToLayout[i];
737
			node.setInternalSize(nodeSize, nodeSize);
738
			node.setInternalLocation(node.getInternalX() + halfNodeSize, node.getInternalY() + halfNodeSize);
739
		}
740
	}
741
742
	/**
743
	 * Convert all node positions into a percentage of the screen. If includeNodeSize
744
	 * is true then this also updates the node's internal size. 
745
	 * @param entitiesToLayout
746
	 */
747
	private void convertPositionsToPercentage(InternalNode[] entitiesToLayout, InternalRelationship[] relationships, DisplayIndependentRectangle layoutBounds, boolean includeNodeSize) {
748
749
		// Adjust node positions and sizes
750
		for (int i = 0; i < entitiesToLayout.length; i++) {
751
			InternalNode node = entitiesToLayout[i];
752
			DisplayIndependentPoint location = node.getInternalLocation().convertToPercent(layoutBounds);
753
			node.setInternalLocation(location.x, location.y);
754
			if (includeNodeSize) { // adjust node sizes
755
				double width = node.getInternalWidth() / layoutBounds.width;
756
				double height = node.getInternalHeight() / layoutBounds.height;
757
				node.setInternalSize(width, height);
758
			}
759
		}
760
761
		// Adjust bendpoint positions
762
		for (int i = 0; i < relationships.length; i++) {
763
			InternalRelationship rel = relationships[i];
764
			for (int j = 0; j < rel.getBendPoints().size(); j++) {
765
				BendPoint bp = (BendPoint) rel.getBendPoints().get(j);
766
				DisplayIndependentPoint toPercent = bp.convertToPercent(layoutBounds);
767
				bp.setX(toPercent.x);
768
				bp.setY(toPercent.y);
769
			}
770
		}
771
	}
772
773
	/**
774
	 * Convert the positions from a percentage of bounds area to fixed
775
	 * coordinates. NOTE: ALL OF THE POSITIONS OF NODES UNTIL NOW WERE FOR THE
776
	 * CENTER OF THE NODE - Convert it to the left top corner.
777
	 * 
778
	 * @param entitiesToLayout
779
	 * @param relationships
780
	 * @param realBounds
781
	 */
782
	private void convertPositionsToCoords(InternalNode[] entitiesToLayout, InternalRelationship[] relationships, DisplayIndependentRectangle screenBounds) {
783
784
		// Adjust node positions and sizes
785
		for (int i = 0; i < entitiesToLayout.length; i++) {
786
			InternalNode node = entitiesToLayout[i];
787
			double width = node.getInternalWidth() * screenBounds.width;
788
			double height = node.getInternalHeight() * screenBounds.height;
789
			DisplayIndependentPoint location = node.getInternalLocation().convertFromPercent(screenBounds);
790
			node.setInternalLocation(location.x - width / 2, location.y - height / 2);
791
			if (resizeEntitiesAfterLayout) {
792
				adjustNodeSizeAndPos(node, height, width);
793
			} else {
794
				node.setInternalSize(width, height);
795
			}
796
		}
797
798
		// Adjust bendpoint positions and shift based on source node size
799
		for (int i = 0; i < relationships.length; i++) {
800
			InternalRelationship rel = relationships[i];
801
			for (int j = 0; j < rel.getBendPoints().size(); j++) {
802
				BendPoint bp = (BendPoint) rel.getBendPoints().get(j);
803
				DisplayIndependentPoint fromPercent = bp.convertFromPercent(screenBounds);
804
				bp.setX(fromPercent.x);
805
				bp.setY(fromPercent.y);
806
			}
807
		}
808
	}
809
810
	/**
811
	 * Adjust node size to take advantage of space. Reset position to top left corner of node. 
812
	 * @param node
813
	 * @param height
814
	 * @param width
815
	 */
816
	private void adjustNodeSizeAndPos(InternalNode node, double height, double width) {
817
		double widthUsingHeight = height * widthToHeightRatio;
818
		if (widthToHeightRatio <= 1.0 && widthUsingHeight <= width) {
819
			double widthToUse = height * widthToHeightRatio;
820
			double leftOut = width - widthToUse;
821
			node.setInternalSize(Math.max(height * widthToHeightRatio, MIN_ENTITY_SIZE), Math.max(height, MIN_ENTITY_SIZE));
822
			node.setInternalLocation(node.getInternalX() + leftOut / 2, node.getInternalY());
823
824
		} else {
825
			double heightToUse = height / widthToHeightRatio;
826
			double leftOut = height - heightToUse;
827
828
			node.setInternalSize(Math.max(width, MIN_ENTITY_SIZE), Math.max(width / widthToHeightRatio, MIN_ENTITY_SIZE));
829
			node.setInternalLocation(node.getInternalX(), node.getInternalY() + leftOut / 2);
830
		}
831
832
	}
833
834
	/**
835
	 * Returns the maximum possible node size as a percentage of the width or height in current coord system.
836
	 */
837
	private double getNodeSize(InternalNode[] entitiesToLayout) {
838
		double width, height;
839
		if (entitiesToLayout.length == 1) {
840
			width = 0.8;
841
			height = 0.8;
842
		} else {
843
			DisplayIndependentDimension minimumDistance = getMinimumDistance(entitiesToLayout);
844
			width = 0.8 * minimumDistance.width;
845
			height = 0.8 * minimumDistance.height;
846
		}
847
		return Math.max(width, height);
848
	}
849
850
	/**
851
	 * Find the bounds in which the nodes are located.  Using the bounds against the real bounds
852
	 * of the screen, the nodes can proportionally be placed within the real bounds.
853
	 * The bounds can be determined either including the size of the nodes or not.  If the size
854
	 * is not included, the bounds will only be guaranteed to include the center of each node.
855
	 */
856
	protected DisplayIndependentRectangle getLayoutBounds(InternalNode[] entitiesToLayout, boolean includeNodeSize) {
857
		double rightSide = Double.MIN_VALUE;
858
		double bottomSide = Double.MIN_VALUE;
859
		double leftSide = Double.MAX_VALUE;
860
		double topSide = Double.MAX_VALUE;
861
		for (int i = 0; i < entitiesToLayout.length; i++) {
862
			InternalNode entity = entitiesToLayout[i];
863
			if (entity.hasPreferredLocation()) {
864
				continue;
865
			}
866
867
			if (includeNodeSize) {
868
				leftSide = Math.min(entity.getInternalX() - entity.getInternalWidth() / 2, leftSide);
869
				topSide = Math.min(entity.getInternalY() - entity.getInternalHeight() / 2, topSide);
870
				rightSide = Math.max(entity.getInternalX() + entity.getInternalWidth() / 2, rightSide);
871
				bottomSide = Math.max(entity.getInternalY() + entity.getInternalHeight() / 2, bottomSide);
872
			} else {
873
				leftSide = Math.min(entity.getInternalX(), leftSide);
874
				topSide = Math.min(entity.getInternalY(), topSide);
875
				rightSide = Math.max(entity.getInternalX(), rightSide);
876
				bottomSide = Math.max(entity.getInternalY(), bottomSide);
877
			}
878
		}
879
		return new DisplayIndependentRectangle(leftSide, topSide, rightSide - leftSide, bottomSide - topSide);
880
	}
881
882
	/** 
883
	 * minDistance is the closest that any two points are together.
884
	 * These two points become the center points for the two closest nodes, 
885
	 * which we wish to make them as big as possible without overlapping.
886
	 * This will be the maximum of minDistanceX and minDistanceY minus a bit, lets say 20%
887
	 * 
888
	 * We make the recommended node size a square for convenience.
889
	 * 
890
	 * 
891
	 *    _______
892
	 *   |       | 
893
	 *   |       |
894
	 *   |   +   |
895
	 *   |   |\  |
896
	 *   |___|_\_|_____
897
	 *       | | \     |
898
	 *       | |  \    |
899
	 *       +-|---+   |
900
	 *         |       |
901
	 *         |_______|
902
	 * 
903
	 *  
904
	 * 
905
	 */
906
	private DisplayIndependentDimension getMinimumDistance(InternalNode[] entitiesToLayout) {
907
		DisplayIndependentDimension horAndVertdistance = new DisplayIndependentDimension(Double.MAX_VALUE, Double.MAX_VALUE);
908
		double minDistance = Double.MAX_VALUE; // the minimum distance between all the nodes
909
		//TODO: Very Slow!
910
		for (int i = 0; i < entitiesToLayout.length; i++) {
911
			InternalNode layoutEntity1 = entitiesToLayout[i];
912
			double x1 = layoutEntity1.getInternalX();
913
			double y1 = layoutEntity1.getInternalY();
914
			for (int j = i + 1; j < entitiesToLayout.length; j++) {
915
				InternalNode layoutEntity2 = entitiesToLayout[j];
916
				double x2 = layoutEntity2.getInternalX();
917
				double y2 = layoutEntity2.getInternalY();
918
				double distanceX = Math.abs(x1 - x2);
919
				double distanceY = Math.abs(y1 - y2);
920
				double distance = Math.sqrt(Math.pow(distanceX, 2) + Math.pow(distanceY, 2));
921
922
				if (distance < minDistance) {
923
					minDistance = distance;
924
					horAndVertdistance.width = distanceX;
925
					horAndVertdistance.height = distanceY;
926
				}
927
			}
928
		}
929
		return horAndVertdistance;
930
	}
931
932
	/**
933
	 * Set the width to height ratio you want the entities to use
934
	 */
935
	public void setEntityAspectRatio(double ratio) {
936
		widthToHeightRatio = ratio;
937
	}
938
939
	/**
940
	 * Returns the width to height ratio this layout will use to set the size of the entities.
941
	 */
942
	public double getEntityAspectRatio() {
943
		return widthToHeightRatio;
944
	}
945
946
	/**
947
	 * A layout algorithm could take an uncomfortable amout of time to complete.  To relieve some of
948
	 * the mystery, the layout algorithm will notify each ProgressListener of its progress. 
949
	 */
950
	public void addProgressListener(ProgressListener listener) {
951
		if (!progressListeners.contains(listener)) {
952
			progressListeners.add(listener);
953
		}
954
	}
955
956
	/**
957
	 * Removes the given progress listener, preventing it from receiving any more updates.
958
	 */
959
	public void removeProgressListener(ProgressListener listener) {
960
		if (progressListeners.contains(listener)) {
961
			progressListeners.remove(listener);
962
		}
963
	}
964
965
	/**
966
	 * Updates the layout locations so the external nodes know about the new locations
967
	 */
968
	protected void updateLayoutLocations(InternalNode[] nodes) {
969
		for (int i = 0; i < nodes.length; i++) {
970
			InternalNode node = nodes[i];
971
			if (!node.hasPreferredLocation()) {
972
				node.setLocation(node.getInternalX(), node.getInternalY());
973
974
				if ((layout_styles & LayoutStyles.NO_LAYOUT_NODE_RESIZING) != 1) {
975
					// Only set the size if we are supposed to
976
					node.setSize(node.getInternalWidth(), node.getInternalHeight());
977
				}
978
			}
979
		}
980
	}
981
982
	protected void fireProgressStarted(int totalNumberOfSteps) {
983
		ProgressEvent event = new ProgressEvent(0, totalNumberOfSteps);
984
		for (int i = 0; i < progressListeners.size(); i++) {
985
			ProgressListener listener = (ProgressListener) progressListeners.get(i);
986
987
			listener.progressStarted(event);
988
		}
989
	}
990
991
	protected void fireProgressEnded(int totalNumberOfSteps) {
992
		ProgressEvent event = new ProgressEvent(totalNumberOfSteps, totalNumberOfSteps);
993
		for (int i = 0; i < progressListeners.size(); i++) {
994
			ProgressListener listener = (ProgressListener) progressListeners.get(i);
995
			listener.progressEnded(event);
996
		}
997
998
	}
999
1000
	/**
1001
	 * Fires an event to notify all of the registered ProgressListeners that another step
1002
	 * has been completed in the algorithm.
1003
	 * @param currentStep The current step completed.
1004
	 * @param totalNumberOfSteps The total number of steps in the algorithm.
1005
	 */
1006
	protected void fireProgressEvent(int currentStep, int totalNumberOfSteps) {
1007
1008
		// Update the layout locations to the external nodes
1009
		Calendar now = Calendar.getInstance();
1010
		now.add(Calendar.MILLISECOND, -MIN_TIME_DELAY_BETWEEN_PROGRESS_EVENTS);
1011
1012
		if (now.after(lastProgressEventFired) || currentStep == totalNumberOfSteps) {
1013
			ProgressEvent event = new ProgressEvent(currentStep, totalNumberOfSteps);
1014
1015
			for (int i = 0; i < progressListeners.size(); i++) {
1016
1017
				ProgressListener listener = (ProgressListener) progressListeners.get(i);
1018
				listener.progressUpdated(event);
1019
			}
1020
			lastProgressEventFired = Calendar.getInstance();
1021
		}
1022
1023
	}
1024
1025
	protected int getNumberOfProgressListeners() {
1026
		return progressListeners.size();
1027
	}
1028
1029
	private void checkThread() {
1030
		if (this.creationThread != Thread.currentThread()) {
1031
			throw new RuntimeException("Invalid Thread Access.");
1032
		}
1033
	}
1034
1035
}
(-)src/org/eclipse/zest/layouts/algorithms/HorizontalLayoutAlgorithm.java (-55 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     Ian Bull     - updated and modified
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
12
13
import org.eclipse.zest.layouts.LayoutStyles;
14
15
/**
16
 * @version 2.0
17
 * @author Casey Best and Rob Lintern
18
 */
19
public class HorizontalLayoutAlgorithm extends GridLayoutAlgorithm {
20
21
	
22
	public HorizontalLayoutAlgorithm(int styles) {
23
		super(styles);
24
	}
25
26
	/**
27
	 * Horizontal Layout Algorithm constructor.  Sets the Style to none.
28
	 */
29
	public HorizontalLayoutAlgorithm() {
30
		this( LayoutStyles.NONE );
31
	}
32
	/**
33
	 * Calculates and returns an array containing the number of columns, followed by the number of rows
34
	 */
35
	protected int[] calculateNumberOfRowsAndCols (int numChildren, double boundX, double boundY, double boundWidth, double boundHeight) {
36
		int rows = 1;
37
		int cols = numChildren;
38
		int[] result = {cols, rows};
39
		return result;
40
	}
41
	
42
	protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) {
43
		if ( asynchronous && continueous ) {
44
			return false;
45
		} else if ( asynchronous && !continueous ) {
46
			return true;
47
		} else if ( !asynchronous && continueous ) {
48
			return false;
49
		} else if ( !asynchronous && !continueous ) {
50
			return true;
51
		}
52
		
53
		return false;
54
	}
55
}
(-)src/org/eclipse/zest/layouts/algorithms/TreeLayoutAlgorithm.java (-522 / +116 lines)
Lines 1-580 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright (c) 2005-2009 The Chisel Group and others. All rights reserved. This
3
 * All rights reserved. This program and the accompanying materials
3
 * program and the accompanying materials are made available under the terms of
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * which accompanies this distribution, and is available at
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 *
7
 * Contributors: The Chisel Group - initial API and implementation
8
 * Contributors:
8
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 *     The Chisel Group, University of Victoria
9
 *               Ian Bull
10
 *******************************************************************************/
10
 ******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
11
package org.eclipse.zest.layouts.algorithms;
12
12
13
import java.util.ArrayList;
14
import java.util.Arrays;
15
import java.util.Collection;
16
import java.util.Collections;
17
import java.util.Comparator;
18
import java.util.HashSet;
19
import java.util.Iterator;
13
import java.util.Iterator;
20
import java.util.List;
21
import java.util.Set;
22
14
23
import org.eclipse.zest.layouts.LayoutStyles;
15
import org.eclipse.zest.layouts.LayoutAlgorithm;
16
import org.eclipse.zest.layouts.algorithms.TreeLayoutObserver.TreeNode;
24
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
17
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
25
import org.eclipse.zest.layouts.dataStructures.InternalNode;
18
import org.eclipse.zest.layouts.interfaces.EntityLayout;
26
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;
19
import org.eclipse.zest.layouts.interfaces.LayoutContext;
27
import org.eclipse.zest.layouts.exampleStructures.SimpleRelationship;
28
29
30
20
31
/**
21
/**
32
 * The TreeLayoutAlgorithm class implements a simple algorithm to
22
 * The TreeLayoutAlgorithm class implements a simple algorithm to arrange graph
33
 * arrange graph nodes in a layered vertical tree-like layout. 
23
 * nodes in a layered tree-like layout.
34
 * 
24
 * 
35
 * This is by no means an efficiently coded algorithm.
25
 * @version 3.0
36
 *
26
 * @author Mateusz Matela
37
 * @version  2.0
27
 * @author Casey Best and Rob Lintern (version 2.0)
38
 * @author   Casey Best and Rob Lintern (version 1.0 by Jingwei Wu)
28
 * @author Jingwei Wu (version 1.0)
39
 */
29
 */
40
public class TreeLayoutAlgorithm extends AbstractLayoutAlgorithm {
30
public class TreeLayoutAlgorithm implements LayoutAlgorithm {
41
   
42
    private final static double DEFAULT_WEIGHT = 0;
43
    private final static boolean DEFAULT_MARKED = false;
44
    
45
	private final static boolean AS_DESTINATION = false;
46
	private final static boolean AS_SOURCE = true;
47
    
48
    private final static int NUM_DESCENDENTS_INDEX = 0;
49
    private final static int NUM_LEVELS_INDEX = 1;
50
    
51
    private ArrayList treeRoots;
52
    
53
    private double boundsX;
54
    private double boundsY;
55
    private double boundsWidth;
56
    private double boundsHeight;
57
    private DisplayIndependentRectangle layoutBounds = null;
58
    
59
    private List [] parentLists;
60
    private List [] childrenLists;
61
    private double [] weights;
62
    private boolean [] markedArr;
63
	
64
	/////////////////////////////////////////////////////////////////////////
65
	/////                        Constructors                           /////
66
	/////////////////////////////////////////////////////////////////////////
67
31
68
	/**
32
	/**
69
	 * Constructs a new TreeLayoutAlgorithm object.
33
	 * Tree direction constant for which root is placed at the top and branches
70
	 */
34
	 * spread downwards
71
	public TreeLayoutAlgorithm( int styles ) {
72
		super( styles );
73
	}
74
	
75
	/**
76
	 * Tree layout algorithm Constructor with NO Style
77
	 *
78
	 */
35
	 */
79
	public TreeLayoutAlgorithm() {
36
	public final static int TOP_DOWN = 1;
80
		this( LayoutStyles.NONE );
81
	}
82
	
83
	/////////////////////////////////////////////////////////////////////////
84
	/////                        Public Methods                         /////
85
	/////////////////////////////////////////////////////////////////////////
86
	
87
	public void setLayoutArea(double x, double y, double width, double height) {
88
		throw new RuntimeException();
89
	}
90
	
91
	protected int getCurrentLayoutStep() {
92
		// TODO Auto-generated method stub
93
		return 0;
94
	}
95
	
96
	protected int getTotalNumberOfLayoutSteps() {
97
		return 4;
98
	}
99
37
100
	/**
38
	/**
101
	 * Executes this TreeLayoutAlgorithm layout algorithm by referencing the
39
	 * Tree direction constant for which root is placed at the bottom and
102
	 * data stored in the repository system. Once done, the result
40
	 * branches spread upwards
103
	 * will be saved to the data repository.
104
	 * 
105
	 * @param entitiesToLayout Apply the algorithm to these entities
106
	 * @param relationshipsToConsider Only consider these relationships when applying the algorithm.
107
	 * @param boundsX The left side of the bounds in which the layout can place the entities.
108
	 * @param boundsY The top side of the bounds in which the layout can place the entities.
109
	 * @param boundsWidth The width of the bounds in which the layout can place the entities.
110
	 * @param boundsHeight The height of the bounds in which the layout can place the entities.
111
	 * @throws RuntimeException Thrown if entitiesToLayout doesn't contain all of the endpoints for each relationship in relationshipsToConsider
112
	 */
41
	 */
113
	protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) {
42
	public final static int BOTTOM_UP = 2;
114
		// Filter unwanted entities and relationships
115
		//super.applyLayout (entitiesToLayout, relationshipsToConsider, boundsX, boundsY, boundsWidth, boundsHeight);
116
117
        parentLists = new List [entitiesToLayout.length];
118
        childrenLists = new List [entitiesToLayout.length];
119
        weights = new double [entitiesToLayout.length];
120
        markedArr = new boolean [entitiesToLayout.length];
121
        for (int i = 0; i < entitiesToLayout.length; i++) {
122
            parentLists[i] = new ArrayList();
123
            childrenLists[i] = new ArrayList();
124
            weights[i] = DEFAULT_WEIGHT;
125
            markedArr[i] = DEFAULT_MARKED;
126
        }
127
        
128
		this.boundsHeight = height;
129
		this.boundsWidth = width;
130
		this.boundsX = x;
131
		this.boundsY = y;
132
		layoutBounds = new DisplayIndependentRectangle(boundsX, boundsY, boundsWidth, boundsHeight);
133
	
134
	}
135
43
136
	protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY, double boundsWidth, double boundsHeight) {
137
		
138
		if (entitiesToLayout.length > 0) {
139
			int totalProgress = 4;	
140
			fireProgressEvent (1, totalProgress);
141
			
142
			//List roots = new ArrayList();
143
			treeRoots = new ArrayList();
144
			buildForest(treeRoots, entitiesToLayout, relationshipsToConsider);
145
			fireProgressEvent (2, totalProgress);
146
			computePositions(treeRoots, entitiesToLayout);
147
			fireProgressEvent (3, totalProgress);
148
			defaultFitWithinBounds(entitiesToLayout, layoutBounds);
149
150
		}
151
	}
152
	
153
	protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) {
154
		updateLayoutLocations(entitiesToLayout);
155
		fireProgressEvent (4, 4);
156
	}
157
	
158
	/**
44
	/**
159
	 * Returns the last found roots
45
	 * Tree direction constant for which root is placed at the left and branches
46
	 * spread to the right
160
	 */
47
	 */
161
	public List getRoots () {
48
	public final static int LEFT_RIGHT = 3;
162
		return treeRoots;
163
	}
164
49
165
	/**
50
	/**
166
	 * Finds all the relationships in which the node <code>obj<code>
51
	 * Tree direction constant for which root is placed at the right and
167
	 * plays the specified <code>role</code>.
52
	 * branches spread to the left
168
	 * @param entity The node that concerns the relations to be found.
169
	 * @param role The role played by the <code>obj</code>. Its type
170
	 * must be of <code>ACTOR_ROLE</code> or <code>ACTEE_ROLE</code>.
171
	 * @see SimpleRelationship
172
	 */
53
	 */
173
    private Collection findRelationships(Object entity, boolean objectAsSource, InternalRelationship [] relationshipsToConsider) {
54
	public final static int RIGHT_LEFT = 4;
174
		Collection foundRels = new ArrayList();
175
        for (int i = 0; i < relationshipsToConsider.length; i++) {
176
            InternalRelationship rel = relationshipsToConsider[i];
177
			if (objectAsSource && rel.getSource().equals (entity)) {
178
				foundRels.add(rel);
179
			} else if (!objectAsSource && rel.getDestination().equals (entity)) {
180
				foundRels.add(rel);
181
			}
182
		}
183
		return foundRels;
184
	}
185
55
186
	/**
56
	private int direction = TOP_DOWN;
187
	 * Finds the relation that has the lowest index in the relation
188
	 * repository in which the node <code>obj<code> plays the specified
189
	 * <code>role</code>.
190
	 * @param obj The node that concerns the relations to be found.
191
	 * @param role The role played by the <code>obj</code>. Its type must
192
	 * be of <code>ACTOR_ROLE</code> or <code>ACTEE_ROLE</code>.
193
	 * @see SimpleRelationship
194
	 * @see SimpleRelationship#ACTOR_ROLE
195
	 * @see SimpleRelationship#ACTEE_ROLE
196
	 */
197
    private InternalRelationship findRelationship(Object entity, boolean objectAsSource, InternalRelationship [] relationshipsToConsider) {
198
		InternalRelationship relationship = null;
199
        for (int i = 0; i < relationshipsToConsider.length && relationship == null; i++) {
200
            InternalRelationship possibleRel = relationshipsToConsider[i];
201
			if (objectAsSource && possibleRel.getSource().equals (entity)) {
202
				relationship = possibleRel;
203
			} else if (!objectAsSource && possibleRel.getDestination().equals (entity)) {
204
				relationship = possibleRel;
205
			}
206
		}
207
		return relationship;
208
	}
209
57
58
	private boolean resize = false;
210
59
60
	private LayoutContext context;
211
61
212
	/////////////////////////////////////////////////////////////////////////
62
	private DisplayIndependentRectangle bounds;
213
	/////                        Private Methods                        /////
214
	/////////////////////////////////////////////////////////////////////////
215
63
64
	private double leafSize, layerSize;
216
65
217
	/**
66
	private TreeLayoutObserver treeObserver;
218
	 * Builds the tree forest that is used to calculate positions
67
219
	 * for each node in this TreeLayoutAlgorithm.
68
	public TreeLayoutAlgorithm() {
220
	 */
221
	private void buildForest(List roots, InternalNode [] entities, InternalRelationship [] relationships) {
222
		List unplacedEntities = new ArrayList (Arrays.asList(entities));
223
		buildForestRecursively(roots, unplacedEntities, entities, relationships);
224
	}
69
	}
225
70
226
	/**
71
	public TreeLayoutAlgorithm(int direction) {
227
	 * Builds the forest recursively. All entities
72
		setDirection(direction);
228
	 * will be placed somewhere in the forest. 
229
	 */
230
	private void buildForestRecursively(List roots, List unplacedEntities, InternalNode [] entities, InternalRelationship [] relationships) {
231
		if (unplacedEntities.size() == 0) {
232
			return; // no more entities to place
233
		}
234
		
235
		// get the first entity in the list of unplaced entities, find its root, and build this root's tree
236
		InternalNode layoutEntity = (InternalNode) unplacedEntities.get(0);
237
		InternalNode rootEntity = findRootObjectRecursive(layoutEntity, new HashSet(), relationships);
238
        int rootEntityIndex = indexOfInternalNode(entities, rootEntity);
239
		buildTreeRecursively(rootEntity, rootEntityIndex, 0, entities, relationships);
240
		roots.add(rootEntity);
241
		
242
		// now see which nodes are left to be placed in a tree somewhere
243
		List unmarkedCopy = new ArrayList(unplacedEntities);
244
		for (Iterator iter = unmarkedCopy.iterator(); iter.hasNext();) {
245
            InternalNode tmpEntity = (InternalNode) iter.next();
246
            int tmpEntityIndex = indexOfInternalNode(entities, tmpEntity);
247
            boolean isMarked = markedArr[tmpEntityIndex];
248
 			if (isMarked) {
249
 			   unplacedEntities.remove(tmpEntity);
250
			}
251
		}
252
		buildForestRecursively(roots, unplacedEntities, entities, relationships);
253
	}
73
	}
254
74
255
	/**
75
	public int getDirection() {
256
	 * Finds the root node that can be treated as the root of a tree.
76
		return direction;
257
	 * The found root node should be one of the unmarked nodes.
258
	 */
259
	private InternalNode findRootObjectRecursive(InternalNode currentEntity, Set seenAlready, InternalRelationship [] relationshipsToConsider) {
260
		InternalNode rootEntity = null;
261
		InternalRelationship rel = findRelationship(currentEntity, AS_DESTINATION, relationshipsToConsider);
262
		if (rel == null) {
263
			rootEntity = currentEntity;
264
		} else {
265
			InternalNode parentEntity = rel.getSource();
266
			if (!seenAlready.contains(parentEntity)) {
267
				seenAlready.add(parentEntity);
268
				rootEntity = findRootObjectRecursive(parentEntity, seenAlready, relationshipsToConsider);
269
			} else {
270
				rootEntity = currentEntity;
271
			}
272
		}
273
		return rootEntity;
274
	}
77
	}
275
78
79
	public void setDirection(int direction) {
80
		if (direction == TOP_DOWN || direction == BOTTOM_UP || direction == LEFT_RIGHT || direction == RIGHT_LEFT)
81
			this.direction = direction;
82
		else
83
			throw new IllegalArgumentException("Invalid direction: " + direction);
84
	}
276
85
277
	
278
	/**
86
	/**
279
	 * Builds a tree of the passed in entity.
87
	 * 
280
	 * The entity will pass a weight value to all of its children recursively.
88
	 * @return true if this algorithm is set to resize elements
281
	 */
89
	 */
282
	private void buildTreeRecursively(InternalNode layoutEntity, int i, double weight, InternalNode [] entities, final InternalRelationship [] relationships) {
90
	public boolean isResizing() {
283
		// No need to do further computation!
91
		return resize;
284
		if (layoutEntity == null) {
285
			return;
286
		}
287
288
		// A marked entity means that it has been added to the
289
		// forest, and its weight value needs to be modified.		
290
		if (markedArr[i]) {
291
			modifyWeightRecursively(layoutEntity, i, weight, new HashSet(), entities, relationships);
292
			return; //No need to do further computation.
293
		}
294
295
		// Mark this entity, set its weight value and create a new tree node.
296
        markedArr[i] = true;
297
		weights[i] = weight;
298
		
299
		// collect the children of this entity and put them in order
300
		Collection rels = findRelationships(layoutEntity, AS_SOURCE, relationships);
301
		List children = new ArrayList ();
302
		for (Iterator iter = rels.iterator(); iter.hasNext();) {
303
			InternalRelationship layoutRel = (InternalRelationship) iter.next();
304
			InternalNode childEntity = layoutRel.getDestination();
305
			children.add(childEntity);
306
		}
307
		
308
		if (comparator != null) {
309
			Collections.sort(children, comparator); 
310
		} else {
311
            // sort the children by level, then by number of descendents, then by number of children
312
            // TODO: SLOW
313
		    Collections.sort(children, new Comparator () {           
314
                public int compare(Object o1, Object o2) {
315
                    InternalNode node1 = (InternalNode) o1;
316
                    InternalNode node2 = (InternalNode) o2;
317
                    int [] numDescendentsAndLevel1 = new int [2];
318
                    int [] numDescendentsAndLevel2 = new int [2];
319
                    int level1 = numDescendentsAndLevel1[NUM_LEVELS_INDEX];
320
                    int level2 = numDescendentsAndLevel2[NUM_LEVELS_INDEX];
321
                    if (level1 == level2) {
322
                        getNumDescendentsAndLevel(node1, relationships, numDescendentsAndLevel1);
323
                        getNumDescendentsAndLevel(node2, relationships, numDescendentsAndLevel2);
324
                        int numDescendents1 = numDescendentsAndLevel1[NUM_DESCENDENTS_INDEX];
325
                        int numDescendents2 = numDescendentsAndLevel2[NUM_DESCENDENTS_INDEX];
326
                        if (numDescendents1 == numDescendents2) {
327
                            int numChildren1 = getNumChildren(node1, relationships);
328
                            int numChildren2 = getNumChildren(node1, relationships);
329
                            return numChildren2 - numChildren1;
330
                        } else {
331
                            return numDescendents2 - numDescendents1;
332
                        }
333
                    } else {
334
                        return level2 - level1;
335
                    }
336
                    //return getNumChildren(node2, relationships) - getNumChildren(node1, relationships);
337
                }           
338
            });
339
		}
340
		
341
		// map children to this parent, and vice versa
342
		for (Iterator iter = children.iterator(); iter.hasNext();) {
343
			InternalNode childEntity = (InternalNode) iter.next();
344
			int childEntityIndex = indexOfInternalNode(entities, childEntity);
345
			if (!childrenLists[i].contains(childEntity)) {
346
				childrenLists[i].add(childEntity);
347
			}
348
			if (!parentLists[childEntityIndex].contains(layoutEntity)) {
349
				parentLists[childEntityIndex].add(layoutEntity);
350
			}
351
		}
352
		
353
		for (Iterator iter = children.iterator(); iter.hasNext();) {
354
			InternalNode childEntity = (InternalNode) iter.next();
355
            int childEntityIndex = indexOfInternalNode(entities, childEntity);
356
			buildTreeRecursively(childEntity, childEntityIndex, weight + 1, entities, relationships);
357
		}
358
	}
92
	}
359
    
93
360
    private int getNumChildren (InternalNode layoutEntity, InternalRelationship [] relationships) {
361
        return findRelationships(layoutEntity, AS_SOURCE, relationships).size();
362
    }
363
    
364
    private void getNumDescendentsAndLevel (InternalNode layoutEntity, InternalRelationship [] relationships, int [] numDescendentsAndLevel) {
365
        getNumDescendentsAndLevelRecursive(layoutEntity, relationships, new HashSet(), numDescendentsAndLevel, 0);
366
    }
367
    
368
    private void getNumDescendentsAndLevelRecursive (InternalNode layoutEntity, InternalRelationship [] relationships, Set seenAlready, int [] numDescendentsAndLevel, int currentLevel) {
369
        if (seenAlready.contains(layoutEntity)) {
370
            return;
371
        }
372
        seenAlready.add(layoutEntity);
373
        numDescendentsAndLevel[NUM_LEVELS_INDEX] = Math.max(numDescendentsAndLevel[NUM_LEVELS_INDEX], currentLevel);
374
        Collection rels = findRelationships(layoutEntity, AS_SOURCE, relationships);
375
        for (Iterator iter = rels.iterator(); iter.hasNext();) {
376
            InternalRelationship layoutRel = (InternalRelationship) iter.next();
377
            InternalNode childEntity = layoutRel.getDestination();
378
            numDescendentsAndLevel[NUM_DESCENDENTS_INDEX]++;
379
            getNumDescendentsAndLevelRecursive(childEntity, relationships, seenAlready, numDescendentsAndLevel, currentLevel + 1);
380
            
381
        }
382
    }
383
        
384
	
385
	/**
94
	/**
386
	 * Modifies the weight value of the marked node recursively.
95
	 * 
96
	 * @param resizing
97
	 *            true if this algorithm should resize elements (default is
98
	 *            false)
387
	 */
99
	 */
388
	private void modifyWeightRecursively(InternalNode layoutEntity, int i, double weight, Set descendentsSeenSoFar, InternalNode [] entities, InternalRelationship [] relationships) {
100
	public void setResizing(boolean resizing) {
389
        // No need to do further computation!
101
		resize = resizing;
390
		if (layoutEntity == null) {
102
	}
391
			return;
392
		}
393
103
394
		if (descendentsSeenSoFar.contains(layoutEntity)) {
104
	public void setLayoutContext(LayoutContext context) {
395
			return; //No need to do further computation.
105
		if (treeObserver != null) {
106
			treeObserver.stop();
396
		}
107
		}
397
		
108
		this.context = context;
398
		descendentsSeenSoFar.add(layoutEntity);
109
		treeObserver = new TreeLayoutObserver(context, null);
399
		// No need to do further computation!
110
	}
400
		if (weight < weights[i]) {
111
112
	public void applyLayout(boolean clean) {
113
		if (!clean)
401
			return;
114
			return;
402
		}
403
115
404
		weights[i] = weight;
116
		internalApplyLayout();
405
		Collection rels = findRelationships(layoutEntity, AS_SOURCE, relationships);
406
		
407
		
408
		for (Iterator iter = rels.iterator(); iter.hasNext();) {
409
			InternalRelationship tmpRel = (InternalRelationship) iter.next();
410
			InternalNode tmpEntity = tmpRel.getDestination();
411
            int tmpEntityIndex = indexOfInternalNode(entities, tmpEntity);
412
			modifyWeightRecursively(tmpEntity, tmpEntityIndex, weight + 1, descendentsSeenSoFar, entities, relationships);
413
		}
414
	}
415
117
416
	/**
118
		EntityLayout[] entities = context.getEntities();
417
	 * Gets the maxium weight of a tree in the forest of this TreeLayoutAlgorithm.
119
418
	 */
120
		if (resize) {
419
	private double getMaxiumWeightRecursive(InternalNode layoutEntity, int i, Set seenAlready, InternalNode [] entities) {
121
			AlgorithmHelper.maximizeSizes(entities);
420
		double result = 0;
421
        if (seenAlready.contains(layoutEntity)) {
422
            return result;
423
        }
424
        seenAlready.add(layoutEntity);
425
        List children = childrenLists[i];
426
		if (children.isEmpty()) {
427
			result = weights[i];
428
		} else {
429
			//TODO: SLOW
430
            for (Iterator iter = children.iterator(); iter.hasNext();) {
431
                InternalNode childEntity = (InternalNode) iter.next();
432
                int childEntityIndex = indexOfInternalNode(entities, childEntity);
433
                result = Math.max(result, getMaxiumWeightRecursive(childEntity, childEntityIndex, seenAlready, entities));
434
			}
435
		}
122
		}
436
		return result;
123
124
		DisplayIndependentRectangle bounds2 = new DisplayIndependentRectangle(bounds);
125
		AlgorithmHelper.fitWithinBounds(entities, bounds2, resize);
437
	}
126
	}
438
	
439
	/**
440
	 * Computes positions for each node in this TreeLayoutAlgorithm by
441
	 * referencing the forest that holds those nodes.
442
	 */
443
    private void computePositions(List roots, InternalNode [] entities) {
444
		// No need to do further computation!
445
		if (roots.size() == 0) {
446
			return;
447
		}
448
127
449
		int totalLeafCount = 0;
128
	void internalApplyLayout() {
450
		double maxWeight = 0;
129
		TreeNode superRoot = treeObserver.getSuperRoot();
451
		for (int i = 0; i < roots.size(); i++) {
130
		bounds = context.getBounds();
452
			InternalNode rootEntity = (InternalNode) roots.get(i);
131
		if (direction == TOP_DOWN || direction == BOTTOM_UP) {
453
            int rootEntityIndex = indexOfInternalNode(entities, rootEntity);
132
			leafSize = bounds.width / superRoot.numOfLeaves;
454
			totalLeafCount = totalLeafCount + getNumberOfLeaves(rootEntity, rootEntityIndex, entities);
133
			layerSize = bounds.height / superRoot.height;
455
			maxWeight = Math.max(maxWeight, getMaxiumWeightRecursive(rootEntity, rootEntityIndex, new HashSet(), entities) + 1.0);
134
		} else {
135
			leafSize = bounds.height / superRoot.numOfLeaves;
136
			layerSize = bounds.width / superRoot.height;
456
		}
137
		}
457
		
458
		double width = 1.0 / totalLeafCount;
459
		double height = 1.0 / maxWeight;
460
461
		int leafCountSoFar = 0;
138
		int leafCountSoFar = 0;
462
		
139
		for (Iterator iterator = superRoot.getChildren().iterator(); iterator.hasNext();) {
463
		//TODO: SLOW!
140
			TreeNode rootInfo = (TreeNode) iterator.next();
464
		for (int i = 0; i < roots.size(); i++) {
141
			computePositionRecursively(rootInfo, leafCountSoFar);
465
			InternalNode rootEntity = (InternalNode) roots.get(i);
142
			leafCountSoFar = leafCountSoFar + rootInfo.numOfLeaves;
466
            int rootEntityIndex = indexOfInternalNode(entities, rootEntity);
467
			computePositionRecursively(rootEntity, rootEntityIndex, leafCountSoFar, width, height, new HashSet(), entities);
468
			leafCountSoFar = leafCountSoFar + getNumberOfLeaves(rootEntity, rootEntityIndex, entities);
469
		}
143
		}
470
	}
144
	}
471
	
145
472
	/**
146
	/**
473
	 * Computes positions recursively until the leaf nodes are reached.
147
	 * Computes positions recursively until the leaf nodes are reached.
474
	 */
148
	 */
475
	private void computePositionRecursively(InternalNode layoutEntity, int i, int relativePosition, double width, double height, Set seenAlready, InternalNode [] entities) {
149
	private void computePositionRecursively(TreeNode entityInfo, int relativePosition) {
476
        if (seenAlready.contains(layoutEntity)) {
150
		double breadthPosition = relativePosition + entityInfo.numOfLeaves / 2.0;
477
			return;
151
		double depthPosition = (entityInfo.depth + 0.5);
478
		}
152
479
	    seenAlready.add(layoutEntity);
153
		switch (direction) {
480
		double level = getLevel(layoutEntity, i, entities);
154
		case TOP_DOWN:
481
		int breadth = getNumberOfLeaves(layoutEntity, i, entities);
155
			entityInfo.getNode().setLocation(breadthPosition * leafSize, depthPosition * layerSize);
482
		double absHPosition = relativePosition + breadth / 2.0;
156
			break;
483
		double absVPosition = (level + 0.5);
157
		case BOTTOM_UP:
484
158
			entityInfo.getNode().setLocation(breadthPosition * leafSize, bounds.height - depthPosition * layerSize);
485
		double posx = absHPosition * width;
159
			break;
486
		double posy = absVPosition * height;
160
		case LEFT_RIGHT:
487
        double weight = weights[i];
161
			entityInfo.getNode().setLocation(depthPosition * layerSize, breadthPosition * leafSize);
488
		posy = posy  + height * (weight - level);
162
			break;
489
		layoutEntity.setInternalLocation( posx, posy );
163
		case RIGHT_LEFT:
490
		
164
			entityInfo.getNode().setLocation(bounds.width - depthPosition * layerSize, breadthPosition * leafSize);
491
165
			break;
492
		int relativeCount = 0;
166
		}
493
		List children = childrenLists[i];
167
494
		//TODO: Slow
168
		for (Iterator iterator = entityInfo.children.iterator(); iterator.hasNext();) {
495
        for (Iterator iter = children.iterator(); iter.hasNext();) {
169
			TreeNode childInfo = (TreeNode) iterator.next();
496
            InternalNode childEntity = (InternalNode) iter.next();
170
			computePositionRecursively(childInfo, relativePosition);
497
            int childEntityIndex = indexOfInternalNode(entities, childEntity);
171
			relativePosition += childInfo.numOfLeaves;
498
			computePositionRecursively(childEntity, childEntityIndex, relativePosition + relativeCount, width, height, seenAlready, entities);
499
			relativeCount = relativeCount + getNumberOfLeaves(childEntity, childEntityIndex, entities);
500
		}
172
		}
501
	}
173
	}
502
	
503
	private int getNumberOfLeaves (InternalNode layoutEntity, int i, InternalNode [] entities) {
504
	    return getNumberOfLeavesRecursive(layoutEntity, i, new HashSet(), entities);
505
	}
506
	
507
	private int getNumberOfLeavesRecursive(InternalNode layoutEntity, int i, Set seen, InternalNode [] entities) {
508
        int numLeaves = 0;
509
        List children = childrenLists[i];
510
        if (children.size() == 0) {
511
            numLeaves = 1;
512
        } else {
513
			//TODO: SLOW!
514
            for (Iterator iter = children.iterator(); iter.hasNext();) {
515
                InternalNode childEntity = (InternalNode) iter.next();
516
	            if (!seen.contains(childEntity)) {
517
		            seen.add (childEntity);
518
                    int childEntityIndex = indexOfInternalNode(entities, childEntity);
519
		            numLeaves += getNumberOfLeavesRecursive(childEntity, childEntityIndex, seen, entities);
520
	            } else {
521
	            	numLeaves = 1;
522
	            }
523
	        }
524
        }
525
        return numLeaves;
526
    }
527
	
528
	private int getLevel (InternalNode layoutEntity, int i, InternalNode [] entities) {
529
	    return getLevelRecursive(layoutEntity, i, new HashSet(), entities);
530
	}
531
	
532
	private int getLevelRecursive(InternalNode layoutEntity, int i, Set seen, InternalNode [] entities) {
533
        if (seen.contains(layoutEntity)) {
534
            return 0;
535
        }
536
        seen.add(layoutEntity);
537
		List parents = parentLists[i];
538
		int maxParentLevel = 0; 
539
		for (Iterator iter = parents.iterator(); iter.hasNext();) {
540
			InternalNode parentEntity = (InternalNode) iter.next();
541
            int parentEntityIndex = indexOfInternalNode(entities, parentEntity);
542
            int parentLevel = getLevelRecursive(parentEntity, parentEntityIndex, seen, entities) + 1;
543
            maxParentLevel = Math.max(maxParentLevel, parentLevel);
544
		}
545
        return maxParentLevel;
546
    }
547
    
548
    /**
549
     * Note: Use this as little as possible!
550
     * TODO limit the use of this method 
551
     * @param nodes
552
     * @param nodeToFind
553
     * @return
554
     */
555
    private int indexOfInternalNode (InternalNode [] nodes, InternalNode nodeToFind) {
556
        for (int i = 0; i < nodes.length; i++) {
557
            InternalNode node = nodes[i];
558
            if (node.equals(nodeToFind)) {
559
                return i;
560
            }
561
        }
562
        throw new RuntimeException("Couldn't find index of internal node: " + nodeToFind);
563
    }
564
565
566
	protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) {
567
		if ( asynchronous && continueous ) {
568
			return false;
569
		} else if ( asynchronous && !continueous ) {
570
			return true;
571
		} else if ( !asynchronous && continueous ) {
572
			return false;
573
		} else if ( !asynchronous && !continueous ) {
574
			return true;
575
		}
576
		
577
		return false;
578
	}
579
580
} 
174
} 
(-)src/org/eclipse/zest/layouts/algorithms/VerticalLayoutAlgorithm.java (-52 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
12
13
import org.eclipse.zest.layouts.LayoutStyles;
14
15
/**
16
 * @version  2.0
17
 * @author   Casey Best and Rob Lintern (version 1.0 by Rob Lintern)
18
 */
19
public class VerticalLayoutAlgorithm extends GridLayoutAlgorithm {
20
21
	
22
	/**
23
	 * Veertical Layout Algorithm constructor with no styles.
24
	 *
25
	 */
26
	public VerticalLayoutAlgorithm() {
27
		this(LayoutStyles.NONE );
28
	}
29
	
30
	public VerticalLayoutAlgorithm(int styles) {
31
		super(styles);
32
	}
33
34
	/**
35
	 * Calculates and returns an array containing the number of columns, followed by the number of rows
36
	 */
37
	protected int[] calculateNumberOfRowsAndCols (int numChildren, double boundX, double boundY, double boundWidth, double boundHeight) {
38
		int cols = 1;
39
		int rows = numChildren;
40
		int[] result = {cols, rows};
41
		return result;
42
	}
43
	
44
	protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) {
45
		if ( asynchronous && continueous ) return false;
46
		else if ( asynchronous && !continueous ) return true;
47
		else if ( !asynchronous && continueous ) return false;
48
		else if ( !asynchronous && !continueous ) return true;
49
		
50
		return false;
51
	}
52
}
(-)src/org/eclipse/zest/layouts/algorithms/DirectedGraphLayoutAlgorithm.java (-59 / +72 lines)
Lines 1-13 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright (c) 2005-2009 The Chisel Group and others. All rights reserved. This
3
 * All rights reserved. This program and the accompanying materials
3
 * program and the accompanying materials are made available under the terms of
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * which accompanies this distribution, and is available at
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 *
7
 * Contributors: The Chisel Group - initial API and implementation
8
 * Contributors:
8
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 *     The Chisel Group, University of Victoria
9
 *               Ian Bull
10
 *******************************************************************************/
10
 ******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
11
package org.eclipse.zest.layouts.algorithms;
12
12
13
import java.lang.reflect.Field;
13
import java.lang.reflect.Field;
Lines 20-30 Link Here
20
import org.eclipse.draw2d.graph.DirectedGraphLayout;
20
import org.eclipse.draw2d.graph.DirectedGraphLayout;
21
import org.eclipse.draw2d.graph.Edge;
21
import org.eclipse.draw2d.graph.Edge;
22
import org.eclipse.draw2d.graph.Node;
22
import org.eclipse.draw2d.graph.Node;
23
import org.eclipse.swt.SWT;
23
import org.eclipse.zest.layouts.LayoutAlgorithm;
24
import org.eclipse.zest.layouts.dataStructures.InternalNode;
24
import org.eclipse.zest.layouts.interfaces.ConnectionLayout;
25
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;
25
import org.eclipse.zest.layouts.interfaces.EntityLayout;
26
import org.eclipse.zest.layouts.interfaces.LayoutContext;
27
import org.eclipse.zest.layouts.interfaces.NodeLayout;
28
import org.eclipse.zest.layouts.interfaces.SubgraphLayout;
26
29
27
public class DirectedGraphLayoutAlgorithm extends AbstractLayoutAlgorithm {
30
public class DirectedGraphLayoutAlgorithm implements LayoutAlgorithm {
28
31
29
	class ExtendedDirectedGraphLayout extends DirectedGraphLayout {
32
	class ExtendedDirectedGraphLayout extends DirectedGraphLayout {
30
33
Lines 51-124 Link Here
51
				e.printStackTrace();
54
				e.printStackTrace();
52
			}
55
			}
53
		}
56
		}
57
	}
58
59
	public static final int HORIZONTAL = 1;
60
61
	public static final int VERTICAL = 2;
62
63
	private int orientation = VERTICAL;
64
65
	private LayoutContext context;
66
67
	private HorizontalShiftAlgorithm hsAlgorithm = new HorizontalShiftAlgorithm();
54
68
69
	public DirectedGraphLayoutAlgorithm() {
55
	}
70
	}
56
71
57
	public DirectedGraphLayoutAlgorithm(int styles) {
72
	public DirectedGraphLayoutAlgorithm(int orientation) {
58
		super(styles);
73
		if (orientation == VERTICAL)
74
			this.orientation = orientation;
59
	}
75
	}
60
76
61
	protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY, double boundsWidth, double boundsHeight) {
77
	public int getOrientation() {
62
		HashMap mapping = new HashMap(entitiesToLayout.length);
78
		return orientation;
79
	}
80
81
	public void setOrientation(int orientation) {
82
		if (orientation == HORIZONTAL || orientation == VERTICAL)
83
			this.orientation = orientation;
84
	}
85
86
	public void applyLayout(boolean clean) {
87
		if (!clean)
88
			return;
89
		HashMap mapping = new HashMap();
63
		DirectedGraph graph = new DirectedGraph();
90
		DirectedGraph graph = new DirectedGraph();
64
		for (int i = 0; i < entitiesToLayout.length; i++) {
91
		EntityLayout[] entities = context.getEntities();
65
			InternalNode internalNode = entitiesToLayout[i];
92
		for (int i = 0; i < entities.length; i++) {
66
			Node node = new Node(internalNode);
93
			Node node = new Node(entities[i]);
67
			node.setSize(new Dimension(10, 10));
94
			node.setSize(new Dimension(10, 10));
68
			mapping.put(internalNode, node);
95
			mapping.put(entities[i], node);
69
			graph.nodes.add(node);
96
			graph.nodes.add(node);
70
		}
97
		}
71
		for (int i = 0; i < relationshipsToConsider.length; i++) {
98
		ConnectionLayout[] connections = context.getConnections();
72
			InternalRelationship relationship = relationshipsToConsider[i];
99
		for (int i = 0; i < connections.length; i++) {
73
			Node source = (Node) mapping.get(relationship.getSource());
100
			Node source = (Node) mapping.get(getEntity(connections[i].getSource()));
74
			Node dest = (Node) mapping.get(relationship.getDestination());
101
			Node dest = (Node) mapping.get(getEntity(connections[i].getTarget()));
75
			Edge edge = new Edge(relationship, source, dest);
102
			if (source != null && dest != null) {
76
			graph.edges.add(edge);
103
				Edge edge = new Edge(connections[i], source, dest);
104
				graph.edges.add(edge);
105
			}
77
		}
106
		}
78
		DirectedGraphLayout directedGraphLayout = new ExtendedDirectedGraphLayout();
107
		DirectedGraphLayout directedGraphLayout = new ExtendedDirectedGraphLayout();
79
		directedGraphLayout.visit(graph);
108
		directedGraphLayout.visit(graph);
80
109
81
		for (Iterator iterator = graph.nodes.iterator(); iterator.hasNext();) {
110
		for (Iterator iterator = graph.nodes.iterator(); iterator.hasNext();) {
82
			Node node = (Node) iterator.next();
111
			Node node = (Node) iterator.next();
83
			InternalNode internalNode = (InternalNode) node.data;
112
			EntityLayout entity = (EntityLayout) node.data;
84
			// For horizontal layout transpose the x and y coordinates
113
			if (orientation == VERTICAL) {
85
			if ((layout_styles & SWT.HORIZONTAL) == SWT.HORIZONTAL) {
114
				entity.setLocation(node.x, node.y);
86
				internalNode.setInternalLocation(node.y, node.x);
115
			} else {
87
			}else {
116
				entity.setLocation(node.y, node.x);
88
				internalNode.setInternalLocation(node.x, node.y);
89
			}
117
			}
90
		}
118
		}
91
		updateLayoutLocations(entitiesToLayout);
92
	}
93
94
	protected int getCurrentLayoutStep() {
95
		// TODO Auto-generated method stub
96
		return 0;
97
	}
98
99
	protected int getTotalNumberOfLayoutSteps() {
100
		// TODO Auto-generated method stub
101
		return 0;
102
	}
103
119
104
	protected boolean isValidConfiguration(boolean asynchronous, boolean continuous) {
120
		hsAlgorithm.applyLayout(clean);
105
		// TODO Auto-generated method stub
106
		return true;
107
	}
121
	}
108
122
109
	protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) {
123
	private EntityLayout getEntity(NodeLayout node) {
110
		// TODO Auto-generated method stub
124
		if (!node.isPruned())
111
125
			return node;
126
		SubgraphLayout subgraph = node.getSubgraph();
127
		if (subgraph.isGraphEntity())
128
			return subgraph;
129
		return null;
112
	}
130
	}
113
131
114
	protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) {
132
	public void setLayoutContext(LayoutContext context) {
115
		// TODO Auto-generated method stub
133
		this.context = context;
116
134
		hsAlgorithm.setLayoutContext(context);
117
	}
118
119
	public void setLayoutArea(double x, double y, double width, double height) {
120
		// TODO Auto-generated method stub
121
122
	}
135
	}
123
136
124
}
137
}
(-)src/org/eclipse/zest/layouts/algorithms/CompositeLayoutAlgorithm.java (-62 / +20 lines)
Lines 1-77 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright (c) 2005-2009 The Chisel Group and others. All rights reserved. This
3
 * All rights reserved. This program and the accompanying materials
3
 * program and the accompanying materials are made available under the terms of
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * which accompanies this distribution, and is available at
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 *
7
 * Contributors: The Chisel Group - initial API and implementation
8
 * Contributors:
8
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 *     The Chisel Group, University of Victoria
9
 *               Ian Bull
10
 *******************************************************************************/
10
 ******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
11
package org.eclipse.zest.layouts.algorithms;
12
12
13
import org.eclipse.zest.layouts.InvalidLayoutConfiguration;
14
import org.eclipse.zest.layouts.LayoutAlgorithm;
13
import org.eclipse.zest.layouts.LayoutAlgorithm;
15
import org.eclipse.zest.layouts.dataStructures.InternalNode;
14
import org.eclipse.zest.layouts.interfaces.LayoutContext;
16
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;
17
15
18
public class CompositeLayoutAlgorithm extends AbstractLayoutAlgorithm {
16
public class CompositeLayoutAlgorithm implements LayoutAlgorithm {
19
17
20
	LayoutAlgorithm[] algorithms = null;
18
	private LayoutAlgorithm[] algorithms = null;
21
19
22
	public CompositeLayoutAlgorithm(int styles, LayoutAlgorithm[] algoirthms) {
20
	public CompositeLayoutAlgorithm(LayoutAlgorithm[] algorithms) {
23
		super(styles);
21
		this.algorithms = algorithms;
24
		this.algorithms = algoirthms;
25
	}
22
	}
26
	
27
	public CompositeLayoutAlgorithm( LayoutAlgorithm[] algoirthms) {
28
		this(0, algoirthms);
29
	}
30
31
	protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY, double boundsWidth, double boundsHeight) {
32
23
24
	public void applyLayout(boolean clean) {
33
		for (int i = 0; i < algorithms.length; i++) {
25
		for (int i = 0; i < algorithms.length; i++) {
34
			try {
26
			algorithms[i].applyLayout(clean);
35
				algorithms[i].applyLayout(entitiesToLayout, relationshipsToConsider, boundsX, boundsY, boundsWidth, boundsHeight, this.internalAsynchronous, this.internalContinuous);
36
			} catch (InvalidLayoutConfiguration e) {
37
				e.printStackTrace();
38
			}
39
		}
40
		for (int i = 0; i < entitiesToLayout.length; i++) {
41
			entitiesToLayout[i].getLayoutEntity().setLocationInLayout(entitiesToLayout[i].getXInLayout(), entitiesToLayout[i].getYInLayout());
42
		}
27
		}
43
44
		//updateLayoutLocations(entitiesToLayout);
45
	}
46
47
	protected int getCurrentLayoutStep() {
48
		// TODO Auto-generated method stub
49
		return 0;
50
	}
51
52
	protected int getTotalNumberOfLayoutSteps() {
53
		// TODO Auto-generated method stub
54
		return 0;
55
	}
56
57
	protected boolean isValidConfiguration(boolean asynchronous, boolean continuous) {
58
		// TODO Auto-generated method stub
59
		return true;
60
	}
28
	}
61
29
62
	protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) {
30
	public void setLayoutContext(LayoutContext context) {
63
		// TODO Auto-generated method stub
31
		for (int i = 0; i < algorithms.length; i++) {
64
32
			algorithms[i].setLayoutContext(context);
65
	}
33
		}
66
67
	protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) {
68
		// TODO Auto-generated method stub
69
70
	}
71
72
	public void setLayoutArea(double x, double y, double width, double height) {
73
		// TODO Auto-generated method stub
74
75
	}
34
	}
76
77
}
35
}
(-)src/org/eclipse/zest/layouts/algorithms/HorizontalShift.java (-131 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
12
13
import java.util.ArrayList;
14
import java.util.Collections;
15
import java.util.Comparator;
16
import java.util.Iterator;
17
import java.util.List;
18
19
import org.eclipse.zest.layouts.LayoutEntity;
20
import org.eclipse.zest.layouts.dataStructures.InternalNode;
21
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;
22
23
/**
24
 * This layout shifts overlapping nodes to the right.
25
 * @author Ian Bull
26
 */
27
public class HorizontalShift extends AbstractLayoutAlgorithm {
28
29
	private static final double DELTA = 10;
30
	private static final double VSPACING = 2;
31
32
	public HorizontalShift(int styles) {
33
		super(styles);
34
	}
35
36
	protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider,
37
			double boundsX, double boundsY, double boundsWidth, double boundsHeight) {
38
		
39
		ArrayList row = new ArrayList();
40
		for ( int i =0; i < entitiesToLayout.length; i++) {
41
			addToRowList(entitiesToLayout[i], row);
42
		}
43
44
		int heightSoFar = 0;
45
		
46
		Collections.sort(row, new Comparator() {
47
48
			public int compare(Object arg0, Object arg1) {
49
				// TODO Auto-generated method stub
50
				List a0 = (List) arg0;
51
				List a1 = (List) arg1;
52
				LayoutEntity node0 = ((InternalNode)a0.get(0)).getLayoutEntity();
53
				LayoutEntity node1 = ((InternalNode)a1.get(0)).getLayoutEntity();
54
				return (int) (node0.getYInLayout() - (node1.getYInLayout()));
55
			}
56
			
57
		});
58
59
		Iterator iterator = row.iterator();
60
		while (iterator.hasNext() ) {
61
			List currentRow = (List) iterator.next();
62
			Collections.sort(currentRow, new Comparator() {
63
				public int compare(Object arg0, Object arg1) {
64
					return (int) (((InternalNode)arg1).getLayoutEntity().getYInLayout() - ((InternalNode)arg0).getLayoutEntity().getYInLayout());
65
				}
66
			});
67
			Iterator iterator2 = currentRow.iterator();
68
			int i = 0;
69
			int width = (int) ((boundsWidth / 2) - currentRow.size() * 75);
70
			
71
			heightSoFar += ((InternalNode)currentRow.get(0)).getLayoutEntity().getHeightInLayout() + VSPACING*8 ;
72
			while(iterator2.hasNext()) {
73
				InternalNode currentNode = (InternalNode) iterator2.next();
74
				
75
				double location = width + 10*++i;
76
				currentNode.setLocation(location , heightSoFar);
77
				width += currentNode.getLayoutEntity().getWidthInLayout();
78
			}
79
		}
80
	}
81
	
82
	
83
	private void addToRowList( InternalNode node, ArrayList list) {
84
		double  layoutY = node.getLayoutEntity().getYInLayout();
85
		
86
		for ( int i = 0; i < list.size(); i++ ) {
87
			List currentRow = (List) list.get(i);
88
			InternalNode currentRowNode = (InternalNode) currentRow.get(0);
89
			double currentRowY = currentRowNode.getLayoutEntity().getYInLayout();
90
			//double currentRowHeight = currentRowNode.getLayoutEntity().getHeightInLayout();
91
			if ( layoutY >= (currentRowY-DELTA) && layoutY <= currentRowY + DELTA ) {
92
				currentRow.add(node);
93
				//list.add(i, currentRow);
94
				return;
95
			}
96
		}
97
		List newRow = new ArrayList();
98
		newRow.add(node);
99
		list.add(newRow);
100
	}
101
102
	protected int getCurrentLayoutStep() {
103
		// TODO Auto-generated method stub
104
		return 0;
105
	}
106
107
	protected int getTotalNumberOfLayoutSteps() {
108
		// TODO Auto-generated method stub
109
		return 0;
110
	}
111
112
	protected boolean isValidConfiguration(boolean asynchronous, boolean continuous) {
113
		// TODO Auto-generated method stub
114
		return true;
115
	}
116
117
	protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) {
118
		// TODO Auto-generated method stub
119
	}
120
121
	protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider,
122
			double x, double y, double width, double height) {
123
		// TODO Auto-generated method stub
124
125
	}
126
127
	public void setLayoutArea(double x, double y, double width, double height) {
128
		// TODO Auto-generated method stub
129
	}
130
}
131
(-)src/org/eclipse/zest/layouts/algorithms/RadialLayoutAlgorithm.java (-122 / +69 lines)
Lines 1-149 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright (c) 2005-2009 The Chisel Group and others. All rights reserved. This
3
 * All rights reserved. This program and the accompanying materials
3
 * program and the accompanying materials are made available under the terms of
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * which accompanies this distribution, and is available at
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 *
7
 * Contributors: The Chisel Group - initial API and implementation
8
 * Contributors:
8
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 *     The Chisel Group, University of Victoria
9
 *               Ian Bull
10
 *******************************************************************************/
10
 ******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
11
package org.eclipse.zest.layouts.algorithms;
12
12
13
import java.util.Iterator;
13
import org.eclipse.zest.layouts.LayoutAlgorithm;
14
import java.util.List;
15
16
import org.eclipse.zest.layouts.LayoutStyles;
17
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint;
14
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint;
18
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
15
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
19
import org.eclipse.zest.layouts.dataStructures.InternalNode;
16
import org.eclipse.zest.layouts.interfaces.EntityLayout;
20
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;
17
import org.eclipse.zest.layouts.interfaces.LayoutContext;
21
22
18
23
/**
19
/**
24
 * This layout will take the given entities, apply a tree layout to them, and then display the 
20
 * This layout will take the given entities, apply a tree layout to them, and
25
 * tree in a circular fashion with the roots in the center.
21
 * then display the tree in a circular fashion with the roots in the center.
26
 * 
22
 * 
27
 * @author Casey Best
23
 * @author Casey Best
28
 * @auhtor Rob Lintern
24
 * @auhtor Rob Lintern
29
 */
25
 */
30
public class RadialLayoutAlgorithm extends TreeLayoutAlgorithm {
26
public class RadialLayoutAlgorithm implements LayoutAlgorithm {
27
31
	private static final double MAX_DEGREES = Math.PI * 2;
28
	private static final double MAX_DEGREES = Math.PI * 2;
32
	private double startDegree;
29
	private double startDegree = 0;
33
	private double endDegree;
30
	private double endDegree = MAX_DEGREES;
34
	private TreeLayoutAlgorithm treeLayout;
31
35
	private List roots;
32
	private LayoutContext context;
36
	
33
	private boolean resize = false;
37
	
34
38
	/**
35
	private TreeLayoutAlgorithm treeLayout = new TreeLayoutAlgorithm();
39
	 * Creates a radial layout with no style.
40
	 */
41
	public RadialLayoutAlgorithm() {
42
		this ( LayoutStyles.NONE );
43
	}
44
	
45
	//TODO: This is a really strange pattern.  It extends tree layout and it contains a tree layout ? 
46
	public RadialLayoutAlgorithm ( int styles ) {
47
		super( styles );
48
		treeLayout = new TreeLayoutAlgorithm( styles );
49
		startDegree = 0;
50
		endDegree = MAX_DEGREES;
51
	}
52
	
53
	public void setLayoutArea(double x, double y, double width, double height) {
54
		throw new RuntimeException("Operation not implemented");
55
	}
56
	
57
	
36
	
58
	protected boolean isValidConfiguration(boolean asynchronous, boolean continueous) {		
37
	public void applyLayout(boolean clean) {
59
		if ( asynchronous && continueous ) return false;
38
		if (!clean)
60
		else if ( asynchronous && !continueous ) return true;
39
			return;
61
		else if ( !asynchronous && continueous ) return false;
40
		treeLayout.internalApplyLayout();
62
		else if ( !asynchronous && !continueous ) return true;
41
		EntityLayout[] entities = context.getEntities();
63
		
42
		DisplayIndependentRectangle bounds = context.getBounds();
64
		return false;	
43
		computeRadialPositions(entities, bounds);
44
		if (resize)
45
			AlgorithmHelper.maximizeSizes(entities);
46
		AlgorithmHelper.fitWithinBounds(entities, bounds, resize);
47
	}
48
49
	private void computeRadialPositions(EntityLayout[] entities, DisplayIndependentRectangle bounds) {
50
		DisplayIndependentRectangle layoutBounds = AlgorithmHelper.getLayoutBounds(entities, false);
51
		layoutBounds.x = bounds.x;
52
		layoutBounds.width = bounds.width;
53
		for (int i = 0; i < entities.length; i++) {
54
			DisplayIndependentPoint location = entities[i].getLocation();
55
			double percenttheta = (location.x - layoutBounds.x) / layoutBounds.width;
56
			double distance = (location.y - layoutBounds.y) / layoutBounds.height;
57
			double theta = startDegree + Math.abs(endDegree - startDegree) * percenttheta;
58
			location.x = distance * Math.cos(theta);
59
			location.y = distance * Math.sin(theta);
60
			entities[i].setLocation(location.x, location.y);
61
		}
65
	}
62
	}
66
	
67
63
68
	DisplayIndependentRectangle layoutBounds = null;
64
	public void setLayoutContext(LayoutContext context) {
69
	protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) {
65
		this.context = context;
70
		// TODO Auto-generated method stub
66
		treeLayout.setLayoutContext(context);
71
		layoutBounds = new DisplayIndependentRectangle(x, y, width, height);
72
		super.preLayoutAlgorithm(entitiesToLayout, relationshipsToConsider, x, y,
73
				width, height);
74
	}
67
	}
75
	
76
	protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) {
77
		roots = treeLayout.getRoots();
78
		computeRadialPositions (entitiesToLayout, layoutBounds);
79
		
80
		defaultFitWithinBounds(entitiesToLayout, layoutBounds);
81
		
82
		super.postLayoutAlgorithm(entitiesToLayout, relationshipsToConsider);
83
68
84
	}
85
	
86
	/**
69
	/**
87
	 * Set the range the radial layout will use when applyLayout is called.
70
	 * Set the range the radial layout will use when applyLayout is called. Both
88
	 * Both values must be in radians.
71
	 * values must be in radians.
89
	 */
72
	 */
90
	public void setRangeToLayout (double startDegree, double endDegree) {
73
	public void setRangeToLayout(double startDegree, double endDegree) {
91
	    this.startDegree = startDegree;
74
		this.startDegree = startDegree;
92
	    this.endDegree = endDegree;
75
		this.endDegree = endDegree;
93
	}
76
	}
94
	
77
95
	/**
96
	 * Take the tree and make it round.  This is done by determining the location of each entity in terms
97
	 * of its percentage in the tree layout.  Then apply that percentage to the radius and distance from
98
	 * the center.
99
	 */
100
	protected void computeRadialPositions (InternalNode[] entities, DisplayIndependentRectangle bounds2) { //TODO TODO TODO
101
		DisplayIndependentRectangle bounds = new DisplayIndependentRectangle(getLayoutBounds(entities, true));
102
		bounds.height = bounds2.height;
103
		bounds.y = bounds2.y;
104
        for (int i = 0; i < entities.length; i++) {
105
            InternalNode entity = entities[i];
106
			double percentTheta = (entity.getInternalX() - bounds.x) / bounds.width;
107
			double distance = (entity.getInternalY() - bounds.y) / bounds.height;
108
			double theta = startDegree + Math.abs(endDegree - startDegree) * percentTheta;
109
			double newX = distance * Math.cos (theta);
110
			double newY = distance * Math.sin (theta);
111
			
112
			entity.setInternalLocation( newX, newY );
113
		}
114
	}
115
	
116
	/**
78
	/**
117
	 * Find the bounds in which the nodes are located.  Using the bounds against the real bounds
79
	 * 
118
	 * of the screen, the nodes can proportionally be placed within the real bounds.
80
	 * @return true if this algorithm is set to resize elements
119
	 * The bounds can be determined either including the size of the nodes or not.  If the size
120
	 * is not included, the bounds will only be guaranteed to include the center of each node.
121
	 */
81
	 */
122
	protected DisplayIndependentRectangle getLayoutBounds (InternalNode[] entitiesToLayout, boolean includeNodeSize) {
82
	public boolean isResizing() {
123
		DisplayIndependentRectangle layoutBounds = super.getLayoutBounds(entitiesToLayout, includeNodeSize);
83
		return resize;
124
		DisplayIndependentPoint centerPoint = (roots != null) ? determineCenterPoint(roots) : 
125
		    new DisplayIndependentPoint (layoutBounds.x + layoutBounds.width / 2, layoutBounds.y + layoutBounds.height / 2);
126
		//	The center entity is determined in applyLayout
127
		double maxDistanceX = Math.max( 
128
				Math.abs (layoutBounds.x + layoutBounds.width - centerPoint.x),
129
				Math.abs (centerPoint.x - layoutBounds.x));
130
		double maxDistanceY = Math.max( 
131
				Math.abs (layoutBounds.y + layoutBounds.height - centerPoint.y),
132
				Math.abs (centerPoint.y - layoutBounds.y));
133
		layoutBounds = new DisplayIndependentRectangle (centerPoint.x - maxDistanceX, centerPoint.y - maxDistanceY, maxDistanceX * 2, maxDistanceY * 2);
134
		return layoutBounds;
135
	}
84
	}
136
	
85
137
	/**
86
	/**
138
	 * Find the center point between the roots
87
	 * 
88
	 * @param resizing
89
	 *            true if this algorithm should resize elements (default is
90
	 *            false)
139
	 */
91
	 */
140
	private DisplayIndependentPoint determineCenterPoint (List roots) {
92
	public void setResizing(boolean resizing) {
141
		double totalX = 0, totalY = 0;
93
		resize = resizing;
142
		for ( Iterator iterator = roots.iterator(); iterator.hasNext(); ) {
94
		treeLayout.setResizing(resize);
143
			InternalNode entity = (InternalNode)iterator.next();
144
			totalX += entity.getInternalX();
145
			totalY += entity.getInternalY();
146
		}
147
		return new DisplayIndependentPoint (totalX / roots.size(), totalY / roots.size());
148
	}
95
	}
149
}
96
}
(-)src/org/eclipse/zest/layouts/algorithms/internal/DynamicScreen.java (-126 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms.internal;
12
13
import java.util.Comparator;
14
import java.util.TreeSet;
15
16
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint;
17
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
18
import org.eclipse.zest.layouts.dataStructures.InternalNode;
19
20
21
public class DynamicScreen {
22
	
23
	private TreeSet XCoords = null;
24
	private TreeSet YCoords = null;
25
	
26
	
27
	
28
	private DisplayIndependentRectangle screenBounds = null;
29
	
30
	
31
	double minX = 0.0;
32
	double minY = 0.0;
33
	double maxX = 0.0;
34
	double maxY = 0.0;
35
	public void cleanScreen() {
36
		minX = 0.0;
37
		minY = 0.0;
38
		maxX = 0.0;
39
		maxY = 0.0;
40
	}
41
	
42
	class XComparator implements Comparator {
43
		public int compare(Object arg0, Object arg1) {
44
			InternalNode n1 = (InternalNode)arg0;
45
			InternalNode n2 = (InternalNode)arg1;
46
			if ( n1.getInternalX() > n2.getInternalX() ) return +1;
47
			else if ( n1.getInternalX() < n2.getInternalX() ) return -1;
48
			else {
49
				return n1.toString().compareTo( n2.toString() );
50
			}
51
			
52
		}		
53
	}
54
	class YComparator implements Comparator {
55
		public int compare(Object arg0, Object arg1) {
56
			InternalNode n1 = (InternalNode)arg0;
57
			InternalNode n2 = (InternalNode)arg1;
58
			if ( n1.getInternalY() > n2.getInternalY() ) return +1;
59
			else if ( n1.getInternalY() < n2.getInternalY() ) return -1;
60
			else {
61
				return n1.toString().compareTo( n2.toString() );
62
			}
63
64
		}		
65
	}
66
	
67
	
68
69
	
70
	public DynamicScreen(int x, int y, int width, int height) {
71
		XCoords = new TreeSet(new XComparator());
72
		YCoords = new TreeSet(new YComparator());
73
		
74
		
75
		
76
		this.screenBounds = new DisplayIndependentRectangle(x,y,width,height);
77
	}
78
	
79
	
80
	public void removeNode( InternalNode node ) {
81
		XCoords.remove( node );
82
		YCoords.remove( node );
83
	}
84
	
85
	public void addNode( InternalNode node ) {		
86
		XCoords.add( node );
87
		YCoords.add( node );
88
	}
89
	
90
	public DisplayIndependentPoint getScreenLocation( InternalNode node ) {
91
		
92
		DisplayIndependentRectangle layoutBounds = calculateBounds();
93
		
94
		double x = (layoutBounds.width == 0) ? 0 : (node.getInternalX() - layoutBounds.x) / layoutBounds.width;
95
		double y = (layoutBounds.height == 0) ? 0 : (node.getInternalY() - layoutBounds.y) / layoutBounds.height;		
96
		
97
		x = screenBounds.x + x * screenBounds.width;
98
		y = screenBounds.y + y * screenBounds.height;
99
		
100
		return new DisplayIndependentPoint( x, y );
101
	}
102
	 
103
	public DisplayIndependentPoint getVirtualLocation( DisplayIndependentPoint point ) {
104
		
105
		DisplayIndependentRectangle layoutBounds = calculateBounds();
106
		
107
		
108
		double x = (point.x/screenBounds.width) * layoutBounds.width + layoutBounds.x;
109
		double y = (point.y/screenBounds.height)  * layoutBounds.height + layoutBounds.y;
110
		
111
		return new DisplayIndependentPoint( x, y );
112
	}
113
	
114
	private DisplayIndependentRectangle calculateBounds() {		
115
		InternalNode n1 = (InternalNode) XCoords.first();
116
		InternalNode n2 = (InternalNode) XCoords.last();
117
		InternalNode n3 = (InternalNode) YCoords.first();
118
		InternalNode n4 = (InternalNode) YCoords.last();
119
		double x = n1.getInternalX();
120
		double width = n2.getInternalX();
121
		double y = n3.getInternalY();
122
		double height = n4.getInternalY();
123
		return new DisplayIndependentRectangle(x, y, width - x, height - y);
124
	}
125
126
}
(-)src/org/eclipse/zest/layouts/algorithms/internal/CycleChecker.java (-119 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
12
package org.eclipse.zest.layouts.algorithms.internal;
13
14
import java.util.ArrayList;
15
import java.util.Arrays;
16
import java.util.Hashtable;
17
import java.util.Iterator;
18
import java.util.List;
19
20
import org.eclipse.zest.layouts.LayoutEntity;
21
import org.eclipse.zest.layouts.LayoutRelationship;
22
import org.eclipse.zest.layouts.algorithms.AbstractLayoutAlgorithm;
23
import org.eclipse.zest.layouts.exampleStructures.SimpleRelationship;
24
25
26
/**
27
 * Checks for cycles in the given graph.
28
 * 
29
 * @author Casey Best
30
 */
31
public class CycleChecker {
32
	/**
33
	 * Tests if there is a directed cirlce in the graph formed by the given entities and relationships.
34
	 * @param entities The entities in the graph to check
35
	 * @param relationships The relationships in the graph to check
36
	 * @param cycle Populated with the cycle encountered, if there is one.
37
	 * @throws RuntimeException Thrown if entities doesn't contain all of the endpoints for each relationship in relationships
38
	 * @return <code>true</code> if there is a directed circle.
39
	 * Otherwise, <code>false</code>.
40
	 */
41
	public static boolean hasDirectedCircles(LayoutEntity[] entities, LayoutRelationship[] relationships, List cycle) {
42
		if (!AbstractLayoutAlgorithm.verifyInput(entities, relationships)) {
43
			throw new RuntimeException ("The endpoints of the relationships aren't contained in the entities list.");
44
		}
45
		//Enumeration enum;
46
		//Iterator iterator;
47
48
		Hashtable endPoints = new Hashtable();
49
50
		// Initialize the relation(transitive) vector.
51
        for (int i = 0; i < relationships.length; i++) {
52
            LayoutRelationship rel = relationships[i];
53
54
			//Add the relationship to the source endpoint
55
			Object subject = rel.getSourceInLayout();
56
			List rels = (List) endPoints.get(subject);
57
			if (rels == null) {
58
				rels = new ArrayList();
59
				endPoints.put(subject, rels);
60
			}
61
			if (!rels.contains(rel))
62
				rels.add(rel);
63
		}
64
		boolean hasCyle = hasCycle(new ArrayList(Arrays.asList(entities)), endPoints, cycle);
65
		return hasCyle;
66
	}
67
68
	/**
69
	 * Check passed in nodes for a cycle
70
	 */
71
	private static boolean hasCycle(List nodesToCheck, Hashtable endPoints, List cycle) {
72
		while (nodesToCheck.size() > 0) {
73
			Object checkNode = nodesToCheck.get(0);
74
			List checkedNodes = new ArrayList();
75
			if (hasCycle(checkNode, new ArrayList(), null, endPoints, checkedNodes, cycle)) {
76
				return true;
77
			}
78
			nodesToCheck.removeAll(checkedNodes);
79
		}
80
		return false;
81
	}
82
83
	/**
84
	 * Checks all the nodes attached to the nodeToCheck node for a cycle.  All nodes
85
	 * checked are placed in nodePathSoFar.
86
	 *
87
	 * @returns true if there is a cycle
88
	 */
89
	private static boolean hasCycle(Object nodeToCheck, List nodePathSoFar, SimpleRelationship cameFrom, Hashtable endPoints, List nodesChecked, List cycle) {
90
		if (nodePathSoFar.contains(nodeToCheck)) {
91
			cycle.addAll(nodePathSoFar);
92
			cycle.add(nodeToCheck);
93
			return true;
94
		}
95
		nodePathSoFar.add(nodeToCheck);
96
		nodesChecked.add(nodeToCheck);
97
98
		List relations = (List) endPoints.get(nodeToCheck);
99
		if (relations != null) {
100
			for (Iterator iter = relations.iterator(); iter.hasNext();) {
101
				SimpleRelationship rel = (SimpleRelationship) iter.next();
102
103
				if (cameFrom == null || !rel.equals(cameFrom)) {
104
					Object currentNode = null;
105
					currentNode = rel.getDestinationInLayout();
106
					if (hasCycle(currentNode, nodePathSoFar, rel, endPoints, nodesChecked, cycle)) {
107
						return true;
108
					}
109
				}
110
111
			}
112
		}
113
114
		nodePathSoFar.remove(nodeToCheck);
115
116
		return false;
117
	}
118
119
}
(-)src/org/eclipse/zest/layouts/progress/ProgressEvent.java (-47 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.progress;
12
13
/**
14
 * When an algorithm wants to notify everyone it has completely part of its task, it
15
 * throws a ProgressEvent.  The progress is a number (currentProgress) representing the
16
 * current steps completed out of the total number of steps (totalProgress)
17
 * 
18
 * @author Casey Best
19
 */
20
public class ProgressEvent {
21
	int stepsCompleted;
22
	int totalSteps;
23
	
24
	/**
25
	 * Creates a progress event.
26
	 * @param stepsCompleted The current progress out of the total
27
	 * @param totalNumberOfSteps The number used to indicate when the algorithm will finish
28
	 */
29
	public ProgressEvent (int stepsCompleted, int totalNumberOfSteps) {
30
		this.stepsCompleted = stepsCompleted;
31
		this.totalSteps = totalNumberOfSteps;
32
	}
33
	
34
	/**
35
	 * Returns the number of steps already completed.
36
	 */
37
	public int getStepsCompleted() {
38
		return stepsCompleted;
39
	}
40
	
41
	/**
42
	 * Returns the total number of steps to complete.
43
	 */
44
	public int getTotalNumberOfSteps() {
45
		return totalSteps;
46
	}
47
}
(-)src/org/eclipse/zest/layouts/progress/ProgressListener.java (-38 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.progress;
12
13
14
/**
15
 * Listens for ProgressEvents which are thrown by layout algorithms at frequent intervals.
16
 * 
17
 * @author Ian Bull
18
 * @author Casey Best
19
 */
20
public interface ProgressListener {
21
22
	/**
23
	 * 
24
	 * @param e
25
	 */
26
	public void progressStarted( ProgressEvent e );
27
	
28
	/**
29
	 * Called when the progress of a layout changes
30
	 */
31
	public void progressUpdated (ProgressEvent e);
32
33
	/**
34
	 * 
35
	 * @param e
36
	 */
37
	public void progressEnded( ProgressEvent e );
38
}
(-)src/org/eclipse/zest/layouts/constraints/BasicEntityConstraint.java (-46 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.constraints;
12
13
/**
14
 * 
15
 * @author Chris Bennett
16
 *
17
 */
18
public class BasicEntityConstraint implements LayoutConstraint {
19
	
20
	
21
	public boolean hasPreferredLocation = false;
22
	
23
	public double preferredX;
24
	public double preferredY;
25
	
26
	public boolean hasPreferredSize = false;
27
	public double preferredWidth;
28
	public double preferredHeight;
29
	
30
	public BasicEntityConstraint() {
31
		clear();
32
	} 
33
	
34
	/*
35
	 * (non-Javadoc)
36
	 * @see org.eclipse.zest.layouts.constraints.LayoutConstraint#clear()
37
	 */
38
	public void clear() {
39
		this.hasPreferredLocation = false;
40
		this.hasPreferredSize = false;
41
		this.preferredX = 0.0;
42
		this.preferredY = 0.0;
43
		this.preferredWidth = 0.0;
44
		this.preferredHeight = 0.0;
45
	}
46
}
(-)src/org/eclipse/zest/layouts/constraints/EntityPriorityConstraint.java (-31 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.constraints;
12
13
/**
14
 * A layout constraint that uses priorities
15
 * @author Ian Bull
16
 */
17
public class EntityPriorityConstraint implements LayoutConstraint {
18
19
	// A priority that can be set for nodes.  This could be used
20
	// for a treemap layout
21
	public double priority = 1.0;
22
	
23
	/*
24
	 * (non-Javadoc)
25
	 * @see org.eclipse.zest.layouts.constraints.LayoutConstraint#clear()
26
	 */
27
	public void clear() {
28
		this.priority = 1.0;
29
	}
30
31
}
(-)src/org/eclipse/zest/layouts/constraints/LayoutConstraint.java (-26 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.constraints;
12
13
/**
14
 * @author Ian Bull
15
 * @author Chris Bennett
16
 */
17
public interface LayoutConstraint {
18
19
	// Empty interface
20
	
21
	/**
22
	 * This method clears all the fields of the layout constraints.
23
	 * This should not be called outside the layout package
24
	 */
25
	public void clear();
26
}
(-)src/org/eclipse/zest/layouts/constraints/BasicEdgeConstraints.java (-32 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.constraints;
12
13
/**
14
 * @author Ian Bull
15
 * @author Chris Bennett
16
 */
17
public class BasicEdgeConstraints implements LayoutConstraint {
18
19
	// These should all be accessed directly.  
20
	public boolean isBiDirectional = false;
21
	public int weight = 1;
22
	
23
	/*
24
	 * (non-Javadoc)
25
	 * @see org.eclipse.zest.layouts.constraints.LayoutConstraint#clear()
26
	 */
27
	public void clear() {
28
		this.isBiDirectional = false;
29
		this.weight = 1;
30
	}
31
	
32
}
(-)src/org/eclipse/zest/layouts/constraints/LabelLayoutConstraint.java (-33 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.constraints;
12
13
/**
14
 * @author Ian Bull
15
 * @author Chris Bennett
16
 */
17
public class LabelLayoutConstraint implements LayoutConstraint {
18
	
19
	// These should be accessed directly
20
	public String label;
21
	public int pointSize;
22
	
23
	/*
24
	 * (non-Javadoc)
25
	 * @see org.eclipse.zest.layouts.constraints.LayoutConstraint#clear()
26
	 */
27
	public void clear() {
28
		label = null;
29
		pointSize = 1;
30
	}
31
	
32
}
33
(-)src/org/eclipse/zest/layouts/exampleStructures/SimpleNode.java (-318 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.exampleStructures;
12
13
import java.util.Comparator;
14
import java.util.HashMap;
15
import java.util.LinkedList;
16
import java.util.List;
17
import java.util.Map;
18
import java.util.TreeSet;
19
20
import org.eclipse.zest.layouts.LayoutEntity;
21
import org.eclipse.zest.layouts.constraints.BasicEntityConstraint;
22
import org.eclipse.zest.layouts.constraints.EntityPriorityConstraint;
23
import org.eclipse.zest.layouts.constraints.LabelLayoutConstraint;
24
import org.eclipse.zest.layouts.constraints.LayoutConstraint;
25
26
/**
27
 * Rerpresents a simple node that can be used in the layout algorithms.
28
 * 
29
 * @author Ian Bull
30
 * @author Casey Best (Version 1 by Rob Lintern)
31
 * @version 2
32
 */
33
public class SimpleNode implements LayoutEntity {
34
	private static Object NODE_NORMAL_COLOR;
35
	private static Object NODE_SELECTED_COLOR; 
36
	private static Object NODE_ADJACENT_COLOR;	
37
    private static Object BORDER_NORMAL_COLOR;
38
	private static Object BORDER_SELECTED_COLOR;
39
	private static Object BORDER_ADJACENT_COLOR;	
40
41
    private static final int BORDER_NORMAL_STROKE = 1;
42
	private static final int BORDER_STROKE_SELECTED = 2;
43
	
44
	/**
45
	 * A list of layout dependent attributes
46
	 */
47
	private Map attributes;
48
49
	protected double x, y, width, height;
50
	protected Object realObject;
51
	private boolean ignoreInLayout = false;
52
	
53
	private Object colour = null;
54
	private Object borderColor = null;
55
	private int borderWidth;
56
	
57
	private TreeSet listOfRels = null;
58
	
59
	private Object internalNode;
60
61
	
62
	/**
63
	 * Constructs a new SimpleNode.
64
	 */
65
	public SimpleNode(Object realObject) {
66
		this (realObject, -1, -1, 110, 110);
67
	}
68
	
69
	class UniqueCompare implements Comparator {
70
		public int compare(Object o1, Object o2) {
71
			// TODO this may not always be a unique comparison
72
			return o1.toString().compareTo( o2.toString() );
73
		}
74
	}
75
	
76
	/**
77
	 * Constructs a new SimpleNode.
78
	 */
79
	public SimpleNode(Object realObject, double x, double y, double width, double height) {
80
		this.realObject = realObject;
81
		this.x = x;
82
		this.y = y;
83
		this.width = width;
84
		this.height = height;
85
		this.attributes = new HashMap();
86
		this.borderWidth = BORDER_NORMAL_STROKE;
87
		listOfRels = new TreeSet( new UniqueCompare() );
88
        this.colour = NODE_NORMAL_COLOR;
89
        this.borderColor = BORDER_NORMAL_COLOR;
90
	}
91
    
92
    public static void setNodeColors (Object nodeNormalColor, Object borderNormalColor, Object nodeSelectedColor, Object nodeAdjacentColor, Object borderSelectedColor, Object borderAdjacentColor) {
93
        NODE_NORMAL_COLOR = nodeNormalColor;
94
        BORDER_NORMAL_COLOR = borderNormalColor;
95
        NODE_SELECTED_COLOR = nodeSelectedColor;
96
        NODE_ADJACENT_COLOR = nodeAdjacentColor;
97
        BORDER_SELECTED_COLOR = borderSelectedColor;
98
        BORDER_ADJACENT_COLOR = borderAdjacentColor;       
99
    }
100
	
101
	public void addRelationship( SimpleRelationship rel ) {
102
		listOfRels.add( rel );
103
	}
104
	
105
	
106
	public SimpleRelationship[] getRelationships() {
107
		int size = listOfRels.size();
108
		return (SimpleRelationship[]) this.listOfRels.toArray( new SimpleRelationship[ size ] );
109
	}
110
	
111
	public List getRelatedEntities() {
112
		int size = listOfRels.size();
113
		SimpleRelationship[] a_listOfRels = (SimpleRelationship[]) this.listOfRels.toArray( new SimpleRelationship[ size ] );
114
		LinkedList listOfRelatedEntities = new LinkedList(); 
115
		for (int i = 0; i < a_listOfRels.length; i++) {
116
			SimpleRelationship rel = a_listOfRels[ i ];
117
			if ( rel.sourceEntity != this && rel.destinationEntity != this  ) {
118
				throw new RuntimeException("Problem, we have a relationship and we are not the source or the dest");
119
			}
120
			if ( rel.sourceEntity != this ) {
121
				listOfRelatedEntities.add( rel.sourceEntity );
122
			}
123
			if ( rel.destinationEntity != this ) {
124
				listOfRelatedEntities.add( rel.destinationEntity );
125
			}
126
		
127
		}
128
		return listOfRelatedEntities;
129
	}
130
	
131
	
132
	
133
	/**
134
	 * Ignores this entity in the layout
135
	 * @param ignore Should this entity be ignored
136
	 */
137
	public void ignoreInLayout( boolean ignore ) {
138
		this.ignoreInLayout = ignore;
139
	}
140
	
141
	public Object getRealObject() {
142
		return realObject;
143
	}
144
	
145
	public boolean hasPreferredLocation() {
146
		return this.ignoreInLayout;
147
	}
148
149
	/**
150
	 * Gets the x position of this SimpleNode.
151
	 */
152
	public double getX() {
153
		return x;
154
	}
155
	
156
	/**
157
	 * Gets the y position of this SimpleNode.
158
	 */
159
	public double getY() {
160
		return y;
161
	}
162
163
	/**
164
	 * Get the size of this node
165
	 */
166
	public double getWidth() {
167
		return width;
168
	}
169
170
	/**
171
	 * Get the size of this node
172
	 */
173
	public double getHeight() {
174
		return height;
175
	}
176
		
177
	public void setSizeInLayout(double width, double height) {
178
		if (!ignoreInLayout) {
179
			this.width = width;
180
			this.height = height;
181
		}
182
	}
183
	
184
	public void setLocation( double x, double y ) {
185
		this.x = x;
186
		this.y = y;		
187
	}
188
	
189
	public void setLocationInLayout(double x, double y) {
190
		if (!ignoreInLayout) {
191
			this.x = x;
192
			this.y = y;
193
		}
194
	}
195
	
196
	/**
197
	 * An algorithm may require a place to store information.  Use this structure for that purpose.
198
	 */
199
	public void setAttributeInLayout (Object attribute, Object value) {
200
		attributes.put (attribute, value);
201
	}
202
	
203
	/**
204
	 * An algorithm may require a place to store information.  Use this structure for that purpose.
205
	 */
206
	public Object getAttributeInLayout (Object attribute) {
207
		return attributes.get (attribute);
208
	}
209
210
	public boolean equals(Object object) {
211
		boolean result = false;
212
		if (object instanceof SimpleNode) {
213
			SimpleNode node = (SimpleNode)object;
214
			result = realObject.equals (node.getRealObject());
215
		}
216
		return result;
217
	}
218
	
219
	public int hashCode() {
220
		return realObject.hashCode();
221
	}
222
	
223
	// all objects are equal
224
	public int compareTo(Object arg0) {
225
		return 0;
226
	}
227
	
228
	public String toString() {
229
		return realObject.toString();
230
	}
231
	
232
	public void setSelected() {
233
		this.colour = NODE_SELECTED_COLOR;
234
		this.borderColor = BORDER_SELECTED_COLOR;
235
		this.borderWidth = BORDER_STROKE_SELECTED;
236
	}
237
	
238
	public void setUnSelected() {
239
		this.colour = NODE_NORMAL_COLOR;
240
		this.borderColor = BORDER_NORMAL_COLOR;
241
		this.borderWidth = BORDER_NORMAL_STROKE;
242
	}
243
	
244
	public void setAdjacent() {
245
		this.colour = NODE_ADJACENT_COLOR;
246
		this.borderColor = BORDER_ADJACENT_COLOR;
247
		this.borderWidth = BORDER_STROKE_SELECTED;
248
	}
249
    
250
	public Object getColor() {
251
		return this.colour;
252
	}
253
	
254
	public int getBorderWidth() {
255
		return borderWidth;
256
	}
257
		
258
	public Object getBorderColor() {
259
		return borderColor;
260
	}
261
	
262
	/* (non-Javadoc)
263
	 * @see ca.uvic.cs.chisel.layouts.LayoutEntity#getInternalEntity()
264
	 */
265
	public Object getLayoutInformation() {
266
		return internalNode;
267
	}
268
269
	/* (non-Javadoc)
270
	 * @see ca.uvic.cs.chisel.layouts.LayoutEntity#setInternalEntity(java.lang.Object)
271
	 */
272
	public void setLayoutInformation(Object internalEntity) {
273
		this.internalNode = internalEntity;
274
	}
275
276
	/**
277
	 * Populate the specified layout constraint
278
	 */	
279
	public void populateLayoutConstraint(LayoutConstraint constraint) {
280
		if ( constraint instanceof LabelLayoutConstraint ) {
281
			LabelLayoutConstraint labelConstraint = (LabelLayoutConstraint) constraint;
282
			labelConstraint.label = realObject.toString();
283
			labelConstraint.pointSize = 18;
284
		}		
285
		else if ( constraint instanceof BasicEntityConstraint ) {
286
			// noop
287
		}
288
		else if ( constraint instanceof EntityPriorityConstraint ) {
289
			EntityPriorityConstraint priorityConstraint = (EntityPriorityConstraint) constraint;
290
			priorityConstraint.priority = Math.random() * 10 + 1;
291
		}
292
	}
293
294
	public double getHeightInLayout() {
295
		return this.height;
296
	}
297
298
	public double getWidthInLayout() {
299
		return this.width;
300
	}
301
302
	public double getXInLayout() {
303
		return this.x;
304
	}
305
306
	public double getYInLayout() {
307
		return this.y;
308
	}
309
310
	public Object getGraphData() {
311
		return null;
312
	}
313
314
	public void setGraphData(Object o) {
315
	
316
	}
317
	
318
}
(-)src/org/eclipse/zest/layouts/exampleStructures/SimpleGraph.java (-140 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.exampleStructures;
12
13
import java.util.ArrayList;
14
import java.util.HashMap;
15
import java.util.Iterator;
16
import java.util.List;
17
import java.util.Map;
18
19
import org.eclipse.zest.layouts.LayoutEntity;
20
import org.eclipse.zest.layouts.LayoutGraph;
21
import org.eclipse.zest.layouts.LayoutRelationship;
22
23
24
/**
25
 * Create a very simple graph that can be used in the layout algorithms
26
 * 
27
 * @author Casey Best
28
 * @author Chris Callendar
29
 */
30
public class SimpleGraph implements LayoutGraph {
31
	
32
	Map objectsToNodes;
33
	List relationships;
34
	
35
	public SimpleGraph() {
36
		objectsToNodes = new HashMap();
37
		relationships = new ArrayList();
38
	}
39
	
40
	/**
41
	 * Adds the node.
42
	 * @param node	The node to add.
43
	 */
44
	public void addEntity(LayoutEntity node) {
45
		if (node instanceof SimpleNode) {
46
			objectsToNodes.put(((SimpleNode)node).getRealObject(), node);
47
		}
48
	}
49
	
50
	/**
51
	 * Creates a LayoutEntity containing an object.
52
	 */
53
	public LayoutEntity addObjectNode(Object object) {
54
	    SimpleNode simpleNode = (SimpleNode) objectsToNodes.get (object);
55
		if (simpleNode == null) {
56
			simpleNode = new SimpleNode(object);
57
			objectsToNodes.put (object, simpleNode);
58
		}
59
		return simpleNode;
60
		
61
	}
62
	
63
	/**
64
	 * Add a relationship between two objects.  Layout algorithms need to know
65
	 * whether a relationship is one way or bi-directional.  This method assumes that 
66
	 * all relationships are bi-direcional and have the same weight. 
67
	 */
68
	public void addObjectRelationship (Object sourceNode, Object destinationNode) {
69
		addObjectRelationship(sourceNode, destinationNode, true, 1);
70
	}
71
	
72
	/**
73
	 * Add a relationship between two objects.  Layout algorithms need to know
74
	 * whether a relationship is one way or bi-directional.  
75
	 */
76
	public void addObjectRelationship (Object sourceObject, Object destinationObject, boolean bidirectional, int weight) {
77
		addObjectNode(sourceObject);
78
		addObjectNode(destinationObject);
79
		SimpleNode sourceNode = (SimpleNode) objectsToNodes.get(sourceObject);
80
		SimpleNode destinationNode = (SimpleNode) objectsToNodes.get(destinationObject);
81
		SimpleRelationship simpleRelationship = new SimpleRelationship(sourceNode, destinationNode, bidirectional, weight);
82
		relationships.add(simpleRelationship);
83
	}
84
85
	/* (non-Javadoc)
86
	 * @see ca.uvic.cs.chisel.layouts.LayoutGraph#addRelationship(ca.uvic.cs.chisel.layouts.LayoutEntity, ca.uvic.cs.chisel.layouts.LayoutEntity)
87
	 */
88
	public void addRelationship(LayoutEntity srcNode, LayoutEntity destNode) {
89
		addRelationship(srcNode, destNode, true, 1);
90
	}
91
	
92
	/* (non-Javadoc)
93
	 * @see ca.uvic.cs.chisel.layouts.LayoutGraph#addRelationship(ca.uvic.cs.chisel.layouts.LayoutEntity, ca.uvic.cs.chisel.layouts.LayoutEntity, boolean, int)
94
	 */
95
	public void addRelationship(LayoutEntity srcNode, LayoutEntity destNode, boolean bidirectional, int weight) {
96
		addEntity(srcNode);
97
		addEntity(destNode);
98
		SimpleRelationship rel = new SimpleRelationship(srcNode, destNode, bidirectional, weight);
99
		relationships.add(rel);
100
	}
101
	
102
	/* (non-Javadoc)
103
	 * @see ca.uvic.cs.chisel.layouts.LayoutGraph#addRelationship(ca.uvic.cs.chisel.layouts.LayoutRelationship)
104
	 */
105
	public void addRelationship(LayoutRelationship relationship) {
106
		relationships.add(relationship);
107
	}
108
109
	/**
110
	 * Returns a list of SimpleNodes that represent the objects added to this graph using addNode.  Note that
111
	 * any manipulation to this graph was done on the SimpleNodes, not the real objects.  You
112
	 * must still manipulate them yourself.
113
	 */
114
	public List getEntities() {
115
		return new ArrayList (objectsToNodes.values());
116
	}
117
118
	/**
119
	 * Returns a list of SimpleRelationships that represent the objects added to this graph using addRelationship.
120
	 */
121
	public List getRelationships() {
122
		return relationships;
123
	}
124
	
125
	/**
126
	 * Checks the relationships to see if they are all bidirectional. 
127
	 * @return boolean if all edges are bidirectional.
128
	 */
129
	public boolean isBidirectional() {
130
		boolean isBidirectional = true;
131
		for (Iterator iter = relationships.iterator(); iter.hasNext(); ) {
132
			SimpleRelationship rel = (SimpleRelationship) iter.next();
133
			if (!rel.isBidirectionalInLayout()) {
134
				isBidirectional = false;
135
				break;
136
			}
137
		}
138
		return isBidirectional;
139
	}
140
}
(-)src/org/eclipse/zest/layouts/exampleStructures/SimpleRelationship.java (-274 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.exampleStructures;
12
13
import java.util.HashMap;
14
import java.util.Map;
15
16
import org.eclipse.zest.layouts.LayoutBendPoint;
17
import org.eclipse.zest.layouts.LayoutEntity;
18
import org.eclipse.zest.layouts.LayoutRelationship;
19
import org.eclipse.zest.layouts.constraints.BasicEdgeConstraints;
20
import org.eclipse.zest.layouts.constraints.LabelLayoutConstraint;
21
import org.eclipse.zest.layouts.constraints.LayoutConstraint;
22
import org.eclipse.zest.layouts.dataStructures.BendPoint;
23
24
25
/**
26
 * The SimpleRelation class describes the relationship between
27
 * two objects: source and destination.  Each relationship
28
 * has a weight and direction associated with it.
29
 * Note: The source object is at the beginning of the relationship.
30
 * Note: The destination object is at the end of the relationship.
31
 *
32
 * @version  2.0
33
 * @author   Casey Best (version 1.0 by Jingwei Wu)
34
 * @author Chris Bennett
35
 */
36
public class SimpleRelationship implements LayoutRelationship {
37
	
38
	private static int DEFAULT_REL_LINE_WIDTH = 1;
39
	private static int DEFAULT_REL_LINE_WIDTH_SELECTED = DEFAULT_REL_LINE_WIDTH + 2;
40
	private static Object DEFAULT_RELATIONSHIP_COLOR;
41
	private static Object DEFAULT_RELATIONSHIP_HIGHLIGHT_COLOR;	
42
	
43
	/** The line width for this relationship. */
44
	private int lineWidth  = DEFAULT_REL_LINE_WIDTH;
45
	
46
	/** The color for this relationship. */
47
	private Object color = DEFAULT_RELATIONSHIP_COLOR;
48
	
49
	/**
50
	 * A list of layout dependent attributes
51
	 */
52
	private Map attributes;
53
54
	/**
55
	 * The sourceEntity of this SimpleRelation.
56
	 */
57
	protected LayoutEntity sourceEntity;
58
59
	/**
60
	 * The object of this SimpleRelation.
61
	 */
62
	protected LayoutEntity destinationEntity;
63
64
	/**
65
	 * If directional, algorithms must note the direction of the relationship.
66
	 * If not directional, algorithms are to ignore which direction the relationship is going.
67
	 * Switching the source and destination should make no difference. 
68
	 */
69
	protected boolean bidirectional;
70
71
	/**
72
	 * The weight given to this relation.
73
	 */
74
	private double weight;
75
	
76
	private Object internalRelationship;
77
	
78
	private LayoutBendPoint[] bendPoints;
79
	
80
	private String label;
81
	
82
	/**
83
	 * Constructor.
84
	 * @param sourceEntity The sourceEntity of this SimpleRelation.
85
	 * @param destinationEntity The object of this SimpleRelation.
86
	 * @param bidirectional Determines if the <code>sourceEntity</code> and
87
	 * <code>destinationEntity</code> are equal(exchangeable).
88
	 * @throws java.lang.NullPointerException If either <code>sourceEntity
89
	 * </code> or <code>destinationEntity</code> is <code>null</code>.
90
	 */
91
	public SimpleRelationship(LayoutEntity sourceEntity, LayoutEntity destinationEntity, boolean bidirectional) {
92
		this (sourceEntity, destinationEntity, bidirectional, 1);
93
	}
94
	
95
	/**
96
	 * Constructor.
97
	 * @param sourceEntity The sourceEntity of this SimpleRelation.
98
	 * @param destinationEntity The destinationEntity of this SimpleRelation.
99
	 * @param exchangeable Determines if the <code>sourceEntity</code> and
100
	 * <code>destinationEntity</code> are equal(exchangeable).
101
	 * @throws java.lang.NullPointerException If either <code>sourceEntity
102
	 * </code> or <code>destinationEntity</code> is <code>null</code>.
103
	 */
104
	public SimpleRelationship(LayoutEntity sourceEntity, LayoutEntity destinationEntity, boolean bidirectional, double weight) {
105
		this.destinationEntity = destinationEntity;
106
		this.sourceEntity = sourceEntity;
107
		this.bidirectional = bidirectional;
108
		this.weight = weight;
109
		this.attributes = new HashMap();
110
		this.lineWidth = DEFAULT_REL_LINE_WIDTH;
111
		this.color = DEFAULT_RELATIONSHIP_COLOR;
112
	}
113
114
	/**
115
	 * Gets the sourceEntity of this SimpleRelation whether the relation is
116
	 * exchangeable or not.
117
	 * @return The sourceEntity.
118
	 */
119
	public LayoutEntity getSourceInLayout() {
120
		return sourceEntity;
121
	}
122
123
	/**
124
	 * Gets the destinationEntity of this SimpleRelation whether the relation is
125
	 * exchangeable or not.
126
	 * @return The destinationEntity of this SimpleRelation.
127
	 */
128
	public LayoutEntity getDestinationInLayout() {
129
		return destinationEntity;
130
	}
131
132
	/**
133
	 * If bidirectional, the direction of the relationship doesn't matter.  Switching the source and destination should make no difference.
134
	 * If not bidirectional, layout algorithms need to take into account the direction of the relationship.  The direction is based on the
135
	 * source and destination entities.
136
	 */
137
	public boolean isBidirectionalInLayout() {
138
		return bidirectional;
139
	}
140
141
	public void setWeightInLayout(double weight) {
142
		this.weight = weight;
143
	}
144
145
	public double getWeightInLayout() {
146
		return weight;
147
	}
148
149
	/**
150
	 * An algorithm may require a place to store information.  Use this structure for that purpose.
151
	 */
152
	public void setAttributeInLayout (String attribute, Object value) {
153
		attributes.put (attribute, value);
154
	}
155
	
156
	/**
157
	 * An algorithm may require a place to store information.  Use this structure for that purpose.
158
	 */
159
	public Object getAttributeInLayout (String attribute) {
160
		return attributes.get (attribute);
161
	}
162
163
	public String toString() {
164
		String arrow = (isBidirectionalInLayout() ? " <-> " : " -> "); 
165
		return "(" + sourceEntity + arrow + destinationEntity + ")";
166
	}
167
	
168
	public int getLineWidth() {
169
		return this.lineWidth;
170
	}
171
	
172
	public void setLineWidth( int lineWidth ) {
173
		this.lineWidth = lineWidth;
174
	}
175
	
176
	public void resetLineWidth() {
177
		this.lineWidth = DEFAULT_REL_LINE_WIDTH;
178
	}
179
	
180
	public static void setDefaultSize(int i) {
181
		DEFAULT_REL_LINE_WIDTH = i;
182
		DEFAULT_REL_LINE_WIDTH_SELECTED = DEFAULT_REL_LINE_WIDTH + 2;
183
	}
184
	
185
	public void setSelected() {
186
		this.color = DEFAULT_RELATIONSHIP_HIGHLIGHT_COLOR;
187
		this.lineWidth = DEFAULT_REL_LINE_WIDTH_SELECTED;
188
	}
189
	
190
	public void setUnSelected() {
191
		this.color = DEFAULT_RELATIONSHIP_COLOR;
192
		this.lineWidth = DEFAULT_REL_LINE_WIDTH;
193
	}
194
	
195
	public Object getColor() {
196
		return color;
197
	}
198
	
199
	public void setColor(Object c) {
200
		this.color = c;
201
	}
202
	
203
	public static void setDefaultColor(Object c) {
204
		DEFAULT_RELATIONSHIP_COLOR = c;
205
	}
206
	
207
	public static void setDefaultHighlightColor(Object c) {
208
		DEFAULT_RELATIONSHIP_HIGHLIGHT_COLOR = c;
209
	}
210
211
	/* (non-Javadoc)
212
	 * @see ca.uvic.cs.chisel.layouts.LayoutRelationship#getInternalRelationship()
213
	 */
214
	public Object getLayoutInformation() {
215
		return internalRelationship;
216
	}
217
218
	/* (non-Javadoc)
219
	 * @see ca.uvic.cs.chisel.layouts.LayoutRelationship#setInternalRelationship(java.lang.Object)
220
	 */
221
	public void setLayoutInformation(Object layoutInformation) {
222
		this.internalRelationship = layoutInformation;
223
	}
224
225
226
	public void setBendPoints(LayoutBendPoint[] bendPoints) {
227
		this.bendPoints = bendPoints;
228
	}
229
	
230
	public LayoutBendPoint[] getBendPoints() {
231
		return this.bendPoints;
232
	}
233
	
234
	public void clearBendPoints() {
235
		this.bendPoints = new BendPoint[0];
236
	}
237
	
238
	
239
	public void setDestinationInLayout(LayoutEntity destination) {
240
		this.destinationEntity = destination;
241
	}
242
	
243
	/**
244
	 * Set the label for this edge (available in the label layout constraint). 
245
	 */	
246
	public void setLabel(String label) {
247
		this.label = label;
248
	}
249
250
	/**
251
	 * Populate the specified layout constraint
252
	 */	
253
	public void populateLayoutConstraint(LayoutConstraint constraint) {
254
		if ( constraint instanceof LabelLayoutConstraint ) {
255
			LabelLayoutConstraint labelConstraint = (LabelLayoutConstraint) constraint;
256
			labelConstraint.label = this.label;
257
			labelConstraint.pointSize = 18;
258
		}			
259
		else if ( constraint instanceof BasicEdgeConstraints ) {
260
			// noop
261
			
262
		}
263
	}
264
265
	public Object getGraphData() {
266
		return null;
267
	}
268
269
	public void setGraphData(Object o) {
270
		
271
	}
272
273
	
274
}
(-)src/org/eclipse/zest/layouts/exampleStructures/SimpleFilter.java (-30 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.exampleStructures;
12
13
import org.eclipse.zest.layouts.Filter;
14
import org.eclipse.zest.layouts.LayoutItem;
15
16
/**
17
 * A very simple example of a filter.  This filter never filters
18
 * any object.
19
 * 
20
 * @author Casey Best
21
 */
22
public class SimpleFilter implements Filter {
23
24
	/**
25
	 * Doesn't filter anything
26
	 */
27
	public boolean isObjectFiltered(LayoutItem object) {
28
		return false;
29
	}
30
}
(-)META-INF/MANIFEST.MF (-5 / +1 lines)
Lines 7-18 Link Here
7
Bundle-Localization: plugin
7
Bundle-Localization: plugin
8
Export-Package: org.eclipse.zest.layouts,
8
Export-Package: org.eclipse.zest.layouts,
9
 org.eclipse.zest.layouts.algorithms,
9
 org.eclipse.zest.layouts.algorithms,
10
 org.eclipse.zest.layouts.algorithms.internal,
11
 org.eclipse.zest.layouts.constraints,
12
 org.eclipse.zest.layouts.dataStructures,
10
 org.eclipse.zest.layouts.dataStructures,
13
 org.eclipse.zest.layouts.exampleStructures,
11
 org.eclipse.zest.layouts.interfaces
14
 org.eclipse.zest.layouts.exampleUses,
15
 org.eclipse.zest.layouts.progress
16
Require-Bundle: org.eclipse.swt;visibility:=reexport,
12
Require-Bundle: org.eclipse.swt;visibility:=reexport,
17
 org.eclipse.core.runtime,
13
 org.eclipse.core.runtime,
18
 org.eclipse.jface,
14
 org.eclipse.jface,
(-)src/org/eclipse/zest/layouts/LayoutRelationship.java (-82 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts;
12
13
import org.eclipse.zest.layouts.constraints.LayoutConstraint;
14
15
16
17
/**
18
 * This represents a single relationship, providing the layout algorithms with 
19
 * a common interface to run on.
20
 * 
21
 * @author Casey Best
22
 * @author Chris Callendar
23
 */
24
public interface LayoutRelationship extends LayoutItem {
25
	
26
	
27
	/**
28
	 * Gets the sourceEntity of this SimpleRelation whether the relation is
29
	 * exchangeable or not.
30
	 * @return The sourceEntity.
31
	 */
32
	public LayoutEntity getSourceInLayout();
33
34
	/**
35
	 * Gets the destinationEntity of this SimpleRelation whether the relation is
36
	 * exchangeable or not.
37
	 * @return The destinationEntity of this SimpleRelation.
38
	 */
39
	public LayoutEntity getDestinationInLayout();
40
41
42
	/**
43
	 * Sets the internal relationship object.
44
	 * @param layoutInformation
45
	 */
46
	public void setLayoutInformation(Object layoutInformation);
47
	
48
	/**
49
	 * Returns the internal relationship object.
50
	 * @return Object
51
	 */
52
	public Object getLayoutInformation();
53
	
54
	/**
55
	 * Specify a set of bend points. The layout algorithm using this will pass
56
	 * in an empty array of bendPoints, or not even call this method,
57
	 * if there are no bend points associated with this edge.
58
	 * 
59
	 * If you are updating an existing application you can just implement this 
60
	 * method to do nothing.
61
	 * 
62
	 * @param bendPoints A list of bend points. All bendpoint locations are expressed 
63
	 * as percentages of the bounds (0,0 to 1,1).The first bendpoint in the list must be the 
64
	 * source point of this relationship and the last bendpoint the destination point 
65
	 * for this relationship. This allows the correct positioning of bendpoints 
66
	 * relative to the source and destination points when drawing the graph.
67
	 */
68
	public void setBendPoints(LayoutBendPoint[] bendPoints);
69
70
	/**
71
	 * Clear bend points and related bounds
72
	 * If you are updating an existing application you can just implement this 
73
	 * method to do nothing.
74
	 */
75
	public void clearBendPoints();
76
77
	/**
78
	 * Classes should update the specirfied layout constraint if recognized
79
	 * @return
80
	 */
81
	public void populateLayoutConstraint(LayoutConstraint constraint);
82
}
(-)src/org/eclipse/zest/layouts/LayoutAlgorithm.java (-92 / +31 lines)
Lines 1-111 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright (c) 2005-2009 The Chisel Group and others. All rights reserved. This
3
 * All rights reserved. This program and the accompanying materials
3
 * program and the accompanying materials are made available under the terms of
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * which accompanies this distribution, and is available at
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 *
7
 * Contributors: The Chisel Group - initial API and implementation
8
 * Contributors:
8
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 *     The Chisel Group, University of Victoria
9
 *               Ian Bull
10
 *******************************************************************************/
10
 ******************************************************************************/
11
package org.eclipse.zest.layouts;
11
package org.eclipse.zest.layouts;
12
12
13
import java.util.Comparator;
13
import org.eclipse.zest.layouts.interfaces.LayoutContext;
14
import java.util.List;
15
16
import org.eclipse.zest.layouts.progress.ProgressListener;
17
14
18
/**
15
/**
19
 * A simple interface used by all layouts.
16
 * An interface for all layout algorithms.
20
 * 
17
 * 
21
 * Each layout Algorithm must implement the applyLayoutInternal method which actually compute the layout
22
 * 
18
 * 
23
 * @author Casey Best
24
 * @author Ian Bull
25
 */
19
 */
26
public interface LayoutAlgorithm {
20
public interface LayoutAlgorithm {
27
21
28
	/**
22
	/**
29
	 * Apply the layout to the given entities.  The entities will be moved and resized based
23
	 * Sets the layout context for this algorithm. The receiver will unregister
30
	 * on the algorithm.
24
	 * from its previous layout context and register to the new one
25
	 * (registration means for example adding listeners). After a call to this
26
	 * method, the receiving algorithm can compute and cache internal data
27
	 * related to given context and perform an initial layout.
31
	 * 
28
	 * 
32
	 * @param entitiesToLayout Apply the algorithm to these entities
29
	 * @param context
33
	 * @param relationshipsToConsider Only consider these relationships when applying the algorithm.
30
	 *            a new layout context or null if this algorithm should not
34
	 * @param x The left side of the bounds in which the layout can place the entities.
31
	 *            perform any layout
35
	 * @param y The top side of the bounds in which the layout can place the entities.
36
	 * @param width The width of the bounds in which the layout can place the entities.
37
	 * @param height The height of the bounds in which the layout can place the entities.
38
	 * @param asynchronous Should the algorithm run Asynchronously
39
	 */
40
	public void applyLayout(LayoutEntity[] entitiesToLayout, LayoutRelationship[] relationshipsToConsider, double x, double y, double width, double height, boolean asynchronous, boolean continuous) throws InvalidLayoutConfiguration;
41
42
	/**
43
	 * Returns whether or not the algorithm is currenly running
44
	 * @return True if a layout algorithm is currenly running, false otherwise
45
	 */
46
	public boolean isRunning();
47
48
	/**
49
	 * Determines the order in which the objects should be displayed.
50
	 * Note: Some algorithms force a specific order, in which case
51
	 * this comparator will be ignored.
52
	 */
53
	public void setComparator(Comparator comparator);
54
55
	/**
56
	 * Filters the entities and relationships to apply the layout on
57
	 */
58
	public void setFilter(Filter filter);
59
60
	/**
61
	 * Set the width to height ratio you want the entities to use
62
	 * Note: Each layout is responsible for ensuring this ratio is used.
63
	 * Note: By default the layout will use a ratio of 1.0 for each entity.
64
	 */
65
	public void setEntityAspectRatio(double ratio);
66
67
	/**
68
	 * Returns the width to height ratio this layout will use to set the size of the entities.
69
	 * Note: By default the layout will use a ratio of 1.0 for each entity.
70
	 */
32
	 */
71
	public double getEntityAspectRatio();
33
	public void setLayoutContext(LayoutContext context);
72
73
	/**
74
	 * A layout algorithm could take an uncomfortable amout of time to complete.  To relieve some of
75
	 * the mystery, the layout algorithm will notify each ProgressListener of its progress. 
76
	 */
77
	public void addProgressListener(ProgressListener listener);
78
79
	/**
80
	 * Removes the given progress listener, preventing it from receiving any more updates.
81
	 */
82
	public void removeProgressListener(ProgressListener listener);
83
84
	/**
85
	 * Makes a request to this layout algorithm to stop running.
86
	 */
87
	public void stop();
88
89
	/**
90
	 * Sets the style for this layout algorithm.  This will overwrite any other style set.
91
	 * @param style
92
	 */
93
	public void setStyle(int style);
94
34
95
	/**
35
	/**
36
	 * Makes this algorithm perform layout computation and apply it to its
37
	 * context.
96
	 * 
38
	 * 
97
	 * @return
39
	 * @param clean
40
	 *            if true the receiver should assume that the layout context has
41
	 *            changed significantly and recompute the whole layout even if
42
	 *            it keeps track of changes with listeners. False can be used
43
	 *            after dynamic layout in a context is turned back on so that
44
	 *            layout algorithm working in background can apply accumulated
45
	 *            changes. Static layout algorithm can ignore this call entirely
46
	 *            if clean is false.
98
	 */
47
	 */
99
	public int getStyle();
48
	public void applyLayout(boolean clean);
100
101
	public void addEntity(LayoutEntity entity);
102
103
	public void addRelationship(LayoutRelationship relationship);
104
105
	public void removeEntity(LayoutEntity entity);
106
107
	public void removeRelationship(LayoutRelationship relationship);
108
109
	public void removeRelationships(List relationships);
110
49
111
}
50
}
(-)src/org/eclipse/zest/layouts/LayoutBendPoint.java (-22 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts;
12
13
/**
14
 * Specifies a single bend point in a graph relationship.
15
 * @author Ian Bull
16
 * @author Chris Bennett
17
 */
18
public interface LayoutBendPoint {
19
	public double getX();
20
	public double getY();
21
	public boolean getIsControlPoint();
22
}
(-)src/org/eclipse/zest/layouts/LayoutItem.java (-24 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts;
12
13
/**
14
 * Super interface for both Layout Entities and Layout Relationships
15
 *  
16
 * @author Ian Bull
17
 *
18
 */
19
public interface LayoutItem {
20
21
	public void setGraphData(Object o);
22
	public Object getGraphData();
23
24
}
(-)src/org/eclipse/zest/layouts/InvalidLayoutConfiguration.java (-23 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts;
12
13
/**
14
 * 
15
 * @author Ian Bull
16
 *
17
 */
18
public class InvalidLayoutConfiguration extends Exception {
19
	
20
	static final long serialVersionUID = 0;
21
22
23
}
(-)src/org/eclipse/zest/layouts/LayoutIterationEvent.java (-49 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts;
12
13
import java.util.List;
14
15
/**
16
 * When a layout completes an iteration, it throws this event
17
 * to allow the application to update.  For example, at the
18
 * end of an iteration is can be assumed the layout has placed
19
 * each entity into a new location.  This event allows the application
20
 * to update the GUI to represent the new locations
21
 * 
22
 * @author Casey Best and Rob Lintern
23
 */
24
public class LayoutIterationEvent {
25
    private List relationshipsToLayout, entitiesToLayout;
26
    private int iterationCompleted;
27
    
28
    /**
29
     * Return the relationships used in this layout.
30
     */
31
    public List getRelationshipsToLayout() {
32
        return relationshipsToLayout;
33
    }
34
35
    /**
36
     * Return the entities used in this layout. 
37
     */
38
    public List getEntitiesToLayout() {
39
        return entitiesToLayout;
40
    }
41
42
    /**
43
     * Return the iteration of the layout algorithm that was
44
     * just completed. 
45
     */
46
    public int getIterationCompleted() {
47
        return iterationCompleted;
48
    }
49
}
(-)src/org/eclipse/zest/layouts/NestedLayoutEntity.java (-32 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts;
12
13
import java.util.List;
14
15
16
/**
17
 * Extends LayoutEntity to provide methods for dealing with nested entities.
18
 * 
19
 * @author Chris Callendar
20
 */
21
public interface NestedLayoutEntity extends LayoutEntity {
22
23
	/** Returns the parent entity. */
24
	NestedLayoutEntity getParent();
25
	
26
	/** Returns the list of children. */
27
	List getChildren();
28
	
29
	/** Returns true if this entity has children. */
30
	boolean hasChildren();
31
	
32
}
(-)src/org/eclipse/zest/layouts/LayoutStyles.java (-33 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts;
12
13
/**
14
 * @author Ian Bull
15
 */
16
public interface LayoutStyles {
17
18
	/** Default layout style constant. */
19
	public final static int NONE           = 0x00;
20
	
21
	/** 
22
	 * Layout constant indicating that the layout algorithm 
23
	 * should NOT resize any of the nodes.
24
	 */
25
	public final static int NO_LAYOUT_NODE_RESIZING = 0x01;
26
	
27
	/**
28
	 * Some layouts may prefer to expand their bounds beyond those of the requested bounds. This
29
	 * flag asks the layout not to do so.
30
	 */
31
	public static final int ENFORCE_BOUNDS	= 0X02;
32
	
33
}
(-)src/org/eclipse/zest/layouts/Stoppable.java (-27 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts;
12
13
import org.eclipse.zest.layouts.progress.ProgressListener;
14
15
/**
16
 * @author Ian Bull
17
 */
18
public interface Stoppable {
19
20
	/**
21
	 * This ends the runnable
22
	 */
23
	public void stop();
24
25
	public void addProgressListener(ProgressListener listener);
26
27
}
(-)src/org/eclipse/zest/layouts/LayoutGraph.java (-52 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts;
12
13
import java.util.List;
14
15
/**
16
 * The LayoutGraph interface defines the methods used to add nodes and edges (relationships).
17
 * @author Chris
18
 */
19
public interface LayoutGraph {
20
21
	/**
22
	 * Adds a node to this graph.
23
	 * @param node 	The new node.
24
	 * @return LayoutEntity	The created node
25
	 */
26
	public void addEntity(LayoutEntity node);
27
	
28
	/**
29
	 * Adds the given relationship.
30
	 * @param relationship
31
	 */
32
	public void addRelationship(LayoutRelationship relationship);
33
	
34
	/**
35
	 * Returns a list of LayoutEntity objects that represent the objects added to this graph using addNode.
36
	 * @return List	 A List of LayoutEntity objects.  
37
	 */
38
	public List getEntities();
39
40
	/**
41
	 * Returns a list of LayoutRelationship objects that represent the objects added to this graph using addRelationship.
42
	 * @return List	 A List of LayoutRelationship objects.
43
	 */
44
	public List getRelationships();
45
	
46
	/**
47
	 * Determines if the graph is bidirectional.   
48
	 * @return boolean	If the graph is bidirectional.
49
	 */
50
	public boolean isBidirectional();
51
	
52
}
(-)src/org/eclipse/zest/layouts/LayoutEntity.java (-44 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts;
12
13
import org.eclipse.zest.layouts.constraints.LayoutConstraint;
14
15
/**
16
 * This represents a single entity, providing the layout algorithms with 
17
 * a common interface to run on.
18
 * 
19
 * @author Casey Best
20
 * @author Ian Bull
21
 * @author Chris Bennett
22
 */
23
public interface LayoutEntity extends Comparable, LayoutItem {
24
	
25
	public final static String ATTR_PREFERRED_WIDTH = "tree-preferred-width";
26
    public final static String ATTR_PREFERRED_HEIGHT = "tree-preferred-height";
27
	
28
	public void setLocationInLayout (double x, double y);
29
	public void setSizeInLayout (double width, double height);
30
	
31
	public double getXInLayout();
32
	public double getYInLayout();
33
	public double getWidthInLayout();
34
	public double getHeightInLayout();
35
	
36
	public Object getLayoutInformation();
37
	public void setLayoutInformation(Object internalEntity);
38
	
39
	/**
40
	 * Classes should update the specified layout constraint if recognized
41
	 * @return
42
	 */
43
	public void populateLayoutConstraint(LayoutConstraint constraint);
44
}
(-)src/org/eclipse/zest/layouts/Filter.java (-30 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts;
12
13
/**
14
 * A filter is used to filter objects.  Once implemented, interested
15
 * parties can ask this filter whether or not a specific object
16
 * is filtered.
17
 * 
18
 * For example, in a visualization tool, only unfiltered objects should
19
 * be displayed.  Before displaying an object, the display can ask
20
 * this filter if the object is filtered.
21
 * 
22
 * @author Casey Best
23
 */
24
public interface Filter {
25
	
26
	/**
27
	 * Returns true if the object is filtered, or false if it's not filtered.
28
	 */
29
	public boolean isObjectFiltered (LayoutItem object);
30
}
(-)src/org/eclipse/zest/layouts/dataStructures/InternalRelationship.java (-138 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.dataStructures;
12
13
import java.util.LinkedList;
14
import java.util.List;
15
16
import org.eclipse.zest.layouts.LayoutBendPoint;
17
import org.eclipse.zest.layouts.LayoutEntity;
18
import org.eclipse.zest.layouts.LayoutRelationship;
19
import org.eclipse.zest.layouts.constraints.BasicEdgeConstraints;
20
import org.eclipse.zest.layouts.constraints.LayoutConstraint;
21
22
/**
23
 * @author Ian Bull
24
 */
25
public class InternalRelationship implements LayoutRelationship{
26
	
27
	private LayoutRelationship externalRelationship;
28
	private InternalNode source;
29
	private InternalNode destination;
30
	private Object layoutInfo;
31
	private List bendPoints = new LinkedList();
32
	BasicEdgeConstraints basicEdgeConstraints = new BasicEdgeConstraints();
33
	
34
	public InternalRelationship( LayoutRelationship externalRelationship, InternalNode source, InternalNode destination) {
35
		this.externalRelationship = externalRelationship;
36
		this.externalRelationship.setLayoutInformation(this);
37
		this.source = source;
38
		this.destination = destination;
39
		this.externalRelationship.populateLayoutConstraint(basicEdgeConstraints);
40
	}
41
	
42
	public LayoutRelationship getLayoutRelationship() {
43
		return externalRelationship;
44
	}
45
	
46
	public InternalNode getSource() {
47
		if ( this.source == null ) {
48
			throw new RuntimeException("Source is null");
49
		}
50
		return this.source;
51
	}
52
	
53
	public InternalNode getDestination() {
54
		if ( this.destination == null ) {
55
			throw new RuntimeException("Dest is null");
56
		}
57
		return this.destination;
58
	}
59
	
60
	public double getWeight() {
61
		return this.basicEdgeConstraints.weight;
62
	}
63
	
64
	public boolean isBidirectional() {
65
		return this.basicEdgeConstraints.isBiDirectional;
66
	}
67
	
68
	/**
69
	 * Ensure this is called in order of source to target node position.
70
	 * @param x
71
	 * @param y
72
	 */
73
	public void addBendPoint(double x, double y) {
74
		bendPoints.add(new BendPoint(x, y));
75
	}
76
	
77
	/**
78
	 * Ensure this is called in order of source to target node position.
79
	 * Specifies if the bendpoint is a curve control point
80
	 * @param x
81
	 * @param y
82
	 * @param isControlPoint
83
	 */
84
	public void addBendPoint(double x, double y, boolean isControlPoint) {
85
		bendPoints.add(new BendPoint(x, y, isControlPoint));
86
	}
87
	
88
	public List getBendPoints() {
89
		return this.bendPoints;
90
	}
91
92
	public void clearBendPoints() {
93
		// TODO Auto-generated method stub
94
		
95
	}
96
97
	
98
	
99
	public LayoutEntity getDestinationInLayout() {
100
		// TODO Auto-generated method stub
101
		return destination;
102
	}
103
104
	
105
	public Object getLayoutInformation() {
106
		// TODO Auto-generated method stub
107
		return layoutInfo;
108
	}
109
110
	public LayoutEntity getSourceInLayout() {
111
		// TODO Auto-generated method stub
112
		return source;
113
	}
114
115
	public void populateLayoutConstraint(LayoutConstraint constraint) {
116
		// TODO Auto-generated method stub
117
		
118
	}
119
120
	public void setBendPoints(LayoutBendPoint[] bendPoints) {
121
		// TODO Auto-generated method stub
122
		
123
	}
124
125
	public void setLayoutInformation(Object layoutInformation) {
126
		this.layoutInfo = layoutInformation;
127
		
128
	}
129
130
	public Object getGraphData() {
131
		return null;
132
	}
133
134
	public void setGraphData(Object o) {
135
		
136
	}
137
138
}
(-)src/org/eclipse/zest/layouts/dataStructures/BendPoint.java (-54 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.dataStructures;
12
13
import org.eclipse.zest.layouts.LayoutBendPoint;
14
15
/**
16
 * Implements a single bend point in a graph relationship.
17
 * 
18
 * @author Ian Bull
19
 * @author Chris Bennett
20
 */
21
public class BendPoint extends DisplayIndependentPoint implements LayoutBendPoint {
22
	
23
	private boolean isControlPoint = false; // is this a control point (for use in curves)
24
25
	public BendPoint(double x, double y) {
26
		super(x, y);
27
	}
28
29
	public BendPoint(double x, double y, boolean isControlPoint) {
30
		this(x, y);
31
		this.isControlPoint = isControlPoint;
32
	}
33
34
	public double getX() {
35
		return x;
36
	}
37
38
	public double getY() {
39
		return y;
40
	}
41
42
	public void setX(double x) {
43
		this.x = x;
44
	}
45
46
	public void setY(double y) {
47
		this.y = y;
48
	}
49
50
	public boolean getIsControlPoint() {
51
		return isControlPoint;
52
	}
53
54
}
(-)src/org/eclipse/zest/layouts/dataStructures/InternalNode.java (-240 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.layouts.dataStructures;
12
13
import java.util.HashMap;
14
15
import org.eclipse.zest.layouts.LayoutEntity;
16
import org.eclipse.zest.layouts.constraints.BasicEntityConstraint;
17
import org.eclipse.zest.layouts.constraints.LayoutConstraint;
18
19
/**
20
 * @author Ian Bull
21
 */
22
public class InternalNode implements Comparable, LayoutEntity {
23
	
24
	private LayoutEntity entity = null;
25
	private HashMap attributeMap = new HashMap();
26
	BasicEntityConstraint basicEntityConstraint = new BasicEntityConstraint();
27
	
28
	public InternalNode( LayoutEntity entity ) {
29
		this.entity = entity;
30
		this.entity.setLayoutInformation(this);
31
		this.layoutWidth = entity.getWidthInLayout();
32
		this.layoutHeight = entity.getHeightInLayout();
33
		entity.populateLayoutConstraint(basicEntityConstraint);
34
	}
35
	
36
	public LayoutEntity getLayoutEntity() {
37
		return this.entity;
38
	}
39
	
40
	public double getPreferredX() {
41
		return basicEntityConstraint.preferredX;
42
43
	}
44
	
45
	public double getPreferredY() {
46
		return basicEntityConstraint.preferredY;
47
	}
48
	
49
	public boolean hasPreferredLocation() {
50
		return basicEntityConstraint.hasPreferredLocation;
51
	}
52
	
53
	double dx, dy;
54
	public void setDx( double x ) {
55
		this.dx = x;
56
	}
57
	public void setDy( double y ) {
58
		this.dy = y;
59
	}
60
	public double getDx() {
61
		return this.dx;
62
	}
63
	public double getDy() {
64
		return this.dy;
65
	}	
66
	
67
	public double getCurrentX() {
68
		return entity.getXInLayout();
69
	}
70
	public double getCurrentY() {
71
		return entity.getYInLayout();
72
	}
73
		
74
	public void setLocation( double x, double y ) {
75
		entity.setLocationInLayout( x, y );
76
	}
77
	public void setSize( double width, double height ) {
78
		entity.setSizeInLayout( width, height );
79
	}
80
	
81
	double normalizedX      = 0.0;
82
	double normalizedY      = 0.0;
83
	double normalizedWidth  = 0.0;
84
	double normalizedHeight = 0.0;
85
	
86
	public void setInternalLocation( double x, double y ) {
87
		//entity.setLocationInLayout(x,y);
88
		
89
		normalizedX = x;
90
		normalizedY = y;
91
		
92
	}
93
	
94
	public DisplayIndependentPoint getInternalLocation() {
95
		return new DisplayIndependentPoint(getInternalX(),getInternalY());
96
	}
97
	
98
	public void setInternalSize( double width, double height ) {
99
		normalizedWidth = width;
100
		normalizedHeight = height;
101
	}
102
103
	public double getInternalX() {
104
		//return entity.getXInLayout();
105
		return normalizedX;
106
	}
107
	public double getInternalY() {
108
		//return entity.getYInLayout();
109
		return normalizedY;
110
	}
111
	public double getInternalWidth() {
112
		return normalizedWidth;
113
	}
114
	public double getInternalHeight() {
115
		return normalizedHeight;
116
	}
117
118
	
119
	/**
120
	 * An algorithm may require a place to store information.  Use this structure for that purpose.
121
	 */
122
	public void setAttributeInLayout (Object attribute, Object value) {
123
		attributeMap.put(attribute, value);
124
	}
125
	
126
	/**
127
	 * An algorithm may require a place to store information.  Use this structure for that purpose.
128
	 */
129
	public Object getAttributeInLayout (Object attribute) {
130
		return attributeMap.get( attribute );
131
	}
132
133
	
134
	//TODO: Fix all these preferred stuff!!!!! NOW!
135
	
136
	public boolean hasPreferredWidth () {
137
		return false;
138
	    //return enity.getAttributeInLayout(LayoutEntity.ATTR_PREFERRED_WIDTH) != null;
139
	}
140
	
141
	public double getPreferredWidth () {
142
		return 0.0;
143
//	    if (hasPreferredWidth()) {
144
//	        return ((Double)entity.getAttributeInLayout(LayoutEntity.ATTR_PREFERRED_WIDTH)).doubleValue();
145
//	    } else {
146
//	        return 10.0;
147
//	    }
148
	}
149
	
150
	public boolean hasPreferredHeight () {
151
		return false;
152
	//    return entity.getAttributeInLayout(LayoutEntity.ATTR_PREFERRED_HEIGHT) != null;
153
	}
154
	
155
	public double getPreferredHeight () {
156
		return 0.0;
157
//	    if (hasPreferredHeight()) {
158
//	        return ((Double)entity.getAttributeInLayout(LayoutEntity.ATTR_PREFERRED_HEIGHT)).doubleValue();
159
//	    } else {
160
//	        return 10.0;
161
//	    }
162
	}
163
	
164
	/* (non-Javadoc)
165
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
166
	 */
167
	public int compareTo(Object arg0) {
168
		return 0;
169
	}
170
	
171
	/* (non-Javadoc)
172
	 * @see java.lang.Object#toString()
173
	 */
174
	public String toString() {
175
		return (entity != null ? entity.toString() : "");
176
	}
177
	
178
	double layoutHeight;
179
	double layoutWidth;
180
	double layoutX;
181
	double layoutY;
182
	Object layoutInfo;
183
184
	public double getHeightInLayout() {
185
		// TODO Auto-generated method stub
186
		return layoutHeight;
187
	}
188
189
	public Object getLayoutInformation() {
190
		// TODO Auto-generated method stub
191
		return this.layoutInfo;
192
	}
193
194
	public double getWidthInLayout() {
195
		// TODO Auto-generated method stub
196
		return layoutWidth;
197
	}
198
199
	public double getXInLayout() {
200
		// TODO Auto-generated method stub
201
		return layoutX;
202
	}
203
204
	public double getYInLayout() {
205
		// TODO Auto-generated method stub
206
		return layoutY;
207
	}
208
209
	public void populateLayoutConstraint(LayoutConstraint constraint) {
210
		// TODO Auto-generated method stub
211
		
212
	}
213
214
	public void setLayoutInformation(Object internalEntity) {
215
		this.layoutInfo = internalEntity;
216
		
217
	}
218
219
	public void setLocationInLayout(double x, double y) {
220
		// TODO Auto-generated method stub
221
		this.layoutX = x;
222
		this.layoutY = y;
223
		
224
	}
225
226
	public void setSizeInLayout(double width, double height) {
227
		this.layoutWidth = width;
228
		this.layoutHeight = height;	
229
	}
230
231
	public Object getGraphData() {
232
		return null;
233
	}
234
235
	public void setGraphData(Object o) {
236
		// TODO Auto-generated method stub
237
		
238
	}
239
	
240
}
(-)src/org/eclipse/zest/layouts/interfaces/ConnectionLayout.java (+48 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.layouts.interfaces;
11
12
13
public interface ConnectionLayout {
14
15
	public NodeLayout getSource();
16
17
	public NodeLayout getTarget();
18
19
	/**
20
	 * 
21
	 * @return weight assigned to this connection
22
	 */
23
	public double getWeight();
24
25
	/**
26
	 * Checks if this connection is directed. For undirected connections, source
27
	 * and target nodes should be considered just adjacent nodes without
28
	 * dividing to source/target.
29
	 * 
30
	 * @return true if this connection is directed
31
	 */
32
	public boolean isDirected();
33
34
	/**
35
	 * Changes the visibility state of this connection.
36
	 * 
37
	 * @param visible
38
	 *            true if this connection should be visible, false otherwise
39
	 */
40
	public void setVisible(boolean visible);
41
42
	/**
43
	 * Checks the visibility state of this connection.
44
	 * 
45
	 * @return true if this connection is visible, false otherwise
46
	 */
47
	public boolean isVisible();
48
}
(-)src/org/eclipse/zest/layouts/interfaces/ExpandCollapseManager.java (+63 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.layouts.interfaces;
11
12
/**
13
 * A manager that controls expanding and collapsing nodes in a Graph.
14
 */
15
public interface ExpandCollapseManager {
16
17
	/**
18
	 * Initializes the expansion state of all nodes in given layout context. The
19
	 * receiver can initialize its internal state related to the layout context
20
	 * and add its listeners if necessary.
21
	 * 
22
	 * @param context
23
	 *            the context to initialize
24
	 */
25
	public void initExpansion(LayoutContext context);
26
27
	/**
28
	 * Changes the expanded state of given node. It prunes/unprunes nodes and
29
	 * hides/shows connections in the graph according to its policy. If
30
	 * requested operation cannot be currently performed on the node, it does
31
	 * nothing.
32
	 * 
33
	 * @param context
34
	 *            context in which to perform the operation
35
	 * @param node
36
	 *            node to expand or collapse
37
	 * @param expanded
38
	 *            true to expand, false to collapse
39
	 */
40
	public void setExpanded(LayoutContext context, NodeLayout node, boolean expanded);
41
42
	/**
43
	 * Checks if given node can be expanded.
44
	 * 
45
	 * @param context
46
	 *            context containing the node
47
	 * @param node
48
	 *            node to check
49
	 * @return
50
	 */
51
	public boolean canExpand(LayoutContext context, NodeLayout node);
52
53
	/**
54
	 * Checks if given node can be collapsed.
55
	 * 
56
	 * @param context
57
	 *            context containing the node
58
	 * @param node
59
	 *            node to check
60
	 * @return
61
	 */
62
	public boolean canCollapse(LayoutContext context, NodeLayout node);
63
}
(-).refactorings/2009/8/35/refactorings.history (+3 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<session version="1.0">&#x0A;<refactoring accessors="true" comment="Delete 11 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original elements:&#x0D;&#x0A;     org.eclipse.zest.layouts.Filter.java&#x0D;&#x0A;     org.eclipse.zest.layouts.InvalidLayoutConfiguration.java&#x0D;&#x0A;     org.eclipse.zest.layouts.LayoutBendPoint.java&#x0D;&#x0A;     org.eclipse.zest.layouts.LayoutEntity.java&#x0D;&#x0A;     org.eclipse.zest.layouts.LayoutGraph.java&#x0D;&#x0A;     org.eclipse.zest.layouts.LayoutItem.java&#x0D;&#x0A;     org.eclipse.zest.layouts.LayoutIterationEvent.java&#x0D;&#x0A;     org.eclipse.zest.layouts.LayoutRelationship.java&#x0D;&#x0A;     org.eclipse.zest.layouts.LayoutStyles.java&#x0D;&#x0A;     org.eclipse.zest.layouts.NestedLayoutEntity.java&#x0D;&#x0A;     org.eclipse.zest.layouts.Stoppable.java" description="Delete elements" element1="/src&lt;org.eclipse.zest.layouts{LayoutStyles.java" element10="/src&lt;org.eclipse.zest.layouts{InvalidLayoutConfiguration.java" element11="/src&lt;org.eclipse.zest.layouts{LayoutItem.java" element2="/src&lt;org.eclipse.zest.layouts{Stoppable.java" element3="/src&lt;org.eclipse.zest.layouts{Filter.java" element4="/src&lt;org.eclipse.zest.layouts{LayoutGraph.java" element5="/src&lt;org.eclipse.zest.layouts{LayoutIterationEvent.java" element6="/src&lt;org.eclipse.zest.layouts{NestedLayoutEntity.java" element7="/src&lt;org.eclipse.zest.layouts{LayoutEntity.java" element8="/src&lt;org.eclipse.zest.layouts{LayoutBendPoint.java" element9="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.layouts/src/org.eclipse.zest.layouts.algorithms.internal&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.layouts/src/org.eclipse.zest.layouts.constraints&apos;" description="Delete element" element1="/src&lt;org.eclipse.zest.layouts.constraints" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470169378" subPackages="false" version="1.0"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.layouts/src/org.eclipse.zest.layouts.progress&apos;" description="Delete element" element1="/src&lt;org.eclipse.zest.layouts.progress" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470188073" subPackages="false" version="1.0"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.layouts/src/interfaces&apos;" description="Delete element" element1="/src&lt;interfaces" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251470206585" subPackages="false" version="1.0"/>&#x0A;<refactoring accessors="true" comment="Delete 3 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original elements:&#x0D;&#x0A;     org.eclipse.zest.layouts.dataStructures.BendPoint.java&#x0D;&#x0A;     org.eclipse.zest.layouts.dataStructures.InternalNode.java&#x0D;&#x0A;     org.eclipse.zest.layouts.dataStructures.InternalRelationship.java" description="Delete elements" element1="/src&lt;org.eclipse.zest.layouts.dataStructures{InternalNode.java" element2="/src&lt;org.eclipse.zest.layouts.dataStructures{InternalRelationship.java" element3="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.layouts.algorithms.AbstractLayoutAlgorithm.java&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.layouts.algorithms.ContinuousLayoutAlgorithm.java&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.layouts.algorithms.HorizontalShift.java&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.layouts.algorithms.HorizontalLayoutAlgorithm.java&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.layouts.algorithms.HorizontalTreeLayoutAlgorithm.java&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.layouts.algorithms.VerticalLayoutAlgorithm.java&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.layouts&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.layouts/src/org.eclipse.zest.layouts.exampleStructures&apos;" description="Delete element" element1="/src&lt;org.eclipse.zest.layouts.exampleStructures" elements="1" flags="589830" id="org.eclipse.jdt.ui.delete" resources="0" stamp="1251471154148" subPackages="false" version="1.0"/>
3
</session>
(-)src/org/eclipse/zest/layouts/algorithms/TreeLayoutObserver.java (+563 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005-2009 The Chisel Group and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: The Chisel Group - initial API and implementation
8
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 *               Ian Bull
10
 ******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
12
13
import java.util.ArrayList;
14
import java.util.Collections;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.Iterator;
18
import java.util.LinkedList;
19
import java.util.List;
20
import java.util.ListIterator;
21
import java.util.Set;
22
23
import org.eclipse.zest.layouts.interfaces.ConnectionLayout;
24
import org.eclipse.zest.layouts.interfaces.GraphStructureListener;
25
import org.eclipse.zest.layouts.interfaces.LayoutContext;
26
import org.eclipse.zest.layouts.interfaces.NodeLayout;
27
28
/**
29
 * A helper class for layout algorithms that are based on tree structure. It
30
 * keeps track of changes in observed layout context and stores current
31
 * information about the tree structure - children of each node and several
32
 * other parameters.
33
 */
34
public class TreeLayoutObserver {
35
36
	/**
37
	 * <code>TreeLayoutObserver</code> uses instance of this class to create
38
	 * instances of {@link TreeNode}. It may be extended and passed to
39
	 * <code>TreeLayoutObserver</code>'s constructor in order to build a tree
40
	 * structure made of <code>TreeNode</code>'s subclasses.
41
	 */
42
	public static class TreeNodeFactory {
43
		public TreeNode createTreeNode(NodeLayout nodeLayout, TreeLayoutObserver observer) {
44
			return new TreeNode(nodeLayout, observer);
45
		}
46
	}
47
48
	/**
49
	 * Represents a node in a tree structure and stores all information related
50
	 * to it. May be subclassed if additional data and behavior is necessary.
51
	 */
52
	public static class TreeNode {
53
		final protected NodeLayout node;
54
		final protected TreeLayoutObserver owner;
55
		protected int height = 0;
56
		protected int depth = -1;
57
		protected int numOfLeaves = 0;
58
		protected int numOfDescendants = 0;
59
		protected int order = 0;
60
		protected final List children = new ArrayList();
61
		protected TreeNode parent;
62
		protected boolean firstChild = false, lastChild = false;
63
64
		/**
65
		 * 
66
		 * @return node layout related to this tree node (null for
67
		 *         {@link TreeLayoutObserver#getSuperRoot() Super Root})
68
		 */
69
		public NodeLayout getNode() {
70
			return node;
71
		}
72
73
		/**
74
		 * 
75
		 * @return <code>TreeLayoutObserver</code> owning this tree node
76
		 */
77
		public TreeLayoutObserver getOwner() {
78
			return owner;
79
		}
80
81
		/**
82
		 * 
83
		 * @return height of this node in the tree (the longest distance to a
84
		 *         leaf, 0 for a leaf itself)
85
		 */
86
		public int getHeight() {
87
			return height;
88
		}
89
90
		/**
91
		 * 
92
		 * @return depth of this node in the tree (distance from root, 0 for a
93
		 *         root and -1 for {@link TreeLayoutObserver#getSuperRoot()
94
		 *         Super Root}
95
		 */
96
		public int getDepth() {
97
			return depth;
98
		}
99
100
		/**
101
		 * 
102
		 * @return number of all leaves descending from this node (1 for a leaf
103
		 *         itself)
104
		 */
105
		public int getNumOfLeaves() {
106
			return numOfLeaves;
107
		}
108
109
		/**
110
		 * 
111
		 * @return total number of descendants of this node (0 for leafs)
112
		 */
113
		public int getNumOfDescendants() {
114
			return numOfDescendants;
115
		}
116
117
		/**
118
		 * Returns order in which nodes are visited during Deep First Search.
119
		 * Children are visited in the same order as they were added to their
120
		 * layout context, unless {@link TreeLayoutObserver#recomputeTree()} was
121
		 * called after the nodes were added. In that case the order is
122
		 * determined by order of nodes returned by
123
		 * {@link NodeLayout#getSuccessingNodes()}. Leaves are assigned
124
		 * successive numbers starting from 0, other nodes have order equal to
125
		 * the smallest order of their children.
126
		 * 
127
		 * @return order of this node
128
		 */
129
		public int getOrder() {
130
			return order;
131
		}
132
133
		/**
134
		 * 
135
		 * @return an unmodifiable list of this node's children
136
		 */
137
		public List getChildren() {
138
			return Collections.unmodifiableList(children);
139
		}
140
141
		/**
142
		 * 
143
		 * @return this node's parent
144
		 */
145
		public TreeNode getParent() {
146
			return parent;
147
		}
148
149
		/**
150
		 * 
151
		 * @return true if this node is the first child of its parent (has the
152
		 *         smallest order)
153
		 */
154
		public boolean isFirstChild() {
155
			return firstChild;
156
		}
157
158
		/**
159
		 * 
160
		 * @return
161
		 */
162
		public boolean isLastChild() {
163
			return lastChild;
164
		}
165
166
		/**
167
		 * Creates a tree node related to given layout node
168
		 * 
169
		 * @param node
170
		 *            the layout node
171
		 * @param owner
172
		 *            <code>TreeLayoutObserver</code> owning created node
173
		 */
174
		protected TreeNode(NodeLayout node, TreeLayoutObserver owner) {
175
			this.node = node;
176
			this.owner = owner;
177
		}
178
179
		/**
180
		 * Adds given node to the list of this node's children and set its
181
		 * parent to this node.
182
		 * 
183
		 * @param child
184
		 *            node to add
185
		 */
186
		protected void addChild(TreeNode child) {
187
			children.add(child);
188
			child.parent = this;
189
		}
190
191
		/**
192
		 * Performs a DFS on the tree structure and calculates all parameters of
193
		 * its nodes. Should be called on
194
		 * {@link TreeLayoutObserver#getSuperRoot() Super Root}. Uses recurrence
195
		 * to go through all the nodes.
196
		 */
197
		protected void precomputeTree() {
198
			if (children.isEmpty()) {
199
				height = 0;
200
				numOfLeaves = 1;
201
				numOfDescendants = 0;
202
			} else {
203
				height = 0;
204
				numOfLeaves = 0;
205
				numOfDescendants = 0;
206
				for (ListIterator iterator = children.listIterator(); iterator.hasNext();) {
207
					TreeNode child = (TreeNode) iterator.next();
208
					child.depth = this.depth + 1;
209
					child.order = this.order + this.numOfLeaves;
210
					child.precomputeTree();
211
					child.firstChild = (this.numOfLeaves == 0);
212
					child.lastChild = !iterator.hasNext();
213
214
					this.height = Math.max(this.height, child.height + 1);
215
					this.numOfLeaves += child.numOfLeaves;
216
					this.numOfDescendants += child.numOfDescendants + 1;
217
				}
218
			}
219
		}
220
221
		/**
222
		 * Finds a node that is the best parent for this node. Add this node as
223
		 * a child of the found node.
224
		 */
225
		protected void findNewParent() {
226
			if (parent != null)
227
				parent.children.remove(this);
228
			NodeLayout[] predecessingNodes = node.getPredecessingNodes();
229
			parent = null;
230
			for (int i = 0; i < predecessingNodes.length; i++) {
231
				TreeNode potentialParent = (TreeNode) owner.layoutToTree.get(predecessingNodes[i]);
232
				if (!children.contains(potentialParent) && isBetterParent(potentialParent))
233
					parent = potentialParent;
234
			}
235
			if (parent == null)
236
				parent = owner.superRoot;
237
238
			parent.addChild(this);
239
		}
240
241
		/**
242
		 * Checks if a potential parent would be better for this node than its
243
		 * current parent. A better parent has smaller depth (with exception to
244
		 * {@link TreeLayoutObserver#getSuperRoot() Super Root}, which has depth
245
		 * equal to -1 but is never a better parent than any other node).
246
		 * 
247
		 * @param potentialParent
248
		 *            potential parent to check
249
		 * @return true if potentialParent can be a parent of this node and is
250
		 *         better than its current parent
251
		 */
252
		protected boolean isBetterParent(TreeNode potentialParent) {
253
			if (this.parent == null && !this.isAncestorOf(potentialParent))
254
				return true;
255
			if (potentialParent.depth <= this.depth && potentialParent.depth != -1)
256
				return true;
257
			if (this.parent.depth == -1 && potentialParent.depth >= 0 && !this.isAncestorOf(potentialParent))
258
				return true;
259
			return false;
260
		}
261
262
		/**
263
		 * 
264
		 * @param descendant
265
		 * @return true if this node is an ancestor if given descendant node
266
		 */
267
		public boolean isAncestorOf(TreeNode descendant) {
268
			while (descendant.depth > this.depth)
269
				descendant = descendant.parent;
270
			return descendant == this;
271
		}
272
	}
273
274
	/**
275
	 * A superclass for listeners that can be added to this observer to get
276
	 * notification whenever the tree structure changes.
277
	 */
278
	public static class TreeListener {
279
		/**
280
		 * Called when new node is added to the tree structure. The new node
281
		 * will not have any connections, so it will be a child of
282
		 * {@link TreeLayoutObserver#getSuperRoot() Super Root}
283
		 * 
284
		 * @param newNode
285
		 *            the added node
286
		 */
287
		public void nodeAdded(TreeNode newNode) {
288
			defaultHandle(newNode);
289
		}
290
291
		/**
292
		 * Called when a node is removed from the tree structure. The given node
293
		 * no longer exists in the tree at the moment of call.
294
		 * 
295
		 * @param removedNode
296
		 *            the removed node
297
		 */
298
		public void nodeRemoved(TreeNode removedNode) {
299
			defaultHandle(removedNode);
300
		}
301
302
		/**
303
		 * Called when a node changes its parent.
304
		 * 
305
		 * @param node
306
		 *            node that changes its parent
307
		 * @param previousParent
308
		 *            previous parent of the node
309
		 */
310
		public void parentChanged(TreeNode node, TreeNode previousParent) {
311
			defaultHandle(node);
312
		}
313
314
		/**
315
		 * A convenience method that can be overridden if a listener reacts the
316
		 * same way to all events. By default it's called in every event handler
317
		 * and does nothing.
318
		 * 
319
		 * @param changedNode
320
		 *            the node that has changed
321
		 */
322
		protected void defaultHandle(TreeNode changedNode) {
323
		}
324
	}
325
326
	private GraphStructureListener structureListener = new GraphStructureListener() {
327
328
		public boolean nodeRemoved(LayoutContext context, NodeLayout node) {
329
			TreeNode treeNode = (TreeNode) layoutToTree.get(node);
330
			treeNode.parent.children.remove(treeNode);
331
			superRoot.precomputeTree();
332
			for (Iterator iterator = treeListeners.iterator(); iterator.hasNext();) {
333
				TreeListener listener = (TreeListener) iterator.next();
334
				listener.nodeRemoved(treeNode);
335
			}
336
			return false;
337
		}
338
339
		public boolean nodeAdded(LayoutContext context, NodeLayout node) {
340
			TreeNode treeNode = getTreeNode(node);
341
			superRoot.addChild(treeNode);
342
			superRoot.precomputeTree();
343
			for (Iterator iterator = treeListeners.iterator(); iterator.hasNext();) {
344
				TreeListener listener = (TreeListener) iterator.next();
345
				listener.nodeAdded(treeNode);
346
			}
347
			return false;
348
		}
349
350
		public boolean connectionRemoved(LayoutContext context, ConnectionLayout connection) {
351
			TreeNode node1 = (TreeNode) layoutToTree.get(connection.getSource());
352
			TreeNode node2 = (TreeNode) layoutToTree.get(connection.getTarget());
353
			if (node1.parent == node2) {
354
				node1.findNewParent();
355
				if (node1.parent != node2) {
356
					superRoot.precomputeTree();
357
					fireParentChanged(node1, node2);
358
				}
359
			}
360
			if (node2.parent == node1) {
361
				node2.findNewParent();
362
				if (node2.parent != node1) {
363
					superRoot.precomputeTree();
364
					fireParentChanged(node2, node1);
365
				}
366
			}
367
			return false;
368
		}
369
370
		public boolean connectionAdded(LayoutContext context, ConnectionLayout connection) {
371
			TreeNode source = (TreeNode) layoutToTree.get(connection.getSource());
372
			TreeNode target = (TreeNode) layoutToTree.get(connection.getTarget());
373
			if (source == target)
374
				return false;
375
			if (target.isBetterParent(source)) {
376
				TreeNode previousParent = target.parent;
377
				previousParent.children.remove(target);
378
				source.addChild(target);
379
				superRoot.precomputeTree();
380
				fireParentChanged(target, previousParent);
381
			}
382
			if (!connection.isDirected() && source.isBetterParent(target)) {
383
				TreeNode previousParent = source.parent;
384
				previousParent.children.remove(source);
385
				target.addChild(source);
386
				superRoot.precomputeTree();
387
				fireParentChanged(source, previousParent);
388
			}
389
			return false;
390
		}
391
392
		public boolean connectionWeightChanged(LayoutContext context, ConnectionLayout connection) {
393
			// do nothing
394
			return false;
395
		}
396
397
		public boolean connectionDirectedChanged(LayoutContext context, ConnectionLayout connection) {
398
			connectionRemoved(context, connection);
399
			connectionAdded(context, connection);
400
			return false;
401
		}
402
403
		private void fireParentChanged(TreeNode node, TreeNode previousParent) {
404
			for (Iterator iterator = treeListeners.iterator(); iterator.hasNext();) {
405
				TreeListener listener = (TreeListener) iterator.next();
406
				listener.parentChanged(node, previousParent);
407
			}
408
		}
409
	};
410
411
	private final HashMap layoutToTree = new HashMap();
412
	private final TreeNodeFactory factory;
413
	private final LayoutContext context;
414
	private TreeNode superRoot;
415
	private ArrayList treeListeners = new ArrayList();
416
417
	/**
418
	 * Creates a
419
	 * 
420
	 * @param context
421
	 * @param nodeFactory
422
	 */
423
	public TreeLayoutObserver(LayoutContext context, TreeNodeFactory nodeFactory) {
424
		if (nodeFactory == null)
425
			this.factory = new TreeNodeFactory();
426
		else
427
			this.factory = nodeFactory;
428
		this.context = context;
429
		context.addGraphStructureListener(structureListener);
430
		recomputeTree();
431
	}
432
433
	/**
434
	 * Recomputes all the information about the tree structure (the same effect
435
	 * as creating new <code>TreeLayoutObserver</code>).
436
	 */
437
	public void recomputeTree() {
438
		superRoot = factory.createTreeNode(null, this);
439
		layoutToTree.put(null, superRoot);
440
		createTrees(context.getNodes());
441
	}
442
443
	/**
444
	 * Stops this observer from listening to changes in observed layout context.
445
	 * After calling this method the information about tree structure can be
446
	 * updated only when {@link #recomputeTree()} is called.
447
	 */
448
	public void stop() {
449
		context.removeGraphStructureListener(structureListener);
450
	}
451
452
	/**
453
	 * Returns Super Root, that is an artificial node being a common parent for
454
	 * all nodes in observed tree structure.
455
	 * 
456
	 * @return Super Root
457
	 */
458
	public TreeNode getSuperRoot() {
459
		return superRoot;
460
	}
461
462
	/**
463
	 * Returns a {@link TreeNode} related to given node layout. If such a
464
	 * <code>TreeNode</code> doesn't exist, it's created.
465
	 * 
466
	 * @param node
467
	 * @return
468
	 */
469
	public TreeNode getTreeNode(NodeLayout node) {
470
		TreeNode treeNode = (TreeNode) layoutToTree.get(node);
471
		if (treeNode == null) {
472
			treeNode = factory.createTreeNode(node, this);
473
			layoutToTree.put(node, treeNode);
474
		}
475
		return treeNode;
476
	}
477
478
	/**
479
	 * Adds a listener that will be informed about changes in tree structure.
480
	 * 
481
	 * @param listener
482
	 *            listener to add
483
	 */
484
	public void addTreeListener(TreeListener listener) {
485
		treeListeners.add(listener);
486
	}
487
488
	/**
489
	 * Removes a listener from list of listener to be informed about changes in
490
	 * tree structure.
491
	 * 
492
	 * @param listener
493
	 *            listener to remove
494
	 */
495
	public void removeTreeListener(TreeListener listener) {
496
		treeListeners.add(listener);
497
	}
498
499
	/**
500
	 * Builds a tree structure using BFS method. Created trees are children of
501
	 * {@link #superRoot}.
502
	 * 
503
	 * @param nodes
504
	 */
505
	private void createTrees(NodeLayout[] nodes) {
506
		HashSet alreadyVisited = new HashSet();
507
		LinkedList nodesToAdd = new LinkedList();
508
		for (int i = 0; i < nodes.length; i++) {
509
			NodeLayout root = findRoot(nodes[i], alreadyVisited);
510
			if (root != null) {
511
				alreadyVisited.add(root);
512
				nodesToAdd.addLast(new Object[] { root, superRoot });
513
			}
514
		}
515
		while (!nodesToAdd.isEmpty()) {
516
			Object[] dequeued = (Object[]) nodesToAdd.removeFirst();
517
			TreeNode currentNode = factory.createTreeNode((NodeLayout) dequeued[0], this);
518
			layoutToTree.put(dequeued[0], currentNode);
519
			TreeNode currentRoot = (TreeNode) dequeued[1];
520
521
			currentRoot.addChild(currentNode);
522
			NodeLayout[] children = currentNode.node.getSuccessingNodes();
523
			for (int i = 0; i < children.length; i++) {
524
				if (!alreadyVisited.contains(children[i])) {
525
					alreadyVisited.add(children[i]);
526
					nodesToAdd.addLast(new Object[] { children[i], currentNode });
527
				}
528
			}
529
		}
530
		superRoot.precomputeTree();
531
	}
532
533
	/**
534
	 * Searches for a root of a tree containing given node by continuously
535
	 * grabbing a predecessor of current node. If it reaches an node that exists
536
	 * in alreadyVisited set, it returns null. If it detects a cycle, it returns
537
	 * the first found node of that cycle. If it reaches a node that has no
538
	 * predecessors, it returns that node.
539
	 * 
540
	 * @param nodeLayout
541
	 *            starting node
542
	 * @param alreadyVisited
543
	 *            set of nodes that can't lay on path to the root (if one does,
544
	 *            method stops and returns null).
545
	 * @return
546
	 */
547
	private NodeLayout findRoot(NodeLayout nodeLayout, Set alreadyVisited) {
548
		HashSet alreadyVisitedRoot = new HashSet();
549
		while (true) {
550
			if (alreadyVisited.contains(nodeLayout))
551
				return null;
552
			if (alreadyVisitedRoot.contains(nodeLayout))
553
				return nodeLayout;
554
			alreadyVisitedRoot.add(nodeLayout);
555
			NodeLayout[] predecessingNodes = nodeLayout.getPredecessingNodes();
556
			if (predecessingNodes.length > 0) {
557
				nodeLayout = predecessingNodes[0];
558
			} else {
559
				return nodeLayout;
560
			}
561
		}
562
	}
563
}
(-)src/org/eclipse/zest/layouts/interfaces/LayoutListener.java (+56 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.layouts.interfaces;
11
12
import org.eclipse.zest.layouts.LayoutAlgorithm;
13
14
/**
15
 * A listener added to {@link LayoutContext} that is notified about changes in
16
 * this layout.
17
 */
18
public interface LayoutListener {
19
20
	/**
21
	 * This method is called whenever location of a particular entity (node or
22
	 * subgraph) is changed within observed context. If true is returned, it
23
	 * means that the receiving listener has intercepted this event. Intercepted
24
	 * events will not be passed to the rest of the listeners. If the event is
25
	 * not intercepted by any listener, {@link LayoutAlgorithm#applyLayout()
26
	 * applyLayout()} will be called on the context's main algorithm.
27
	 * 
28
	 * @param context
29
	 *            the layout context that fired the event
30
	 * @param entity
31
	 *            the entity that has moved
32
	 * @return true if no further operations after this event are required
33
	 */
34
	public boolean entityMoved(LayoutContext context, EntityLayout entity);
35
36
	/**
37
	 * This method is called whenever size of a particular entity (node or
38
	 * subgraph) is changed within observed context. This usually implicates
39
	 * change of position (the center of the entity) and the receiver should be
40
	 * aware of it (no additional
41
	 * {@link #entityMoved(LayoutContext, EntityLayout)} event will be fired).
42
	 * 
43
	 * If true is returned, it means that the receiving listener has intercepted
44
	 * this event. Intercepted events will not be passed to the rest of the
45
	 * listeners. If the event is not intercepted by any listener,
46
	 * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the
47
	 * context's main algorithm.
48
	 * 
49
	 * @param context
50
	 *            the layout context that fired the event
51
	 * @param entity
52
	 *            the entity that was resized
53
	 * @return true if no further operations after this event are required
54
	 */
55
	public boolean entityResized(LayoutContext context, EntityLayout entity);
56
}
(-).refactorings/2009/8/35/refactorings.index (+13 lines)
Added Link Here
1
1251470143328	Delete elements
2
1251470164817	Delete element
3
1251470169378	Delete element
4
1251470188073	Delete element
5
1251470206585	Delete element
6
1251470236983	Delete elements
7
1251470323797	Delete element
8
1251470330527	Delete element
9
1251470342814	Delete element
10
1251470441706	Delete element
11
1251470459491	Delete element
12
1251470478305	Delete element
13
1251471154148	Delete element
(-)src/org/eclipse/zest/layouts/interfaces/SubgraphLayout.java (+99 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.layouts.interfaces;
11
12
13
/**
14
 * An interface for subgraphs in layout. A subgraph is a set of pruned nodes
15
 * that will be displayed as one element. A subgraph must contain at least one
16
 * node (empty subgraphs will be removed from its context). Every node can
17
 * belong to at most one subgraph.
18
 */
19
public interface SubgraphLayout extends EntityLayout {
20
21
	/**
22
	 * Constant for top-down direction (default).
23
	 */
24
	public final int TOP_DOWN = 1;
25
26
	/**
27
	 * Constant for bottom-up direction.
28
	 */
29
	public final int BOTTOM_UP = 2;
30
31
	/**
32
	 * Constant for direction from left to right.
33
	 */
34
	public final int LEFT_RIGHT = 3;
35
36
	/**
37
	 * Constant for direction from right to left.
38
	 */
39
	public final int RIGHT_LEFT = 4;
40
41
	/**
42
	 * Returns all the nodes belonging to this subgraph. Replacing elements in
43
	 * the returned array does not affect this subgraph.
44
	 * 
45
	 * @return array of nodes
46
	 */
47
	public NodeLayout[] getNodes();
48
49
	/**
50
	 * 
51
	 * @return number of nodes pruned into this subgraph
52
	 */
53
	public int countNodes();
54
55
	/**
56
	 * Adds nodes to this subgraph. If given nodes already belong to another
57
	 * subgraph, they are first removed from them.
58
	 * 
59
	 * @param nodes
60
	 *            array of nodes to add
61
	 */
62
	public void addNodes(NodeLayout[] nodes);
63
64
	/**
65
	 * Removes nodes from this subgraph.
66
	 * 
67
	 * @param nodes
68
	 *            array of nodes to remove
69
	 */
70
	public void removeNodes(NodeLayout[] nodes);
71
72
	/**
73
	 * Returns true if this subgraph is visualized as a particular object on the
74
	 * graph. If this method returns false, it means that this subgraph will not
75
	 * be visible so all methods related to location, size and direction should
76
	 * be ignored.
77
	 * 
78
	 * @return whether or not this subgraph is a graph entity that should be
79
	 *         laid out.
80
	 */
81
	public boolean isGraphEntity();
82
	
83
	/**
84
	 * @return true if this subgraph is visualized differently depending on
85
	 *         direction
86
	 */
87
	public boolean isDirectionDependant();
88
89
	/**
90
	 * Sets the direction of this subgraph (does nothing in case of subgraphs
91
	 * that don't depend on direction)
92
	 * 
93
	 * @param direction
94
	 *            one of constants: {@link #TOP_DOWN}, {@link #BOTTOM_UP},
95
	 *            {@link #LEFT_RIGHT}, {@link #RIGHT_LEFT}
96
	 */
97
	public void setDirection(int direction);
98
99
}
(-)src/org/eclipse/zest/layouts/algorithms/HorizontalShiftAlgorithm.java (+114 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005-2009 The Chisel Group and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: The Chisel Group - initial API and implementation
8
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 *               Ian Bull
10
 ******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
12
13
import java.util.ArrayList;
14
import java.util.Collections;
15
import java.util.Comparator;
16
import java.util.Iterator;
17
import java.util.List;
18
19
import org.eclipse.zest.layouts.LayoutAlgorithm;
20
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension;
21
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
22
import org.eclipse.zest.layouts.interfaces.EntityLayout;
23
import org.eclipse.zest.layouts.interfaces.LayoutContext;
24
25
/**
26
 * This layout shifts overlapping nodes to the right.
27
 * 
28
 * @author Ian Bull
29
 */
30
public class HorizontalShiftAlgorithm implements LayoutAlgorithm {
31
32
	private static final double DELTA = 10;
33
34
	private static final double VSPACING = 16;
35
36
	private static final double HSPACING = 10;
37
38
	private LayoutContext context;
39
40
	public void applyLayout(boolean clean) {
41
		if (!clean)
42
			return;
43
		ArrayList rowsList = new ArrayList();
44
		EntityLayout[] entities = context.getEntities();
45
46
		for (int i = 0; i < entities.length; i++) {
47
			addToRowList(entities[i], rowsList);
48
		}
49
50
		Collections.sort(rowsList, new Comparator() {
51
			public int compare(Object o1, Object o2) {
52
				List a0 = (List) o1;
53
				List a1 = (List) o2;
54
				EntityLayout entity0 = (EntityLayout) a0.get(0);
55
				EntityLayout entity1 = (EntityLayout) a1.get(0);
56
				return (int) (entity0.getLocation().y - entity1.getLocation().y);
57
			}
58
		});
59
60
		Comparator entityComparator = new Comparator() {
61
			public int compare(Object o1, Object o2) {
62
				return (int) (((EntityLayout) o1).getLocation().y - ((EntityLayout) o2).getLocation().y);
63
			}
64
		};
65
		DisplayIndependentRectangle bounds = context.getBounds();
66
		int heightSoFar = 0;
67
68
		for (Iterator iterator = rowsList.iterator(); iterator.hasNext();) {
69
			List currentRow = (List) iterator.next();
70
			Collections.sort(currentRow, entityComparator);
71
72
			int width = (int) (bounds.width - calculateRowWidth(currentRow)) / 2;
73
74
			heightSoFar += ((EntityLayout) currentRow.get(0)).getSize().height + VSPACING;
75
			for (Iterator iterator2 = currentRow.iterator(); iterator2.hasNext();) {
76
				EntityLayout entity = (EntityLayout) iterator2.next();
77
				DisplayIndependentDimension size = entity.getSize();
78
				entity.setLocation(width + size.width / 2, heightSoFar + size.height / 2);
79
				width += size.width + HSPACING;
80
			}
81
		}
82
	}
83
84
	private double calculateRowWidth(List row) {
85
		double result = 0;
86
		for (Iterator iterator = row.iterator(); iterator.hasNext();) {
87
			EntityLayout entity = (EntityLayout) iterator.next();
88
			result += entity.getSize().width;
89
		}
90
		result += HSPACING * (row.size() - 1);
91
		return result;
92
	}
93
94
	public void setLayoutContext(LayoutContext context) {
95
		this.context = context;
96
	}
97
98
	private void addToRowList(EntityLayout entity, ArrayList rowsList) {
99
		double layoutY = entity.getLocation().y;
100
101
		for (Iterator iterator = rowsList.iterator(); iterator.hasNext();) {
102
			List currentRow = (List) iterator.next();
103
			EntityLayout currentRowEntity = (EntityLayout) currentRow.get(0);
104
			double currentRowY = currentRowEntity.getLocation().y;
105
			if (layoutY >= currentRowY - DELTA && layoutY <= currentRowY + DELTA) {
106
				currentRow.add(entity);
107
				return;
108
			}
109
		}
110
		List newRow = new ArrayList();
111
		newRow.add(entity);
112
		rowsList.add(newRow);
113
	}
114
}
(-)src/org/eclipse/zest/layouts/algorithms/BoxLayoutAlgorithm.java (+48 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.layouts.algorithms;
11
12
/**
13
 * Layout algorithm that places all elements in one column or one row, depending
14
 * on set orientation.
15
 */
16
public class BoxLayoutAlgorithm extends GridLayoutAlgorithm {
17
18
	public static final int HORIZONTAL = 1;
19
20
	public static final int VERTICAL = 2;
21
22
	private int orientation = HORIZONTAL;
23
24
	public BoxLayoutAlgorithm() {
25
	}
26
27
	public BoxLayoutAlgorithm(int orientation) {
28
		setOrientation(orientation);
29
	}
30
31
	public int getOrientation() {
32
		return orientation;
33
	}
34
35
	public void setOrientation(int orientation) {
36
		if (orientation == HORIZONTAL || orientation == VERTICAL)
37
			this.orientation = orientation;
38
		else
39
			throw new RuntimeException("Invalid orientation: " + orientation);
40
	}
41
42
	protected int[] calculateNumberOfRowsAndCols(int numChildren, double boundX, double boundY, double boundWidth, double boundHeight) {
43
		if (orientation == HORIZONTAL)
44
			return new int[] { numChildren, 1 };
45
		else
46
			return new int[] { 1, numChildren };
47
	}
48
}
(-)src/org/eclipse/zest/layouts/algorithms/AlgorithmHelper.java (+208 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005-2009 The Chisel Group and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: The Chisel Group - initial API and implementation
8
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 *               Ian Bull
10
 ******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
12
13
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension;
14
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint;
15
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
16
import org.eclipse.zest.layouts.interfaces.EntityLayout;
17
18
class AlgorithmHelper {
19
20
	public static int MIN_NODE_SIZE = 8;
21
22
	public static double PADDING_PERCENT = 0.8;
23
24
	/**
25
	 * Fits given entities within given bounds, preserving their relative
26
	 * locations.
27
	 * 
28
	 * @param entities
29
	 * @param destinationBounds
30
	 * @param resize
31
	 */
32
	public static void fitWithinBounds(EntityLayout[] entities, DisplayIndependentRectangle destinationBounds, boolean resize) {
33
		if (entities.length == 1) {
34
			fitSingleEntity(entities[0], destinationBounds, resize);
35
			return;
36
		}
37
38
		DisplayIndependentRectangle startingBounds = getLayoutBounds(entities, false);
39
40
		DisplayIndependentRectangle startingBoundsIncludingSize = getLayoutBounds(entities, true);
41
		double sizeScale = Math.min(destinationBounds.width / startingBoundsIncludingSize.width, destinationBounds.height
42
				/ startingBoundsIncludingSize.height);
43
44
		for (int i = 0; i < entities.length; i++) {
45
			EntityLayout entity = entities[i];
46
			DisplayIndependentDimension size = entity.getSize();
47
			if (entity.isMovable()) {
48
				DisplayIndependentPoint location = entity.getLocation();
49
				double percentX = (location.x - startingBounds.x) / (startingBounds.width);
50
				double percentY = (location.y - startingBounds.y) / (startingBounds.height);
51
52
				if (resize && entity.isResizable()) {
53
					size.width *= sizeScale;
54
					size.height *= sizeScale;
55
					entity.setSize(size.width, size.height);
56
				}
57
58
				location.x = destinationBounds.x + size.width / 2 + percentX * (destinationBounds.width - size.width);
59
				location.y = destinationBounds.y + size.height / 2 + percentY * (destinationBounds.height - size.height);
60
				entity.setLocation(location.x, location.y);
61
			} else if (resize && entity.isResizable()) {
62
				entity.setSize(size.width * sizeScale, size.height * sizeScale);
63
			}
64
		}
65
	}
66
67
	private static void fitSingleEntity(EntityLayout entity, DisplayIndependentRectangle destinationBounds, boolean resize) {
68
		if (entity.isMovable()) {
69
			entity.setLocation(destinationBounds.x + destinationBounds.width / 2, destinationBounds.y + destinationBounds.height / 2);
70
		}
71
		if (resize && entity.isResizable()) {
72
			double width = destinationBounds.width;
73
			double height = destinationBounds.height;
74
			double preferredAspectRatio = entity.getPreferredAspectRatio();
75
			if (preferredAspectRatio > 0) {
76
				DisplayIndependentDimension fixedSize = fixAspectRatio(width, height, preferredAspectRatio);
77
				entity.setSize(fixedSize.width, fixedSize.height);
78
			} else {
79
				entity.setSize(width, height);
80
			}
81
		}
82
	}
83
84
	/**
85
	 * Resizes the nodes so that they have a maximal area without overlapping
86
	 * each other, with additional empty space of 20% of node's width (or
87
	 * height, if bigger). It does nothing if there's less than two nodes.
88
	 * 
89
	 * @param entities
90
	 */
91
	public static void maximizeSizes(EntityLayout[] entities) {
92
		if (entities.length > 1) {
93
			DisplayIndependentDimension minDistance = getMinimumDistance(entities);
94
			double nodeSize = Math.max(minDistance.width, minDistance.height) * PADDING_PERCENT;
95
			double width = nodeSize;
96
			double height = nodeSize;
97
			for (int i = 0; i < entities.length; i++) {
98
				EntityLayout entity = entities[i];
99
				if (entity.isResizable()) {
100
					double preferredRatio = entity.getPreferredAspectRatio();
101
					if (preferredRatio > 0) {
102
						DisplayIndependentDimension fixedSize = fixAspectRatio(width, height, preferredRatio);
103
						entity.setSize(fixedSize.width, fixedSize.height);
104
					} else {
105
						entity.setSize(width, height);
106
					}
107
				}
108
			}
109
		}
110
	}
111
112
	private static DisplayIndependentDimension fixAspectRatio(double width, double height, double preferredRatio) {
113
		double actualRatio = width / height;
114
		if (actualRatio > preferredRatio) {
115
			width = height * preferredRatio;
116
			if (width < MIN_NODE_SIZE) {
117
				width = MIN_NODE_SIZE;
118
				height = width / preferredRatio;
119
			}
120
		}
121
		if (actualRatio < preferredRatio) {
122
			height = width / preferredRatio;
123
			if (height < MIN_NODE_SIZE) {
124
				height = MIN_NODE_SIZE;
125
				width = height * preferredRatio;
126
			}
127
		}
128
		return new DisplayIndependentDimension(width, height);
129
	}
130
131
	/**
132
	 * Find the bounds in which the nodes are located. Using the bounds against
133
	 * the real bounds of the screen, the nodes can proportionally be placed
134
	 * within the real bounds. The bounds can be determined either including the
135
	 * size of the nodes or not. If the size is not included, the bounds will
136
	 * only be guaranteed to include the center of each node.
137
	 */
138
	public static DisplayIndependentRectangle getLayoutBounds(EntityLayout[] entities, boolean includeNodeSize) {
139
		double rightSide = Double.NEGATIVE_INFINITY;
140
		double bottomSide = Double.NEGATIVE_INFINITY;
141
		double leftSide = Double.POSITIVE_INFINITY;
142
		double topSide = Double.POSITIVE_INFINITY;
143
		for (int i = 0; i < entities.length; i++) {
144
			EntityLayout entity = entities[i];
145
			DisplayIndependentPoint location = entity.getLocation();
146
			DisplayIndependentDimension size = entity.getSize();
147
			if (includeNodeSize) {
148
				leftSide = Math.min(location.x - size.width / 2, leftSide);
149
				topSide = Math.min(location.y - size.height / 2, topSide);
150
				rightSide = Math.max(location.x + size.width / 2, rightSide);
151
				bottomSide = Math.max(location.y + size.height / 2, bottomSide);
152
			} else {
153
				leftSide = Math.min(location.x, leftSide);
154
				topSide = Math.min(location.y, topSide);
155
				rightSide = Math.max(location.x, rightSide);
156
				bottomSide = Math.max(location.y, bottomSide);
157
			}
158
		}
159
		return new DisplayIndependentRectangle(leftSide, topSide, rightSide - leftSide, bottomSide - topSide);
160
	}
161
162
	/**
163
	 * minDistance is the closest that any two points are together. These two
164
	 * points become the center points for the two closest nodes, which we wish
165
	 * to make them as big as possible without overlapping. This will be the
166
	 * maximum of minDistanceX and minDistanceY minus a bit, lets say 20%
167
	 * 
168
	 * We make the recommended node size a square for convenience.
169
	 * 
170
	 * <pre>
171
	 *    _______
172
	 *   |       | 
173
	 *   |       |
174
	 *   |   +   |
175
	 *   |   |\  |
176
	 *   |___|_\_|_____
177
	 *       | | \     |
178
	 *       | |  \    |
179
	 *       +-|---+   |
180
	 *         |       |
181
	 *         |_______|
182
	 * </pre>
183
	 * 
184
	 * 
185
	 */
186
	public static DisplayIndependentDimension getMinimumDistance(EntityLayout[] entities) {
187
		DisplayIndependentDimension horAndVertdistance = new DisplayIndependentDimension(Double.MAX_VALUE, Double.MAX_VALUE);
188
		double minDistance = Double.MAX_VALUE;
189
190
		// TODO: Very Slow!
191
		for (int i = 0; i < entities.length; i++) {
192
			DisplayIndependentPoint location1 = entities[i].getLocation();
193
			for (int j = i + 1; j < entities.length; j++) {
194
				DisplayIndependentPoint location2 = entities[j].getLocation();
195
				double distanceX = location1.x - location2.x;
196
				double distanceY = location1.y - location2.y;
197
				double distance = distanceX * distanceX + distanceY * distanceY;
198
199
				if (distance < minDistance) {
200
					minDistance = distance;
201
					horAndVertdistance.width = Math.abs(distanceX);
202
					horAndVertdistance.height = Math.abs(distanceY);
203
				}
204
			}
205
		}
206
		return horAndVertdistance;
207
	}
208
}
(-)src/org/eclipse/zest/layouts/interfaces/PruningListener.java (+58 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.layouts.interfaces;
11
12
import org.eclipse.zest.layouts.LayoutAlgorithm;
13
14
/**
15
 * A listener added to {@link LayoutContext} that is notified about pruning and
16
 * unpruning of nodes in this context.
17
 */
18
public interface PruningListener {
19
20
	/**
21
	 * This method is called when some nodes are pruned in a layout context.
22
	 * 
23
	 * If true is returned, it means that the receiving listener has intercepted
24
	 * this event. Intercepted events will not be passed to the rest of the
25
	 * listeners. If the event is not intercepted by any listener,
26
	 * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the
27
	 * context's main algorithm.
28
	 * 
29
	 * @param context
30
	 *            the layout context that fired the event
31
	 * @param nodes
32
	 *            nodes that have been pruned. It can be assumed that all these
33
	 *            nodes have been pruned into the same subgraph.
34
	 * @return true if no further operations after this event are required
35
	 */
36
	public boolean nodesPruned(LayoutContext context, NodeLayout[] nodes);
37
38
	/**
39
	 * This method is called when some nodes are unpruned in a layout context,
40
	 * that is they are no longer part of a subgraph.
41
	 * 
42
	 * If true is returned, it means that the receiving listener has intercepted
43
	 * this event. Intercepted events will not be passed to the rest of the
44
	 * listeners. If the event is not intercepted by any listener,
45
	 * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the
46
	 * context's main algorithm.
47
	 * 
48
	 * @param context
49
	 *            the layout context that fired the event
50
	 * @param nodes
51
	 *            nodes that have been unpruned
52
	 * @param subgraph
53
	 *            subgraph that had contained the nodes while they were pruned
54
	 * @return true if no further operations after this event are required
55
	 */
56
	public boolean nodesUnpruned(LayoutContext context, NodeLayout[] nodes, SubgraphLayout subgraph);
57
58
}
(-)src/org/eclipse/zest/layouts/interfaces/NodeLayout.java (+91 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.layouts.interfaces;
11
12
13
public interface NodeLayout extends EntityLayout {
14
15
	public boolean isPrunable();
16
17
	public boolean isPruned();
18
19
	/**
20
	 * 
21
	 * @return a subgraph this node belongs to or null if this node is not
22
	 *         pruned
23
	 */
24
	public SubgraphLayout getSubgraph();
25
26
	/**
27
	 * 
28
	 * @param subgraph
29
	 *            a subgraph this node should belong to or null if this node
30
	 *            should not be pruned
31
	 */
32
	public void prune(SubgraphLayout subgraph);
33
34
	/**
35
	 * Returns all nodes that are direct successors of this node. Nodes
36
	 * connected with this node by a bidirectional connection are considered
37
	 * both successors and predecessors. Any subsequent changes to the returned
38
	 * array do not affect this node.
39
	 * 
40
	 * @return array of successors of this node
41
	 */
42
	public NodeLayout[] getSuccessingNodes();
43
44
	/**
45
	 * Returns all nodes that are direct predecessors of this node. Nodes
46
	 * connected with this node by a bidirectional connection are considered
47
	 * both successors and predecessors. Any subsequent changes to the returned
48
	 * array do not affect this node.
49
	 * 
50
	 * @return array of predecessors of this node
51
	 */
52
	public NodeLayout[] getPredecessingNodes();
53
54
	/**
55
	 * Returns all connections that have this node as a target. All connections
56
	 * that are bidirectional and are adjacent to this node will be also
57
	 * included in the result. Any subsequent changes to the returned array do
58
	 * not affect this node.
59
	 * 
60
	 * @return array of connections entering this node
61
	 */
62
	public ConnectionLayout[] getIncomingConnections();
63
64
	/**
65
	 * Returns all connections that have this node as a source. All connections
66
	 * that are bidirectional and are adjacent to this node will be also
67
	 * included in the result. Any subsequent changes to the returned array do
68
	 * not affect this node.
69
	 * 
70
	 * @return array of connections leaving this node
71
	 */
72
	public ConnectionLayout[] getOutgoingConnections();
73
74
	/**
75
	 * Sets the minimized state of this Node. Node that is minimized resizes its
76
	 * figure to (0, 0). When it is unminimized, it resizes back to previous
77
	 * dimension. The node's size property is not affected by minimized state,
78
	 * so an it can be minimized even if it's not resizable.
79
	 * 
80
	 * @param minimized
81
	 *            new minimized state
82
	 */
83
	public void setMinimized(boolean minimized);
84
85
	/**
86
	 * @see #setMinimized(boolean)
87
	 * 
88
	 * @return true if this entity is minimized
89
	 */
90
	public boolean isMinimized();
91
}
(-)src/org/eclipse/zest/layouts/interfaces/EntityLayout.java (+106 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.layouts.interfaces;
11
12
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension;
13
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint;
14
15
/**
16
 * A common interface for entities that are displayed on a graph, that is
17
 * {@link NodeLayout nodes} and {@link SubgraphLayout subgraphs}.
18
 */
19
public interface EntityLayout {
20
21
	/**
22
	 * Returns a point laying in the center of this entity. Any subsequent
23
	 * changes to the returned point won't affect this node.
24
	 * 
25
	 * @return position of the center of this node
26
	 */
27
	public DisplayIndependentPoint getLocation();
28
29
	/**
30
	 * Sets the position of this entity. The node will be moved so that it's
31
	 * center is located in the given point.
32
	 * 
33
	 * @param x
34
	 *            the x-position
35
	 * @param y
36
	 *            the y-position
37
	 */
38
	public void setLocation(double x, double y);
39
40
	public DisplayIndependentDimension getSize();
41
42
	public void setSize(double width, double height);
43
44
	/**
45
	 * Returns aspect ratio that is preferred for this entity. Can be 0 if this
46
	 * node can't be resized anyway or it doesn't care about about its ratio.
47
	 * 
48
	 * @return aspect ratio (width / height)
49
	 */
50
	public double getPreferredAspectRatio();
51
52
	public boolean isResizable();
53
54
	public boolean isMovable();
55
56
	/**
57
	 * Returns all entities that are direct successors of this entity. Successor
58
	 * entities of an unpruned node N are:
59
	 * <ul>
60
	 * <li>all unpruned successor nodes of node N</li>
61
	 * <li>all subgraphs that are <code>GraphEntities</code> and contain at
62
	 * least one successor node of node N</li>
63
	 * </ul>
64
	 * Successor entities of a subgraph S that is a <code>GraphEntity</code>
65
	 * are:
66
	 * <ul>
67
	 * <li>all unpruned nodes that are successor of at least one node from
68
	 * subgraph S</li>
69
	 * <li>all subgraphs that are <code>GraphEntities</code> and contain at
70
	 * least one node that is a successor of at least one node from subgraph S</li>
71
	 * </ul>
72
	 * For subgraphs that are not <code>GraphEntities</code> an empty array will
73
	 * be returned.</br>Entities connected with this node by a bidirectional
74
	 * connection are considered both successors and predecessors. Any
75
	 * subsequent changes to the returned array do not affect this node.
76
	 * 
77
	 * @return array of successors of this node
78
	 */
79
	public EntityLayout[] getSuccessingEntities();
80
81
	/**
82
	 * Returns all entities that are direct predecessors of this entity.
83
	 * Predecessor entities of an unpruned node A are:
84
	 * <ul>
85
	 * <li>all unpruned predecessor nodes of node N</li>
86
	 * <li>all subgraphs that are <code>GraphEntities</code> and contain at
87
	 * least one predecessor node of node N</li>
88
	 * </ul>
89
	 * Successor entities of a subgraph S that is a <code>GraphEntity</code>
90
	 * are:
91
	 * <ul>
92
	 * <li>all unpruned nodes that are predecessor of at least one node from
93
	 * subgraph S</li>
94
	 * <li>all subgraphs that are <code>GraphEntities</code> and contain at
95
	 * least one node that is a predecessor of at least one node from subgraph S
96
	 * </li>
97
	 * </ul>
98
	 * For subgraphs that are not <code>GraphEntities</code> an empty array will
99
	 * be returned.</br>Entities connected with this node by a bidirectional
100
	 * connection are considered both successors and predecessors. Any
101
	 * subsequent changes to the returned array do not affect this node.
102
	 * 
103
	 * @return array of predecessors of this node
104
	 */
105
	public EntityLayout[] getPredecessingEntities();
106
}
(-)src/org/eclipse/zest/layouts/interfaces/LayoutContext.java (+229 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.layouts.interfaces;
11
12
import org.eclipse.zest.layouts.LayoutAlgorithm;
13
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
14
15
/**
16
 * Objects implementing LayoutContext interface are used for exchanging of
17
 * information between layout algorithms and graphical objects displaying
18
 * graphs.
19
 */
20
public interface LayoutContext {
21
22
	/**
23
	 * Returns all the nodes that should be laid out. Replacing elements in the
24
	 * returned array does not affect this context.
25
	 * 
26
	 * @return array of nodes to lay out
27
	 */
28
	public NodeLayout[] getNodes();
29
30
	/**
31
	 * Returns all the connections between nodes that should be laid out.
32
	 * Replacing elements in the returned array does not affect this context.
33
	 * 
34
	 * @return array of connections between nodes
35
	 */
36
	public ConnectionLayout[] getConnections();
37
38
	/**
39
	 * Returns all entities that are currently placed on the graph, that is
40
	 * subgraphs and unpruned nodes. Replacing elements in the returned array
41
	 * does not affect this context.
42
	 * 
43
	 * @return array of entities to layout
44
	 */
45
	public EntityLayout[] getEntities();
46
47
	/**
48
	 * Returns all the connections between given source and target entities. If
49
	 * given entity is a subgraph, connections adjacent to each of its nodes
50
	 * will be included in the result. All the undirected nodes connecting the
51
	 * two nodes will be also included in the result. Replacing elements in the
52
	 * returned array does not affect this context.
53
	 * 
54
	 * @param layoutEntity1
55
	 * @param layoutEntity2
56
	 * @return
57
	 */
58
	public ConnectionLayout[] getConnections(EntityLayout layoutEntity1, EntityLayout layoutEntity2);
59
60
	/**
61
	 * 
62
	 * @return bounds in which the graph elements can be placed
63
	 */
64
	public DisplayIndependentRectangle getBounds();
65
66
	/**
67
	 * 
68
	 * @return true if a layout algorithm is allowed to place graph elements
69
	 *         outside of suggested bounds
70
	 */
71
	public boolean isBoundsExpandable();
72
73
	/**
74
	 * Returns all the subgraphs this context's nodes were pruned to. Replacing
75
	 * elements in the returned array does not affect this context.
76
	 * 
77
	 * @return array of subgraphs (may be empty)
78
	 */
79
	public SubgraphLayout[] getSubgraphs();
80
81
	/**
82
	 * Creates a subgraph containing given nodes and adds it to this context. If
83
	 * given nodes already belong to another subgraphs, they are removed from
84
	 * them prior to adding to the new subgraph.
85
	 * 
86
	 * @param nodes
87
	 *            nodes to add to the new subgraph
88
	 */
89
	public SubgraphLayout createSubgraph(NodeLayout[] nodes);
90
91
	/**
92
	 * 
93
	 * @return true if this layout context allows pruning nodes into subgraphs
94
	 */
95
	public boolean isPruningEnabled();
96
97
	/**
98
	 * Checks if this layout context allows layout algorithms to work
99
	 * continuously in background and change the layout with time or in reaction
100
	 * to some events. If background changes are not allowed, a layout algorithm
101
	 * can make changes in layout context only when
102
	 * {@link LayoutAlgorithm#applyLayout(boolean)} is called (otherwise a
103
	 * runtime exception will be thrown).
104
	 * 
105
	 * @return true if background layout changes are enabled
106
	 */
107
	public boolean isBackgroundLayoutEnabled();
108
109
	/**
110
	 * Sets the main layout algorithm for this context. Main algorithm will be
111
	 * used to relayout graph items using {@link LayoutAlgorithm#applyLayout()}
112
	 * after every event that is not intercepted by any listener.
113
	 * 
114
	 * @param algorithm
115
	 */
116
	public void setMainLayoutAlgorithm(LayoutAlgorithm algorithm);
117
118
	/**
119
	 * 
120
	 * @return the main algorithm of this context (see
121
	 *         {@link #setMainLayoutAlgorithm(LayoutAlgorithm)} for details)
122
	 */
123
	public LayoutAlgorithm getMainLayoutAlgorithm();
124
125
	/**
126
	 * Sets the expand/collapse manager for this context. The manger will be
127
	 * used to handle expansion related methods called on the owner of this
128
	 * context.
129
	 * 
130
	 * @param expandCollapseManager
131
	 */
132
	public void setExpandCollapseManager(ExpandCollapseManager expandCollapseManager);
133
134
	/**
135
	 * 
136
	 * @return current expand/collapse manager (can be null, which means that
137
	 *         pruning is not enabled).
138
	 */
139
	public ExpandCollapseManager getExpandCollapseManager();
140
141
	/**
142
	 * Adds a listener to the context that will be notified about changes in
143
	 * this context's layout, that is movement and resizing of nodes /
144
	 * subgraphs. The notifications will not include changes made with API
145
	 * included in layout related interfaces, so that layout algorithms won't be
146
	 * notified about changes they invoke. Only internal changes of the system
147
	 * will fire events.
148
	 * 
149
	 * @param listener
150
	 *            listener to add
151
	 */
152
	public void addLayoutListener(LayoutListener listener);
153
154
	/**
155
	 * Removes a layout listener from this context.
156
	 * 
157
	 * @param listener
158
	 *            listener to remove
159
	 */
160
	public void removeLayoutListener(LayoutListener listener);
161
162
	/**
163
	 * Adds a listener to the context that will be notified about changes in
164
	 * graph structure, that is addition and removal of nodes and connections.
165
	 * The notifications will not include changes made with API included in
166
	 * layout related interfaces, so that layout algorithms won't be notified
167
	 * about changes they invoke. Only internal changes of the system will fire
168
	 * events.
169
	 * 
170
	 * @param listener
171
	 *            listener to add
172
	 */
173
	public void addGraphStructureListener(GraphStructureListener listener);
174
175
	/**
176
	 * Removes a graph structure listener from this context.
177
	 * 
178
	 * @param listener
179
	 *            listener to remove
180
	 */
181
	public void removeGraphStructureListener(GraphStructureListener listener);
182
183
	/**
184
	 * Adds a listener to the context that will be notified about changes
185
	 * related to its configuration.
186
	 * 
187
	 * @param listener
188
	 *            listener to add
189
	 */
190
	public void addContextListener(ContextListener listener);
191
192
	/**
193
	 * Removes a context listener from this context.
194
	 * 
195
	 * @param listener
196
	 *            listener to remove
197
	 */
198
	public void removeContextListener(ContextListener listener);
199
200
	/**
201
	 * Adds a listener to the context that will be notified about changes in
202
	 * graph pruning, that is hiding and showing of nodes. The notifications
203
	 * will not include changes made with API included in layout related
204
	 * interfaces, so that layout algorithms won't be notified about changes
205
	 * they invoke. Only internal changes of the system will fire events.
206
	 * 
207
	 * @param listener
208
	 *            listener to add
209
	 */
210
	public void addPruningListener(PruningListener listener);
211
212
	/**
213
	 * Removes a pruning structure listener from this context.
214
	 * 
215
	 * @param listener
216
	 *            listener to remove
217
	 */
218
	public void removePruningListener(PruningListener listener);
219
220
	/**
221
	 * Causes all the changes made to elements in this context to affect the
222
	 * display.
223
	 * 
224
	 * @param animationHint
225
	 *            a hint for display mechanism indicating whether changes are
226
	 *            major and should be animated (if true) or not.
227
	 */
228
	public void flushChanges(boolean animationHint);
229
}
(-)src/org/eclipse/zest/layouts/interfaces/ContextListener.java (+78 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.layouts.interfaces;
11
12
import org.eclipse.zest.layouts.LayoutAlgorithm;
13
14
/**
15
 * A listener added to {@link LayoutContext} that is notified about general
16
 * changes in this context.
17
 */
18
public interface ContextListener {
19
	public class Stub implements ContextListener {
20
21
		public boolean boundsChanged(LayoutContext context) {
22
			return false;
23
		}
24
25
		public void backgroundEnableChanged(LayoutContext context) {
26
			// do nothing
27
		}
28
29
		public boolean pruningEnablementChanged(LayoutContext context) {
30
			return false;
31
		}
32
33
	}
34
35
	/**
36
	 * This method is called whenever the bounds available in a layout context
37
	 * change.
38
	 * 
39
	 * If true is returned, it means that the receiving listener has intercepted
40
	 * this event. Intercepted events will not be passed to the rest of the
41
	 * listeners. If the event is not intercepted by any listener,
42
	 * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the
43
	 * context's main algorithm.
44
	 * 
45
	 * @param context
46
	 *            the layout context that fired the event
47
	 * @return true if no further operations after this event are required
48
	 */
49
	public boolean boundsChanged(LayoutContext context);
50
51
	/**
52
	 * This method is called whenever graph pruning is enabled or disabled in a
53
	 * layout context.
54
	 * 
55
	 * If true is returned, it means that the receiving listener has intercepted
56
	 * this event. Intercepted events will not be passed to the rest of the
57
	 * listeners. If the event is not intercepted by any listener,
58
	 * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the
59
	 * context's main algorithm.
60
	 * 
61
	 * @param context
62
	 *            the layout context that fired the event
63
	 * @return true if no further operations after this event are required
64
	 */
65
	public boolean pruningEnablementChanged(LayoutContext context);
66
67
	/**
68
	 * This method is called whenever background layout is enabled or disabled
69
	 * in a layout context. If the receiving listener is related to a layout
70
	 * algorithm that performs layout in reaction to events, it should turn
71
	 * automatic flush of changes on or off. Also, eventual additional threads
72
	 * responsible for layout should be stopped or started accordingly.
73
	 * 
74
	 * @param context
75
	 *            the layout context that fired the event
76
	 */
77
	public void backgroundEnableChanged(LayoutContext context);
78
}
(-)src/org/eclipse/zest/layouts/interfaces/GraphStructureListener.java (+168 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.layouts.interfaces;
11
12
import org.eclipse.zest.layouts.LayoutAlgorithm;
13
14
/**
15
 * A listener added to {@link LayoutContext} that is notified about changes in
16
 * this context's graph structure.
17
 */
18
public interface GraphStructureListener {
19
20
	/**
21
	 * A stub implementation of <code>GraphStructureListener</code>. Convenient
22
	 * for creating listeners that don't implements all required methods.
23
	 */
24
	public class Stub implements GraphStructureListener {
25
26
		public boolean nodeAdded(LayoutContext context, NodeLayout node) {
27
			return false;
28
		}
29
30
		public boolean nodeRemoved(LayoutContext context, NodeLayout node) {
31
			return false;
32
		}
33
34
		public boolean connectionAdded(LayoutContext context, ConnectionLayout connection) {
35
			return false;
36
		}
37
38
		public boolean connectionRemoved(LayoutContext context, ConnectionLayout connection) {
39
			return false;
40
		}
41
42
		public boolean connectionWeightChanged(LayoutContext context, ConnectionLayout connection) {
43
			return false;
44
		}
45
46
		public boolean connectionDirectedChanged(LayoutContext context, ConnectionLayout connection) {
47
			return false;
48
		}
49
	}
50
51
	/**
52
	 * This method is called whenever a node is added to a context. No separate
53
	 * events will be fired for eventual connections adjacent to the added node.
54
	 * 
55
	 * If true is returned, it means that the receiving listener has intercepted
56
	 * this event. Intercepted events will not be passed to the rest of the
57
	 * listeners. If the event is not intercepted by any listener,
58
	 * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the
59
	 * context's main algorithm.
60
	 * 
61
	 * @param context
62
	 *            the layout context that fired the event
63
	 * @param node
64
	 *            the added node
65
	 * @return true if no further operations after this event are required
66
	 */
67
	public boolean nodeAdded(LayoutContext context, NodeLayout node);
68
69
	/**
70
	 * This method is called whenever a node is removed from a context. No
71
	 * separate events will be fired for eventual connections adjacent to the
72
	 * removed node.
73
	 * 
74
	 * If true is returned, it means that the receiving listener has intercepted
75
	 * this event. Intercepted events will not be passed to the rest of the
76
	 * listeners. If the event is not intercepted by any listener,
77
	 * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the
78
	 * context's main algorithm.
79
	 * 
80
	 * @param context
81
	 *            the context that fired the event
82
	 * @param node
83
	 *            the removed node
84
	 * @return true if no further operations after this event are required
85
	 */
86
	public boolean nodeRemoved(LayoutContext context, NodeLayout node);
87
88
	/**
89
	 * This method is called whenever a connection is added to a context. It can
90
	 * be assumed that both source and target nodes of the added connection
91
	 * already exist in the context.
92
	 * 
93
	 * This method will be called only if both nodes connected by added
94
	 * connection lay directly in the node container owned by the notifying
95
	 * layout context.
96
	 * 
97
	 * If true is returned, it means that the receiving listener has intercepted
98
	 * this event. Intercepted events will not be passed to the rest of the
99
	 * listeners. If the event is not intercepted by any listener,
100
	 * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the
101
	 * context's main algorithm.
102
	 * 
103
	 * @param context
104
	 *            the context that fired the event
105
	 * @param connection
106
	 *            the added connection
107
	 * @return true if no further operations after this event are required
108
	 */
109
	public boolean connectionAdded(LayoutContext context, ConnectionLayout connection);
110
111
	/**
112
	 * This method is called whenever a connection is removed from a context. It
113
	 * can be assumed that both source and target nodes of the removed
114
	 * connection still exist in the context and will not necessarily be removed
115
	 * along with it.
116
	 * 
117
	 * This method will be called only if both nodes connected by removed
118
	 * connection lay directly in the node container owned by the notifying
119
	 * layout context.
120
	 * 
121
	 * If true is returned, it means that the receiving listener has intercepted
122
	 * this event. Intercepted events will not be passed to the rest of the
123
	 * listeners. If the event is not intercepted by any listener,
124
	 * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the
125
	 * context's main algorithm.
126
	 * 
127
	 * @param context
128
	 *            the context that fired the event
129
	 * @param connection
130
	 *            the added connection
131
	 * @return true if no further operations after this event are required
132
	 */
133
	public boolean connectionRemoved(LayoutContext context, ConnectionLayout connection);
134
135
	/**
136
	 * This method is called whenever a connection changes its weight.
137
	 * 
138
	 * If true is returned, it means that the receiving listener has intercepted
139
	 * this event. Intercepted events will not be passed to the rest of the
140
	 * listeners. If the event is not intercepted by any listener,
141
	 * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the
142
	 * context's main algorithm.
143
	 * 
144
	 * @param context
145
	 *            the context that fired the event
146
	 * @param connection
147
	 *            the affected connection
148
	 * @return true if no further operations after this event are required
149
	 */
150
	public boolean connectionWeightChanged(LayoutContext context, ConnectionLayout connection);
151
152
	/**
153
	 * This method is called whenever a connection changes its directed state.
154
	 * 
155
	 * If true is returned, it means that the receiving listener has intercepted
156
	 * this event. Intercepted events will not be passed to the rest of the
157
	 * listeners. If the event is not intercepted by any listener,
158
	 * {@link LayoutAlgorithm#applyLayout() applyLayout()} will be called on the
159
	 * context's main algorithm.
160
	 * 
161
	 * @param context
162
	 *            the context that fired the event
163
	 * @param connection
164
	 *            the affected connection
165
	 * @return true if no further operations after this event are required
166
	 */
167
	public boolean connectionDirectedChanged(LayoutContext context, ConnectionLayout connection);
168
}
(-)src/org/eclipse/zest/layouts/algorithms/SpaceTreeLayoutAlgorithm.java (+1206 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2005-2009 The Chisel Group and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: The Chisel Group - initial API and implementation
8
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 *               Ian Bull
10
 ******************************************************************************/
11
package org.eclipse.zest.layouts.algorithms;
12
13
import java.util.ArrayList;
14
import java.util.Arrays;
15
import java.util.Collections;
16
import java.util.Comparator;
17
import java.util.Iterator;
18
import java.util.LinkedList;
19
import java.util.List;
20
import java.util.ListIterator;
21
22
import org.eclipse.zest.layouts.LayoutAlgorithm;
23
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension;
24
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint;
25
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
26
import org.eclipse.zest.layouts.interfaces.ContextListener;
27
import org.eclipse.zest.layouts.interfaces.EntityLayout;
28
import org.eclipse.zest.layouts.interfaces.ExpandCollapseManager;
29
import org.eclipse.zest.layouts.interfaces.LayoutContext;
30
import org.eclipse.zest.layouts.interfaces.LayoutListener;
31
import org.eclipse.zest.layouts.interfaces.NodeLayout;
32
import org.eclipse.zest.layouts.interfaces.SubgraphLayout;
33
34
/**
35
 * Layout algorithm implementing SpaceTree. It assumes that nodes in the layout
36
 * context make a tree structure.
37
 * 
38
 * It expands and collapses nodes to optimize use of available space. In order
39
 * to keep the tree structure clearly visible, it also keeps track of the nodes'
40
 * positions to makes sure they stay in their current layer and don't overlap
41
 * with each other.
42
 * 
43
 * It's recommended to set an <code>ExpandCollapseManger</code> returned by
44
 * {@link #getExpandCollapseManager()} in the <code>LayoutContext</code> that
45
 * will be used with this layout algorithm. Other
46
 * <code>ExpandCollapseManager</code>s could also work, but the algorithm's
47
 * functionality would be very limited.
48
 */
49
public class SpaceTreeLayoutAlgorithm implements LayoutAlgorithm {
50
51
	/**
52
	 * Tree direction constant for which root is placed at the top and branches
53
	 * spread downwards
54
	 */
55
	public final static int TOP_DOWN = 1;
56
57
	/**
58
	 * Tree direction constant for which root is placed at the bottom and
59
	 * branches spread upwards
60
	 */
61
	public final static int BOTTOM_UP = 2;
62
63
	/**
64
	 * Tree direction constant for which root is placed at the left and branches
65
	 * spread to the right
66
	 */
67
	public final static int LEFT_RIGHT = 3;
68
69
	/**
70
	 * Tree direction constant for which root is placed at the right and
71
	 * branches spread to the left
72
	 */
73
	public final static int RIGHT_LEFT = 4;
74
75
	private class SpaceTreeNode extends TreeLayoutObserver.TreeNode {
76
		public SubgraphLayout subgraph = null;
77
78
		public boolean expanded = false;
79
		public double positionInLayer;
80
81
		public SpaceTreeNode(NodeLayout node, TreeLayoutObserver owner) {
82
			super(node, owner);
83
		}
84
85
		protected void addChild(TreeLayoutObserver.TreeNode child) {
86
			super.addChild(child);
87
88
			SpaceTreeNode child2 = (SpaceTreeNode) child;
89
			child2.expanded = false;
90
			child2.setSubgraph(null);
91
92
			if (child.depth >= 0)
93
				((SpaceTreeLayer) spaceTreeLayers.get(child.depth)).removeNode(child2);
94
95
			if (expanded) {
96
				child.depth = this.depth + 1;
97
98
				SpaceTreeLayer childLayer;
99
				if (child.depth < spaceTreeLayers.size())
100
					childLayer = ((SpaceTreeLayer) spaceTreeLayers.get(child.depth));
101
				else
102
					spaceTreeLayers.add(childLayer = new SpaceTreeLayer(child.depth));
103
104
				if (childLayer.nodes.isEmpty())
105
					child.order = 0;
106
				else
107
					child.order = ((SpaceTreeNode) childLayer.nodes.get(childLayer.nodes.size() - 1)).order + 1;
108
				childLayer.addNodes(Arrays.asList(new Object[] { child }));
109
			}
110
		}
111
112
		public void precomputeTree() {
113
			super.precomputeTree();
114
			if (this == owner.getSuperRoot()) {
115
				expanded = true;
116
				while (spaceTreeLayers.size() <= this.height)
117
					spaceTreeLayers.add(new SpaceTreeLayer(spaceTreeLayers.size()));
118
119
				if (treeObserver != null)
120
					refreshLayout(true);
121
			}
122
		}
123
124
		public SubgraphLayout collapseAllChildrenIntoSubgraph(SubgraphLayout subgraph, boolean includeYourself) {
125
			expanded = false;
126
			ArrayList allChildren = new ArrayList();
127
			LinkedList nodesToVisit = new LinkedList();
128
			nodesToVisit.addLast(this);
129
			while (!nodesToVisit.isEmpty()) {
130
				SpaceTreeNode currentNode = (SpaceTreeNode) nodesToVisit.removeFirst();
131
				for (Iterator iterator = currentNode.children.iterator(); iterator.hasNext();) {
132
					SpaceTreeNode child = (SpaceTreeNode) iterator.next();
133
					allChildren.add(child.node);
134
					child.setSubgraph(null);
135
					child.expanded = false;
136
					nodesToVisit.addLast(child);
137
				}
138
			}
139
			if (includeYourself)
140
				allChildren.add(this.node);
141
			if (allChildren.isEmpty()) {
142
				setSubgraph(null);
143
				return null;
144
			}
145
			NodeLayout[] childrenArray = (NodeLayout[]) allChildren.toArray(new NodeLayout[allChildren.size()]);
146
			if (subgraph == null) {
147
				subgraph = context.createSubgraph(childrenArray);
148
				subgraph.setDirection(getSubgraphDirection());
149
			} else {
150
				subgraph.addNodes(childrenArray);
151
			}
152
			if (!includeYourself)
153
				setSubgraph(subgraph);
154
			return subgraph;
155
		}
156
157
		public void setSubgraph(SubgraphLayout subgraph) { // !
158
			if (this.subgraph != subgraph) {
159
				this.subgraph = subgraph;
160
				refreshSubgraphLocation();
161
			}
162
		}
163
164
		/**
165
		 * Moves the node back to its layer, as close as possible to given
166
		 * preferred location
167
		 * 
168
		 * @param preferredLocation
169
		 */
170
		public void adjustPosition(DisplayIndependentPoint preferredLocation) { // !
171
			protectedNode = (SpaceTreeNode) owner.getSuperRoot();
172
173
			double newPositionInLayer = (direction == BOTTOM_UP || direction == TOP_DOWN) ? preferredLocation.x - bounds.x : preferredLocation.y
174
					- bounds.y;
175
			if (((SpaceTreeNode) parent).expanded) {
176
				((SpaceTreeLayer) spaceTreeLayers.get(depth)).moveNode(this, newPositionInLayer);
177
				centerParentsTopDown();
178
			}
179
		}
180
181
		public void refreshSubgraphLocation() {
182
			if (subgraph != null && subgraph.isGraphEntity()) {
183
				DisplayIndependentPoint nodeLocation = node.getLocation();
184
				DisplayIndependentDimension nodeSize = node.getSize();
185
				DisplayIndependentDimension subgraphSize = subgraph.getSize();
186
				double x = 0, y = 0;
187
				switch (direction) {
188
				case TOP_DOWN:
189
					x = nodeLocation.x;
190
					y = nodeLocation.y + (nodeSize.height + subgraphSize.height) / 2;
191
					break;
192
				case BOTTOM_UP:
193
					x = nodeLocation.x;
194
					y = nodeLocation.y - (nodeSize.height + subgraphSize.height) / 2;
195
					break;
196
				case LEFT_RIGHT:
197
					x = nodeLocation.x + (nodeSize.width + subgraphSize.width) / 2;
198
					y = nodeLocation.y;
199
					break;
200
				case RIGHT_LEFT:
201
					x = nodeLocation.x - (nodeSize.width + subgraphSize.height) / 2;
202
					y = nodeLocation.y;
203
					break;
204
				}
205
				subgraph.setLocation(x, y);
206
			}
207
			((SpaceTreeLayer) spaceTreeLayers.get(depth)).refreshThickness();
208
		}
209
210
		public double spaceRequiredForNode() {
211
			if (node == null)
212
				return 0;
213
			switch (direction) {
214
			case TOP_DOWN:
215
			case BOTTOM_UP:
216
				return node.getSize().width;
217
			case LEFT_RIGHT:
218
			case RIGHT_LEFT:
219
				return node.getSize().height;
220
			}
221
			throw new RuntimeException("invalid direction");
222
		}
223
224
		public double spaceRequiredForChildren() {
225
			if (children.isEmpty())
226
				return 0;
227
			double result = 0;
228
			for (Iterator iterator = children.iterator(); iterator.hasNext();) {
229
				SpaceTreeNode child = (SpaceTreeNode) iterator.next();
230
				result += child.spaceRequiredForNode();
231
			}
232
			result += leafGap * (children.size() - 1);
233
			return result;
234
		}
235
236
		/**
237
		 * Checks if nodes in given list have proper positions according to
238
		 * their children (a parent's position cannot be smaller than its first
239
		 * child's position nor bigger than its last child's position). If not,
240
		 * it tries to fix them.
241
		 * 
242
		 * @param nodesToCheck
243
		 * @return true if all locations are correct or could be corrected while
244
		 *         checking.
245
		 */
246
		public boolean childrenPositionsOK(ArrayList nodesToCheck) {
247
			for (Iterator iterator = nodesToCheck.iterator(); iterator.hasNext();) {
248
				SpaceTreeNode node = (SpaceTreeNode) iterator.next();
249
				if (node.depth < 0 || node.children.isEmpty())
250
					continue;
251
				SpaceTreeNode child = ((SpaceTreeNode) node.children.get(0));
252
				if (child.positionInLayer > node.positionInLayer) {
253
					((SpaceTreeLayer) spaceTreeLayers.get(node.depth)).moveNode(node, child.positionInLayer);
254
					if (child.positionInLayer > node.positionInLayer) {
255
						((SpaceTreeLayer) spaceTreeLayers.get(child.depth)).moveNode(child, node.positionInLayer);
256
						if (child.positionInLayer > node.positionInLayer) {
257
							return false;
258
						}
259
					}
260
				}
261
				child = ((SpaceTreeNode) node.children.get(node.children.size() - 1));
262
				if (child.positionInLayer < node.positionInLayer) {
263
					((SpaceTreeLayer) spaceTreeLayers.get(node.depth)).moveNode(node, child.positionInLayer);
264
					if (child.positionInLayer < node.positionInLayer) {
265
						((SpaceTreeLayer) spaceTreeLayers.get(child.depth)).moveNode(child, node.positionInLayer);
266
						if (child.positionInLayer < node.positionInLayer) {
267
							return false;
268
						}
269
					}
270
				}
271
			}
272
			return true;
273
		}
274
275
		public void centerParentsBottomUp() {
276
			if (!children.isEmpty() && expanded) {
277
				for (Iterator iterator = children.iterator(); iterator.hasNext();) {
278
					((SpaceTreeNode) iterator.next()).centerParentsBottomUp();
279
				}
280
281
				if (depth >= 0) {
282
					SpaceTreeNode firstChild = (SpaceTreeNode) children.get(0);
283
					SpaceTreeNode lastChild = (SpaceTreeNode) children.get(children.size() - 1);
284
					SpaceTreeLayer layer = (SpaceTreeLayer) spaceTreeLayers.get(depth);
285
					layer.moveNode(this, (firstChild.positionInLayer + lastChild.positionInLayer) / 2);
286
				}
287
			}
288
		}
289
290
		public void centerParentsTopDown() {
291
			if (this == owner.getSuperRoot()) {
292
				this.positionInLayer = getAvailableSpace() / 2;
293
			}
294
			if (!children.isEmpty() && expanded) {
295
				SpaceTreeNode firstChild = (SpaceTreeNode) children.get(0);
296
				SpaceTreeNode lastChild = (SpaceTreeNode) children.get(children.size() - 1);
297
				double offset = this.positionInLayer - (firstChild.positionInLayer + lastChild.positionInLayer) / 2;
298
				if (firstChild.positionInLayer - firstChild.spaceRequiredForNode() / 2 + offset < 0)
299
					offset = -firstChild.positionInLayer + firstChild.spaceRequiredForNode() / 2;
300
				double availableSpace = getAvailableSpace();
301
				if (lastChild.positionInLayer + lastChild.spaceRequiredForNode() / 2 + offset > availableSpace) {
302
					offset = availableSpace - lastChild.positionInLayer - lastChild.spaceRequiredForNode() / 2;
303
				}
304
				SpaceTreeLayer layer = (SpaceTreeLayer) spaceTreeLayers.get(depth + 1);
305
				layer.fitNodesWithinBounds(children, firstChild.positionInLayer + offset, lastChild.positionInLayer + offset);
306
307
				for (Iterator iterator = children.iterator(); iterator.hasNext();) {
308
					((SpaceTreeNode) iterator.next()).centerParentsTopDown();
309
				}
310
			}
311
		}
312
313
		public void flushExpansionChanges() {
314
			if (node != null)
315
				node.prune(null);
316
			if (this.expanded) {
317
				setSubgraph(null);
318
				for (Iterator iterator = children.iterator(); iterator.hasNext();) {
319
					((SpaceTreeNode) iterator.next()).flushExpansionChanges();
320
				}
321
			}
322
			if (!this.expanded && subgraph == null) {
323
				collapseAllChildrenIntoSubgraph(null, false);
324
			}
325
		}
326
327
		public boolean flushCollapseChanges() {
328
			if (!expanded) {
329
				int numberOfChildrenInSubgraph = subgraph == null ? 0 : subgraph.countNodes();
330
				collapseAllChildrenIntoSubgraph(subgraph, false);
331
				int newNumberOfChildrenInSubgraph = (subgraph == null ? 0 : subgraph.countNodes());
332
				if (numberOfChildrenInSubgraph != newNumberOfChildrenInSubgraph && newNumberOfChildrenInSubgraph > 0)
333
					refreshSubgraphLocation();
334
				return numberOfChildrenInSubgraph != newNumberOfChildrenInSubgraph;
335
			}
336
			if (expanded && subgraph == null) {
337
				boolean madeChagnes = false;
338
				for (Iterator iterator = children.iterator(); iterator.hasNext();) {
339
					madeChagnes = ((SpaceTreeNode) iterator.next()).flushCollapseChanges() || madeChagnes;
340
				}
341
				return madeChagnes;
342
			}
343
			return false;
344
		}
345
346
		/**
347
		 * Sets locations of nodes in the graph depending on their current layer
348
		 * and position in layer.
349
		 * 
350
		 * @param thicknessSoFar
351
		 *            sum of thicknesses and gaps for all layers 'above' this
352
		 *            node (should be 0 if called on superRoot)
353
		 * @return true if location of at least one node has changed
354
		 */
355
		public boolean flushLocationChanges(double thicknessSoFar) {
356
			boolean madeChanges = false;
357
			if (node != null) {
358
				DisplayIndependentDimension nodeSize = node.getSize();
359
				double x = 0, y = 0;
360
				switch (direction) {
361
				case TOP_DOWN:
362
					x = bounds.x + positionInLayer;
363
					y = thicknessSoFar + nodeSize.height / 2;
364
					break;
365
				case BOTTOM_UP:
366
					x = bounds.x + positionInLayer;
367
					y = bounds.y + bounds.height - thicknessSoFar - nodeSize.height / 2;
368
					break;
369
				case LEFT_RIGHT:
370
					x = thicknessSoFar + nodeSize.height / 2;
371
					y = bounds.y + positionInLayer;
372
					break;
373
				case RIGHT_LEFT:
374
					x = bounds.x + bounds.width - thicknessSoFar - nodeSize.height / 2;
375
					y = bounds.y + positionInLayer;
376
					break;
377
				}
378
				DisplayIndependentPoint currentLocation = node.getLocation();
379
				if (currentLocation.x != x || currentLocation.y != y) {
380
					node.setLocation(x, y);
381
					refreshSubgraphLocation();
382
					madeChanges = true;
383
				}
384
			}
385
			if (expanded && subgraph == null) {
386
				thicknessSoFar += (depth >= 0 ? ((SpaceTreeLayer) spaceTreeLayers.get(depth)).thickness : 0) + layerGap;
387
				for (Iterator iterator = children.iterator(); iterator.hasNext();) {
388
					SpaceTreeNode child = (SpaceTreeNode) iterator.next();
389
					madeChanges = child.flushLocationChanges(thicknessSoFar) || madeChanges;
390
				}
391
			}
392
			return madeChanges;
393
		}
394
395
		public String toString() {
396
			StringBuffer sb = new StringBuffer();
397
			for (int i = 0; i < depth; i++)
398
				sb.append(" ");
399
			if (node != null)
400
				sb.append(node.toString());
401
			sb.append("|" + this.order);
402
			sb.append('\n');
403
			for (Iterator iterator = children.iterator(); iterator.hasNext();) {
404
				SpaceTreeNode child = (SpaceTreeNode) iterator.next();
405
				sb.append(child.toString());
406
			}
407
			return sb.toString();
408
		}
409
	}
410
411
	private TreeLayoutObserver.TreeNodeFactory spaceTreeNodeFactory = new TreeLayoutObserver.TreeNodeFactory() {
412
		public TreeLayoutObserver.TreeNode createTreeNode(NodeLayout nodeLayout, TreeLayoutObserver observer) {
413
			return new SpaceTreeNode(nodeLayout, observer);
414
		};
415
	};
416
417
	private class SpaceTreeLayer {
418
		public ArrayList nodes = new ArrayList();
419
		private final int depth;
420
		public double thickness = 0;
421
422
		public SpaceTreeLayer(int depth) {
423
			this.depth = depth;
424
		}
425
426
		public void addNodes(List nodesToAdd) {
427
			ListIterator layerIterator = nodes.listIterator();
428
			SpaceTreeNode previousNode = null;
429
			for (Iterator iterator = nodesToAdd.iterator(); iterator.hasNext();) {
430
				SpaceTreeNode nodeToAdd = (SpaceTreeNode) iterator.next();
431
432
				SpaceTreeNode nodeInLayer = null;
433
				while (layerIterator.hasNext()) {
434
					nodeInLayer = (SpaceTreeNode) layerIterator.next();
435
					if (nodeInLayer.order >= nodeToAdd.order)
436
						break;
437
					double expectedPostion = (previousNode == null) ? 0 : previousNode.positionInLayer + expectedDistance(previousNode, nodeInLayer);
438
					nodeInLayer.positionInLayer = Math.max(nodeInLayer.positionInLayer, expectedPostion);
439
					previousNode = nodeInLayer;
440
				}
441
442
				if (nodeInLayer == null) {
443
					layerIterator.add(nodeToAdd);
444
				} else if (nodeInLayer.order == nodeToAdd.order) {
445
					layerIterator.set(nodeToAdd);
446
				} else {
447
					if (nodeInLayer.order > nodeToAdd.order)
448
						layerIterator.previous();
449
					layerIterator.add(nodeToAdd);
450
				}
451
				layerIterator.previous();
452
			}
453
			// move the rest of nodes so that they don't overlap
454
			while (layerIterator.hasNext()) {
455
				SpaceTreeNode nodeInLayer = (SpaceTreeNode) layerIterator.next();
456
				double expectedPostion = (previousNode == null) ? 0 : previousNode.positionInLayer + expectedDistance(previousNode, nodeInLayer);
457
				nodeInLayer.positionInLayer = Math.max(nodeInLayer.positionInLayer, expectedPostion);
458
				previousNode = nodeInLayer;
459
			}
460
461
			refreshThickness();
462
		}
463
464
		public void removeNode(SpaceTreeNode node) {
465
			if (nodes.remove(node)) {
466
				((SpaceTreeLayer) spaceTreeLayers.get(depth + 1)).removeNodes(node.children);
467
				refreshThickness();
468
			}
469
		}
470
471
		public void removeNodes(List nodesToRemove) {
472
			if (this.nodes.removeAll(nodesToRemove)) {
473
				SpaceTreeLayer nextLayer = ((SpaceTreeLayer) spaceTreeLayers.get(depth + 1));
474
				for (Iterator iterator = nodesToRemove.iterator(); iterator.hasNext();) {
475
					SpaceTreeNode nodeToRemove = (SpaceTreeNode) iterator.next();
476
					nextLayer.removeNodes(nodeToRemove.children);
477
				}
478
				refreshThickness();
479
			}
480
		}
481
482
		public void checkThickness(SpaceTreeNode node) {
483
			double nodeThickness = 0;
484
			DisplayIndependentDimension size = node.node.getSize();
485
			nodeThickness = (direction == TOP_DOWN || direction == BOTTOM_UP) ? size.height : size.width;
486
			if (node.subgraph != null && node.subgraph.isGraphEntity()) {
487
				size = node.subgraph.getSize();
488
				nodeThickness += (direction == TOP_DOWN || direction == BOTTOM_UP) ? size.height : size.width;
489
			}
490
			this.thickness = Math.max(this.thickness, nodeThickness);
491
		}
492
493
		public void refreshThickness() {
494
			this.thickness = 0;
495
			for (Iterator iterator = nodes.iterator(); iterator.hasNext();) {
496
				checkThickness((SpaceTreeNode) iterator.next());
497
			}
498
		}
499
500
		public void fitNodesWithinBounds(List nodeList, double startPosition, double endPosition) {
501
			NodeSnapshot[][] snapShot = takeSnapShot();
502
			SpaceTreeNode[] nodes = (SpaceTreeNode[]) nodeList.toArray(new SpaceTreeNode[nodeList.size()]);
503
			double initialStartPosition = nodes[0].positionInLayer;
504
			double initialNodesBredth = nodes[nodes.length - 1].positionInLayer - initialStartPosition;
505
			double[] desiredPositions = new double[nodes.length];
506
			// calculate desired positions for every node, regarding their
507
			// initial initial proportions
508
			for (int i = 0; i < nodes.length; i++) {
509
				double initialPositionAsPercent = (initialNodesBredth > 0) ? (nodes[i].positionInLayer - initialStartPosition) / initialNodesBredth
510
						: 0;
511
				desiredPositions[i] = initialPositionAsPercent * (endPosition - startPosition);
512
			}
513
			// make sure there's proper distance between each pair of
514
			// consecutive nodes
515
			for (int i = 1; i < nodes.length; i++) {
516
				SpaceTreeNode node = nodes[i];
517
				SpaceTreeNode previousNode = nodes[i - 1];
518
				double expectedDistance = expectedDistance(previousNode, node);
519
				if (desiredPositions[i] - desiredPositions[i - 1] < expectedDistance) {
520
					desiredPositions[i] = desiredPositions[i - 1] + expectedDistance;
521
				}
522
			}
523
			// if the above operation caused some nodes to fall out of requested
524
			// bounds, push them back
525
			if (desiredPositions[nodes.length - 1] > (endPosition - startPosition)) {
526
				desiredPositions[nodes.length - 1] = (endPosition - startPosition);
527
				for (int i = nodes.length - 1; i > 0; i--) {
528
					SpaceTreeNode node = nodes[i];
529
					SpaceTreeNode previousNode = nodes[i - 1];
530
					double expectedDistance = expectedDistance(previousNode, node);
531
					if (desiredPositions[i] - desiredPositions[i - 1] < expectedDistance) {
532
						desiredPositions[i - 1] = desiredPositions[i] - expectedDistance;
533
					} else
534
						break;
535
				}
536
			}
537
538
			for (int i = 0; i < nodeList.size(); i++) {
539
				SpaceTreeNode node = (SpaceTreeNode) nodeList.get(i);
540
				double desiredPosition = startPosition + desiredPositions[i];
541
				moveNode(node, desiredPosition);
542
				if (Math.abs(node.positionInLayer - desiredPosition) > 0.5) {
543
					startPosition += (node.positionInLayer - desiredPosition);
544
					i = -1;
545
					revertToShanpshot(snapShot);
546
				}
547
			}
548
		}
549
550
		public void moveNode(SpaceTreeNode node, double newPosition) {
551
			Collections.sort(nodes, new Comparator() {
552
				public int compare(Object arg0, Object arg1) {
553
					return ((SpaceTreeNode) arg0).order - ((SpaceTreeNode) arg1).order;
554
				}
555
			});
556
			double positionInLayerAtStart = node.positionInLayer;
557
			if (newPosition >= positionInLayerAtStart)
558
				moveNodeForward(node, newPosition);
559
			if (newPosition <= positionInLayerAtStart)
560
				moveNodeBackward(node, newPosition);
561
		}
562
563
		/**
564
		 * Tries to increase node's position in layer. It can move a node only
565
		 * if it doesn't cause nodes to fall out of available space (see
566
		 * {@link SpaceTreeLayoutAlgorithm#getAvailableSpace()}. If there's not
567
		 * enough space available, some nodes may be collapsed to increase it as
568
		 * long as it doesn't cause
569
		 * {@link SpaceTreeLayoutAlgorithm#protectedNode} or any of its
570
		 * descendants to be collapsed.
571
		 * 
572
		 * @param nodeToMove
573
		 * @param newPosition
574
		 */
575
		private void moveNodeForward(SpaceTreeNode nodeToMove, double newPosition) {
576
			int nodeIndex = nodes.indexOf(nodeToMove);
577
			if (nodeIndex == -1)
578
				throw new IllegalArgumentException("node not on this layer");
579
			// move forward -> check space to the 'right'
580
			NodeSnapshot[][] snapShot = takeSnapShot();
581
			boolean firstRun = true;
582
			mainLoop: while (firstRun || nodeToMove.positionInLayer < newPosition) {
583
				firstRun = false;
584
				double requiredSpace = 0;
585
				SpaceTreeNode previousNode = nodeToMove;
586
				for (int i = nodeIndex + 1; i < nodes.size(); i++) {
587
					SpaceTreeNode nextNode = (SpaceTreeNode) nodes.get(i);
588
					requiredSpace += expectedDistance(previousNode, nextNode);
589
					previousNode = nextNode;
590
				}
591
				requiredSpace += previousNode.spaceRequiredForNode() / 2;
592
				if (requiredSpace > getAvailableSpace() - newPosition) {
593
					// find nodes to remove
594
					boolean removed = false;
595
					for (int i = nodeIndex; i < nodes.size(); i++) {
596
						SpaceTreeNode nextNode = ((SpaceTreeNode) nodes.get(i));
597
						if (protectedNode == null || (!protectedNode.isAncestorOf(nextNode) && !nextNode.parent.isAncestorOf(protectedNode))) {
598
							collapseNode((SpaceTreeNode) nextNode.parent);
599
							if (nextNode.parent == nodeToMove.parent)
600
								break mainLoop;
601
							removed = true;
602
							break;
603
						}
604
					}
605
					if (!removed) {
606
						// not enough space, but we can't collapse anything...
607
						newPosition = getAvailableSpace() - requiredSpace;
608
						revertToShanpshot(snapShot);
609
						continue mainLoop;
610
					}
611
				}
612
				// move the node and all its neighbors to the 'right'
613
				SpaceTreeNode currentNodeToMove = nodeToMove;
614
				double newPositionForCurrent = newPosition;
615
				for (int i = nodeIndex; i < nodes.size(); i++) {
616
					currentNodeToMove.positionInLayer = newPositionForCurrent;
617
					// move parent if moved node is its first child
618
					if (currentNodeToMove.firstChild) {
619
						SpaceTreeNode parent = (SpaceTreeNode) currentNodeToMove.parent;
620
						if (depth > 0 && parent.positionInLayer <= newPositionForCurrent) {
621
							SpaceTreeLayer parentLayer = (SpaceTreeLayer) spaceTreeLayers.get(depth - 1);
622
							parentLayer.moveNodeForward(parent, newPositionForCurrent);
623
							if (parent.positionInLayer < newPositionForCurrent) {
624
								double delta = newPositionForCurrent - parent.positionInLayer;
625
								newPosition -= delta;
626
								revertToShanpshot(snapShot);
627
								continue mainLoop;
628
							}
629
						}
630
					}
631
					// move children if necessary
632
					if (currentNodeToMove.expanded && !currentNodeToMove.children.isEmpty()) {
633
						SpaceTreeNode lastChild = (SpaceTreeNode) currentNodeToMove.children.get(currentNodeToMove.children.size() - 1);
634
						if (lastChild.positionInLayer < newPositionForCurrent) {
635
							// try to move all the children, that is move the
636
							// first child and the rest will be pushed
637
							SpaceTreeNode firstChild = (SpaceTreeNode) currentNodeToMove.children.get(0);
638
							SpaceTreeLayer childLayer = (SpaceTreeLayer) spaceTreeLayers.get(depth + 1);
639
							double expectedDistanceBetweenChildren = currentNodeToMove.spaceRequiredForChildren() - firstChild.spaceRequiredForNode()
640
									/ 2 - lastChild.spaceRequiredForNode() / 2;
641
							childLayer.moveNodeForward(firstChild, newPositionForCurrent - expectedDistanceBetweenChildren);
642
							if (currentNodeToMove.expanded && lastChild.positionInLayer < newPositionForCurrent) {
643
								// the previous attempt failed -> try to move
644
								// only the last child
645
								childLayer.moveNodeForward(lastChild, newPositionForCurrent);
646
								if (lastChild.positionInLayer < newPositionForCurrent) {
647
									// child couldn't be moved as far as needed
648
									// -> move current node back to the position
649
									// over the child
650
									double delta = newPositionForCurrent - lastChild.positionInLayer;
651
									newPosition -= delta;
652
									revertToShanpshot(snapShot);
653
									continue mainLoop;
654
								}
655
							}
656
						}
657
					}
658
659
					if (i < nodes.size() - 1) {
660
						SpaceTreeNode nextNode = (SpaceTreeNode) nodes.get(i + 1);
661
						newPositionForCurrent += expectedDistance(currentNodeToMove, nextNode);
662
						currentNodeToMove = nextNode;
663
						if (currentNodeToMove.positionInLayer > newPositionForCurrent)
664
							break;
665
					}
666
				}
667
			}
668
		}
669
670
		/**
671
		 * Method complementary to
672
		 * {@link #moveNodeForward(SpaceTreeNode, double)}. Decreases node's
673
		 * position in layer.
674
		 * 
675
		 * @param nodeToMove
676
		 * @param newPosition
677
		 */
678
		private void moveNodeBackward(SpaceTreeNode nodeToMove, double newPosition) {
679
			int nodeIndex = nodes.indexOf(nodeToMove);
680
			if (nodeIndex == -1)
681
				throw new IllegalArgumentException("node not on this layer");
682
			// move backward -> check space to the 'left'
683
			// move and collapse until there's enough space
684
			NodeSnapshot[][] snapShot = takeSnapShot();
685
			boolean firstRun = true;
686
			mainLoop: while (firstRun || nodeToMove.positionInLayer > newPosition) {
687
				firstRun = false;
688
				double requiredSpace = 0;
689
				SpaceTreeNode previousNode = nodeToMove;
690
				for (int i = nodeIndex - 1; i >= 0; i--) {
691
					SpaceTreeNode nextNode = (SpaceTreeNode) nodes.get(i);
692
					requiredSpace += expectedDistance(previousNode, nextNode);
693
					previousNode = nextNode;
694
				}
695
				requiredSpace += previousNode.spaceRequiredForNode() / 2;
696
				if (requiredSpace > newPosition) {
697
					// find nodes to remove
698
					boolean removed = false;
699
					for (int i = nodeIndex; i >= 0; i--) {
700
						SpaceTreeNode nextNode = ((SpaceTreeNode) nodes.get(i));
701
						if (protectedNode == null || (!protectedNode.isAncestorOf(nextNode) && !nextNode.parent.isAncestorOf(protectedNode))) {
702
							collapseNode((SpaceTreeNode) nextNode.parent);
703
							if (nextNode.parent == nodeToMove.parent)
704
								break mainLoop;
705
							nodeIndex -= nextNode.parent.children.size();
706
							removed = true;
707
							break;
708
						}
709
					}
710
					if (!removed) {
711
						// not enough space, but we can't collapse anything...
712
						newPosition = requiredSpace;
713
						revertToShanpshot(snapShot);
714
						continue mainLoop;
715
					}
716
				}
717
				// move the node and all its neighbors to the 'left'
718
				SpaceTreeNode currentNodeToMove = nodeToMove;
719
				double newPositionForCurrent = newPosition;
720
				for (int i = nodeIndex; i >= 0; i--) {
721
					currentNodeToMove.positionInLayer = newPositionForCurrent;
722
					// move parent if moved node is its last child
723
					if (currentNodeToMove.lastChild) {
724
						SpaceTreeNode parent = (SpaceTreeNode) currentNodeToMove.parent;
725
						if (depth > 0 && parent.positionInLayer >= newPositionForCurrent) {
726
							SpaceTreeLayer parentLayer = (SpaceTreeLayer) spaceTreeLayers.get(depth - 1);
727
							parentLayer.moveNodeBackward(parent, newPositionForCurrent);
728
							if (parent.positionInLayer > newPositionForCurrent) {
729
								double delta = parent.positionInLayer - newPositionForCurrent;
730
								newPosition += delta;
731
								revertToShanpshot(snapShot);
732
								continue mainLoop;
733
							}
734
						}
735
					}
736
					// move children if necessary
737
					if (currentNodeToMove.expanded && !currentNodeToMove.children.isEmpty()) {
738
						SpaceTreeNode firstChild = (SpaceTreeNode) currentNodeToMove.children.get(0);
739
						if (firstChild.positionInLayer > newPositionForCurrent) {
740
							// try to move all the children, that is move the
741
							// last child and the rest will be pushed
742
							SpaceTreeNode lastChild = (SpaceTreeNode) currentNodeToMove.children.get(currentNodeToMove.children.size() - 1);
743
							SpaceTreeLayer childLayer = (SpaceTreeLayer) spaceTreeLayers.get(depth + 1);
744
							double expectedDistanceBetweenChildren = currentNodeToMove.spaceRequiredForChildren() - firstChild.spaceRequiredForNode()
745
									/ 2 - lastChild.spaceRequiredForNode() / 2;
746
							childLayer.moveNodeBackward(lastChild, newPositionForCurrent + expectedDistanceBetweenChildren);
747
							if (currentNodeToMove.expanded && firstChild.positionInLayer > newPositionForCurrent) {
748
								// the previous attempt failed -> try to move
749
								// only the first child
750
								childLayer.moveNodeBackward(firstChild, newPositionForCurrent);
751
								if (firstChild.positionInLayer > newPositionForCurrent) {
752
									// child couldn't be moved as far as needed
753
									// -> move current node back to the position
754
									// over the child
755
									double delta = firstChild.positionInLayer - newPositionForCurrent;
756
									newPosition += delta;
757
									revertToShanpshot(snapShot);
758
									continue mainLoop;
759
								}
760
							}
761
						}
762
					}
763
					if (i > 0) {
764
						SpaceTreeNode nextNode = (SpaceTreeNode) nodes.get(i - 1);
765
						newPositionForCurrent -= expectedDistance(currentNodeToMove, nextNode);
766
						currentNodeToMove = nextNode;
767
						if (currentNodeToMove.positionInLayer < newPositionForCurrent)
768
							break;
769
					}
770
				}
771
			}
772
		}
773
774
		public String toString() {
775
			StringBuffer buffer = new StringBuffer();
776
			buffer.append("Layer ").append(depth).append(": ");
777
			for (Iterator iterator = nodes.iterator(); iterator.hasNext();) {
778
				SpaceTreeNode node = (SpaceTreeNode) iterator.next();
779
				buffer.append(node.node).append(", ");
780
			}
781
			return buffer.toString();
782
		}
783
784
		private void collapseNode(SpaceTreeNode node) {
785
			node.expanded = false;
786
			SpaceTreeLayer layer = (SpaceTreeLayer) spaceTreeLayers.get(node.depth + 1);
787
			layer.removeNodes(node.children);
788
			for (Iterator iterator = node.children.iterator(); iterator.hasNext();) {
789
				SpaceTreeNode child = (SpaceTreeNode) iterator.next();
790
				if (child.expanded)
791
					collapseNode(child);
792
			}
793
		}
794
	}
795
796
	private class SpaceTreeExpandCollapseManager implements ExpandCollapseManager {
797
		public void initExpansion(LayoutContext context) {
798
			// do nothing - initialization performed in #setLayoutContext()
799
		}
800
801
		public void setExpanded(LayoutContext context, NodeLayout node, boolean expanded) {
802
			SpaceTreeNode spaceTreeNode = (SpaceTreeNode) treeObserver.getTreeNode(node);
803
			if (expanded) {
804
				maximizeExpansion(spaceTreeNode);
805
				refreshLayout(true);
806
			} else if (spaceTreeNode.expanded) {
807
				spaceTreeNode.expanded = false;
808
				((SpaceTreeLayer) spaceTreeLayers.get(spaceTreeNode.depth + 1)).removeNodes(spaceTreeNode.children);
809
				refreshLayout(true);
810
			}
811
		}
812
813
		public boolean canExpand(LayoutContext context, NodeLayout node) {
814
			SpaceTreeNode spaceTreeNode = (SpaceTreeNode) treeObserver.getTreeNode(node);
815
			if (spaceTreeNode != null) {
816
				// we don't check if node is expanded because it can be expanded
817
				// again
818
				return !spaceTreeNode.children.isEmpty();
819
			}
820
			return false;
821
		}
822
823
		public boolean canCollapse(LayoutContext context, NodeLayout node) {
824
			SpaceTreeNode spaceTreeNode = (SpaceTreeNode) treeObserver.getTreeNode(node);
825
			if (spaceTreeNode != null) {
826
				return spaceTreeNode.expanded && !spaceTreeNode.children.isEmpty();
827
			}
828
			return false;
829
		}
830
831
		public void maximizeExpansion(SpaceTreeNode nodeToExpand) {
832
			protectedNode = nodeToExpand;
833
			double availableSpace = getAvailableSpace();
834
			double requiredSpace = 0;
835
836
			((SpaceTreeLayer) spaceTreeLayers.get(nodeToExpand.depth + 1)).removeNodes(nodeToExpand.children);
837
838
			ArrayList nodesInThisLayer = null;
839
			ArrayList nodesInNextLayer = new ArrayList();
840
			nodesInNextLayer.add(nodeToExpand);
841
			double spaceRequiredInNextLayer = nodeToExpand.spaceRequiredForNode();
842
			for (int layer = 0; !nodesInNextLayer.isEmpty(); layer++) {
843
				NodeSnapshot[][] snapShot = takeSnapShot();
844
				requiredSpace = Math.max(requiredSpace, spaceRequiredInNextLayer);
845
				spaceRequiredInNextLayer = 0;
846
847
				nodesInThisLayer = nodesInNextLayer;
848
				nodesInNextLayer = new ArrayList();
849
850
				int numOfNodesWithChildren = 0;
851
				for (Iterator iterator = nodesInThisLayer.iterator(); iterator.hasNext();) {
852
					SpaceTreeNode node = (SpaceTreeNode) iterator.next();
853
					if (!node.children.isEmpty()) {
854
						node.expanded = true;
855
						spaceRequiredInNextLayer += node.spaceRequiredForChildren();
856
						nodesInNextLayer.addAll(node.children);
857
						numOfNodesWithChildren++;
858
					}
859
				}
860
861
				for (Iterator iterator = nodesInNextLayer.iterator(); iterator.hasNext();) {
862
					SpaceTreeNode node = (SpaceTreeNode) iterator.next();
863
					node.expanded = false;
864
				}
865
866
				if (numOfNodesWithChildren == 0)
867
					break;
868
869
				spaceRequiredInNextLayer += branchGap * (numOfNodesWithChildren - 1);
870
871
				boolean addedNewLayer = false;
872
				if ((spaceRequiredInNextLayer <= requiredSpace || spaceRequiredInNextLayer <= availableSpace || (layer < 1 && nodeToExpand.depth
873
						+ layer < 1))
874
						&& !nodesInNextLayer.isEmpty()) {
875
					// add next layer and center its nodes
876
877
					SpaceTreeLayer childLayer = (SpaceTreeLayer) spaceTreeLayers.get(nodeToExpand.depth + layer + 1);
878
					childLayer.addNodes(nodesInNextLayer);
879
					SpaceTreeNode firstChild = ((SpaceTreeNode) nodesInNextLayer.get(0));
880
					SpaceTreeNode lastChild = ((SpaceTreeNode) nodesInNextLayer.get(nodesInNextLayer.size() - 1));
881
					double boundsWidth = spaceRequiredInNextLayer - firstChild.spaceRequiredForNode() / 2 - lastChild.spaceRequiredForNode() / 2;
882
					double startPosition = Math.max((availableSpace - boundsWidth) / 2, firstChild.spaceRequiredForNode() / 2);
883
					setAvailableSpace(spaceRequiredInNextLayer);
884
					childLayer.fitNodesWithinBounds(nodesInNextLayer, startPosition, startPosition + boundsWidth);
885
					setAvailableSpace(0);
886
					if (nodeToExpand.childrenPositionsOK(nodesInThisLayer) || layer == 0 || nodeToExpand.depth + layer < 1)
887
						addedNewLayer = true;
888
				}
889
				if (!addedNewLayer) {
890
					revertToShanpshot(snapShot);
891
					break;
892
				}
893
			}
894
			nodeToExpand.centerParentsBottomUp();
895
			nodeToExpand.centerParentsTopDown();
896
		}
897
	};
898
899
	private SpaceTreeExpandCollapseManager expandCollapseManager = new SpaceTreeExpandCollapseManager();
900
901
	private ContextListener contextListener = new ContextListener.Stub() {
902
		public boolean boundsChanged(LayoutContext context) {
903
			boolean previousBoundsWrong = (bounds == null || bounds.width <= 0 || bounds.height <= 0);
904
			bounds = context.getBounds();
905
			if (bounds.width > 0 && bounds.height > 0 && previousBoundsWrong) {
906
				expandCollapseManager.maximizeExpansion((SpaceTreeNode) treeObserver.getSuperRoot());
907
				refreshLayout(false);
908
			}
909
			return false;
910
		}
911
	};
912
913
	private LayoutListener layoutListener = new LayoutListener() {
914
915
		public boolean entityMoved(LayoutContext context, EntityLayout entity) {
916
			if (entity instanceof NodeLayout) {
917
				defaultNodeHandle(context, (NodeLayout) entity);
918
			}
919
			if (entity instanceof SubgraphLayout) {
920
				defaultSubgraphHandle(context, (SubgraphLayout) entity);
921
			}
922
			return false;
923
		}
924
925
		public boolean entityResized(LayoutContext context, EntityLayout entity) {
926
			if (entity instanceof NodeLayout) {
927
				setAvailableSpace(getAvailableSpace() + ((SpaceTreeNode) treeObserver.getTreeNode((NodeLayout) entity)).spaceRequiredForNode());
928
				defaultNodeHandle(context, (NodeLayout) entity);
929
				setAvailableSpace(0);
930
			}
931
			if (entity instanceof SubgraphLayout) {
932
				defaultSubgraphHandle(context, (SubgraphLayout) entity);
933
			}
934
			return false;
935
		}
936
937
		/**
938
		 * Finds a root of given subgraph, updates the root position and moves
939
		 * the subgraph to proper position
940
		 * 
941
		 * @param context
942
		 * @param subgraph
943
		 */
944
		private void defaultSubgraphHandle(LayoutContext context, SubgraphLayout subgraph) {
945
			SpaceTreeNode node = (SpaceTreeNode) treeObserver.getTreeNode(subgraph.getNodes()[0]);
946
			while (node != null && node.node != null && node.node.getSubgraph() == subgraph) {
947
				node = (SpaceTreeNode) node.parent;
948
			}
949
			if (node != null && node.subgraph == subgraph) {
950
				node.adjustPosition(subgraph.getLocation());
951
				if (context.isBackgroundLayoutEnabled()) {
952
					((SpaceTreeNode) treeObserver.getSuperRoot()).flushLocationChanges(0);
953
					node.refreshSubgraphLocation();
954
					context.flushChanges(false);
955
				}
956
			}
957
		}
958
959
		private void defaultNodeHandle(LayoutContext context, NodeLayout node) {
960
			if (bounds.width <= 0 || bounds.height <= 0)
961
				return;
962
			SpaceTreeNode spaceTreeNode = (SpaceTreeNode) treeObserver.getTreeNode(node);
963
			spaceTreeNode.adjustPosition(node.getLocation());
964
			if (context.isBackgroundLayoutEnabled()) {
965
				((SpaceTreeNode) treeObserver.getSuperRoot()).flushLocationChanges(0);
966
				spaceTreeNode.refreshSubgraphLocation();
967
				context.flushChanges(false);
968
			}
969
		}
970
	};
971
972
	private int direction = TOP_DOWN;
973
974
	private double leafGap = 15;
975
	private double branchGap = leafGap + 5;
976
	private double layerGap = 20;
977
978
	private boolean directionChanged = false;
979
980
	private LayoutContext context;
981
982
	private DisplayIndependentRectangle bounds;
983
984
	private TreeLayoutObserver treeObserver;
985
986
	private double availableSpace;
987
988
	private ArrayList spaceTreeLayers = new ArrayList();
989
990
	/**
991
	 * If not null, this node and all of its children shall not be collapsed
992
	 * during node movements.
993
	 */
994
	private SpaceTreeNode protectedNode = null;
995
996
	/**
997
	 * Constructs an instance of <code>SpaceTreeLayoutAlgorithm</code> that
998
	 * places the root of a tree at the top of the graph.
999
	 */
1000
	public SpaceTreeLayoutAlgorithm() {
1001
	}
1002
1003
	/**
1004
	 * Constructs an instance of <code>SpaceTreeLayoutAlgorithm</code> that
1005
	 * places the root of a tree according to given direction
1006
	 * 
1007
	 * @param direction
1008
	 *            direction of the tree, sould be one of the following:
1009
	 *            {@link #TOP_DOWN}, {@link #BOTTOM_UP}, {@link #LEFT_RIGHT},
1010
	 *            {@link #RIGHT_LEFT}.
1011
	 */
1012
	public SpaceTreeLayoutAlgorithm(int direction) {
1013
		setDirection(direction);
1014
	}
1015
1016
	/**
1017
	 * 
1018
	 * @return current direction (placement) of the tree
1019
	 */
1020
	public int getDirection() {
1021
		return direction;
1022
	}
1023
1024
	/**
1025
	 * Sets direction (placement) of the tree
1026
	 * 
1027
	 * @param direction
1028
	 *            direction of the tree, sould be one of the following:
1029
	 *            {@link #TOP_DOWN}, {@link #BOTTOM_UP}, {@link #LEFT_RIGHT},
1030
	 *            {@link #RIGHT_LEFT}.
1031
	 */
1032
	public void setDirection(int direction) {
1033
		if (direction == this.direction)
1034
			return;
1035
		if (direction == TOP_DOWN || direction == BOTTOM_UP || direction == LEFT_RIGHT || direction == RIGHT_LEFT) {
1036
			this.direction = direction;
1037
			directionChanged = true;
1038
			if (context.isBackgroundLayoutEnabled())
1039
				checkPendingChangeDirection();
1040
		} else
1041
			throw new IllegalArgumentException("Invalid direction: " + direction);
1042
	}
1043
1044
	public void applyLayout(boolean clean) {
1045
		bounds = context.getBounds();
1046
1047
		if (bounds.width <= 0 || bounds.height <= 0)
1048
			return;
1049
1050
		if (clean) {
1051
			treeObserver.recomputeTree();
1052
			expandCollapseManager.maximizeExpansion((SpaceTreeNode) treeObserver.getSuperRoot());
1053
		}
1054
		SpaceTreeNode superRoot = ((SpaceTreeNode) treeObserver.getSuperRoot());
1055
		superRoot.flushExpansionChanges();
1056
		superRoot.flushLocationChanges(0);
1057
		checkPendingChangeDirection();
1058
	}
1059
1060
	public void setLayoutContext(LayoutContext context) {
1061
		if (this.context != null) {
1062
			this.context.removeContextListener(contextListener);
1063
			this.context.removeLayoutListener(layoutListener);
1064
			treeObserver.stop();
1065
		}
1066
		this.context = context;
1067
		context.addContextListener(contextListener);
1068
		context.addLayoutListener(layoutListener);
1069
		treeObserver = new TreeLayoutObserver(context, spaceTreeNodeFactory);
1070
1071
		bounds = context.getBounds();
1072
	}
1073
1074
	/**
1075
	 * 
1076
	 * @return <code>ExpandCollapseManager</code> that can (and should) be used
1077
	 *         on layout context managed by this layout algorithm.
1078
	 */
1079
	public ExpandCollapseManager getExpandCollapseManager() {
1080
		return expandCollapseManager;
1081
	}
1082
1083
	private void checkPendingChangeDirection() {
1084
		if (directionChanged) {
1085
			SubgraphLayout[] subgraphs = context.getSubgraphs();
1086
			int subgraphDirection = getSubgraphDirection();
1087
			for (int i = 0; i < subgraphs.length; i++) {
1088
				subgraphs[i].setDirection(subgraphDirection);
1089
			}
1090
			directionChanged = false;
1091
		}
1092
	}
1093
1094
	private int getSubgraphDirection() {
1095
		switch (direction) {
1096
		case TOP_DOWN:
1097
			return SubgraphLayout.TOP_DOWN;
1098
		case BOTTOM_UP:
1099
			return SubgraphLayout.BOTTOM_UP;
1100
		case LEFT_RIGHT:
1101
			return SubgraphLayout.LEFT_RIGHT;
1102
		case RIGHT_LEFT:
1103
			return SubgraphLayout.RIGHT_LEFT;
1104
		}
1105
		throw new RuntimeException();
1106
	}
1107
1108
	protected void refreshLayout(boolean animation) {
1109
		if (!context.isBackgroundLayoutEnabled())
1110
			return;
1111
		SpaceTreeNode superRoot = (SpaceTreeNode) treeObserver.getSuperRoot();
1112
		if (animation && superRoot.flushCollapseChanges())
1113
			context.flushChanges(true);
1114
		if (superRoot.flushLocationChanges(0) && animation)
1115
			context.flushChanges(true);
1116
		superRoot.flushExpansionChanges();
1117
		superRoot.flushLocationChanges(0);
1118
		context.flushChanges(animation);
1119
	}
1120
1121
	/**
1122
	 * Available space is the biggest of the following values:
1123
	 * <ul>
1124
	 * <li>Space provided by current context bounds</li>
1125
	 * <li>Space already taken by the widest layer</li>
1126
	 * <li>Value set with {@link #setAvailableSpace(double)}</li>
1127
	 * </ul>
1128
	 * 
1129
	 * @return
1130
	 */
1131
	private double getAvailableSpace() {
1132
		double result = (direction == TOP_DOWN || direction == BOTTOM_UP) ? bounds.width : bounds.height;
1133
		result = Math.max(result, this.availableSpace);
1134
		for (Iterator iterator = spaceTreeLayers.iterator(); iterator.hasNext();) {
1135
			SpaceTreeLayer layer = (SpaceTreeLayer) iterator.next();
1136
			if (!layer.nodes.isEmpty()) {
1137
				SpaceTreeNode first = (SpaceTreeNode) layer.nodes.get(0);
1138
				SpaceTreeNode last = (SpaceTreeNode) layer.nodes.get(layer.nodes.size() - 1);
1139
				result = Math.max(result, last.positionInLayer - first.positionInLayer + (first.spaceRequiredForNode() + last.spaceRequiredForNode())
1140
						/ 2);
1141
			} else
1142
				break;
1143
		}
1144
		return result;
1145
	}
1146
1147
	/**
1148
	 * This method allows to reserve more space than actual layout bounds
1149
	 * provide or nodes currently occupy.
1150
	 * 
1151
	 * @param availableSpace
1152
	 */
1153
	private void setAvailableSpace(double availableSpace) {
1154
		this.availableSpace = availableSpace;
1155
	}
1156
1157
	private double expectedDistance(SpaceTreeNode node, SpaceTreeNode neighbor) {
1158
		double expectedDistance = (node.spaceRequiredForNode() + neighbor.spaceRequiredForNode()) / 2;
1159
		expectedDistance += (node.parent == neighbor.parent) ? leafGap : branchGap;
1160
		return expectedDistance;
1161
	}
1162
1163
	private class NodeSnapshot {
1164
		SpaceTreeNode node;
1165
		double position;
1166
		boolean expanded;
1167
	}
1168
1169
	/**
1170
	 * Stores current expansion state of tree nodes and their position in layers
1171
	 * 
1172
	 * @return array containing state of all unpruned nodes
1173
	 */
1174
	private NodeSnapshot[][] takeSnapShot() {
1175
		NodeSnapshot[][] result = new NodeSnapshot[spaceTreeLayers.size()][];
1176
		for (int i = 0; i < result.length; i++) {
1177
			SpaceTreeLayer layer = (SpaceTreeLayer) spaceTreeLayers.get(i);
1178
			result[i] = new NodeSnapshot[layer.nodes.size()];
1179
			for (int j = 0; j < result[i].length; j++) {
1180
				result[i][j] = new NodeSnapshot();
1181
				result[i][j].node = ((SpaceTreeNode) layer.nodes.get(j));
1182
				result[i][j].position = result[i][j].node.positionInLayer;
1183
				result[i][j].expanded = result[i][j].node.expanded;
1184
			}
1185
		}
1186
		return result;
1187
	}
1188
1189
	/**
1190
	 * Restores tree nodes' expansion state and position in layers
1191
	 * 
1192
	 * @param snapShot
1193
	 *            state obtained with {@link #takeSnapShot()}
1194
	 */
1195
	private void revertToShanpshot(NodeSnapshot[][] snapShot) {
1196
		for (int i = 0; i < snapShot.length; i++) {
1197
			SpaceTreeLayer layer = (SpaceTreeLayer) spaceTreeLayers.get(i);
1198
			layer.nodes.clear();
1199
			for (int j = 0; j < snapShot[i].length; j++) {
1200
				snapShot[i][j].node.positionInLayer = snapShot[i][j].position;
1201
				snapShot[i][j].node.expanded = snapShot[i][j].expanded;
1202
				layer.nodes.add(snapShot[i][j].node);
1203
			}
1204
		}
1205
	}
1206
}
(-)src/org/eclipse/zest/tests/swt/PaintSnippet.java (-4 / +5 lines)
Lines 1-11 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 ******************************************************************************/
11
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
12
package org.eclipse.zest.tests.swt;
11
13
Lines 13-19 Link Here
13
import org.eclipse.zest.core.widgets.Graph;
15
import org.eclipse.zest.core.widgets.Graph;
14
import org.eclipse.zest.core.widgets.GraphConnection;
16
import org.eclipse.zest.core.widgets.GraphConnection;
15
import org.eclipse.zest.core.widgets.GraphNode;
17
import org.eclipse.zest.core.widgets.GraphNode;
16
import org.eclipse.zest.layouts.LayoutStyles;
17
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
18
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
18
import org.eclipse.swt.SWT;
19
import org.eclipse.swt.SWT;
19
import org.eclipse.swt.events.PaintEvent;
20
import org.eclipse.swt.events.PaintEvent;
Lines 66-72 Link Here
66
		new GraphConnection(g, SWT.NONE, n, n2);
67
		new GraphConnection(g, SWT.NONE, n, n2);
67
		new GraphConnection(g, SWT.NONE, n2, n3);
68
		new GraphConnection(g, SWT.NONE, n2, n3);
68
		new GraphConnection(g, SWT.NONE, n3, n);
69
		new GraphConnection(g, SWT.NONE, n3, n);
69
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
70
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true);
70
71
71
		b.addSelectionListener(new SelectionListener() {
72
		b.addSelectionListener(new SelectionListener() {
72
73
(-)src/org/eclipse/zest/tests/swt/GraphSnippet7.java (-71 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
11
12
import org.eclipse.zest.core.widgets.Graph;
13
import org.eclipse.zest.core.widgets.GraphConnection;
14
import org.eclipse.zest.core.widgets.GraphNode;
15
import org.eclipse.zest.layouts.LayoutStyles;
16
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
17
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.events.MouseEvent;
19
import org.eclipse.swt.events.MouseMoveListener;
20
import org.eclipse.swt.layout.FillLayout;
21
import org.eclipse.swt.widgets.Display;
22
import org.eclipse.swt.widgets.Shell;
23
24
/**
25
 * This snippet shows how to use the findFigureAt to get the figure under the mouse
26
 * 
27
 * @author Ian Bull
28
 * 
29
 */
30
public class GraphSnippet7 {
31
32
	/**
33
	 * @param args
34
	 */
35
	public static void main(String[] args) {
36
		Display d = new Display();
37
		Shell shell = new Shell(d);
38
		shell.setText("GraphSnippet7");
39
		shell.setLayout(new FillLayout());
40
		shell.setSize(400, 400);
41
42
		final Graph g = new Graph(shell, SWT.NONE);
43
44
		GraphNode n = new GraphNode(g, SWT.NONE, "Paper");
45
		GraphNode n2 = new GraphNode(g, SWT.NONE, "Rock");
46
		GraphNode n3 = new GraphNode(g, SWT.NONE, "Scissors");
47
		new GraphConnection(g, SWT.NONE, n, n2);
48
		new GraphConnection(g, SWT.NONE, n2, n3);
49
		new GraphConnection(g, SWT.NONE, n3, n);
50
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
51
		
52
		g.addMouseMoveListener(new MouseMoveListener() {
53
54
			public void mouseMove(MouseEvent e) {
55
				// Get the figure at the current mouse location 
56
				Object o = g.getFigureAt(e.x, e.y);
57
				if ( o != null ) {
58
					System.out.println(o + " is at: (" + e.x + "," + e.y + ")");
59
				}
60
			}
61
			
62
		});
63
64
		shell.open();
65
		while (!shell.isDisposed()) {
66
			while (!d.readAndDispatch()) {
67
				d.sleep();
68
			}
69
		}
70
	}
71
}
(-)src/org/eclipse/zest/tests/swt/GraphSnippet12.java (-164 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
11
12
import java.util.Iterator;
13
14
import org.eclipse.draw2d.ColorConstants;
15
import org.eclipse.draw2d.Ellipse;
16
import org.eclipse.draw2d.Figure;
17
import org.eclipse.draw2d.FreeformLayout;
18
import org.eclipse.draw2d.IFigure;
19
import org.eclipse.draw2d.ImageFigure;
20
import org.eclipse.draw2d.PolylineShape;
21
import org.eclipse.draw2d.geometry.Point;
22
import org.eclipse.draw2d.geometry.Rectangle;
23
import org.eclipse.swt.SWT;
24
import org.eclipse.swt.events.SelectionEvent;
25
import org.eclipse.swt.events.SelectionListener;
26
import org.eclipse.swt.graphics.Image;
27
import org.eclipse.swt.layout.FillLayout;
28
import org.eclipse.swt.widgets.Display;
29
import org.eclipse.swt.widgets.Shell;
30
import org.eclipse.zest.core.widgets.CGraphNode;
31
import org.eclipse.zest.core.widgets.Graph;
32
import org.eclipse.zest.core.widgets.GraphConnection;
33
import org.eclipse.zest.core.widgets.GraphNode;
34
import org.eclipse.zest.layouts.LayoutStyles;
35
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
36
37
/**
38
 * 
39
 * This snippet shows how to create a curved connection using Zest.
40
 * 
41
 * @author Ian Bull
42
 * 
43
 */
44
public class GraphSnippet12 {
45
46
	public static IFigure createPersonFigure(Image headImage) {
47
		Figure person = new Figure();
48
		person.setLayoutManager(new FreeformLayout());
49
		IFigure head = null;
50
		if ( headImage != null ) {
51
			headImage = new Image(headImage.getDevice(), headImage.getImageData().scaledTo(40, 50));
52
			head = new ImageFigure(headImage);
53
		}
54
		else
55
			head = new Ellipse();
56
		head.setSize(40, 50);
57
		
58
		PolylineShape body = new PolylineShape();
59
		body.setLineWidth(1);
60
		body.setStart(new Point(20,40));
61
		body.setEnd(new Point(20,100));
62
		body.setBounds(new Rectangle(0,0,40,100));
63
		
64
		PolylineShape leftLeg = new PolylineShape();
65
		leftLeg.setLineWidth(1);
66
		leftLeg.setStart(new Point(20,100));
67
		leftLeg.setEnd(new Point(0,130));
68
		leftLeg.setBounds(new Rectangle(0,0,40,130));
69
		
70
		PolylineShape rightLeg = new PolylineShape();
71
		rightLeg.setLineWidth(1);
72
		rightLeg.setStart(new Point(20,100));
73
		rightLeg.setEnd(new Point(40,130));
74
		rightLeg.setBounds(new Rectangle(0,0,40,130));
75
		
76
		PolylineShape leftArm = new PolylineShape();
77
		leftArm.setLineWidth(1);
78
		leftArm.setStart(new Point(20,60));
79
		leftArm.setEnd(new Point(0,50));
80
		leftArm.setBounds(new Rectangle(0,0,40,130));
81
		
82
		PolylineShape rightArm = new PolylineShape();
83
		rightArm.setLineWidth(1);
84
		rightArm.setStart(new Point(20,60));
85
		rightArm.setEnd(new Point(40,50));
86
		rightArm.setBounds(new Rectangle(0,0,40,130));
87
		
88
		person.add(head);
89
		person.add(body);
90
		person.add(leftLeg);
91
		person.add(rightLeg);
92
		person.add(leftArm);
93
		person.add(rightArm);
94
		person.setSize(40,130);
95
		return person;
96
	}
97
98
	public static void main(String[] args) {
99
		final Display d = new Display();
100
		Shell shell = new Shell(d);
101
		shell.setText("GraphSnippet11");
102
		shell.setLayout(new FillLayout());
103
		shell.setSize(400, 400);
104
105
		
106
		final Graph g = new Graph(shell, SWT.NONE);
107
		g.addSelectionListener(new SelectionListener(){
108
		
109
			public void widgetSelected(SelectionEvent e) {
110
				Iterator iter = g.getSelection().iterator();
111
				while(iter.hasNext()) {
112
					Object o = iter.next();
113
					if ( o instanceof CGraphNode) {
114
						IFigure figure = ((CGraphNode)o).getFigure();
115
						figure.setBackgroundColor(ColorConstants.blue);
116
						figure.setForegroundColor(ColorConstants.blue);
117
					}
118
				}
119
				iter = g.getNodes().iterator();
120
				while ( iter.hasNext()) {
121
					Object o = iter.next();
122
					if ( o instanceof CGraphNode) {
123
						if ( !g.getSelection().contains(o)) {
124
							((CGraphNode)o).getFigure().setBackgroundColor(ColorConstants.black);
125
							((CGraphNode)o).getFigure().setForegroundColor(ColorConstants.black);
126
						}
127
					}
128
				}
129
			}
130
		
131
			public void widgetDefaultSelected(SelectionEvent e) {
132
				// TODO Auto-generated method stub
133
				
134
			}
135
		});
136
		
137
		Image zx = new Image(d, "zx.png");
138
		Image ibull = new Image(d, "ibull.jpg");
139
		CGraphNode n = new CGraphNode(g, SWT.NONE, createPersonFigure(zx));
140
		CGraphNode n2 = new CGraphNode(g, SWT.NONE,  createPersonFigure(ibull));
141
		GraphNode n3 = new GraphNode(g, SWT.NONE, "PDE");
142
		GraphNode n4 = new GraphNode(g, SWT.NONE, "Zest");
143
		GraphNode n5 = new GraphNode(g, SWT.NONE, "PDE Viz tool");
144
		
145
		new GraphConnection(g, SWT.NONE, n, n2);
146
		new GraphConnection(g, SWT.NONE, n, n3);
147
		new GraphConnection(g, SWT.NONE, n2, n4);
148
		new GraphConnection(g, SWT.NONE, n, n5);
149
		new GraphConnection(g, SWT.NONE, n2, n5);
150
		new GraphConnection(g, SWT.NONE, n3, n5);
151
		new GraphConnection(g, SWT.NONE, n4, n5);
152
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
153
154
		shell.open();
155
		while (!shell.isDisposed()) {
156
			while (!d.readAndDispatch()) {
157
				d.sleep();
158
			}
159
		}
160
		zx.dispose();
161
		ibull.dispose();
162
	}
163
164
}
(-)src/org/eclipse/zest/tests/swt/GraphSnippet10.java (-78 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
11
12
import org.eclipse.swt.SWT;
13
import org.eclipse.swt.events.SelectionAdapter;
14
import org.eclipse.swt.events.SelectionEvent;
15
import org.eclipse.swt.layout.FillLayout;
16
import org.eclipse.swt.widgets.Button;
17
import org.eclipse.swt.widgets.Display;
18
import org.eclipse.swt.widgets.Shell;
19
import org.eclipse.zest.core.widgets.Graph;
20
import org.eclipse.zest.core.widgets.GraphConnection;
21
import org.eclipse.zest.core.widgets.GraphNode;
22
import org.eclipse.zest.layouts.LayoutStyles;
23
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
24
25
/**
26
 * 
27
 * This snippet shows how to create a curved connection using Zest.
28
 * Each time the Button is clicked, the curve changes.
29
 * 
30
 * @author Ian Bull
31
 * 
32
 */
33
public class GraphSnippet10 {
34
35
	public static void main(String[] args) {
36
		Display d = new Display();
37
		Shell shell = new Shell(d);
38
		shell.setText("GraphSnippet1");
39
		shell.setLayout(new FillLayout());
40
		shell.setSize(400, 400);
41
42
		final Graph g = new Graph(shell, SWT.NONE);
43
44
		GraphNode n = new GraphNode(g, SWT.NONE, "Paper");
45
		n.setBorderColor(org.eclipse.draw2d.ColorConstants.yellow);
46
		n.setBorderWidth(3);
47
		GraphNode n2 = new GraphNode(g, SWT.NONE, "Rock");
48
		GraphNode n3 = new GraphNode(g, SWT.NONE, "Scissors");
49
		final GraphConnection connection = new GraphConnection(g, SWT.NONE, n, n2);
50
		connection.setLineWidth(3);
51
		new GraphConnection(g, SWT.NONE, n2, n3);
52
		new GraphConnection(g, SWT.NONE, n3, n);
53
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
54
		
55
		Button button = new Button(shell, SWT.PUSH);
56
		button.setText("Change Curve");
57
		button.addSelectionListener(new SelectionAdapter() {
58
			int count = 0;
59
			public void widgetSelected(SelectionEvent e) {
60
				count = ++count % 16;
61
				if ( count > 8 ) {
62
					connection.setCurveDepth((-16 + count) * 10);
63
				}
64
				else {
65
					connection.setCurveDepth(count * 10);
66
				}
67
			}
68
		});
69
70
		shell.open();
71
		while (!shell.isDisposed()) {
72
			while (!d.readAndDispatch()) {
73
				d.sleep();
74
			}
75
		}
76
	}
77
78
}
(-)src/org/eclipse/zest/tests/swt/GraphSnippet8.java (-120 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
11
12
import org.eclipse.draw2d.ColorConstants;
13
import org.eclipse.swt.SWT;
14
import org.eclipse.swt.layout.FillLayout;
15
import org.eclipse.swt.widgets.Display;
16
import org.eclipse.swt.widgets.Shell;
17
import org.eclipse.zest.core.widgets.Graph;
18
import org.eclipse.zest.core.widgets.GraphConnection;
19
import org.eclipse.zest.core.widgets.GraphNode;
20
import org.eclipse.zest.core.widgets.ZestStyles;
21
import org.eclipse.zest.layouts.Filter;
22
import org.eclipse.zest.layouts.LayoutItem;
23
import org.eclipse.zest.layouts.LayoutStyles;
24
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
25
26
/**
27
 * This snippet shows how to filter elements in the layout.  The Data on the tree
28
 * connections are set to "False", meaning they won't be filtered.  
29
 * 
30
 * @author Ian Bull
31
 * 
32
 */
33
public class GraphSnippet8 {
34
35
	/**
36
	 * @param args
37
	 */
38
	public static void main(String[] args) {
39
		Display display = new Display();
40
		Shell shell = new Shell(display);
41
		shell.setText("GraphSnippet8");
42
		shell.setLayout(new FillLayout());
43
		shell.setSize(400, 400);
44
45
		final Graph graph = new Graph(shell, SWT.NONE);
46
47
		GraphNode a = new GraphNode(graph, SWT.NONE, "Root");
48
		GraphNode b = new GraphNode(graph, SWT.NONE, "B");
49
		GraphNode c = new GraphNode(graph, SWT.NONE, "C");
50
		GraphNode d = new GraphNode(graph, SWT.NONE, "D");
51
		GraphNode e = new GraphNode(graph, SWT.NONE, "E");
52
		GraphNode f = new GraphNode(graph, SWT.NONE, "F");
53
		GraphNode g = new GraphNode(graph, SWT.NONE, "G");
54
		GraphNode h = new GraphNode(graph, SWT.NONE, "H");
55
		GraphConnection connection = new GraphConnection(graph, SWT.NONE, a, b);
56
		connection.setData(Boolean.FALSE);
57
		connection = new GraphConnection(graph, SWT.NONE, a, c);
58
		connection.setData(Boolean.FALSE);
59
		connection = new GraphConnection(graph, SWT.NONE, a, c);
60
		connection.setData(Boolean.FALSE);
61
		connection = new GraphConnection(graph, SWT.NONE, a, d);
62
		connection.setData(Boolean.FALSE);
63
		connection = new GraphConnection(graph, SWT.NONE, b, e);
64
		connection.setData(Boolean.FALSE);
65
		connection = new GraphConnection(graph, SWT.NONE, b, f);
66
		connection.setData(Boolean.FALSE);
67
		connection = new GraphConnection(graph, SWT.NONE, c, g);
68
		connection.setData(Boolean.FALSE);
69
		connection = new GraphConnection(graph, SWT.NONE, d, h);
70
		connection.setData(Boolean.FALSE);
71
		
72
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, b, c);
73
		connection.setLineColor(ColorConstants.red);
74
		connection.setLineWidth(3);
75
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, c, d);
76
		connection.setLineColor(ColorConstants.red);
77
		connection.setLineWidth(3);
78
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, e, f);
79
		connection.setLineColor(ColorConstants.red);
80
		connection.setLineWidth(3);
81
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, f, g);
82
		connection.setLineColor(ColorConstants.red);
83
		connection.setLineWidth(3);
84
		
85
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, h, e);
86
		connection.setLineColor(ColorConstants.red);
87
		connection.setLineWidth(3);
88
		
89
		TreeLayoutAlgorithm treeLayoutAlgorithm = new TreeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING);
90
		Filter filter = new Filter() {
91
			public boolean isObjectFiltered(LayoutItem item) {
92
93
				// Get the "Connection" from the Layout Item
94
				// and use this connection to get the "Graph Data"
95
				Object object = item.getGraphData();
96
				if  (object instanceof GraphConnection ) {
97
					GraphConnection connection = (GraphConnection) object;
98
					if ( connection.getData() != null && connection.getData() instanceof Boolean ) {
99
						// If the data is false, don't filter, otherwise, filter.
100
						return ((Boolean)connection.getData()).booleanValue();
101
					}
102
					return true;
103
				}
104
				return false;
105
			}
106
			
107
		};
108
		treeLayoutAlgorithm.setFilter(filter);
109
		graph.setLayoutAlgorithm(treeLayoutAlgorithm, true);
110
		
111
112
		shell.open();
113
		while (!shell.isDisposed()) {
114
			while (!display.readAndDispatch()) {
115
				display.sleep();
116
			}
117
		}
118
	}
119
120
}
(-)src/org/eclipse/zest/tests/swt/ZoomSnippet.java (-151 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
11
12
import org.eclipse.zest.core.widgets.Graph;
13
import org.eclipse.zest.core.widgets.GraphConnection;
14
import org.eclipse.zest.core.widgets.GraphContainer;
15
import org.eclipse.zest.core.widgets.GraphItem;
16
import org.eclipse.zest.core.widgets.GraphNode;
17
import org.eclipse.zest.core.widgets.ZestStyles;
18
import org.eclipse.zest.layouts.LayoutAlgorithm;
19
import org.eclipse.zest.layouts.LayoutStyles;
20
import org.eclipse.zest.layouts.algorithms.CompositeLayoutAlgorithm;
21
import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm;
22
import org.eclipse.zest.layouts.algorithms.HorizontalShift;
23
import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm;
24
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
25
import org.eclipse.swt.SWT;
26
import org.eclipse.swt.events.KeyEvent;
27
import org.eclipse.swt.events.KeyListener;
28
import org.eclipse.swt.graphics.Image;
29
import org.eclipse.swt.layout.FillLayout;
30
import org.eclipse.swt.widgets.Display;
31
import org.eclipse.swt.widgets.Shell;
32
33
public class ZoomSnippet {
34
35
	private static Image image1;
36
	private static Image classImage;
37
38
	public static void createContainer(Graph g) {
39
		GraphContainer a = new GraphContainer(g, SWT.NONE, "SomeClass.java", classImage);
40
		int r = (int) ((Math.random() * 3) + 1);
41
		r = 2;
42
		populateContainer(a, g, r, true);
43
		for (int i = 0; i < 4; i++) {
44
			GraphContainer b = new GraphContainer(g, SWT.NONE, "SomeNestedClass.java", classImage);
45
			r = (int) ((Math.random() * 3) + 1);
46
			r = 2;
47
			populateContainer(b, g, r, false);
48
			new GraphConnection(g, SWT.NONE, a, b);
49
			for (int j = 0; j < 4; j++) {
50
				GraphContainer c = new GraphContainer(g, SWT.NONE, "DefaultAction.java", classImage);
51
				r = (int) ((Math.random() * 3) + 1);
52
				r = 2;
53
				populateContainer(c, g, r, true);
54
				new GraphConnection(g, SWT.NONE, b, c);
55
			}
56
		}
57
	}
58
59
	public static void populateContainer(GraphContainer c, Graph g, int number, boolean radial) {
60
		GraphNode a = new GraphNode(c, ZestStyles.NODES_FISHEYE | ZestStyles.NODES_HIDE_TEXT, "SomeClass.java", classImage);
61
		for (int i = 0; i < 4; i++) {
62
			GraphNode b = new GraphNode(c, ZestStyles.NODES_FISHEYE | ZestStyles.NODES_HIDE_TEXT, "SomeNestedClass.java", classImage);
63
			new GraphConnection(g, SWT.NONE, a, b);
64
			for (int j = 0; j < 4; j++) {
65
				GraphNode d = new GraphNode(c, ZestStyles.NODES_FISHEYE | ZestStyles.NODES_HIDE_TEXT, "DefaultAction.java", classImage);
66
				new GraphConnection(g, SWT.NONE, b, d);
67
				if (number > 2) {
68
					for (int k = 0; k < 4; k++) {
69
						GraphNode e = new GraphNode(c, ZestStyles.NODES_FISHEYE | ZestStyles.NODES_HIDE_TEXT, "LastAction(Hero).java", classImage);
70
						new GraphConnection(g, SWT.NONE, d, e);
71
						if (number > 3) {
72
							for (int l = 0; l < 4; l++) {
73
								GraphNode f = new GraphNode(c, ZestStyles.NODES_FISHEYE | ZestStyles.NODES_HIDE_TEXT, "LastAction(Hero).java", classImage);
74
								new GraphConnection(g, SWT.NONE, e, f);
75
							}
76
						}
77
					}
78
				}
79
			}
80
		}
81
		if (number == 1) {
82
			c.setScale(0.75);
83
		} else if (number == 2) {
84
			c.setScale(0.50);
85
		} else {
86
			c.setScale(0.25);
87
		}
88
		if (radial) {
89
			c.setLayoutAlgorithm(new RadialLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
90
		} else {
91
			c.setLayoutAlgorithm(new TreeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
92
		}
93
	}
94
95
	/**
96
	 * @param args
97
	 */
98
	public static void main(String[] args) {
99
		// Create the shell
100
		Display d = new Display();
101
102
		image1 = new Image(Display.getDefault(), ZoomSnippet.class.getResourceAsStream("package_obj.gif"));
103
		classImage = new Image(Display.getDefault(), ZoomSnippet.class.getResourceAsStream("class_obj.gif"));
104
105
		Shell shell = new Shell(d);
106
		shell.setText("GraphSnippet1");
107
		shell.setLayout(new FillLayout());
108
		shell.setSize(500, 800);
109
110
		final Graph g = new Graph(shell, SWT.NONE);
111
		createContainer(g);
112
113
		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) });
114
		//g.setLayoutAlgorithm(new GridLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
115
		g.setLayoutAlgorithm(compositeLayoutAlgorithm, true);
116
117
		g.addKeyListener(new KeyListener() {
118
			boolean flip = true;
119
120
			public void keyPressed(KeyEvent e) {
121
122
				if (g.getSelection().size() == 1) {
123
					GraphNode item = (GraphNode) g.getSelection().get(0);
124
					if (item.getItemType() == GraphItem.CONTAINER) {
125
						if (flip) {
126
							(item).setSize(500, 100);
127
						} else {
128
							(item).setSize(0, 0);
129
						}
130
						flip = !flip;
131
					}
132
				}
133
134
			}
135
136
			public void keyReleased(KeyEvent e) {
137
				// TODO Auto-generated method stub
138
139
			}
140
141
		});
142
143
		shell.open();
144
		while (!shell.isDisposed()) {
145
			while (!d.readAndDispatch()) {
146
				d.sleep();
147
			}
148
		}
149
		image1.dispose();
150
	}
151
}
(-)src/org/eclipse/zest/tests/swt/GraphSnippet3.java (-73 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.tests.swt;
12
13
import org.eclipse.zest.core.widgets.Graph;
14
import org.eclipse.zest.core.widgets.GraphConnection;
15
import org.eclipse.zest.core.widgets.GraphNode;
16
import org.eclipse.zest.core.widgets.ZestStyles;
17
import org.eclipse.zest.layouts.LayoutStyles;
18
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
19
import org.eclipse.swt.SWT;
20
import org.eclipse.swt.events.SelectionAdapter;
21
import org.eclipse.swt.events.SelectionEvent;
22
import org.eclipse.swt.graphics.Image;
23
import org.eclipse.swt.layout.FillLayout;
24
import org.eclipse.swt.widgets.Display;
25
import org.eclipse.swt.widgets.Shell;
26
27
/**
28
 * Adds a selection listener to the nodes to tell when a selection event has
29
 * happened.
30
 * 
31
 * @author Ian Bull
32
 * 
33
 */
34
public class GraphSnippet3 {
35
36
	public static void main(String[] args) {
37
		Display d = new Display();
38
		Shell shell = new Shell(d);
39
		Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION);
40
		Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
41
		Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR);
42
		shell.setLayout(new FillLayout());
43
		shell.setSize(400, 400);
44
45
		Graph g = new Graph(shell, SWT.NONE);
46
		g.addSelectionListener(new SelectionAdapter() {
47
			public void widgetSelected(SelectionEvent e) {
48
				System.out.println(((Graph) e.widget).getSelection());
49
			}
50
		});
51
		
52
		g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED);
53
		GraphNode n1 = new GraphNode(g, SWT.NONE, "Information", image1);
54
		GraphNode n2 = new GraphNode(g, SWT.NONE, "Warning", image2);
55
		GraphNode n3 = new GraphNode(g, SWT.NONE, "Error", image3);
56
57
		new GraphConnection(g, SWT.NONE, n1, n2);
58
		new GraphConnection(g, SWT.NONE, n2, n3);
59
60
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
61
62
		shell.open();
63
		while (!shell.isDisposed()) {
64
			while (!d.readAndDispatch()) {
65
				d.sleep();
66
			}
67
		}
68
		image1.dispose();
69
		image2.dispose();
70
		image3.dispose();
71
72
	}
73
}
(-)src/org/eclipse/zest/tests/swt/CustomLayout.java (-52 / +31 lines)
Lines 1-3 Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 ******************************************************************************/
1
package org.eclipse.zest.tests.swt;
12
package org.eclipse.zest.tests.swt;
2
13
3
import org.eclipse.swt.SWT;
14
import org.eclipse.swt.SWT;
Lines 7-16 Link Here
7
import org.eclipse.zest.core.widgets.Graph;
18
import org.eclipse.zest.core.widgets.Graph;
8
import org.eclipse.zest.core.widgets.GraphConnection;
19
import org.eclipse.zest.core.widgets.GraphConnection;
9
import org.eclipse.zest.core.widgets.GraphNode;
20
import org.eclipse.zest.core.widgets.GraphNode;
10
import org.eclipse.zest.layouts.LayoutEntity;
21
import org.eclipse.zest.layouts.LayoutAlgorithm;
11
import org.eclipse.zest.layouts.algorithms.AbstractLayoutAlgorithm;
22
import org.eclipse.zest.layouts.interfaces.EntityLayout;
12
import org.eclipse.zest.layouts.dataStructures.InternalNode;
23
import org.eclipse.zest.layouts.interfaces.LayoutContext;
13
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;
14
24
15
/**
25
/**
16
 * This snippet shows how to create a custom layout. This layout simply lays the nodes out vertically
26
 * This snippet shows how to create a custom layout. This layout simply lays the nodes out vertically
Lines 36-94 Link Here
36
		new GraphConnection(g, SWT.NONE, n, n2);
46
		new GraphConnection(g, SWT.NONE, n, n2);
37
		new GraphConnection(g, SWT.NONE, n2, n3);
47
		new GraphConnection(g, SWT.NONE, n2, n3);
38
		new GraphConnection(g, SWT.NONE, n3, n);
48
		new GraphConnection(g, SWT.NONE, n3, n);
39
		g.setLayoutAlgorithm(new AbstractLayoutAlgorithm(SWT.NONE) {
49
		
40
50
		LayoutAlgorithm layoutAlgorithm = new LayoutAlgorithm() {
51
			private LayoutContext context;
52
			public void setLayoutContext(LayoutContext context) {
53
				this.context = context;
54
			}
41
			
55
			
42
			private int totalSteps;
56
			public void applyLayout(boolean clean) {
43
			private int currentStep;
57
				EntityLayout[] entitiesToLayout = context.getEntities();
44
58
				int totalSteps = entitiesToLayout.length;
45
			protected void applyLayoutInternal(InternalNode[] entitiesToLayout,
59
				double distance = context.getBounds().width / totalSteps;
46
					InternalRelationship[] relationshipsToConsider, double boundsX, double boundsY, double boundsWidth,
47
					double boundsHeight) {
48
				
49
				totalSteps = entitiesToLayout.length;
50
				double distance = boundsWidth / totalSteps;
51
				int xLocation = 0;
60
				int xLocation = 0;
52
			
61
53
				fireProgressStarted(totalSteps);
62
				for (int currentStep = 0; currentStep < entitiesToLayout.length; currentStep++) {
54
				
63
					EntityLayout layoutEntity = entitiesToLayout[currentStep];
55
				for (currentStep = 0; currentStep < entitiesToLayout.length; currentStep++) {
64
					layoutEntity.setLocation(xLocation, layoutEntity.getLocation().y);
56
					LayoutEntity layoutEntity = entitiesToLayout[currentStep].getLayoutEntity();
57
					layoutEntity.setLocationInLayout(xLocation, layoutEntity.getYInLayout());
58
					xLocation+= distance;
65
					xLocation+= distance;
59
					fireProgressEvent(currentStep, totalSteps);
60
				}
66
				}
61
				fireProgressEnded(totalSteps);
62
			}
63
64
			protected int getCurrentLayoutStep() {
65
				return 0;
66
			}
67
68
			protected int getTotalNumberOfLayoutSteps() {
69
				return totalSteps;
70
			}
67
			}
71
68
		};
72
			protected boolean isValidConfiguration(boolean asynchronous, boolean continuous) {
69
		g.setLayoutAlgorithm(layoutAlgorithm, true);
73
				return true;
70
		
74
			}
75
76
			protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout,
77
					InternalRelationship[] relationshipsToConsider) {
78
				// Do nothing
79
			}
80
81
			protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout,
82
					InternalRelationship[] relationshipsToConsider, double x, double y, double width, double height) {
83
				// do nothing
84
			}
85
86
			public void setLayoutArea(double x, double y, double width, double height) {
87
				// do nothing
88
			}
89
			
90
		}, true);
91
92
		shell.open();
71
		shell.open();
93
		while (!shell.isDisposed()) {
72
		while (!shell.isDisposed()) {
94
			while (!d.readAndDispatch()) {
73
			while (!d.readAndDispatch()) {
(-)src/org/eclipse/zest/tests/swt/GraphSnippet13.java (-182 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
11
12
import java.util.Iterator;
13
14
import org.eclipse.draw2d.ColorConstants;
15
import org.eclipse.draw2d.Ellipse;
16
import org.eclipse.draw2d.Figure;
17
import org.eclipse.draw2d.FlowLayout;
18
import org.eclipse.draw2d.FreeformLayout;
19
import org.eclipse.draw2d.IFigure;
20
import org.eclipse.draw2d.ImageFigure;
21
import org.eclipse.draw2d.Label;
22
import org.eclipse.draw2d.MarginBorder;
23
import org.eclipse.draw2d.PolylineShape;
24
import org.eclipse.draw2d.geometry.Point;
25
import org.eclipse.draw2d.geometry.Rectangle;
26
import org.eclipse.swt.SWT;
27
import org.eclipse.swt.events.SelectionEvent;
28
import org.eclipse.swt.events.SelectionListener;
29
import org.eclipse.swt.graphics.Image;
30
import org.eclipse.swt.layout.FillLayout;
31
import org.eclipse.swt.widgets.Display;
32
import org.eclipse.swt.widgets.Shell;
33
import org.eclipse.zest.core.widgets.CGraphNode;
34
import org.eclipse.zest.core.widgets.Graph;
35
import org.eclipse.zest.core.widgets.GraphConnection;
36
import org.eclipse.zest.core.widgets.GraphContainer;
37
import org.eclipse.zest.core.widgets.GraphNode;
38
import org.eclipse.zest.core.widgets.ZestStyles;
39
import org.eclipse.zest.layouts.LayoutStyles;
40
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
41
42
/**
43
 * 
44
 * This snippet shows how to create a curved connection using Zest.
45
 * 
46
 * @author Ian Bull
47
 * 
48
 */
49
public class GraphSnippet13 {
50
51
	public static IFigure createPersonFigure(Image headImage) {
52
		Figure person = new Figure();
53
		person.setLayoutManager(new FreeformLayout());
54
		IFigure head = null;
55
		if ( headImage != null ) {
56
			headImage = new Image(headImage.getDevice(), headImage.getImageData().scaledTo(40, 50));
57
			head = new ImageFigure(headImage);
58
		}
59
		else
60
			head = new Ellipse();
61
		head.setSize(40, 50);
62
		
63
		PolylineShape body = new PolylineShape();
64
		body.setLineWidth(1);
65
		body.setStart(new Point(20,40));
66
		body.setEnd(new Point(20,100));
67
		body.setBounds(new Rectangle(0,0,40,100));
68
		
69
		PolylineShape leftLeg = new PolylineShape();
70
		leftLeg.setLineWidth(1);
71
		leftLeg.setStart(new Point(20,100));
72
		leftLeg.setEnd(new Point(0,130));
73
		leftLeg.setBounds(new Rectangle(0,0,40,130));
74
		
75
		PolylineShape rightLeg = new PolylineShape();
76
		rightLeg.setLineWidth(1);
77
		rightLeg.setStart(new Point(20,100));
78
		rightLeg.setEnd(new Point(40,130));
79
		rightLeg.setBounds(new Rectangle(0,0,40,130));
80
		
81
		PolylineShape leftArm = new PolylineShape();
82
		leftArm.setLineWidth(1);
83
		leftArm.setStart(new Point(20,60));
84
		leftArm.setEnd(new Point(0,50));
85
		leftArm.setBounds(new Rectangle(0,0,40,130));
86
		
87
		PolylineShape rightArm = new PolylineShape();
88
		rightArm.setLineWidth(1);
89
		rightArm.setStart(new Point(20,60));
90
		rightArm.setEnd(new Point(40,50));
91
		rightArm.setBounds(new Rectangle(0,0,40,130));
92
		
93
		person.add(head);
94
		person.add(body);
95
		person.add(leftLeg);
96
		person.add(rightLeg);
97
		person.add(leftArm);
98
		person.add(rightArm);
99
		person.setSize(40,130);
100
		return person;
101
	}
102
103
	public static void main(String[] args) {
104
		final Display d = new Display();
105
		Shell shell = new Shell(d);
106
		shell.setText("GraphSnippet11");
107
		shell.setLayout(new FillLayout());
108
		shell.setSize(400, 400);
109
110
		
111
		final Graph g = new Graph(shell, SWT.NONE);
112
		g.addSelectionListener(new SelectionListener(){
113
		
114
			public void widgetSelected(SelectionEvent e) {
115
				Iterator iter = g.getSelection().iterator();
116
				while(iter.hasNext()) {
117
					Object o = iter.next();
118
					if ( o instanceof CGraphNode) {
119
						IFigure figure = ((CGraphNode)o).getFigure();
120
						figure.setBackgroundColor(ColorConstants.blue);
121
						figure.setForegroundColor(ColorConstants.blue);
122
					}
123
				}
124
				iter = g.getNodes().iterator();
125
				while ( iter.hasNext()) {
126
					Object o = iter.next();
127
					if ( o instanceof CGraphNode) {
128
						if ( !g.getSelection().contains(o)) {
129
							((CGraphNode)o).getFigure().setBackgroundColor(ColorConstants.black);
130
							((CGraphNode)o).getFigure().setForegroundColor(ColorConstants.black);
131
						}
132
					}
133
				}
134
			}
135
		
136
			public void widgetDefaultSelected(SelectionEvent e) {
137
				// TODO Auto-generated method stub
138
				
139
			}
140
		});
141
		
142
		Image zx = new Image(d, "zxsnow.png");
143
		IFigure tooltip = new Figure();
144
		tooltip.setBorder(new MarginBorder(5,5,5,5));
145
		FlowLayout layout = new FlowLayout(false);
146
		layout.setMajorSpacing(3);
147
		layout.setMinorAlignment(3);
148
		tooltip.setLayoutManager(new FlowLayout(false));
149
		tooltip.add(new ImageFigure(zx));
150
		tooltip.add(new Label("Name: " + "Chris Aniszczyk"));
151
		tooltip.add(new Label("Location: " + "Austin, Texas"));
152
		
153
		Image ibull = new Image(d, "ibull.jpg");
154
		GraphContainer c1 = new GraphContainer(g, SWT.NONE);
155
		c1.setText("Canada");
156
		GraphContainer c2 = new GraphContainer(g, SWT.NONE);
157
		c2.setText("USA");
158
		
159
		GraphNode n1 = new GraphNode(c1, SWT.NONE, "Ian B.");
160
		n1.setSize(200, 100);
161
		GraphNode n2 = new GraphNode(c2, SWT.NONE, "Chris A.");
162
		n2.setTooltip(tooltip);
163
		
164
		GraphConnection connection = new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, n1, n2);
165
		connection.setCurveDepth(-30);
166
		GraphConnection connection2 = new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, n2, n1);
167
		connection2.setCurveDepth(-30);
168
		
169
		
170
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
171
172
		shell.open();
173
		while (!shell.isDisposed()) {
174
			while (!d.readAndDispatch()) {
175
				d.sleep();
176
			}
177
		}
178
		zx.dispose();
179
		ibull.dispose();
180
	}
181
182
}
(-)src/org/eclipse/zest/tests/swt/GraphSnippet4.java (-103 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.tests.swt;
12
13
import org.eclipse.draw2d.IFigure;
14
import org.eclipse.draw2d.Label;
15
import org.eclipse.zest.core.widgets.Graph;
16
import org.eclipse.zest.core.widgets.GraphConnection;
17
import org.eclipse.zest.core.widgets.GraphNode;
18
import org.eclipse.zest.core.widgets.ZestStyles;
19
import org.eclipse.swt.SWT;
20
import org.eclipse.swt.graphics.GC;
21
import org.eclipse.swt.graphics.Image;
22
import org.eclipse.swt.layout.FillLayout;
23
import org.eclipse.swt.widgets.Display;
24
import org.eclipse.swt.widgets.Shell;
25
26
/**
27
 * This snippet shows how a custom figure can be used as a ToolTip for connections.
28
 * Let your mouse hover over an edge to see the custom tooltip.
29
 * 
30
 * @author Ian Bull
31
 * 
32
 */
33
public class GraphSnippet4 {
34
	
35
	
36
	/**
37
	 * Merges 2 images so they appear beside each other
38
	 * 
39
	 * You must dispose this image!
40
	 * @param image1
41
	 * @param image2
42
	 * @param result
43
	 * @return
44
	 */
45
	public static Image mergeImages(Image image1, Image image2) {
46
		Image mergedImage = new Image(Display.getDefault(), image1.getBounds().width + image2.getBounds().width, image1.getBounds().height);
47
		GC gc = new GC(mergedImage);
48
		gc.drawImage(image1, 0, 0);
49
		gc.drawImage(image2, image1.getBounds().width, 0);
50
		gc.dispose();
51
		return mergedImage;
52
	}
53
	
54
55
	/**
56
	 * @param args
57
	 */
58
	public static void main(String[] args) {
59
		Display d = new Display();
60
		Shell shell = new Shell(d);
61
		shell.setText("Graph Snippet 4");
62
		Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION);
63
		Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
64
		Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR);
65
		shell.setLayout(new FillLayout());
66
		shell.setSize(400, 400);
67
68
		Graph g = new Graph(shell, SWT.NONE);
69
		g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED );
70
		GraphNode n1 = new GraphNode(g, SWT.NONE, "Information", image1);
71
		GraphNode n2 = new GraphNode(g, SWT.NONE, "Warning", image2);
72
		GraphNode n3 = new GraphNode(g, SWT.NONE, "Error", image3);
73
		
74
		GraphConnection connection1 = new GraphConnection(g, SWT.NONE, n1, n2);
75
		GraphConnection connection2 = new GraphConnection(g, SWT.NONE, n2, n3);
76
		
77
		Image information2warningImage = mergeImages(image1, image2);
78
		Image warning2error = mergeImages(image2, image3);
79
		IFigure tooltip1 = new Label("Information to Warning", information2warningImage);
80
		IFigure tooltip2 = new Label("Warning to Error", warning2error);
81
		connection1.setTooltip(tooltip1);
82
		connection2.setTooltip(tooltip2);
83
		
84
		n1.setLocation(10, 10);
85
		n2.setLocation(200, 10);
86
		n3.setLocation(200, 200);
87
88
		shell.open();
89
		while (!shell.isDisposed()) {
90
			while (!d.readAndDispatch()) {
91
				d.sleep();
92
			}
93
		}
94
		
95
		image1.dispose();
96
		image2.dispose();
97
		image3.dispose();
98
		
99
		information2warningImage.dispose();
100
		warning2error.dispose();
101
102
	}
103
}
(-)src/org/eclipse/zest/tests/swt/GraphSnippet2.java (-66 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.tests.swt;
12
13
import org.eclipse.zest.core.widgets.Graph;
14
import org.eclipse.zest.core.widgets.GraphConnection;
15
import org.eclipse.zest.core.widgets.GraphNode;
16
import org.eclipse.zest.core.widgets.ZestStyles;
17
import org.eclipse.zest.layouts.LayoutStyles;
18
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
19
import org.eclipse.swt.SWT;
20
import org.eclipse.swt.graphics.Image;
21
import org.eclipse.swt.layout.FillLayout;
22
import org.eclipse.swt.widgets.Display;
23
import org.eclipse.swt.widgets.Shell;
24
25
/**
26
 * This snippet creates a very simple graph with an Icon and Label.
27
 * 
28
 * This snippet shows how to use directed edges and self loops.
29
 * 
30
 * @author Ian Bull
31
 * 
32
 */
33
public class GraphSnippet2 {
34
35
	public static void main(String[] args) {
36
		Display d = new Display();
37
		Shell shell = new Shell(d);
38
		Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION);
39
		Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
40
		Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR);
41
		shell.setLayout(new FillLayout());
42
		shell.setSize(400, 400);
43
44
		Graph g = new Graph(shell, SWT.NONE);
45
		g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED);
46
		GraphNode n1 = new GraphNode(g, SWT.NONE, "Information", image1);
47
		GraphNode n2 = new GraphNode(g, SWT.NONE, "Warning", image2);
48
		GraphNode n3 = new GraphNode(g, SWT.NONE, "Error", image3);
49
50
		new GraphConnection(g, SWT.NONE, n1, n2);
51
		new GraphConnection(g, SWT.NONE, n2, n3);
52
		new GraphConnection(g, SWT.NONE, n3, n3);
53
54
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
55
56
		shell.open();
57
		while (!shell.isDisposed()) {
58
			while (!d.readAndDispatch()) {
59
				d.sleep();
60
			}
61
		}
62
		image1.dispose();
63
		image2.dispose();
64
		image3.dispose();
65
	}
66
}
(-)src/org/eclipse/zest/tests/swt/GraphSnippet5.java (-137 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
11
12
import java.util.ArrayList;
13
import java.util.HashMap;
14
import java.util.Iterator;
15
import java.util.List;
16
import java.util.Map;
17
18
import org.eclipse.draw2d.ColorConstants;
19
import org.eclipse.zest.core.widgets.Graph;
20
import org.eclipse.zest.core.widgets.GraphConnection;
21
import org.eclipse.zest.core.widgets.GraphItem;
22
import org.eclipse.zest.core.widgets.GraphNode;
23
import org.eclipse.zest.core.widgets.ZestStyles;
24
import org.eclipse.swt.SWT;
25
import org.eclipse.swt.events.KeyAdapter;
26
import org.eclipse.swt.events.KeyEvent;
27
import org.eclipse.swt.events.PaintEvent;
28
import org.eclipse.swt.events.PaintListener;
29
import org.eclipse.swt.graphics.Font;
30
import org.eclipse.swt.graphics.FontData;
31
import org.eclipse.swt.graphics.Image;
32
import org.eclipse.swt.graphics.Region;
33
import org.eclipse.swt.layout.FillLayout;
34
import org.eclipse.swt.widgets.Display;
35
import org.eclipse.swt.widgets.Shell;
36
37
/**
38
 * This snippet shows how you can add a paint listener to a Zest graph to paint on top of
39
 * the widget.  This snippet allows you to type and it selects all the nodes that match 
40
 * what you type.
41
 * 
42
 * @author Ian Bull
43
 * 
44
 */
45
public class GraphSnippet5 {
46
	public static final int BACKSPACE = 8;
47
	public static final int ENTER = 13;
48
49
	/**
50
	 * @param args
51
	 */
52
	public static void main(String[] args) {
53
		final Map figureListing = new HashMap();
54
		final StringBuffer stringBuffer = new StringBuffer();
55
		final Display d = new Display();
56
		FontData fontData = d.getSystemFont().getFontData()[0];
57
		fontData.height = 42;
58
59
		final Font font = new Font(d, fontData);
60
61
		Shell shell = new Shell(d);
62
		shell.setText("Graph Snippet 5");
63
		Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION);
64
		Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
65
		Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR);
66
		shell.setLayout(new FillLayout());
67
		shell.setSize(400, 400);
68
69
		final Graph g = new Graph(shell, SWT.NONE);
70
		g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED);
71
		GraphNode n1 = new GraphNode(g, SWT.NONE, "org.eclipse.Information", image1);
72
		GraphNode n2 = new GraphNode(g, SWT.NONE, "org.eclipse.Warning", image2);
73
		GraphNode n3 = new GraphNode(g, SWT.NONE, "org.eclipse.Error", image3);
74
		figureListing.put(n1.getText().toLowerCase(), n1);
75
		figureListing.put(n2.getText().toLowerCase(), n2);
76
		figureListing.put(n3.getText().toLowerCase(), n3);
77
78
		new GraphConnection(g, SWT.NONE, n1, n2);
79
		new GraphConnection(g, SWT.NONE, n2, n3);
80
		n1.setLocation(10, 10);
81
		n2.setLocation(200, 10);
82
		n3.setLocation(200, 200);
83
84
		g.addKeyListener(new KeyAdapter() {
85
86
			public void keyPressed(KeyEvent e) {
87
				boolean complete = false;
88
				if (e.keyCode == BACKSPACE) {
89
					if (stringBuffer.length() > 0) {
90
						stringBuffer.deleteCharAt(stringBuffer.length() - 1);
91
					}
92
				} else if (e.keyCode == ENTER) {
93
					complete = true;
94
				} else if ((e.character >= 'a' && e.character <= 'z') || (e.character >= 'A' && e.character <= 'Z') || (e.character == '.') || (e.character >= '0' && e.character <= '9')) {
95
					stringBuffer.append(e.character);
96
				}
97
				Iterator iterator = figureListing.keySet().iterator();
98
				List list = new ArrayList();
99
				if (stringBuffer.length() > 0) {
100
					while (iterator.hasNext()) {
101
						String string = (String) iterator.next();
102
						if (string.indexOf(stringBuffer.toString().toLowerCase()) >= 0) {
103
							list.add(figureListing.get(string));
104
						}
105
					}
106
				}
107
				g.setSelection((GraphItem[]) list.toArray(new GraphItem[list.size()]));
108
				if (complete && stringBuffer.length() > 0) {
109
					stringBuffer.delete(0, stringBuffer.length());
110
				}
111
112
				g.redraw();
113
			}
114
115
		});
116
117
		g.addPaintListener(new PaintListener() {
118
			public void paintControl(PaintEvent e) {
119
				e.gc.setFont(font);
120
				e.gc.setClipping((Region) null);
121
				e.gc.setForeground(ColorConstants.black);
122
				e.gc.drawText(stringBuffer.toString(), 50, 50, true);
123
			}
124
		});
125
126
		shell.open();
127
		while (!shell.isDisposed()) {
128
			while (!d.readAndDispatch()) {
129
				d.sleep();
130
			}
131
		}
132
		image1.dispose();
133
		image2.dispose();
134
		image3.dispose();
135
		font.dispose();
136
	}
137
}
(-)src/org/eclipse/zest/tests/swt/GraphSnippet1.java (-60 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
11
12
import org.eclipse.zest.core.widgets.Graph;
13
import org.eclipse.zest.core.widgets.GraphConnection;
14
import org.eclipse.zest.core.widgets.GraphNode;
15
import org.eclipse.zest.layouts.LayoutStyles;
16
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
17
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.layout.FillLayout;
19
import org.eclipse.swt.widgets.Display;
20
import org.eclipse.swt.widgets.Shell;
21
22
/**
23
 * This snippet creates a very simple graph where Rock is connected to Paper
24
 * which is connected to scissors which is connected to rock.
25
 * 
26
 * The nodes a positioned using a SpringLayout Algorithm, and they can be moved
27
 * around.
28
 * 
29
 * 
30
 * @author Ian Bull
31
 * 
32
 */
33
public class GraphSnippet1 {
34
35
	public static void main(String[] args) {
36
		Display d = new Display();
37
		Shell shell = new Shell(d);
38
		shell.setText("GraphSnippet1");
39
		shell.setLayout(new FillLayout());
40
		shell.setSize(400, 400);
41
42
		Graph g = new Graph(shell, SWT.NONE);
43
44
		GraphNode n = new GraphNode(g, SWT.NONE, "Paper");
45
		GraphNode n2 = new GraphNode(g, SWT.NONE, "Rock");
46
		GraphNode n3 = new GraphNode(g, SWT.NONE, "Scissors");
47
		new GraphConnection(g, SWT.NONE, n, n2);
48
		new GraphConnection(g, SWT.NONE, n2, n3);
49
		new GraphConnection(g, SWT.NONE, n3, n);
50
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
51
52
		shell.open();
53
		while (!shell.isDisposed()) {
54
			while (!d.readAndDispatch()) {
55
				d.sleep();
56
			}
57
		}
58
	}
59
60
}
(-)src/org/eclipse/zest/tests/swt/GraphSnippet9.java (-54 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
11
12
import org.eclipse.swt.SWT;
13
import org.eclipse.swt.layout.FillLayout;
14
import org.eclipse.swt.widgets.Display;
15
import org.eclipse.swt.widgets.Shell;
16
import org.eclipse.zest.core.widgets.Graph;
17
import org.eclipse.zest.core.widgets.GraphConnection;
18
import org.eclipse.zest.core.widgets.GraphNode;
19
import org.eclipse.zest.core.widgets.ZestStyles;
20
21
/**
22
 * This snippet demonstrates a self loop with a label.
23
 * 
24
 * @author Ian Bull
25
 * 
26
 */
27
public class GraphSnippet9 {
28
29
	/**
30
	 * @param args
31
	 */
32
	public static void main(String[] args) {
33
		Display display = new Display();
34
		Shell shell = new Shell(display);
35
		shell.setText("GraphSnippet9");
36
		shell.setLayout(new FillLayout());
37
		shell.setSize(400, 400);
38
39
		final Graph graph = new Graph(shell, SWT.NONE);
40
41
		GraphNode a = new GraphNode(graph, ZestStyles.CONNECTIONS_DIRECTED, "Root");
42
		GraphConnection connection = new GraphConnection(graph, SWT.NONE, a, a);
43
		connection.setText("A to A");
44
		a.setLocation(100, 100);
45
46
		shell.open();
47
		while (!shell.isDisposed()) {
48
			while (!display.readAndDispatch()) {
49
				display.sleep();
50
			}
51
		}
52
	}
53
54
}
(-)src/org/eclipse/zest/tests/swt/LayoutExample.java (-86 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
11
12
import org.eclipse.zest.core.widgets.ConstraintAdapter;
13
import org.eclipse.zest.core.widgets.Graph;
14
import org.eclipse.zest.core.widgets.GraphConnection;
15
import org.eclipse.zest.core.widgets.GraphNode;
16
import org.eclipse.zest.layouts.LayoutStyles;
17
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
18
import org.eclipse.zest.layouts.constraints.BasicEdgeConstraints;
19
import org.eclipse.zest.layouts.constraints.LayoutConstraint;
20
import org.eclipse.swt.SWT;
21
import org.eclipse.swt.layout.FillLayout;
22
import org.eclipse.swt.widgets.Display;
23
import org.eclipse.swt.widgets.Shell;
24
25
/**
26
 * This snippet shows how to use the findFigureAt to get the figure under the
27
 * mouse
28
 * 
29
 * @author Ian Bull
30
 * 
31
 */
32
public class LayoutExample {
33
34
	/**
35
	 * @param args
36
	 */
37
	public static void main(String[] args) {
38
		// Create the shell
39
		Display d = new Display();
40
		Shell shell = new Shell(d);
41
		shell.setText("GraphSnippet1");
42
		shell.setLayout(new FillLayout());
43
		shell.setSize(400, 400);
44
45
		final Graph g = new Graph(shell, SWT.NONE);
46
		GraphNode root = new GraphNode(g, SWT.NONE, "Root");
47
		for (int i = 0; i < 3; i++) {
48
			GraphNode n = new GraphNode(g, SWT.NONE, "1 - " + i);
49
			for (int j = 0; j < 3; j++) {
50
				GraphNode n2 = new GraphNode(g, SWT.NONE, "2 - " + j);
51
				new GraphConnection(g, SWT.NONE, n, n2);
52
			}
53
			new GraphConnection(g, SWT.NONE, root, n);
54
		}
55
56
		SpringLayoutAlgorithm springLayoutAlgorithm = new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING);
57
58
		ConstraintAdapter constraintAdapters = new ConstraintAdapter() {
59
60
			public void populateConstraint(Object object, LayoutConstraint constraint) {
61
				if (constraint instanceof BasicEdgeConstraints) {
62
					BasicEdgeConstraints basicEdgeConstraints = (BasicEdgeConstraints) constraint;
63
					GraphConnection connection = (GraphConnection) object;
64
					if (connection.getSource().getText().equals("Root")) {
65
						basicEdgeConstraints.weight = 1;
66
					}
67
					else {
68
						basicEdgeConstraints.weight = -1;
69
					}
70
				}
71
72
			}
73
		};
74
75
		g.addConstraintAdapter(constraintAdapters);
76
		g.setLayoutAlgorithm(springLayoutAlgorithm, true);
77
78
		shell.open();
79
		while (!shell.isDisposed()) {
80
			while (!d.readAndDispatch()) {
81
				d.sleep();
82
			}
83
		}
84
	}
85
86
}
(-)src/org/eclipse/zest/tests/swt/GraphSnippet6.java (-71 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.tests.swt;
12
13
import org.eclipse.zest.core.widgets.Graph;
14
import org.eclipse.zest.core.widgets.GraphConnection;
15
import org.eclipse.zest.core.widgets.GraphNode;
16
import org.eclipse.zest.core.widgets.ZestStyles;
17
import org.eclipse.zest.layouts.LayoutStyles;
18
import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm;
19
import org.eclipse.swt.SWT;
20
import org.eclipse.swt.graphics.Image;
21
import org.eclipse.swt.layout.FillLayout;
22
import org.eclipse.swt.widgets.Display;
23
import org.eclipse.swt.widgets.Shell;
24
25
/**
26
 * This snippet creates a graph with 80*3 nodes (240 nodes).  Only the icons are shown for the nodes, but if
27
 * you mouse over the node you get the entire text.
28
 * 
29
 * @author Ian Bull
30
 * 
31
 */
32
public class GraphSnippet6 {
33
34
	/**
35
	 * @param args
36
	 */
37
	public static void main(String[] args) {
38
		Display d = new Display();
39
		Shell shell = new Shell(d);
40
		shell.setText("GraphSnippet6");
41
		Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION);
42
		Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
43
		Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR);
44
		shell.setLayout(new FillLayout());
45
		shell.setSize(800, 800);
46
47
		Graph g = new Graph(shell, SWT.NONE);
48
		g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED);
49
		for (int i = 0; i < 80; i++) {
50
			GraphNode n1 = new GraphNode(g, ZestStyles.NODES_HIDE_TEXT | ZestStyles.NODES_FISHEYE, "Information", image1);
51
			GraphNode n2 = new GraphNode(g, ZestStyles.NODES_HIDE_TEXT | ZestStyles.NODES_FISHEYE, "Warning", image2);
52
			GraphNode n3 = new GraphNode(g, ZestStyles.NODES_HIDE_TEXT | ZestStyles.NODES_FISHEYE, "Error", image3);
53
			new GraphConnection(g, SWT.NONE, n1, n2);
54
			new GraphConnection(g, SWT.NONE, n2, n3);
55
			new GraphConnection(g, SWT.NONE, n3, n3);
56
		}
57
		g.setLayoutAlgorithm(new GridLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
58
59
		shell.open();
60
		while (!shell.isDisposed()) {
61
			while (!d.readAndDispatch()) {
62
				d.sleep();
63
			}
64
		}
65
		image1.dispose();
66
		image2.dispose();
67
		image3.dispose();
68
69
	}
70
71
}
(-)src/org/eclipse/zest/tests/swt/GraphSnippet11.java (-69 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
11
12
import org.eclipse.draw2d.ColorConstants;
13
import org.eclipse.swt.SWT;
14
import org.eclipse.swt.graphics.Color;
15
import org.eclipse.swt.layout.FillLayout;
16
import org.eclipse.swt.widgets.Display;
17
import org.eclipse.swt.widgets.Shell;
18
import org.eclipse.zest.core.widgets.Graph;
19
import org.eclipse.zest.core.widgets.GraphConnection;
20
import org.eclipse.zest.core.widgets.GraphNode;
21
import org.eclipse.zest.core.widgets.ZestStyles;
22
import org.eclipse.zest.layouts.LayoutStyles;
23
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
24
25
/**
26
 * 
27
 * This snippet shows how to create a curved connection using Zest.
28
 * 
29
 * @author Ian Bull
30
 * 
31
 */
32
public class GraphSnippet11 {
33
34
35
	public static void createConnection( Graph g, GraphNode n1, GraphNode n2, Color color, int curve) {
36
		GraphConnection connection = new GraphConnection(g, SWT.NONE, n1, n2);
37
		connection.setLineColor(color);
38
		connection.setCurveDepth(curve);
39
		connection.setLineWidth(1);
40
	}
41
	
42
	public static void main(String[] args) {
43
		Display d = new Display();
44
		Shell shell = new Shell(d);
45
		shell.setText("GraphSnippet11");
46
		shell.setLayout(new FillLayout());
47
		shell.setSize(400, 400);
48
49
		final Graph g = new Graph(shell, SWT.NONE);
50
		GraphNode n = new GraphNode(g, SWT.NONE, "Node 1");
51
		GraphNode n2 = new GraphNode(g, SWT.NONE, "Node 2");
52
		createConnection(g, n, n2, ColorConstants.darkGreen, 20);
53
		createConnection(g, n, n2, ColorConstants.darkGreen, -20);
54
		createConnection(g, n, n2, ColorConstants.darkBlue, 40);
55
		createConnection(g, n, n2, ColorConstants.darkBlue, -40);
56
		createConnection(g, n, n2, ColorConstants.darkGray, 60);
57
		createConnection(g, n, n2, ColorConstants.darkGray, -60);
58
		createConnection(g, n, n2, ColorConstants.black, 0);
59
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
60
61
		shell.open();
62
		while (!shell.isDisposed()) {
63
			while (!d.readAndDispatch()) {
64
				d.sleep();
65
			}
66
		}
67
	}
68
69
}
(-)src/org/eclipse/zest/tests/swt/HelloWorld.java (-4 / +5 lines)
Lines 1-18 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 ******************************************************************************/
11
 ******************************************************************************/
10
package org.eclipse.zest.tests.swt;
12
package org.eclipse.zest.tests.swt;
11
13
12
import org.eclipse.zest.core.widgets.Graph;
14
import org.eclipse.zest.core.widgets.Graph;
13
import org.eclipse.zest.core.widgets.GraphConnection;
15
import org.eclipse.zest.core.widgets.GraphConnection;
14
import org.eclipse.zest.core.widgets.GraphNode;
16
import org.eclipse.zest.core.widgets.GraphNode;
15
import org.eclipse.zest.layouts.LayoutStyles;
16
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
17
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
17
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.layout.FillLayout;
19
import org.eclipse.swt.layout.FillLayout;
Lines 41-47 Link Here
41
		GraphNode hello = new GraphNode(g, SWT.NONE, "Hello");
42
		GraphNode hello = new GraphNode(g, SWT.NONE, "Hello");
42
		GraphNode world = new GraphNode(g, SWT.NONE, "World");
43
		GraphNode world = new GraphNode(g, SWT.NONE, "World");
43
		new GraphConnection(g, SWT.NONE, hello, world);
44
		new GraphConnection(g, SWT.NONE, hello, world);
44
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
45
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true);
45
46
46
		shell.open();
47
		shell.open();
47
		while (!shell.isDisposed()) {
48
		while (!shell.isDisposed()) {
(-)src/org/eclipse/zest/tests/uml/UMLExample.java (-12 / +22 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 7-25 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
10
 *******************************************************************************/
11
 *******************************************************************************/
11
package org.eclipse.zest.tests.uml;
12
package org.eclipse.zest.tests.uml;
12
13
13
import org.eclipse.draw2d.IFigure;
14
import org.eclipse.draw2d.IFigure;
14
import org.eclipse.draw2d.Label;
15
import org.eclipse.draw2d.Label;
15
import org.eclipse.zest.core.widgets.Graph;
16
import org.eclipse.draw2d.geometry.Dimension;
16
import org.eclipse.zest.core.widgets.GraphConnection;
17
import org.eclipse.zest.core.widgets.GraphContainer;
18
import org.eclipse.zest.core.widgets.GraphNode;
19
import org.eclipse.zest.core.widgets.IContainer;
20
import org.eclipse.zest.core.widgets.ZestStyles;
21
import org.eclipse.zest.layouts.LayoutStyles;
22
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
23
import org.eclipse.swt.SWT;
17
import org.eclipse.swt.SWT;
24
import org.eclipse.swt.graphics.Color;
18
import org.eclipse.swt.graphics.Color;
25
import org.eclipse.swt.graphics.Font;
19
import org.eclipse.swt.graphics.Font;
Lines 27-32 Link Here
27
import org.eclipse.swt.layout.FillLayout;
21
import org.eclipse.swt.layout.FillLayout;
28
import org.eclipse.swt.widgets.Display;
22
import org.eclipse.swt.widgets.Display;
29
import org.eclipse.swt.widgets.Shell;
23
import org.eclipse.swt.widgets.Shell;
24
import org.eclipse.zest.core.widgets.Graph;
25
import org.eclipse.zest.core.widgets.GraphConnection;
26
import org.eclipse.zest.core.widgets.GraphContainer;
27
import org.eclipse.zest.core.widgets.GraphNode;
28
import org.eclipse.zest.core.widgets.ZestStyles;
29
import org.eclipse.zest.layouts.LayoutAlgorithm;
30
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
31
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
30
32
31
/**
33
/**
32
 * Adds a selection listener to the nodes to tell when a selection event has
34
 * Adds a selection listener to the nodes to tell when a selection event has
Lines 82-94 Link Here
82
84
83
		IFigure customFigure = null;
85
		IFigure customFigure = null;
84
86
85
		public UMLNode(IContainer graphModel, int style, IFigure figure) {
87
		public UMLNode(Graph graphModel, int style, IFigure figure) {
88
			super(graphModel, style, figure);
89
		}
90
		
91
		public UMLNode(GraphContainer graphModel, int style, IFigure figure) {
86
			super(graphModel, style, figure);
92
			super(graphModel, style, figure);
87
		}
93
		}
88
94
89
		protected IFigure createFigureForModel() {
95
		protected IFigure createFigureForModel() {
90
			return (IFigure) this.getData();
96
			return (IFigure) this.getData();
91
		}
97
		}
98
		
99
		public Dimension getSize() {
100
			return ((IFigure) this.getData()).getPreferredSize();
101
		}
92
102
93
	}
103
	}
94
104
Lines 119-126 Link Here
119
		new GraphConnection(g, SWT.NONE, n1, n2);
129
		new GraphConnection(g, SWT.NONE, n1, n2);
120
		new GraphConnection(g, SWT.NONE, n, n1);
130
		new GraphConnection(g, SWT.NONE, n, n1);
121
131
122
		c.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
132
		c.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true);
123
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
133
		g.setLayoutAlgorithm(new TreeLayoutAlgorithm(), true);
124
134
125
		shell.open();
135
		shell.open();
126
		while (!shell.isDisposed()) {
136
		while (!shell.isDisposed()) {
(-)src/org/eclipse/zest/tests/jface/GraphJFaceSnippet3.java (-135 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.jface;
11
12
import java.io.BufferedReader;
13
import java.io.File;
14
import java.io.FileReader;
15
import java.io.IOException;
16
import java.util.ArrayList;
17
import java.util.StringTokenizer;
18
19
import org.eclipse.jface.viewers.LabelProvider;
20
import org.eclipse.jface.viewers.Viewer;
21
import org.eclipse.zest.core.viewers.GraphViewer;
22
import org.eclipse.zest.core.viewers.IGraphContentProvider;
23
import org.eclipse.zest.layouts.LayoutStyles;
24
import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm;
25
import org.eclipse.swt.SWT;
26
import org.eclipse.swt.layout.FillLayout;
27
import org.eclipse.swt.widgets.Display;
28
import org.eclipse.swt.widgets.FileDialog;
29
import org.eclipse.swt.widgets.Shell;
30
31
/**
32
 * This snippet uses a very simple file format to read a graph. Edges are listed
33
 * on a new line in a file as such: 
34
 * a calls b 
35
 * b calls c 
36
 * c calld d
37
 * 
38
 * The content provider creates an edge for each line in the file and names the
39
 * sources and destination from the line.
40
 * 
41
 * 
42
 * @author Ian Bull
43
 * 
44
 */
45
public class GraphJFaceSnippet3 {
46
47
	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";
48
49
	static class SimpleGraphContentProvider implements IGraphContentProvider {
50
51
		private StringTokenizer graph;
52
53
		public Object getDestination(Object rel) {
54
			String string = (String) rel;
55
			String[] parts = string.split(" ");
56
			return parts[2];
57
		}
58
59
		public Object[] getElements(Object input) {
60
			ArrayList listOfEdges = new ArrayList();
61
			while (graph.hasMoreTokens()) {
62
				listOfEdges.add(graph.nextToken());
63
			}
64
			return listOfEdges.toArray();
65
		}
66
67
		public Object getSource(Object rel) {
68
			String string = (String) rel;
69
			String[] parts = string.split(" ");
70
			return parts[0];
71
		}
72
73
		public double getWeight(Object connection) {
74
			return 0;
75
		}
76
77
		public void dispose() {
78
79
		}
80
81
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
82
			if (newInput != null) {
83
				graph = new StringTokenizer((String) newInput, "\n");
84
			}
85
		}
86
87
	}
88
89
	public static void main(String[] args) throws IOException {
90
		Display display = new Display();
91
		Shell shell = new Shell(display);
92
		shell.setText("Simple Graph File Format");
93
94
		FileDialog dialog = new FileDialog(shell, SWT.OPEN);
95
		dialog.setFilterNames(new String[] { "Simple Graph Files (*.sgf)", "All Files (*.*)" });
96
		dialog.setFilterExtensions(new String[] { "*.sgf", "*.*" }); //Windows wild cards
97
98
		String directory = System.getProperty("user.dir") + "/src/org/eclipse/zest/tests/jface/SimpleGraph.sgf"; //eclipse/zest/examples/jface/";
99
		System.out.println(directory);
100
		dialog.setFilterPath(directory);
101
		//dialog.setFilterPath(System.getProperty("user.dir") + "src/org/eclipse/zest/examples/jface/"); //Windows path
102
103
		shell.setLayout(new FillLayout(SWT.VERTICAL));
104
		shell.setSize(400, 400);
105
		GraphViewer viewer = null;
106
107
		viewer = new GraphViewer(shell, SWT.NONE);
108
		viewer.setContentProvider(new SimpleGraphContentProvider());
109
		viewer.setLabelProvider(new LabelProvider());
110
		viewer.setLayoutAlgorithm(new RadialLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING));
111
112
		shell.open();
113
		String fileName = dialog.open();
114
115
		if (fileName == null) {
116
			// use the sample graph
117
			viewer.setInput(graph);
118
		} else {
119
			FileReader fileReader = new FileReader(new File(fileName));
120
			BufferedReader bufferedReader = new BufferedReader(fileReader);
121
			StringBuffer stringBuffer = new StringBuffer();
122
			while (bufferedReader.ready()) {
123
				stringBuffer.append(bufferedReader.readLine() + "\n");
124
			}
125
			viewer.setInput(stringBuffer.toString());
126
		}
127
128
		while (!shell.isDisposed()) {
129
			if (!display.readAndDispatch()) {
130
				display.sleep();
131
			}
132
		}
133
		display.dispose();
134
	}
135
}
(-)src/org/eclipse/zest/tests/jface/GraphJFaceSnippet1.java (-6 / +6 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 7-12 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
10
 *******************************************************************************/
11
 *******************************************************************************/
11
package org.eclipse.zest.tests.jface;
12
package org.eclipse.zest.tests.jface;
12
13
Lines 14-23 Link Here
14
import org.eclipse.jface.viewers.LabelProvider;
15
import org.eclipse.jface.viewers.LabelProvider;
15
import org.eclipse.jface.viewers.SelectionChangedEvent;
16
import org.eclipse.jface.viewers.SelectionChangedEvent;
16
import org.eclipse.jface.viewers.Viewer;
17
import org.eclipse.jface.viewers.Viewer;
17
import org.eclipse.zest.layouts.LayoutStyles;
18
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
19
import org.eclipse.zest.core.viewers.GraphViewer;
20
import org.eclipse.zest.core.viewers.IGraphEntityContentProvider;
21
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.SWT;
22
import org.eclipse.swt.events.SelectionAdapter;
19
import org.eclipse.swt.events.SelectionAdapter;
23
import org.eclipse.swt.events.SelectionEvent;
20
import org.eclipse.swt.events.SelectionEvent;
Lines 26-31 Link Here
26
import org.eclipse.swt.widgets.Button;
23
import org.eclipse.swt.widgets.Button;
27
import org.eclipse.swt.widgets.Display;
24
import org.eclipse.swt.widgets.Display;
28
import org.eclipse.swt.widgets.Shell;
25
import org.eclipse.swt.widgets.Shell;
26
import org.eclipse.zest.core.viewers.GraphViewer;
27
import org.eclipse.zest.core.viewers.IGraphEntityContentProvider;
28
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
29
29
30
/**
30
/**
31
 * This snippet shows how to use the IGraphEntityContentProvider to build a graph.  
31
 * This snippet shows how to use the IGraphEntityContentProvider to build a graph.  
Lines 113-119 Link Here
113
113
114
		viewer.setContentProvider(new MyContentProvider());
114
		viewer.setContentProvider(new MyContentProvider());
115
		viewer.setLabelProvider(new MyLabelProvider());
115
		viewer.setLabelProvider(new MyLabelProvider());
116
		viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING));
116
		viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm());
117
		viewer.addSelectionChangedListener(new ISelectionChangedListener() {
117
		viewer.addSelectionChangedListener(new ISelectionChangedListener() {
118
			public void selectionChanged(SelectionChangedEvent event) {
118
			public void selectionChanged(SelectionChangedEvent event) {
119
				System.out.println("Selection changed: " + (event.getSelection()));
119
				System.out.println("Selection changed: " + (event.getSelection()));
(-)src/org/eclipse/zest/tests/jface/GraphJFaceSnippet7.java (-182 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.jface;
11
12
13
import org.eclipse.draw2d.IFigure;
14
import org.eclipse.draw2d.Label;
15
import org.eclipse.jface.viewers.LabelProvider;
16
import org.eclipse.jface.viewers.Viewer;
17
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.events.SelectionEvent;
19
import org.eclipse.swt.events.SelectionListener;
20
import org.eclipse.swt.graphics.Font;
21
import org.eclipse.swt.graphics.Image;
22
import org.eclipse.swt.layout.FillLayout;
23
import org.eclipse.swt.widgets.Button;
24
import org.eclipse.swt.widgets.Display;
25
import org.eclipse.swt.widgets.Shell;
26
import org.eclipse.zest.core.viewers.EntityConnectionData;
27
import org.eclipse.zest.core.viewers.GraphViewer;
28
import org.eclipse.zest.core.viewers.IFigureProvider;
29
import org.eclipse.zest.core.viewers.IGraphEntityContentProvider;
30
import org.eclipse.zest.core.viewers.INestedContentProvider;
31
import org.eclipse.zest.layouts.LayoutStyles;
32
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
33
import org.eclipse.zest.tests.uml.UMLClassFigure;
34
35
/**
36
 * This snippet shows how to use the INestedGraphContentProvider to create a graph
37
 * with Zest. In this example, getElements returns 3 edges: * Rock2Paper *
38
 * Paper2Scissors * Scissors2Rock
39
 * 
40
 * And for each of these, the source and destination are returned in getSource
41
 * and getDestination.
42
 * 
43
 * A label provider is also used to create the text and icons for the graph.
44
 * 
45
 * @author Ian Bull
46
 * 
47
 */
48
public class GraphJFaceSnippet7 {
49
50
	public static IFigure createClassFigure1(Font classFont, Image classImage, Image publicField, Image privateField) {
51
		Label classLabel1 = new Label("Table", classImage);
52
		classLabel1.setFont(classFont);
53
54
		UMLClassFigure classFigure = new UMLClassFigure(classLabel1);
55
		Label attribute1 = new Label("columns: Column[]", privateField);
56
57
		Label attribute2 = new Label("rows: Row[]", privateField);
58
59
		Label method1 = new Label("getColumns(): Column[]", publicField);
60
		Label method2 = new Label("getRows(): Row[]", publicField);
61
		classFigure.getAttributesCompartment().add(attribute1);
62
		classFigure.getAttributesCompartment().add(attribute2);
63
		classFigure.getMethodsCompartment().add(method1);
64
		classFigure.getMethodsCompartment().add(method2);
65
		classFigure.setSize(-1, -1);
66
67
		return classFigure;
68
	}
69
	
70
	static class MyContentProvider implements IGraphEntityContentProvider, INestedContentProvider {
71
72
		public Object[] getConnectedTo(Object entity) {
73
			if (entity.equals("First")) {
74
				return new Object[] { "Second" };
75
			}
76
			if (entity.equals("Second")) {
77
				return new Object[] { "Third", "rock" };
78
			}
79
			if (entity.equals("Third")) {
80
				return new Object[] { "First" };
81
			}
82
			if ( entity.equals("rock")) {
83
				return new Object[] { "paper" };
84
			}
85
			return null;
86
		}
87
88
		public Object[] getElements(Object inputElement) {
89
			return new String[] { "First", "Second", "Third" };
90
		}
91
92
		public double getWeight(Object entity1, Object entity2) {
93
			return 0;
94
		}
95
96
		public void dispose() {
97
98
		}
99
100
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
101
102
		}
103
104
		public Object[] getChildren(Object element) {
105
			// TODO Auto-generated method stub
106
			return new Object[] {"rock", "paper", "scissors"};
107
		}
108
109
		public boolean hasChildren(Object element) {
110
			// TODO Auto-generated method stub
111
			if ( element.equals("First")) return true;
112
			return false;
113
		}
114
115
	}
116
117
118
	
119
	static class MyLabelProvider extends LabelProvider implements IFigureProvider {
120
		final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
121
122
		public Image getImage(Object element) {
123
			if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) {
124
				return image;
125
			}
126
			return null;
127
		}
128
129
		public String getText(Object element) {
130
			if ( element instanceof EntityConnectionData ) return "";
131
			return element.toString();
132
		}
133
		
134
		public IFigure getFigure(Object element) {
135
			Font classFont = new Font(null, "Arial", 12, SWT.BOLD);
136
			Image classImage = new Image(Display.getDefault(), UMLClassFigure.class.getResourceAsStream("class_obj.gif"));
137
			Image privateField = new Image(Display.getDefault(), UMLClassFigure.class.getResourceAsStream("field_private_obj.gif"));
138
			Image publicField= new Image(Display.getDefault(), UMLClassFigure.class.getResourceAsStream("methpub_obj.gif"));
139
			return createClassFigure1(classFont, classImage, publicField, privateField);
140
		}
141
142
	}
143
144
	static GraphViewer viewer = null;
145
146
	/**
147
	 * @param args
148
	 */
149
	public static void main(String[] args) {
150
		Display d = new Display();
151
		Shell shell = new Shell(d);
152
		shell.setText("GraphJFaceSnippet2");
153
		shell.setLayout(new FillLayout(SWT.VERTICAL));
154
		shell.setSize(400, 400);
155
		viewer = new GraphViewer(shell, SWT.NONE);
156
		viewer.setContentProvider(new MyContentProvider());
157
		viewer.setLabelProvider(new MyLabelProvider());
158
		viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING));
159
		viewer.setInput(new Object());
160
		
161
		Button button = new Button(shell, SWT.PUSH);
162
		button.setText("push");
163
		button.addSelectionListener(new SelectionListener() {
164
165
			public void widgetDefaultSelected(SelectionEvent e) {
166
			}
167
168
			public void widgetSelected(SelectionEvent e) {
169
				viewer.setInput(new Object());
170
			}
171
			
172
		});
173
		shell.open();
174
		while (!shell.isDisposed()) {
175
			while (!d.readAndDispatch()) {
176
				d.sleep();
177
			}
178
		}
179
180
	}
181
182
}
(-)src/org/eclipse/zest/tests/jface/GraphJFaceSnippet5.java (-141 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.jface;
11
12
import org.eclipse.jface.viewers.LabelProvider;
13
import org.eclipse.jface.viewers.Viewer;
14
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
15
import org.eclipse.zest.core.viewers.GraphViewer;
16
import org.eclipse.zest.core.viewers.IGraphContentProvider;
17
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.events.SelectionAdapter;
19
import org.eclipse.swt.events.SelectionEvent;
20
import org.eclipse.swt.graphics.Image;
21
import org.eclipse.swt.layout.FillLayout;
22
import org.eclipse.swt.layout.GridData;
23
import org.eclipse.swt.layout.GridLayout;
24
import org.eclipse.swt.widgets.Button;
25
import org.eclipse.swt.widgets.Composite;
26
import org.eclipse.swt.widgets.Display;
27
import org.eclipse.swt.widgets.Shell;
28
29
/**
30
 * This snippet shows how the refresh works on a Zest viewer.
31
 */
32
public class GraphJFaceSnippet5 {
33
34
	static class MyContentProvider implements IGraphContentProvider {
35
36
		Object[] elements = new Object[] { "Rock2Paper", "Paper2Scissors", "Scissors2Rock" };
37
38
		public Object getDestination(Object rel) {
39
			if ("Rock2Paper".equals(rel)) {
40
				return "Rock";
41
			} else if ("Paper2Scissors".equals(rel) || "Scissors2Paper".equals(rel)) {
42
				return "Paper";
43
			} else if ("Scissors2Rock".equals(rel)) {
44
				return "Scissors";
45
			}
46
			return null;
47
		}
48
49
		public Object[] getElements(Object input) {
50
			return elements;
51
		}
52
53
		public Object getSource(Object rel) {
54
			if ("Rock2Paper".equals(rel)) {
55
				return "Paper";
56
			} else if ("Paper2Scissors".equals(rel) || "Scissors2Paper".equals(rel)) {
57
				return "Scissors";
58
			} else if ("Scissors2Rock".equals(rel)) {
59
				return "Rock";
60
			}
61
			return null;
62
		}
63
64
		public void setElements(Object[] elements) {
65
			this.elements = elements;
66
		}
67
68
		public double getWeight(Object connection) {
69
			return 0;
70
		}
71
72
		public void dispose() {
73
		}
74
75
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
76
		}
77
78
	}
79
80
	static class MyLabelProvider extends LabelProvider {
81
		final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING);	
82
		
83
		public MyLabelProvider() {
84
			
85
		}
86
		
87
		public String getText(Object element) {
88
			return element.toString();
89
		}
90
		
91
		public Image getImage(Object element) {
92
			return image;
93
		}
94
	}
95
96
	static GraphViewer viewer = null;
97
	private static MyContentProvider contentProvider;
98
99
	/**
100
	 * @param args
101
	 */
102
	public static void main(String[] args) {
103
		Display d = new Display();
104
		Shell shell = new Shell(d);
105
		shell.setText("GraphJFaceSnippet2");
106
		shell.setLayout(new FillLayout(SWT.VERTICAL));
107
		shell.setSize(400, 400);
108
		Composite parent = new Composite(shell, SWT.NONE);
109
		parent.setLayout(new GridLayout(2, false));
110
		buildViewer(parent);
111
		buildButton(parent);
112
		shell.open();
113
		while (!shell.isDisposed()) {
114
			while (!d.readAndDispatch()) {
115
				d.sleep();
116
			}
117
		}
118
119
	}
120
121
	private static void buildButton(Composite parent) {
122
		Button button = new Button(parent, SWT.PUSH);
123
		button.setText("Refresh");
124
		button.addSelectionListener(new SelectionAdapter() {
125
			public void widgetSelected(SelectionEvent e) {
126
				contentProvider.setElements(new Object[] { "Rock2Paper", "Scissors2Paper", "Scissors2Rock" });
127
				viewer.refresh();
128
			}
129
		});
130
	}
131
132
	private static void buildViewer(Composite parent) {
133
		viewer = new GraphViewer(parent, SWT.NONE);
134
		viewer.getGraphControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
135
		contentProvider = new MyContentProvider();
136
		viewer.setContentProvider(contentProvider);
137
		viewer.setLabelProvider(new MyLabelProvider());
138
		viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm());
139
		viewer.setInput(new Object());
140
	}
141
}
(-)src/org/eclipse/zest/tests/jface/GraphJFaceSnippet2.java (-4 / +5 lines)
Lines 1-17 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 ******************************************************************************/
11
 ******************************************************************************/
10
package org.eclipse.zest.tests.jface;
12
package org.eclipse.zest.tests.jface;
11
13
12
import org.eclipse.jface.viewers.LabelProvider;
14
import org.eclipse.jface.viewers.LabelProvider;
13
import org.eclipse.jface.viewers.Viewer;
15
import org.eclipse.jface.viewers.Viewer;
14
import org.eclipse.zest.layouts.LayoutStyles;
15
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
16
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
16
import org.eclipse.zest.core.viewers.GraphViewer;
17
import org.eclipse.zest.core.viewers.GraphViewer;
17
import org.eclipse.zest.core.viewers.IGraphContentProvider;
18
import org.eclipse.zest.core.viewers.IGraphContentProvider;
Lines 107-113 Link Here
107
		viewer = new GraphViewer(shell, SWT.NONE);
108
		viewer = new GraphViewer(shell, SWT.NONE);
108
		viewer.setContentProvider(new MyContentProvider());
109
		viewer.setContentProvider(new MyContentProvider());
109
		viewer.setLabelProvider(new MyLabelProvider());
110
		viewer.setLabelProvider(new MyLabelProvider());
110
		viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING));
111
		viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm());
111
		viewer.setInput(new Object());
112
		viewer.setInput(new Object());
112
		shell.open();
113
		shell.open();
113
		while (!shell.isDisposed()) {
114
		while (!shell.isDisposed()) {
(-)src/org/eclipse/zest/tests/jface/GraphJFaceSnippet4.java (-133 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.jface;
11
12
import java.util.Iterator;
13
14
import org.eclipse.jface.viewers.ISelectionChangedListener;
15
import org.eclipse.jface.viewers.LabelProvider;
16
import org.eclipse.jface.viewers.SelectionChangedEvent;
17
import org.eclipse.jface.viewers.StructuredSelection;
18
import org.eclipse.jface.viewers.Viewer;
19
import org.eclipse.zest.layouts.LayoutStyles;
20
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
21
import org.eclipse.zest.core.viewers.GraphViewer;
22
import org.eclipse.zest.core.viewers.IGraphContentProvider;
23
import org.eclipse.swt.SWT;
24
import org.eclipse.swt.graphics.Image;
25
import org.eclipse.swt.layout.FillLayout;
26
import org.eclipse.swt.widgets.Display;
27
import org.eclipse.swt.widgets.Shell;
28
29
public class GraphJFaceSnippet4 {
30
	static class MyContentProvider implements IGraphContentProvider {
31
32
		public Object getDestination(Object rel) {
33
			if ("Rock2Paper".equals(rel)) {
34
				return "Rock";
35
			} else if ("Paper2Scissors".equals(rel)) {
36
				return "Paper";
37
			} else if ("Scissors2Rock".equals(rel)) {
38
				return "Scissors";
39
			}
40
			return null;
41
		}
42
43
		public Object[] getElements(Object input) {
44
			return new Object[] { "Rock2Paper", "Paper2Scissors", "Scissors2Rock" };
45
		}
46
47
		public Object getSource(Object rel) {
48
			if ("Rock2Paper".equals(rel)) {
49
				return "Paper";
50
			} else if ("Paper2Scissors".equals(rel)) {
51
				return "Scissors";
52
			} else if ("Scissors2Rock".equals(rel)) {
53
				return "Rock";
54
			}
55
			return null;
56
		}
57
58
		public double getWeight(Object connection) {
59
			return 0;
60
		}
61
62
		public void dispose() {
63
		}
64
65
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
66
		}
67
68
	}
69
70
	static class MyLabelProvider extends LabelProvider {
71
		final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
72
73
		public Image getImage(Object element) {
74
			if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) {
75
				return image;
76
			}
77
			return null;
78
		}
79
80
		public String getText(Object element) {
81
			return element.toString();
82
		}
83
84
	}
85
86
	static GraphViewer viewer = null;
87
88
	/**
89
	 * @param args
90
	 */
91
	public static void main(String[] args) {
92
		Display d = new Display();
93
		Shell shell = new Shell(d);
94
		shell.setText("GraphJFaceSnippet2");
95
		shell.setLayout(new FillLayout(SWT.VERTICAL));
96
		shell.setSize(400, 400);
97
		viewer = new GraphViewer(shell, SWT.NONE);
98
		viewer.setContentProvider(new MyContentProvider());
99
		viewer.setLabelProvider(new MyLabelProvider());
100
		viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING));
101
		viewer.setInput(new Object());
102
		viewer.addSelectionChangedListener(new ISelectionChangedListener() {
103
104
			public void selectionChanged(SelectionChangedEvent event) {
105
				System.out.println("Selection Changed: " + selectionToString((StructuredSelection) event.getSelection()));
106
			}
107
108
			private String selectionToString(StructuredSelection selection) {
109
				StringBuffer stringBuffer = new StringBuffer();
110
				Iterator iterator = selection.iterator();
111
				boolean first = true;
112
				while (iterator.hasNext()) {
113
					if (first) {
114
						first = false;
115
					} else {
116
						stringBuffer.append(" : ");
117
					}
118
					stringBuffer.append(iterator.next());
119
				}
120
				return stringBuffer.toString();
121
			}
122
123
		});
124
		shell.open();
125
		while (!shell.isDisposed()) {
126
			while (!d.readAndDispatch()) {
127
				d.sleep();
128
			}
129
		}
130
131
	}
132
133
}
(-)src/org/eclipse/zest/tests/jface/GraphJFaceSnippet6.java (-147 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.tests.jface;
11
12
13
import org.eclipse.jface.viewers.LabelProvider;
14
import org.eclipse.jface.viewers.Viewer;
15
import org.eclipse.swt.SWT;
16
import org.eclipse.swt.events.SelectionEvent;
17
import org.eclipse.swt.events.SelectionListener;
18
import org.eclipse.swt.graphics.Image;
19
import org.eclipse.swt.layout.FillLayout;
20
import org.eclipse.swt.widgets.Button;
21
import org.eclipse.swt.widgets.Display;
22
import org.eclipse.swt.widgets.Shell;
23
import org.eclipse.zest.core.viewers.EntityConnectionData;
24
import org.eclipse.zest.core.viewers.GraphViewer;
25
import org.eclipse.zest.core.viewers.IGraphEntityContentProvider;
26
import org.eclipse.zest.core.viewers.INestedContentProvider;
27
import org.eclipse.zest.layouts.LayoutStyles;
28
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
29
30
/**
31
 * This snippet shows how to use the INestedGraphContentProvider to create a graph
32
 * with Zest. In this example, getElements returns 3 edges: * Rock2Paper *
33
 * Paper2Scissors * Scissors2Rock
34
 * 
35
 * And for each of these, the source and destination are returned in getSource
36
 * and getDestination.
37
 * 
38
 * A label provider is also used to create the text and icons for the graph.
39
 * 
40
 * @author Ian Bull
41
 * 
42
 */
43
public class GraphJFaceSnippet6 {
44
45
	static class MyContentProvider implements IGraphEntityContentProvider, INestedContentProvider {
46
47
		public Object[] getConnectedTo(Object entity) {
48
			if (entity.equals("First")) {
49
				return new Object[] { "Second" };
50
			}
51
			if (entity.equals("Second")) {
52
				return new Object[] { "Third", "rock" };
53
			}
54
			if (entity.equals("Third")) {
55
				return new Object[] { "First" };
56
			}
57
			if ( entity.equals("rock")) {
58
				return new Object[] { "paper" };
59
			}
60
			return null;
61
		}
62
63
		public Object[] getElements(Object inputElement) {
64
			return new String[] { "First", "Second", "Third" };
65
		}
66
67
		public double getWeight(Object entity1, Object entity2) {
68
			return 0;
69
		}
70
71
		public void dispose() {
72
73
		}
74
75
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
76
77
		}
78
79
		public Object[] getChildren(Object element) {
80
			// TODO Auto-generated method stub
81
			return new Object[] {"rock", "paper", "scissors"};
82
		}
83
84
		public boolean hasChildren(Object element) {
85
			// TODO Auto-generated method stub
86
			if ( element.equals("First")) return true;
87
			return false;
88
		}
89
90
	}
91
92
	static class MyLabelProvider extends LabelProvider {
93
		final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
94
95
		public Image getImage(Object element) {
96
			if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) {
97
				return image;
98
			}
99
			return null;
100
		}
101
102
		public String getText(Object element) {
103
			if ( element instanceof EntityConnectionData ) return "";
104
			return element.toString();
105
		}
106
107
	}
108
109
	static GraphViewer viewer = null;
110
111
	/**
112
	 * @param args
113
	 */
114
	public static void main(String[] args) {
115
		Display d = new Display();
116
		Shell shell = new Shell(d);
117
		shell.setText("GraphJFaceSnippet2");
118
		shell.setLayout(new FillLayout(SWT.VERTICAL));
119
		shell.setSize(400, 400);
120
		viewer = new GraphViewer(shell, SWT.NONE);
121
		viewer.setContentProvider(new MyContentProvider());
122
		viewer.setLabelProvider(new MyLabelProvider());
123
		viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING));
124
		viewer.setInput(new Object());
125
		
126
		Button button = new Button(shell, SWT.PUSH);
127
		button.setText("push");
128
		button.addSelectionListener(new SelectionListener() {
129
130
			public void widgetDefaultSelected(SelectionEvent e) {
131
			}
132
133
			public void widgetSelected(SelectionEvent e) {
134
				viewer.setInput(new Object());
135
			}
136
			
137
		});
138
		shell.open();
139
		while (!shell.isDisposed()) {
140
			while (!d.readAndDispatch()) {
141
				d.sleep();
142
			}
143
		}
144
145
	}
146
147
}
(-)src/org/eclipse/zest/tests/swt/TreeLayoutExample.java (+160 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import java.util.List;
15
16
import org.eclipse.jface.action.Action;
17
import org.eclipse.jface.action.MenuManager;
18
import org.eclipse.swt.SWT;
19
import org.eclipse.swt.events.SelectionAdapter;
20
import org.eclipse.swt.events.SelectionEvent;
21
import org.eclipse.swt.layout.GridData;
22
import org.eclipse.swt.layout.GridLayout;
23
import org.eclipse.swt.widgets.Button;
24
import org.eclipse.swt.widgets.Display;
25
import org.eclipse.swt.widgets.Shell;
26
import org.eclipse.zest.core.widgets.DAGExpandCollapseManager;
27
import org.eclipse.zest.core.widgets.DefaultSubgraph;
28
import org.eclipse.zest.core.widgets.Graph;
29
import org.eclipse.zest.core.widgets.GraphConnection;
30
import org.eclipse.zest.core.widgets.GraphItem;
31
import org.eclipse.zest.core.widgets.GraphNode;
32
import org.eclipse.zest.core.widgets.ZestStyles;
33
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
34
35
public class TreeLayoutExample {
36
	/**
37
	 * @param args
38
	 */
39
	public static void main(String[] args) {
40
		// Create the shell
41
		Display d = new Display();
42
		Shell shell = new Shell(d);
43
		shell.setText("Tree Layout Example");
44
		GridLayout gridLayout = new GridLayout();
45
		gridLayout.numColumns = 10;
46
		shell.setLayout(gridLayout);
47
		shell.setSize(500, 500);
48
49
		final Graph g = new Graph(shell, SWT.NONE);
50
		final TreeLayoutAlgorithm algorithm = new TreeLayoutAlgorithm();
51
		g
52
				.setSubgraphFactory(new DefaultSubgraph.PrunedSuccessorsSubgraphFactory());
53
		g.setLayoutAlgorithm(algorithm, false);
54
		g.setExpandCollapseManager(new DAGExpandCollapseManager());
55
56
57
		g.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 10, 10));
58
		g.setSize(500, 500);
59
60
		GraphNode root = new GraphNode(g, SWT.NONE, "Root");
61
62
		GraphNode lastNode = null;
63
		for (int i = 0; i < 3; i++) {
64
			GraphNode n = new GraphNode(g, SWT.NONE, "1 - " + i);
65
			if (lastNode != null)
66
				new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, n,
67
						lastNode);
68
			for (int j = 0; j < 1; j++) {
69
				GraphNode n2 = new GraphNode(g, SWT.NONE, "2 - " + j);
70
				GraphConnection c = new GraphConnection(g,
71
						ZestStyles.CONNECTIONS_DIRECTED, n, n2);
72
				c.setWeight(-1);
73
				c.setDirected(true);
74
				lastNode = n2;
75
			}
76
77
			new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, root, n);
78
		}
79
80
81
		hookMenu(g);
82
83
		final Button buttonTopDown = new Button(shell, SWT.FLAT);
84
		buttonTopDown.setText("TOP_DOWN");
85
86
		final Button buttonBottomUp = new Button(shell, SWT.FLAT);
87
		buttonBottomUp.setText("BOTTOM_UP");
88
		buttonBottomUp.setLayoutData(new GridData());
89
90
		final Button buttonLeftRight = new Button(shell, SWT.FLAT);
91
		buttonLeftRight.setText("LEFT_RIGHT");
92
93
		final Button buttonRightLeft = new Button(shell, SWT.FLAT);
94
		buttonRightLeft.setText("RIGHT_LEFT");
95
96
		SelectionAdapter buttonListener = new SelectionAdapter() {
97
			public void widgetSelected(SelectionEvent e) {
98
				if (e.widget == buttonTopDown)
99
					algorithm.setDirection(TreeLayoutAlgorithm.TOP_DOWN);
100
				if (e.widget == buttonBottomUp)
101
					algorithm.setDirection(TreeLayoutAlgorithm.BOTTOM_UP);
102
				if (e.widget == buttonLeftRight)
103
					algorithm.setDirection(TreeLayoutAlgorithm.LEFT_RIGHT);
104
				if (e.widget == buttonRightLeft)
105
					algorithm.setDirection(TreeLayoutAlgorithm.RIGHT_LEFT);
106
107
				g.applyLayout();
108
			}
109
		};
110
		buttonTopDown.addSelectionListener(buttonListener);
111
		buttonBottomUp.addSelectionListener(buttonListener);
112
		buttonLeftRight.addSelectionListener(buttonListener);
113
		buttonRightLeft.addSelectionListener(buttonListener);
114
		
115
		final Button resizeButton = new Button(shell, SWT.CHECK);
116
		resizeButton.setText("Resize");
117
		resizeButton.addSelectionListener(new SelectionAdapter() {
118
			public void widgetSelected(SelectionEvent e) {
119
				algorithm.setResizing(resizeButton.getSelection());
120
			}
121
		});
122
123
		shell.open();
124
		while (!shell.isDisposed()) {
125
			while (!d.readAndDispatch()) {
126
				d.sleep();
127
			}
128
		}
129
	}
130
131
	private static void hookMenu(final Graph g) {
132
		MenuManager menuMgr = new MenuManager("#PopupMenu");
133
134
		Action expandAction = new Action() {
135
			public void run() {
136
				List selection = g.getSelection();
137
				if (!selection.isEmpty()) {
138
					GraphNode selected = (GraphNode) selection.get(0);
139
					g.setExpanded((GraphNode) selected, true);
140
				}
141
			}
142
		};
143
		expandAction.setText("expand");
144
		menuMgr.add(expandAction);
145
146
		Action collapseAction = new Action() {
147
			public void run() {
148
				List selection = g.getSelection();
149
				if (!selection.isEmpty()) {
150
					GraphItem selected = (GraphItem) selection.get(0);
151
					g.setExpanded((GraphNode) selected, false);
152
				}
153
			}
154
		};
155
		collapseAction.setText("collapse");
156
		menuMgr.add(collapseAction);
157
158
		g.setMenu(menuMgr.createContextMenu(g));
159
	}
160
}
(-)src/org/eclipse/zest/tests/swt/IconsGraphSnippet.java (+72 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.zest.core.widgets.Graph;
15
import org.eclipse.zest.core.widgets.GraphConnection;
16
import org.eclipse.zest.core.widgets.GraphNode;
17
import org.eclipse.zest.core.widgets.ZestStyles;
18
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
19
import org.eclipse.swt.SWT;
20
import org.eclipse.swt.graphics.Image;
21
import org.eclipse.swt.layout.FillLayout;
22
import org.eclipse.swt.widgets.Display;
23
import org.eclipse.swt.widgets.Shell;
24
25
/**
26
 * This snippet creates a very simple graph with an Icon and Label.
27
 * 
28
 * This snippet shows how to use directed edges and self loops.
29
 * 
30
 * @author Ian Bull
31
 * 
32
 */
33
public class IconsGraphSnippet {
34
35
	public static void main(String[] args) {
36
		Display d = new Display();
37
		Shell shell = new Shell(d);
38
		Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION);
39
		Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
40
		Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR);
41
		shell.setLayout(new FillLayout());
42
		shell.setSize(400, 400);
43
44
		Graph g = new Graph(shell, SWT.NONE);
45
		g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED);
46
		GraphNode n1 = new GraphNode(g, SWT.NONE);
47
		n1.setText("Information");
48
		n1.setImage(image1);
49
		GraphNode n2 = new GraphNode(g, SWT.NONE);
50
		n2.setText("Warning");
51
		n2.setImage(image2);
52
		GraphNode n3 = new GraphNode(g, SWT.NONE);
53
		n3.setText("Error");
54
		n3.setImage(image3);
55
56
		new GraphConnection(g, SWT.NONE, n1, n2);
57
		new GraphConnection(g, SWT.NONE, n2, n3);
58
		new GraphConnection(g, SWT.NONE, n3, n3);
59
60
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true);
61
62
		shell.open();
63
		while (!shell.isDisposed()) {
64
			while (!d.readAndDispatch()) {
65
				d.sleep();
66
			}
67
		}
68
		image1.dispose();
69
		image2.dispose();
70
		image3.dispose();
71
	}
72
}
(-).refactorings/2009/8/35/refactorings.index (+5 lines)
Added Link Here
1
1251471945100	Delete element
2
1251472688225	Delete element
3
1251472860601	Delete elements
4
1251472916946	Delete element
5
1251473212253	Delete elements
(-)src/org/eclipse/zest/tests/swt/CurvedEdgeGraphSnippet2.java (+69 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 ******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.draw2d.ColorConstants;
15
import org.eclipse.swt.SWT;
16
import org.eclipse.swt.graphics.Color;
17
import org.eclipse.swt.layout.FillLayout;
18
import org.eclipse.swt.widgets.Display;
19
import org.eclipse.swt.widgets.Shell;
20
import org.eclipse.zest.core.widgets.Graph;
21
import org.eclipse.zest.core.widgets.GraphConnection;
22
import org.eclipse.zest.core.widgets.GraphNode;
23
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
24
25
/**
26
 * 
27
 * This snippet shows how to create a curved connection using Zest.
28
 * 
29
 * @author Ian Bull
30
 * 
31
 */
32
public class CurvedEdgeGraphSnippet2 {
33
34
35
	public static void createConnection( Graph g, GraphNode n1, GraphNode n2, Color color, int curve) {
36
		GraphConnection connection = new GraphConnection(g, SWT.NONE, n1, n2);
37
		connection.setLineColor(color);
38
		connection.setCurveDepth(curve);
39
		connection.setLineWidth(1);
40
	}
41
	
42
	public static void main(String[] args) {
43
		Display d = new Display();
44
		Shell shell = new Shell(d);
45
		shell.setText("GraphSnippet11");
46
		shell.setLayout(new FillLayout());
47
		shell.setSize(400, 400);
48
49
		final Graph g = new Graph(shell, SWT.NONE);
50
		GraphNode n = new GraphNode(g, SWT.NONE, "Node 1");
51
		GraphNode n2 = new GraphNode(g, SWT.NONE, "Node 2");
52
		createConnection(g, n, n2, ColorConstants.darkGreen, 20);
53
		createConnection(g, n, n2, ColorConstants.darkGreen, -20);
54
		createConnection(g, n, n2, ColorConstants.darkBlue, 40);
55
		createConnection(g, n, n2, ColorConstants.darkBlue, -40);
56
		createConnection(g, n, n2, ColorConstants.darkGray, 60);
57
		createConnection(g, n, n2, ColorConstants.darkGray, -60);
58
		createConnection(g, n, n2, ColorConstants.black, 0);
59
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true);
60
61
		shell.open();
62
		while (!shell.isDisposed()) {
63
			while (!d.readAndDispatch()) {
64
				d.sleep();
65
			}
66
		}
67
	}
68
69
}
(-)src/org/eclipse/zest/tests/swt/ContainerResizeGraphSnippet.java (+174 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.swt.SWT;
15
import org.eclipse.swt.events.KeyEvent;
16
import org.eclipse.swt.events.KeyListener;
17
import org.eclipse.swt.graphics.Image;
18
import org.eclipse.swt.layout.FillLayout;
19
import org.eclipse.swt.widgets.Display;
20
import org.eclipse.swt.widgets.Shell;
21
import org.eclipse.zest.core.widgets.Graph;
22
import org.eclipse.zest.core.widgets.GraphConnection;
23
import org.eclipse.zest.core.widgets.GraphContainer;
24
import org.eclipse.zest.core.widgets.GraphItem;
25
import org.eclipse.zest.core.widgets.GraphNode;
26
import org.eclipse.zest.core.widgets.ZestStyles;
27
import org.eclipse.zest.layouts.LayoutAlgorithm;
28
import org.eclipse.zest.layouts.algorithms.CompositeLayoutAlgorithm;
29
import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm;
30
import org.eclipse.zest.layouts.algorithms.HorizontalShiftAlgorithm;
31
import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm;
32
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
33
34
public class ContainerResizeGraphSnippet {
35
36
	private static Image image1;
37
	private static Image classImage;
38
39
	public static void createContainer(Graph g) {
40
		GraphContainer a = new GraphContainer(g, SWT.NONE);
41
		a.setText("SomeClass.java");
42
		a.setImage(classImage);
43
		int r = (int) ((Math.random() * 3) + 1);
44
		r = 2;
45
		populateContainer(a, g, r, true);
46
		for (int i = 0; i < 4; i++) {
47
			GraphContainer b = new GraphContainer(g, SWT.NONE);
48
			b.setText("SomeTestedClass.java");
49
			b.setImage(classImage);
50
			r = (int) ((Math.random() * 3) + 1);
51
			r = 2;
52
			populateContainer(b, g, r, false);
53
			new GraphConnection(g, SWT.NONE, a, b);
54
			for (int j = 0; j < 4; j++) {
55
				GraphContainer c = new GraphContainer(g, SWT.NONE);
56
				c.setText("DefaultAction.java");
57
				c.setImage(classImage);
58
				r = (int) ((Math.random() * 3) + 1);
59
				r = 2;
60
				populateContainer(c, g, r, true);
61
				new GraphConnection(g, SWT.NONE, b, c);
62
			}
63
		}
64
	}
65
66
	public static void populateContainer(GraphContainer c, Graph g, int number, boolean radial) {
67
		GraphNode a = new GraphNode(c, ZestStyles.NODES_FISHEYE
68
				| ZestStyles.NODES_HIDE_TEXT);
69
		a.setText("SomeClass.java");
70
		a.setImage(classImage);
71
		for (int i = 0; i < 4; i++) {
72
			GraphNode b = new GraphNode(c, ZestStyles.NODES_FISHEYE
73
					| ZestStyles.NODES_HIDE_TEXT);
74
			b.setText("SomeNestedClass.java");
75
			b.setImage(classImage);
76
			new GraphConnection(g, SWT.NONE, a, b);
77
			for (int j = 0; j < 4; j++) {
78
				GraphNode d = new GraphNode(c, ZestStyles.NODES_FISHEYE
79
						| ZestStyles.NODES_HIDE_TEXT);
80
				d.setText("DefaultAction.java");
81
				d.setImage(classImage);
82
				new GraphConnection(g, SWT.NONE, b, d);
83
				if (number > 2) {
84
					for (int k = 0; k < 4; k++) {
85
						GraphNode e = new GraphNode(c, ZestStyles.NODES_FISHEYE
86
								| ZestStyles.NODES_HIDE_TEXT);
87
						e.setText("LastAction(Hero).java");
88
						e.setImage(classImage);
89
						new GraphConnection(g, SWT.NONE, d, e);
90
						if (number > 3) {
91
							for (int l = 0; l < 4; l++) {
92
								GraphNode f = new GraphNode(c,
93
										ZestStyles.NODES_FISHEYE
94
												| ZestStyles.NODES_HIDE_TEXT);
95
								f.setText("LastAction(Hero).java");
96
								f.setImage(classImage);
97
								new GraphConnection(g, SWT.NONE, e, f);
98
							}
99
						}
100
					}
101
				}
102
			}
103
		}
104
		if (number == 1) {
105
			c.setScale(0.75);
106
		} else if (number == 2) {
107
			c.setScale(0.50);
108
		} else {
109
			c.setScale(0.25);
110
		}
111
		if (radial) {
112
			c.setLayoutAlgorithm(new RadialLayoutAlgorithm(), true);
113
		} else {
114
			c.setLayoutAlgorithm(new TreeLayoutAlgorithm(), true);
115
		}
116
	}
117
118
	/**
119
	 * @param args
120
	 */
121
	public static void main(String[] args) {
122
		// Create the shell
123
		Display d = new Display();
124
125
		image1 = new Image(Display.getDefault(), ContainerResizeGraphSnippet.class.getResourceAsStream("package_obj.gif"));
126
		classImage = new Image(Display.getDefault(), ContainerResizeGraphSnippet.class.getResourceAsStream("class_obj.gif"));
127
128
		Shell shell = new Shell(d);
129
		shell.setText("GraphSnippet1");
130
		shell.setLayout(new FillLayout());
131
		shell.setSize(500, 800);
132
133
		final Graph g = new Graph(shell, SWT.NONE);
134
		createContainer(g);
135
136
		CompositeLayoutAlgorithm compositeLayoutAlgorithm = new CompositeLayoutAlgorithm(new LayoutAlgorithm[] { new GridLayoutAlgorithm(), new HorizontalShiftAlgorithm() });
137
		//g.setLayoutAlgorithm(new GridLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
138
		g.setLayoutAlgorithm(compositeLayoutAlgorithm, true);
139
140
		g.addKeyListener(new KeyListener() {
141
			boolean flip = true;
142
143
			public void keyPressed(KeyEvent e) {
144
145
				if (g.getSelection().size() == 1) {
146
					GraphNode item = (GraphNode) g.getSelection().get(0);
147
					if (item.getItemType() == GraphItem.CONTAINER) {
148
						if (flip) {
149
							(item).setSize(500, 100);
150
						} else {
151
							(item).setSize(0, 0);
152
						}
153
						flip = !flip;
154
					}
155
				}
156
157
			}
158
159
			public void keyReleased(KeyEvent e) {
160
				// TODO Auto-generated method stub
161
162
			}
163
164
		});
165
166
		shell.open();
167
		while (!shell.isDisposed()) {
168
			while (!d.readAndDispatch()) {
169
				d.sleep();
170
			}
171
		}
172
		image1.dispose();
173
	}
174
}
(-)src/org/eclipse/zest/tests/jface/NestedGraphJFaceSnippet.java (+148 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 ******************************************************************************/
12
package org.eclipse.zest.tests.jface;
13
14
15
import org.eclipse.jface.viewers.LabelProvider;
16
import org.eclipse.jface.viewers.Viewer;
17
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.events.SelectionEvent;
19
import org.eclipse.swt.events.SelectionListener;
20
import org.eclipse.swt.graphics.Image;
21
import org.eclipse.swt.layout.FillLayout;
22
import org.eclipse.swt.widgets.Button;
23
import org.eclipse.swt.widgets.Display;
24
import org.eclipse.swt.widgets.Shell;
25
import org.eclipse.zest.core.viewers.EntityConnectionData;
26
import org.eclipse.zest.core.viewers.GraphViewer;
27
import org.eclipse.zest.core.viewers.IGraphEntityContentProvider;
28
import org.eclipse.zest.core.viewers.INestedContentProvider;
29
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
30
31
/**
32
 * This snippet shows how to use the INestedGraphContentProvider to create a graph
33
 * with Zest. In this example, getElements returns 3 edges: * Rock2Paper *
34
 * Paper2Scissors * Scissors2Rock
35
 * 
36
 * And for each of these, the source and destination are returned in getSource
37
 * and getDestination.
38
 * 
39
 * A label provider is also used to create the text and icons for the graph.
40
 * 
41
 * @author Ian Bull
42
 * 
43
 */
44
public class NestedGraphJFaceSnippet {
45
46
	static class MyContentProvider implements IGraphEntityContentProvider, INestedContentProvider {
47
48
		public Object[] getConnectedTo(Object entity) {
49
			if (entity.equals("First")) {
50
				return new Object[] { "Second" };
51
			}
52
			if (entity.equals("Second")) {
53
				return new Object[] { "Third", "rock" };
54
			}
55
			if (entity.equals("Third")) {
56
				return new Object[] { "First" };
57
			}
58
			if ( entity.equals("rock")) {
59
				return new Object[] { "paper" };
60
			}
61
			return null;
62
		}
63
64
		public Object[] getElements(Object inputElement) {
65
			return new String[] { "First", "Second", "Third" };
66
		}
67
68
		public double getWeight(Object entity1, Object entity2) {
69
			return 0;
70
		}
71
72
		public void dispose() {
73
74
		}
75
76
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
77
78
		}
79
80
		public Object[] getChildren(Object element) {
81
			// TODO Auto-generated method stub
82
			return new Object[] {"rock", "paper", "scissors"};
83
		}
84
85
		public boolean hasChildren(Object element) {
86
			// TODO Auto-generated method stub
87
			if ( element.equals("First")) return true;
88
			return false;
89
		}
90
91
	}
92
93
	static class MyLabelProvider extends LabelProvider {
94
		final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
95
96
		public Image getImage(Object element) {
97
			if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) {
98
				return image;
99
			}
100
			return null;
101
		}
102
103
		public String getText(Object element) {
104
			if ( element instanceof EntityConnectionData ) return "";
105
			return element.toString();
106
		}
107
108
	}
109
110
	static GraphViewer viewer = null;
111
112
	/**
113
	 * @param args
114
	 */
115
	public static void main(String[] args) {
116
		Display d = new Display();
117
		Shell shell = new Shell(d);
118
		shell.setText("GraphJFaceSnippet2");
119
		shell.setLayout(new FillLayout(SWT.VERTICAL));
120
		shell.setSize(400, 400);
121
		viewer = new GraphViewer(shell, SWT.NONE);
122
		viewer.setContentProvider(new MyContentProvider());
123
		viewer.setLabelProvider(new MyLabelProvider());
124
		viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm());
125
		viewer.setInput(new Object());
126
		
127
		Button button = new Button(shell, SWT.PUSH);
128
		button.setText("push");
129
		button.addSelectionListener(new SelectionListener() {
130
131
			public void widgetDefaultSelected(SelectionEvent e) {
132
			}
133
134
			public void widgetSelected(SelectionEvent e) {
135
				viewer.setInput(new Object());
136
			}
137
			
138
		});
139
		shell.open();
140
		while (!shell.isDisposed()) {
141
			while (!d.readAndDispatch()) {
142
				d.sleep();
143
			}
144
		}
145
146
	}
147
148
}
(-)src/org/eclipse/zest/tests/swt/FilterGraphSnippet.java (+117 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.draw2d.ColorConstants;
15
import org.eclipse.swt.SWT;
16
import org.eclipse.swt.layout.FillLayout;
17
import org.eclipse.swt.widgets.Display;
18
import org.eclipse.swt.widgets.Shell;
19
import org.eclipse.zest.core.widgets.Graph;
20
import org.eclipse.zest.core.widgets.GraphConnection;
21
import org.eclipse.zest.core.widgets.GraphItem;
22
import org.eclipse.zest.core.widgets.GraphNode;
23
import org.eclipse.zest.core.widgets.LayoutFilter;
24
import org.eclipse.zest.core.widgets.ZestStyles;
25
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
26
27
/**
28
 * This snippet shows how to filter elements in the layout.  The Data on the tree
29
 * connections are set to "False", meaning they won't be filtered.  
30
 * 
31
 * @author Ian Bull
32
 * 
33
 */
34
public class FilterGraphSnippet {
35
36
	/**
37
	 * @param args
38
	 */
39
	public static void main(String[] args) {
40
		Display display = new Display();
41
		Shell shell = new Shell(display);
42
		shell.setText("GraphSnippet8");
43
		shell.setLayout(new FillLayout());
44
		shell.setSize(400, 400);
45
46
		final Graph graph = new Graph(shell, SWT.NONE);
47
48
		GraphNode a = new GraphNode(graph, SWT.NONE, "Root");
49
		GraphNode b = new GraphNode(graph, SWT.NONE, "B");
50
		GraphNode c = new GraphNode(graph, SWT.NONE, "C");
51
		GraphNode d = new GraphNode(graph, SWT.NONE, "D");
52
		GraphNode e = new GraphNode(graph, SWT.NONE, "E");
53
		GraphNode f = new GraphNode(graph, SWT.NONE, "F");
54
		GraphNode g = new GraphNode(graph, SWT.NONE, "G");
55
		GraphNode h = new GraphNode(graph, SWT.NONE, "H");
56
		GraphConnection connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, a, b);
57
		connection.setData(Boolean.TRUE);
58
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, a, c);
59
		connection.setData(Boolean.TRUE);
60
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, a, c);
61
		connection.setData(Boolean.TRUE);
62
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, a, d);
63
		connection.setData(Boolean.TRUE);
64
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, b, e);
65
		connection.setData(Boolean.FALSE);
66
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, b, f);
67
		connection.setData(Boolean.FALSE);
68
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, c, g);
69
		connection.setData(Boolean.FALSE);
70
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, d, h);
71
		connection.setData(Boolean.FALSE);
72
		
73
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, b, c);
74
		connection.setLineColor(ColorConstants.red);
75
		connection.setLineWidth(3);
76
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, c, d);
77
		connection.setLineColor(ColorConstants.red);
78
		connection.setLineWidth(3);
79
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, e, f);
80
		connection.setLineColor(ColorConstants.red);
81
		connection.setLineWidth(3);
82
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, f, g);
83
		connection.setLineColor(ColorConstants.red);
84
		connection.setLineWidth(3);
85
		
86
		connection = new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, h, e);
87
		connection.setLineColor(ColorConstants.red);
88
		connection.setLineWidth(3);
89
		
90
		TreeLayoutAlgorithm treeLayoutAlgorithm = new TreeLayoutAlgorithm();
91
		LayoutFilter filter = new LayoutFilter() {
92
			public boolean isObjectFiltered(GraphItem item) {
93
				if  (item instanceof GraphConnection ) {
94
					GraphConnection connection = (GraphConnection) item;
95
					Object data = connection.getData();
96
					if ( data != null && data instanceof Boolean ) {
97
						// If the data is false, don't filter, otherwise, filter.
98
						return ((Boolean) data).booleanValue();
99
					}
100
					return true;
101
				}
102
				return false;
103
			}
104
		};
105
		graph.addLayoutFilter(filter);
106
		graph.setLayoutAlgorithm(treeLayoutAlgorithm, true);
107
		
108
109
		shell.open();
110
		while (!shell.isDisposed()) {
111
			while (!display.readAndDispatch()) {
112
				display.sleep();
113
			}
114
		}
115
	}
116
117
}
(-)src/org/eclipse/zest/tests/swt/RadialLayoutExample.java (+55 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.swt.SWT;
15
import org.eclipse.swt.layout.FillLayout;
16
import org.eclipse.swt.widgets.Display;
17
import org.eclipse.swt.widgets.Shell;
18
import org.eclipse.zest.core.widgets.Graph;
19
import org.eclipse.zest.core.widgets.GraphConnection;
20
import org.eclipse.zest.core.widgets.GraphNode;
21
import org.eclipse.zest.layouts.LayoutAlgorithm;
22
import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm;
23
24
public class RadialLayoutExample {
25
	public static void main(String[] args) {
26
		// Create the shell
27
		Display d = new Display();
28
		Shell shell = new Shell(d);
29
		shell.setText("GraphSnippet1");
30
		shell.setLayout(new FillLayout());
31
		shell.setSize(500, 500);
32
33
		final Graph g = new Graph(shell, SWT.NONE);
34
		g.setSize(500, 500);
35
		GraphNode root = new GraphNode(g, SWT.NONE, "Root");
36
		for (int i = 0; i < 3; i++) {
37
			GraphNode n = new GraphNode(g, SWT.NONE, "1 - " + i);
38
			for (int j = 0; j < 3; j++) {
39
				GraphNode n2 = new GraphNode(g, SWT.NONE, "2 - " + j);
40
				new GraphConnection(g, SWT.NONE, n, n2).setWeight(-1);
41
			}
42
			new GraphConnection(g, SWT.NONE, root, n);
43
		}
44
45
		final LayoutAlgorithm layoutAlgorithm = new RadialLayoutAlgorithm();
46
47
		g.setLayoutAlgorithm(layoutAlgorithm, true);
48
		shell.open();
49
		while (!shell.isDisposed()) {
50
			while (!d.readAndDispatch()) {
51
				d.sleep();
52
			}
53
		}
54
	}
55
}
(-)src/org/eclipse/zest/tests/jface/CustomFigureGraphJFaceSnippet.java (+177 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 ******************************************************************************/
12
package org.eclipse.zest.tests.jface;
13
14
15
import org.eclipse.draw2d.IFigure;
16
import org.eclipse.draw2d.Label;
17
import org.eclipse.jface.viewers.LabelProvider;
18
import org.eclipse.jface.viewers.Viewer;
19
import org.eclipse.swt.SWT;
20
import org.eclipse.swt.events.SelectionEvent;
21
import org.eclipse.swt.events.SelectionListener;
22
import org.eclipse.swt.graphics.Font;
23
import org.eclipse.swt.graphics.Image;
24
import org.eclipse.swt.layout.FillLayout;
25
import org.eclipse.swt.widgets.Button;
26
import org.eclipse.swt.widgets.Display;
27
import org.eclipse.swt.widgets.Shell;
28
import org.eclipse.zest.core.viewers.EntityConnectionData;
29
import org.eclipse.zest.core.viewers.GraphViewer;
30
import org.eclipse.zest.core.viewers.IFigureProvider;
31
import org.eclipse.zest.core.viewers.IGraphEntityContentProvider;
32
import org.eclipse.zest.core.viewers.INestedContentProvider;
33
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
34
import org.eclipse.zest.tests.uml.UMLClassFigure;
35
36
/**
37
 * This snippet shows how to use Zest viewers with custom figures.
38
 * It creates a figure containing UML representation of Table class. 
39
 * 
40
 * @author Ian Bull
41
 * 
42
 */
43
public class CustomFigureGraphJFaceSnippet {
44
45
	public static IFigure createClassFigure1(Font classFont, Image classImage, Image publicField, Image privateField) {
46
		Label classLabel1 = new Label("Table", classImage);
47
		classLabel1.setFont(classFont);
48
49
		UMLClassFigure classFigure = new UMLClassFigure(classLabel1);
50
		Label attribute1 = new Label("columns: Column[]", privateField);
51
52
		Label attribute2 = new Label("rows: Row[]", privateField);
53
54
		Label method1 = new Label("getColumns(): Column[]", publicField);
55
		Label method2 = new Label("getRows(): Row[]", publicField);
56
		classFigure.getAttributesCompartment().add(attribute1);
57
		classFigure.getAttributesCompartment().add(attribute2);
58
		classFigure.getMethodsCompartment().add(method1);
59
		classFigure.getMethodsCompartment().add(method2);
60
		classFigure.setSize(-1, -1);
61
62
		return classFigure;
63
	}
64
	
65
	static class MyContentProvider implements IGraphEntityContentProvider, INestedContentProvider {
66
67
		public Object[] getConnectedTo(Object entity) {
68
			if (entity.equals("First")) {
69
				return new Object[] { "Second" };
70
			}
71
			if (entity.equals("Second")) {
72
				return new Object[] { "Third", "rock" };
73
			}
74
			if (entity.equals("Third")) {
75
				return new Object[] { "First" };
76
			}
77
			if ( entity.equals("rock")) {
78
				return new Object[] { "paper" };
79
			}
80
			return null;
81
		}
82
83
		public Object[] getElements(Object inputElement) {
84
			return new String[] { "First", "Second", "Third" };
85
		}
86
87
		public double getWeight(Object entity1, Object entity2) {
88
			return 0;
89
		}
90
91
		public void dispose() {
92
93
		}
94
95
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
96
97
		}
98
99
		public Object[] getChildren(Object element) {
100
			// TODO Auto-generated method stub
101
			return new Object[] {"rock", "paper", "scissors"};
102
		}
103
104
		public boolean hasChildren(Object element) {
105
			// TODO Auto-generated method stub
106
			if ( element.equals("First")) return true;
107
			return false;
108
		}
109
110
	}
111
112
113
	
114
	static class MyLabelProvider extends LabelProvider implements IFigureProvider {
115
		final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
116
117
		public Image getImage(Object element) {
118
			if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) {
119
				return image;
120
			}
121
			return null;
122
		}
123
124
		public String getText(Object element) {
125
			if ( element instanceof EntityConnectionData ) return "";
126
			return element.toString();
127
		}
128
		
129
		public IFigure getFigure(Object element) {
130
			Font classFont = new Font(null, "Arial", 12, SWT.BOLD);
131
			Image classImage = new Image(Display.getDefault(), UMLClassFigure.class.getResourceAsStream("class_obj.gif"));
132
			Image privateField = new Image(Display.getDefault(), UMLClassFigure.class.getResourceAsStream("field_private_obj.gif"));
133
			Image publicField= new Image(Display.getDefault(), UMLClassFigure.class.getResourceAsStream("methpub_obj.gif"));
134
			return createClassFigure1(classFont, classImage, publicField, privateField);
135
		}
136
137
	}
138
139
	static GraphViewer viewer = null;
140
141
	/**
142
	 * @param args
143
	 */
144
	public static void main(String[] args) {
145
		Display d = new Display();
146
		Shell shell = new Shell(d);
147
		shell.setText("GraphJFaceSnippet2");
148
		shell.setLayout(new FillLayout(SWT.VERTICAL));
149
		shell.setSize(400, 400);
150
		viewer = new GraphViewer(shell, SWT.NONE);
151
		viewer.setContentProvider(new MyContentProvider());
152
		viewer.setLabelProvider(new MyLabelProvider());
153
		viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm());
154
		viewer.setInput(new Object());
155
		
156
		Button button = new Button(shell, SWT.PUSH);
157
		button.setText("push");
158
		button.addSelectionListener(new SelectionListener() {
159
160
			public void widgetDefaultSelected(SelectionEvent e) {
161
			}
162
163
			public void widgetSelected(SelectionEvent e) {
164
				viewer.setInput(new Object());
165
			}
166
			
167
		});
168
		shell.open();
169
		while (!shell.isDisposed()) {
170
			while (!d.readAndDispatch()) {
171
				d.sleep();
172
			}
173
		}
174
175
	}
176
177
}
(-)src/org/eclipse/zest/tests/swt/SpringLayoutProgress.java (+103 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *     Ian Bull
12
 *******************************************************************************/
13
package org.eclipse.zest.tests.swt;
14
15
import org.eclipse.swt.SWT;
16
import org.eclipse.swt.events.SelectionAdapter;
17
import org.eclipse.swt.events.SelectionEvent;
18
import org.eclipse.swt.layout.GridData;
19
import org.eclipse.swt.layout.GridLayout;
20
import org.eclipse.swt.widgets.Button;
21
import org.eclipse.swt.widgets.Display;
22
import org.eclipse.swt.widgets.Label;
23
import org.eclipse.swt.widgets.Shell;
24
import org.eclipse.zest.core.widgets.Graph;
25
import org.eclipse.zest.core.widgets.GraphConnection;
26
import org.eclipse.zest.core.widgets.GraphNode;
27
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
28
29
/**
30
 * 
31
 */
32
public class SpringLayoutProgress {
33
	static Runnable r = null;
34
			
35
	/**
36
	 * @param args
37
	 */
38
	public static void main(String[] args) {
39
		// Create the shell
40
		Display d = new Display();
41
		Shell shell = new Shell(d);
42
		shell.setText("GraphSnippet1");
43
		GridLayout gridLayout = new GridLayout();
44
		gridLayout.numColumns = 5;
45
		shell.setLayout(gridLayout);
46
		shell.setSize(500, 500);
47
48
		final Graph g = new Graph(shell, SWT.NONE);
49
		g.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 5, 5));
50
		g.setSize(500, 500);
51
		GraphNode root = new GraphNode(g, SWT.NONE, "Root");
52
		for (int i = 0; i < 3; i++) {
53
			GraphNode n = new GraphNode(g, SWT.NONE, "1 - " + i);
54
			for (int j = 0; j < 3; j++) {
55
				GraphNode n2 = new GraphNode(g, SWT.NONE, "2 - " + j);
56
				new GraphConnection(g, SWT.NONE, n, n2).setWeight(-1);
57
			}
58
			new GraphConnection(g, SWT.NONE, root, n);
59
		}
60
61
62
		final SpringLayoutAlgorithm springLayoutAlgorithm = new SpringLayoutAlgorithm();
63
64
		g.setLayoutAlgorithm(springLayoutAlgorithm, false);
65
66
		Button b = new Button(shell, SWT.FLAT);
67
		b.setText("step");
68
69
		final Label label = new Label(shell, SWT.LEFT);
70
		label.setText("<--click");
71
		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
72
73
		b.addSelectionListener(new SelectionAdapter() {
74
			int steps = 0;
75
			public void widgetSelected(SelectionEvent e) {
76
				
77
				r = new Runnable() {
78
					public void run() {
79
						springLayoutAlgorithm.performOneIteration();
80
						g.redraw();
81
						label.setText("steps: " + ++steps);
82
						try {
83
							Thread.sleep(50);
84
						} catch (InterruptedException e) {
85
							e.printStackTrace();
86
						}
87
						Display.getCurrent().asyncExec(r);
88
					}
89
				};
90
				Display.getCurrent().asyncExec(r);
91
92
			}
93
		});
94
95
		shell.open();
96
		while (!shell.isDisposed()) {
97
			while (!d.readAndDispatch()) {
98
				d.sleep();
99
			}
100
		}
101
	}
102
103
}
(-).refactorings/2009/8/35/refactorings.history (+3 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<session version="1.0">&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.tests&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.tests&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.tests.swt.LayoutExample.java&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.tests&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.tests&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.tests.swt.ZoomSnippet.java&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 12 element(s) from project &apos;org.eclipse.zest.tests&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.tests&apos;&#x0D;&#x0A;- Original elements:&#x0D;&#x0A;     org.eclipse.zest.tests.swt.GraphSnippet1.java&#x0D;&#x0A;     org.eclipse.zest.tests.swt.GraphSnippet10.java&#x0D;&#x0A;     org.eclipse.zest.tests.swt.GraphSnippet11.java&#x0D;&#x0A;     org.eclipse.zest.tests.swt.GraphSnippet12.java&#x0D;&#x0A;     org.eclipse.zest.tests.swt.GraphSnippet13.java&#x0D;&#x0A;     org.eclipse.zest.tests.swt.GraphSnippet2.java&#x0D;&#x0A;     org.eclipse.zest.tests.swt.GraphSnippet3.java&#x0D;&#x0A;     org.eclipse.zest.tests.swt.GraphSnippet4.java&#x0D;&#x0A;     org.eclipse.zest.tests.swt.GraphSnippet5.java&#x0D;&#x0A;     org.eclipse.zest.tests.swt.GraphSnippet6.java&#x0D;&#x0A;     org.eclipse.zest.tests.swt.GraphSnippet7.java&#x0D;&#x0A;     org.eclipse.zest.tests.swt.GraphSnippet8.java" description="Delete elements" element1="/src&lt;org.eclipse.zest.tests.swt{GraphSnippet12.java" element10="/src&lt;org.eclipse.zest.tests.swt{GraphSnippet8.java" element11="/src&lt;org.eclipse.zest.tests.swt{GraphSnippet5.java" element12="/src&lt;org.eclipse.zest.tests.swt{GraphSnippet11.java" element2="/src&lt;org.eclipse.zest.tests.swt{GraphSnippet10.java" element3="/src&lt;org.eclipse.zest.tests.swt{GraphSnippet7.java" element4="/src&lt;org.eclipse.zest.tests.swt{GraphSnippet13.java" element5="/src&lt;org.eclipse.zest.tests.swt{GraphSnippet4.java" element6="/src&lt;org.eclipse.zest.tests.swt{GraphSnippet1.java" element7="/src&lt;org.eclipse.zest.tests.swt{GraphSnippet2.java" element8="/src&lt;org.eclipse.zest.tests.swt{GraphSnippet6.java" element9="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.tests&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.tests&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.tests.swt.GraphSnippet9.java&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 5 element(s) from project &apos;org.eclipse.zest.tests&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.tests&apos;&#x0D;&#x0A;- Original elements:&#x0D;&#x0A;     org.eclipse.zest.tests.jface.GraphJFaceSnippet3.java&#x0D;&#x0A;     org.eclipse.zest.tests.jface.GraphJFaceSnippet4.java&#x0D;&#x0A;     org.eclipse.zest.tests.jface.GraphJFaceSnippet5.java&#x0D;&#x0A;     org.eclipse.zest.tests.jface.GraphJFaceSnippet6.java&#x0D;&#x0A;     org.eclipse.zest.tests.jface.GraphJFaceSnippet7.java" description="Delete elements" element1="/src&lt;org.eclipse.zest.tests.jface{GraphJFaceSnippet5.java" element2="/src&lt;org.eclipse.zest.tests.jface{GraphJFaceSnippet3.java" element3="/src&lt;org.eclipse.zest.tests.jface{GraphJFaceSnippet4.java" element4="/src&lt;org.eclipse.zest.tests.jface{GraphJFaceSnippet6.java" element5="/src&lt;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"/>
3
</session>
(-)src/org/eclipse/zest/tests/swt/SelfLoopGraphSnippet.java (+56 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 ******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.swt.SWT;
15
import org.eclipse.swt.layout.FillLayout;
16
import org.eclipse.swt.widgets.Display;
17
import org.eclipse.swt.widgets.Shell;
18
import org.eclipse.zest.core.widgets.Graph;
19
import org.eclipse.zest.core.widgets.GraphConnection;
20
import org.eclipse.zest.core.widgets.GraphNode;
21
import org.eclipse.zest.core.widgets.ZestStyles;
22
23
/**
24
 * This snippet demonstrates a self loop with a label.
25
 * 
26
 * @author Ian Bull
27
 * 
28
 */
29
public class SelfLoopGraphSnippet {
30
31
	/**
32
	 * @param args
33
	 */
34
	public static void main(String[] args) {
35
		Display display = new Display();
36
		Shell shell = new Shell(display);
37
		shell.setText("GraphSnippet9");
38
		shell.setLayout(new FillLayout());
39
		shell.setSize(400, 400);
40
41
		final Graph graph = new Graph(shell, SWT.NONE);
42
43
		GraphNode a = new GraphNode(graph, ZestStyles.CONNECTIONS_DIRECTED, "Root");
44
		GraphConnection connection = new GraphConnection(graph, SWT.NONE, a, a);
45
		connection.setText("A to A");
46
		a.setLocation(100, 100);
47
48
		shell.open();
49
		while (!shell.isDisposed()) {
50
			while (!display.readAndDispatch()) {
51
				display.sleep();
52
			}
53
		}
54
	}
55
56
}
(-)src/org/eclipse/zest/tests/swt/DAGExample.java (+145 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Ian Bull
10
 *******************************************************************************/
11
package org.eclipse.zest.tests.swt;
12
13
import java.util.List;
14
15
import org.eclipse.jface.action.Action;
16
import org.eclipse.jface.action.MenuManager;
17
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.events.SelectionAdapter;
19
import org.eclipse.swt.events.SelectionEvent;
20
import org.eclipse.swt.layout.GridData;
21
import org.eclipse.swt.layout.GridLayout;
22
import org.eclipse.swt.widgets.Button;
23
import org.eclipse.swt.widgets.Display;
24
import org.eclipse.swt.widgets.Shell;
25
import org.eclipse.zest.core.widgets.DAGExpandCollapseManager;
26
import org.eclipse.zest.core.widgets.DefaultSubgraph;
27
import org.eclipse.zest.core.widgets.Graph;
28
import org.eclipse.zest.core.widgets.GraphConnection;
29
import org.eclipse.zest.core.widgets.GraphItem;
30
import org.eclipse.zest.core.widgets.GraphNode;
31
import org.eclipse.zest.core.widgets.ZestStyles;
32
import org.eclipse.zest.layouts.LayoutAlgorithm;
33
import org.eclipse.zest.layouts.algorithms.DirectedGraphLayoutAlgorithm;
34
35
public class DAGExample {
36
	/**
37
	 * @param args
38
	 */
39
	public static void main(String[] args) {
40
		// Create the shell
41
		Display d = new Display();
42
		Shell shell = new Shell(d);
43
		shell.setText("GraphSnippet1");
44
		GridLayout gridLayout = new GridLayout();
45
		gridLayout.numColumns = 10;
46
		shell.setLayout(gridLayout);
47
		shell.setSize(500, 500);
48
49
		final Graph g = new Graph(shell, SWT.NONE);
50
		// LayoutAlgorithm algorithm = new CompositeLayoutAlgorithm(
51
		// new LayoutAlgorithm[] { new DirectedGraphLayoutAlgorithm(),
52
		// new HorizontalShiftAlgorithm() });
53
		LayoutAlgorithm algorithm = new DirectedGraphLayoutAlgorithm();
54
55
		g.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 10, 10));
56
		g.setSize(500, 500);
57
58
		g
59
				.setSubgraphFactory(new DefaultSubgraph.PrunedSuccessorsSubgraphFactory());
60
		g.setLayoutAlgorithm(algorithm, false);
61
		final DAGExpandCollapseManager dagExpandCollapseManager = new DAGExpandCollapseManager();
62
		g.setExpandCollapseManager(dagExpandCollapseManager);
63
64
		GraphNode root = new GraphNode(g, SWT.NONE, "Root");
65
		GraphNode a = new GraphNode(g, SWT.NONE, "A");
66
		GraphNode b = new GraphNode(g, SWT.NONE, "B");
67
		GraphNode c = new GraphNode(g, SWT.NONE, "C");
68
		GraphNode e = new GraphNode(g, SWT.NONE, "D");
69
70
		GraphNode f = new GraphNode(g, SWT.NONE, "E");
71
		GraphNode h = new GraphNode(g, SWT.NONE, "F");
72
73
		new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, root, a);
74
		new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, root, b);
75
		new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, root, c);
76
		new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, a, c);
77
		new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, c, e);
78
79
		new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, e, f);
80
		new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, e, h);
81
		new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, root, h);
82
83
		hookMenu(g);
84
85
		final Button buttonApply = new Button(shell, SWT.FLAT);
86
		buttonApply.setText("Apply");
87
88
		SelectionAdapter buttonListener = new SelectionAdapter() {
89
			public void widgetSelected(SelectionEvent e) {
90
				g.applyLayout();
91
			}
92
		};
93
		buttonApply.addSelectionListener(buttonListener);
94
95
		final Button buttonHideAll = new Button(shell, SWT.CHECK);
96
		buttonHideAll.setText("Hide all connections of collapsed nodes");
97
98
		buttonListener = new SelectionAdapter() {
99
			public void widgetSelected(SelectionEvent e) {
100
				dagExpandCollapseManager.setHidingConnections(buttonHideAll
101
						.getSelection());
102
			}
103
		};
104
		buttonHideAll.addSelectionListener(buttonListener);
105
		
106
107
108
		shell.open();
109
		while (!shell.isDisposed()) {
110
			while (!d.readAndDispatch()) {
111
				d.sleep();
112
			}
113
		}
114
	}
115
116
	private static void hookMenu(final Graph g) {
117
		MenuManager menuMgr = new MenuManager("#PopupMenu");
118
119
		Action expandAction = new Action() {
120
			public void run() {
121
				List selection = g.getSelection();
122
				if (!selection.isEmpty()) {
123
					GraphNode selected = (GraphNode) selection.get(0);
124
					g.setExpanded((GraphNode) selected, true);
125
				}
126
			}
127
		};
128
		expandAction.setText("expand");
129
		menuMgr.add(expandAction);
130
131
		Action collapseAction = new Action() {
132
			public void run() {
133
				List selection = g.getSelection();
134
				if (!selection.isEmpty()) {
135
					GraphItem selected = (GraphItem) selection.get(0);
136
					g.setExpanded((GraphNode) selected, false);
137
				}
138
			}
139
		};
140
		collapseAction.setText("collapse");
141
		menuMgr.add(collapseAction);
142
143
		g.setMenu(menuMgr.createContextMenu(g));
144
	}
145
}
(-)src/org/mati/zest/examples/SpaceTreeBuilding.java (+120 lines)
Added Link Here
1
package org.mati.zest.examples;
2
3
import java.util.List;
4
5
import org.eclipse.jface.action.Action;
6
import org.eclipse.jface.action.MenuManager;
7
import org.eclipse.swt.SWT;
8
import org.eclipse.swt.layout.FillLayout;
9
import org.eclipse.swt.widgets.Display;
10
import org.eclipse.swt.widgets.Shell;
11
import org.eclipse.zest.core.widgets.DefaultSubgraph;
12
import org.eclipse.zest.core.widgets.Graph;
13
import org.eclipse.zest.core.widgets.GraphConnection;
14
import org.eclipse.zest.core.widgets.GraphItem;
15
import org.eclipse.zest.core.widgets.GraphNode;
16
import org.eclipse.zest.layouts.algorithms.SpaceTreeLayoutAlgorithm;
17
18
/**
19
 * This example shows how SpringLayoutAlgorithm reacts to graph structure
20
 * related events, automatically rebuilding trees every time a new connection is
21
 * added.
22
 */
23
public class SpaceTreeBuilding {
24
	private static GraphNode parentNode = null;
25
	private static GraphNode childNode = null;
26
27
	public static void main(String[] args) {
28
		Display d = new Display();
29
		Shell shell = new Shell(d);
30
		shell.setText("GraphSnippet1");
31
		shell.setLayout(new FillLayout());
32
		shell.setSize(400, 400);
33
34
		final Graph g = new Graph(shell, SWT.NONE);
35
		
36
		hookMenu(g);
37
38
		SpaceTreeLayoutAlgorithm spaceTreeLayoutAlgorithm = new SpaceTreeLayoutAlgorithm();
39
		g.setLayoutAlgorithm(spaceTreeLayoutAlgorithm, false);
40
		g.setExpandCollapseManager(spaceTreeLayoutAlgorithm
41
				.getExpandCollapseManager());
42
		
43
		g.setSubgraphFactory(new DefaultSubgraph.LabelSubgraphFactory());
44
45
		for (int i = 0; i < 20; i++) {
46
			GraphNode graphNode = new GraphNode(g, SWT.NONE);
47
			graphNode.setText("" + i);
48
		}
49
50
		shell.open();
51
		while (!shell.isDisposed()) {
52
			while (!d.readAndDispatch()) {
53
				d.sleep();
54
			}
55
		}
56
	}
57
58
	private static void tryToAddConnection(Graph g) {
59
		if (parentNode != null && childNode != null) {
60
			new GraphConnection(g, SWT.NONE, parentNode, childNode);
61
			parentNode = childNode = null;
62
		}
63
	}
64
65
	private static void hookMenu(final Graph g) {
66
		MenuManager menuMgr = new MenuManager("#PopupMenu");
67
		
68
		Action parentAction = new Action() {
69
			public void run() {
70
				List selection = g.getSelection();
71
				if (!selection.isEmpty()) {
72
					GraphNode selected = (GraphNode) selection.get(0);
73
					parentNode = selected;
74
					tryToAddConnection(g);
75
				}
76
			}
77
		};
78
		parentAction.setText("use as parent");
79
		menuMgr.add(parentAction);
80
81
		Action childAction = new Action() {
82
			public void run() {
83
				List selection = g.getSelection();
84
				if (!selection.isEmpty()) {
85
					GraphNode selected = (GraphNode) selection.get(0);
86
					childNode = selected;
87
					tryToAddConnection(g);
88
				}
89
			}
90
		};
91
		childAction.setText("use as child");
92
		menuMgr.add(childAction);
93
94
		Action expandAction = new Action() {
95
			public void run() {
96
				List selection = g.getSelection();
97
				if (!selection.isEmpty()) {
98
					GraphNode selected = (GraphNode) selection.get(0);
99
					g.setExpanded((GraphNode) selected, true);
100
				}
101
			}
102
		};
103
		expandAction.setText("expand");
104
		menuMgr.add(expandAction);
105
106
		Action collapseAction = new Action() {
107
			public void run() {
108
				List selection = g.getSelection();
109
				if (!selection.isEmpty()) {
110
					GraphItem selected = (GraphItem) selection.get(0);
111
					g.setExpanded((GraphNode) selected, false);
112
				}
113
			}
114
		};
115
		collapseAction.setText("collapse");
116
		menuMgr.add(collapseAction);
117
118
		g.setMenu(menuMgr.createContextMenu(g));
119
	}
120
}
(-)src/org/eclipse/zest/tests/swt/ConnectionToolTipGraphSnippet.java (+110 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.draw2d.IFigure;
15
import org.eclipse.draw2d.Label;
16
import org.eclipse.zest.core.widgets.Graph;
17
import org.eclipse.zest.core.widgets.GraphConnection;
18
import org.eclipse.zest.core.widgets.GraphNode;
19
import org.eclipse.zest.core.widgets.ZestStyles;
20
import org.eclipse.swt.SWT;
21
import org.eclipse.swt.graphics.GC;
22
import org.eclipse.swt.graphics.Image;
23
import org.eclipse.swt.layout.FillLayout;
24
import org.eclipse.swt.widgets.Display;
25
import org.eclipse.swt.widgets.Shell;
26
27
/**
28
 * This snippet shows how a custom figure can be used as a ToolTip for connections.
29
 * Let your mouse hover over an edge to see the custom tooltip.
30
 * 
31
 * @author Ian Bull
32
 * 
33
 */
34
public class ConnectionToolTipGraphSnippet {
35
	
36
	
37
	/**
38
	 * Merges 2 images so they appear beside each other
39
	 * 
40
	 * You must dispose this image!
41
	 * @param image1
42
	 * @param image2
43
	 * @param result
44
	 * @return
45
	 */
46
	public static Image mergeImages(Image image1, Image image2) {
47
		Image mergedImage = new Image(Display.getDefault(), image1.getBounds().width + image2.getBounds().width, image1.getBounds().height);
48
		GC gc = new GC(mergedImage);
49
		gc.drawImage(image1, 0, 0);
50
		gc.drawImage(image2, image1.getBounds().width, 0);
51
		gc.dispose();
52
		return mergedImage;
53
	}
54
	
55
56
	/**
57
	 * @param args
58
	 */
59
	public static void main(String[] args) {
60
		Display d = new Display();
61
		Shell shell = new Shell(d);
62
		shell.setText("Graph Snippet 4");
63
		Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION);
64
		Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
65
		Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR);
66
		shell.setLayout(new FillLayout());
67
		shell.setSize(400, 400);
68
69
		Graph g = new Graph(shell, SWT.NONE);
70
		g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED );
71
		GraphNode n1 = new GraphNode(g, SWT.NONE);
72
		n1.setText("Information");
73
		n1.setImage(image1);
74
		GraphNode n2 = new GraphNode(g, SWT.NONE);
75
		n2.setText("Warning");
76
		n2.setImage(image2);
77
		GraphNode n3 = new GraphNode(g, SWT.NONE);
78
		n3.setText("Error");
79
		n3.setImage(image3);
80
		
81
		GraphConnection connection1 = new GraphConnection(g, SWT.NONE, n1, n2);
82
		GraphConnection connection2 = new GraphConnection(g, SWT.NONE, n2, n3);
83
		
84
		Image information2warningImage = mergeImages(image1, image2);
85
		Image warning2error = mergeImages(image2, image3);
86
		IFigure tooltip1 = new Label("Information to Warning", information2warningImage);
87
		IFigure tooltip2 = new Label("Warning to Error", warning2error);
88
		connection1.setTooltip(tooltip1);
89
		connection2.setTooltip(tooltip2);
90
		
91
		n1.setLocation(10, 10);
92
		n2.setLocation(200, 10);
93
		n3.setLocation(200, 200);
94
95
		shell.open();
96
		while (!shell.isDisposed()) {
97
			while (!d.readAndDispatch()) {
98
				d.sleep();
99
			}
100
		}
101
		
102
		image1.dispose();
103
		image2.dispose();
104
		image3.dispose();
105
		
106
		information2warningImage.dispose();
107
		warning2error.dispose();
108
109
	}
110
}
(-)src/org/eclipse/zest/tests/swt/SpringLayoutExample.java (+60 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.swt.SWT;
15
import org.eclipse.swt.layout.FillLayout;
16
import org.eclipse.swt.widgets.Display;
17
import org.eclipse.swt.widgets.Shell;
18
import org.eclipse.zest.core.widgets.Graph;
19
import org.eclipse.zest.core.widgets.GraphConnection;
20
import org.eclipse.zest.core.widgets.GraphNode;
21
import org.eclipse.zest.layouts.LayoutAlgorithm;
22
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
23
24
public class SpringLayoutExample {
25
26
	/**
27
	 * @param args
28
	 */
29
	public static void main(String[] args) {
30
		// Create the shell
31
		Display d = new Display();
32
		Shell shell = new Shell(d);
33
		shell.setText("GraphSnippet1");
34
		shell.setLayout(new FillLayout());
35
		shell.setSize(500, 500);
36
37
		final Graph g = new Graph(shell, SWT.NONE);
38
		g.setSize(500, 500);
39
		GraphNode root = new GraphNode(g, SWT.NONE, "Root");
40
		for (int i = 0; i < 3; i++) {
41
			GraphNode n = new GraphNode(g, SWT.NONE, "1 - " + i);
42
			for (int j = 0; j < 3; j++) {
43
				GraphNode n2 = new GraphNode(g, SWT.NONE, "2 - " + j);
44
				new GraphConnection(g, SWT.NONE, n, n2).setWeight(-1);
45
			}
46
			new GraphConnection(g, SWT.NONE, root, n);
47
		}
48
49
		final LayoutAlgorithm layoutAlgorithm = new SpringLayoutAlgorithm();
50
51
		g.setLayoutAlgorithm(layoutAlgorithm, true);
52
		shell.open();
53
		while (!shell.isDisposed()) {
54
			while (!d.readAndDispatch()) {
55
				d.sleep();
56
			}
57
		}
58
	}
59
60
}
(-)src/org/eclipse/zest/tests/jface/SelectionListenerGraphJFaceSnippet.java (+134 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 ******************************************************************************/
12
package org.eclipse.zest.tests.jface;
13
14
import java.util.Iterator;
15
16
import org.eclipse.jface.viewers.ISelectionChangedListener;
17
import org.eclipse.jface.viewers.LabelProvider;
18
import org.eclipse.jface.viewers.SelectionChangedEvent;
19
import org.eclipse.jface.viewers.StructuredSelection;
20
import org.eclipse.jface.viewers.Viewer;
21
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
22
import org.eclipse.zest.core.viewers.GraphViewer;
23
import org.eclipse.zest.core.viewers.IGraphContentProvider;
24
import org.eclipse.swt.SWT;
25
import org.eclipse.swt.graphics.Image;
26
import org.eclipse.swt.layout.FillLayout;
27
import org.eclipse.swt.widgets.Display;
28
import org.eclipse.swt.widgets.Shell;
29
30
public class SelectionListenerGraphJFaceSnippet {
31
	static class MyContentProvider implements IGraphContentProvider {
32
33
		public Object getDestination(Object rel) {
34
			if ("Rock2Paper".equals(rel)) {
35
				return "Rock";
36
			} else if ("Paper2Scissors".equals(rel)) {
37
				return "Paper";
38
			} else if ("Scissors2Rock".equals(rel)) {
39
				return "Scissors";
40
			}
41
			return null;
42
		}
43
44
		public Object[] getElements(Object input) {
45
			return new Object[] { "Rock2Paper", "Paper2Scissors", "Scissors2Rock" };
46
		}
47
48
		public Object getSource(Object rel) {
49
			if ("Rock2Paper".equals(rel)) {
50
				return "Paper";
51
			} else if ("Paper2Scissors".equals(rel)) {
52
				return "Scissors";
53
			} else if ("Scissors2Rock".equals(rel)) {
54
				return "Rock";
55
			}
56
			return null;
57
		}
58
59
		public double getWeight(Object connection) {
60
			return 0;
61
		}
62
63
		public void dispose() {
64
		}
65
66
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
67
		}
68
69
	}
70
71
	static class MyLabelProvider extends LabelProvider {
72
		final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
73
74
		public Image getImage(Object element) {
75
			if (element.equals("Rock") || element.equals("Paper") || element.equals("Scissors")) {
76
				return image;
77
			}
78
			return null;
79
		}
80
81
		public String getText(Object element) {
82
			return element.toString();
83
		}
84
85
	}
86
87
	static GraphViewer viewer = null;
88
89
	/**
90
	 * @param args
91
	 */
92
	public static void main(String[] args) {
93
		Display d = new Display();
94
		Shell shell = new Shell(d);
95
		shell.setText("GraphJFaceSnippet2");
96
		shell.setLayout(new FillLayout(SWT.VERTICAL));
97
		shell.setSize(400, 400);
98
		viewer = new GraphViewer(shell, SWT.NONE);
99
		viewer.setContentProvider(new MyContentProvider());
100
		viewer.setLabelProvider(new MyLabelProvider());
101
		viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm());
102
		viewer.setInput(new Object());
103
		viewer.addSelectionChangedListener(new ISelectionChangedListener() {
104
105
			public void selectionChanged(SelectionChangedEvent event) {
106
				System.out.println("Selection Changed: " + selectionToString((StructuredSelection) event.getSelection()));
107
			}
108
109
			private String selectionToString(StructuredSelection selection) {
110
				StringBuffer stringBuffer = new StringBuffer();
111
				Iterator iterator = selection.iterator();
112
				boolean first = true;
113
				while (iterator.hasNext()) {
114
					if (first) {
115
						first = false;
116
					} else {
117
						stringBuffer.append(" : ");
118
					}
119
					stringBuffer.append(iterator.next());
120
				}
121
				return stringBuffer.toString();
122
			}
123
124
		});
125
		shell.open();
126
		while (!shell.isDisposed()) {
127
			while (!d.readAndDispatch()) {
128
				d.sleep();
129
			}
130
		}
131
132
	}
133
134
}
(-)src/org/eclipse/zest/tests/jface/FileProviderJFaceSnippet.java (+136 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 ******************************************************************************/
12
package org.eclipse.zest.tests.jface;
13
14
import java.io.BufferedReader;
15
import java.io.File;
16
import java.io.FileReader;
17
import java.io.IOException;
18
import java.util.ArrayList;
19
import java.util.StringTokenizer;
20
21
import org.eclipse.jface.viewers.LabelProvider;
22
import org.eclipse.jface.viewers.Viewer;
23
import org.eclipse.swt.SWT;
24
import org.eclipse.swt.layout.FillLayout;
25
import org.eclipse.swt.widgets.Display;
26
import org.eclipse.swt.widgets.FileDialog;
27
import org.eclipse.swt.widgets.Shell;
28
import org.eclipse.zest.core.viewers.GraphViewer;
29
import org.eclipse.zest.core.viewers.IGraphContentProvider;
30
import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm;
31
32
/**
33
 * This snippet uses a very simple file format to read a graph. Edges are listed
34
 * on a new line in a file as such: 
35
 * a calls b 
36
 * b calls c 
37
 * c calld d
38
 * 
39
 * The content provider creates an edge for each line in the file and names the
40
 * sources and destination from the line.
41
 * 
42
 * 
43
 * @author Ian Bull
44
 * 
45
 */
46
public class FileProviderJFaceSnippet {
47
48
	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";
49
50
	static class SimpleGraphContentProvider implements IGraphContentProvider {
51
52
		private StringTokenizer graph;
53
54
		public Object getDestination(Object rel) {
55
			String string = (String) rel;
56
			String[] parts = string.split(" ");
57
			return parts[2];
58
		}
59
60
		public Object[] getElements(Object input) {
61
			ArrayList listOfEdges = new ArrayList();
62
			while (graph.hasMoreTokens()) {
63
				listOfEdges.add(graph.nextToken());
64
			}
65
			return listOfEdges.toArray();
66
		}
67
68
		public Object getSource(Object rel) {
69
			String string = (String) rel;
70
			String[] parts = string.split(" ");
71
			return parts[0];
72
		}
73
74
		public double getWeight(Object connection) {
75
			return 0;
76
		}
77
78
		public void dispose() {
79
80
		}
81
82
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
83
			if (newInput != null) {
84
				graph = new StringTokenizer((String) newInput, "\n");
85
			}
86
		}
87
88
	}
89
90
	public static void main(String[] args) throws IOException {
91
		Display display = new Display();
92
		Shell shell = new Shell(display);
93
		shell.setText("Simple Graph File Format");
94
95
		FileDialog dialog = new FileDialog(shell, SWT.OPEN);
96
		dialog.setFilterNames(new String[] { "Simple Graph Files (*.sgf)", "All Files (*.*)" });
97
		dialog.setFilterExtensions(new String[] { "*.sgf", "*.*" }); //Windows wild cards
98
99
		String directory = System.getProperty("user.dir") + "/src/org/eclipse/zest/tests/jface/SimpleGraph.sgf"; //eclipse/zest/examples/jface/";
100
		System.out.println(directory);
101
		dialog.setFilterPath(directory);
102
		//dialog.setFilterPath(System.getProperty("user.dir") + "src/org/eclipse/zest/examples/jface/"); //Windows path
103
104
		shell.setLayout(new FillLayout(SWT.VERTICAL));
105
		shell.setSize(400, 400);
106
		GraphViewer viewer = null;
107
108
		viewer = new GraphViewer(shell, SWT.NONE);
109
		viewer.setContentProvider(new SimpleGraphContentProvider());
110
		viewer.setLabelProvider(new LabelProvider());
111
		viewer.setLayoutAlgorithm(new RadialLayoutAlgorithm());
112
113
		shell.open();
114
		String fileName = dialog.open();
115
116
		if (fileName == null) {
117
			// use the sample graph
118
			viewer.setInput(graph);
119
		} else {
120
			FileReader fileReader = new FileReader(new File(fileName));
121
			BufferedReader bufferedReader = new BufferedReader(fileReader);
122
			StringBuffer stringBuffer = new StringBuffer();
123
			while (bufferedReader.ready()) {
124
				stringBuffer.append(bufferedReader.readLine() + "\n");
125
			}
126
			viewer.setInput(stringBuffer.toString());
127
		}
128
129
		while (!shell.isDisposed()) {
130
			if (!display.readAndDispatch()) {
131
				display.sleep();
132
			}
133
		}
134
		display.dispose();
135
	}
136
}
(-)src/org/eclipse/zest/tests/swt/SimpleGraphSnippet.java (+61 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.swt.SWT;
15
import org.eclipse.swt.layout.FillLayout;
16
import org.eclipse.swt.widgets.Display;
17
import org.eclipse.swt.widgets.Shell;
18
import org.eclipse.zest.core.widgets.Graph;
19
import org.eclipse.zest.core.widgets.GraphConnection;
20
import org.eclipse.zest.core.widgets.GraphNode;
21
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
22
23
/**
24
 * This snippet creates a very simple graph where Rock is connected to Paper
25
 * which is connected to scissors which is connected to rock.
26
 * 
27
 * The nodes a positioned using a SpringLayout Algorithm, and they can be moved
28
 * around.
29
 * 
30
 * 
31
 * @author Ian Bull
32
 * 
33
 */
34
public class SimpleGraphSnippet {
35
36
	public static void main(String[] args) {
37
		Display d = new Display();
38
		Shell shell = new Shell(d);
39
		shell.setText("GraphSnippet1");
40
		shell.setLayout(new FillLayout());
41
		shell.setSize(400, 400);
42
43
		Graph g = new Graph(shell, SWT.NONE);
44
45
		GraphNode n = new GraphNode(g, SWT.NONE, "Paper");
46
		GraphNode n2 = new GraphNode(g, SWT.NONE, "Rock");
47
		GraphNode n3 = new GraphNode(g, SWT.NONE, "Scissors");
48
		new GraphConnection(g, SWT.NONE, n, n2);
49
		new GraphConnection(g, SWT.NONE, n2, n3);
50
		new GraphConnection(g, SWT.NONE, n3, n);
51
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true);
52
53
		shell.open();
54
		while (!shell.isDisposed()) {
55
			while (!d.readAndDispatch()) {
56
				d.sleep();
57
			}
58
		}
59
	}
60
61
}
(-)src/org/eclipse/zest/tests/swt/FindFigureGraphSnippet.java (+72 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 ******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.zest.core.widgets.Graph;
15
import org.eclipse.zest.core.widgets.GraphConnection;
16
import org.eclipse.zest.core.widgets.GraphNode;
17
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
18
import org.eclipse.swt.SWT;
19
import org.eclipse.swt.events.MouseEvent;
20
import org.eclipse.swt.events.MouseMoveListener;
21
import org.eclipse.swt.layout.FillLayout;
22
import org.eclipse.swt.widgets.Display;
23
import org.eclipse.swt.widgets.Shell;
24
25
/**
26
 * This snippet shows how to use the findFigureAt to get the figure under the mouse
27
 * 
28
 * @author Ian Bull
29
 * 
30
 */
31
public class FindFigureGraphSnippet {
32
33
	/**
34
	 * @param args
35
	 */
36
	public static void main(String[] args) {
37
		Display d = new Display();
38
		Shell shell = new Shell(d);
39
		shell.setText("GraphSnippet7");
40
		shell.setLayout(new FillLayout());
41
		shell.setSize(400, 400);
42
43
		final Graph g = new Graph(shell, SWT.NONE);
44
45
		GraphNode n = new GraphNode(g, SWT.NONE, "Paper");
46
		GraphNode n2 = new GraphNode(g, SWT.NONE, "Rock");
47
		GraphNode n3 = new GraphNode(g, SWT.NONE, "Scissors");
48
		new GraphConnection(g, SWT.NONE, n, n2);
49
		new GraphConnection(g, SWT.NONE, n2, n3);
50
		new GraphConnection(g, SWT.NONE, n3, n);
51
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true);
52
		
53
		g.addMouseMoveListener(new MouseMoveListener() {
54
55
			public void mouseMove(MouseEvent e) {
56
				// Get the figure at the current mouse location 
57
				Object o = g.getFigureAt(e.x, e.y);
58
				if ( o != null ) {
59
					System.out.println(o + " is at: (" + e.x + "," + e.y + ")");
60
				}
61
			}
62
			
63
		});
64
65
		shell.open();
66
		while (!shell.isDisposed()) {
67
			while (!d.readAndDispatch()) {
68
				d.sleep();
69
			}
70
		}
71
	}
72
}
(-)src/org/eclipse/zest/tests/swt/FisheyeGraphSnippet.java (+77 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.swt.SWT;
15
import org.eclipse.swt.graphics.Image;
16
import org.eclipse.swt.layout.FillLayout;
17
import org.eclipse.swt.widgets.Display;
18
import org.eclipse.swt.widgets.Shell;
19
import org.eclipse.zest.core.widgets.Graph;
20
import org.eclipse.zest.core.widgets.GraphConnection;
21
import org.eclipse.zest.core.widgets.GraphNode;
22
import org.eclipse.zest.core.widgets.ZestStyles;
23
import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm;
24
25
/**
26
 * This snippet creates a graph with 80*3 nodes (240 nodes).  Only the icons are shown for the nodes, but if
27
 * you mouse over the node you get the entire text.
28
 * 
29
 * @author Ian Bull
30
 * 
31
 */
32
public class FisheyeGraphSnippet {
33
34
	/**
35
	 * @param args
36
	 */
37
	public static void main(String[] args) {
38
		Display d = new Display();
39
		Shell shell = new Shell(d);
40
		shell.setText("GraphSnippet6");
41
		Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION);
42
		Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
43
		Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR);
44
		shell.setLayout(new FillLayout());
45
		shell.setSize(800, 800);
46
47
		Graph g = new Graph(shell, SWT.NONE);
48
		g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED);
49
		for (int i = 0; i < 80; i++) {
50
			GraphNode n1 = new GraphNode(g, ZestStyles.NODES_HIDE_TEXT
51
					| ZestStyles.NODES_FISHEYE, "Information");
52
			n1.setImage(image1);
53
			GraphNode n2 = new GraphNode(g, ZestStyles.NODES_HIDE_TEXT
54
					| ZestStyles.NODES_FISHEYE, "Warning");
55
			n2.setImage(image2);
56
			GraphNode n3 = new GraphNode(g, ZestStyles.NODES_HIDE_TEXT
57
					| ZestStyles.NODES_FISHEYE, "Error");
58
			n3.setImage(image3);
59
			new GraphConnection(g, SWT.NONE, n1, n2);
60
			new GraphConnection(g, SWT.NONE, n2, n3);
61
			new GraphConnection(g, SWT.NONE, n3, n3);
62
		}
63
		g.setLayoutAlgorithm(new GridLayoutAlgorithm(), true);
64
65
		shell.open();
66
		while (!shell.isDisposed()) {
67
			while (!d.readAndDispatch()) {
68
				d.sleep();
69
			}
70
		}
71
		image1.dispose();
72
		image2.dispose();
73
		image3.dispose();
74
75
	}
76
77
}
(-)src/org/eclipse/zest/tests/swt/CustomFigureGraphSnippet.java (+165 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import java.util.Iterator;
15
16
import org.eclipse.draw2d.ColorConstants;
17
import org.eclipse.draw2d.Ellipse;
18
import org.eclipse.draw2d.Figure;
19
import org.eclipse.draw2d.FreeformLayout;
20
import org.eclipse.draw2d.IFigure;
21
import org.eclipse.draw2d.ImageFigure;
22
import org.eclipse.draw2d.PolylineShape;
23
import org.eclipse.draw2d.geometry.Point;
24
import org.eclipse.draw2d.geometry.Rectangle;
25
import org.eclipse.swt.SWT;
26
import org.eclipse.swt.events.SelectionEvent;
27
import org.eclipse.swt.events.SelectionListener;
28
import org.eclipse.swt.graphics.Image;
29
import org.eclipse.swt.layout.FillLayout;
30
import org.eclipse.swt.widgets.Display;
31
import org.eclipse.swt.widgets.Shell;
32
import org.eclipse.zest.core.widgets.Graph;
33
import org.eclipse.zest.core.widgets.GraphConnection;
34
import org.eclipse.zest.core.widgets.GraphNode;
35
import org.eclipse.zest.core.widgets.custom.CGraphNode;
36
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
37
38
/**
39
 * 
40
 * This snippet shows how to create a graph with custom figures as nodes.
41
 * 
42
 * @author Ian Bull
43
 * 
44
 */
45
public class CustomFigureGraphSnippet {
46
47
	public static IFigure createPersonFigure(Image headImage) {
48
		Figure person = new Figure();
49
		person.setLayoutManager(new FreeformLayout());
50
		IFigure head = null;
51
		if ( headImage != null ) {
52
			headImage = new Image(headImage.getDevice(), headImage.getImageData().scaledTo(40, 50));
53
			head = new ImageFigure(headImage);
54
		}
55
		else
56
			head = new Ellipse();
57
		head.setSize(40, 50);
58
		
59
		PolylineShape body = new PolylineShape();
60
		body.setLineWidth(1);
61
		body.setStart(new Point(20,40));
62
		body.setEnd(new Point(20,100));
63
		body.setBounds(new Rectangle(0,0,40,100));
64
		
65
		PolylineShape leftLeg = new PolylineShape();
66
		leftLeg.setLineWidth(1);
67
		leftLeg.setStart(new Point(20,100));
68
		leftLeg.setEnd(new Point(0,130));
69
		leftLeg.setBounds(new Rectangle(0,0,40,130));
70
		
71
		PolylineShape rightLeg = new PolylineShape();
72
		rightLeg.setLineWidth(1);
73
		rightLeg.setStart(new Point(20,100));
74
		rightLeg.setEnd(new Point(40,130));
75
		rightLeg.setBounds(new Rectangle(0,0,40,130));
76
		
77
		PolylineShape leftArm = new PolylineShape();
78
		leftArm.setLineWidth(1);
79
		leftArm.setStart(new Point(20,60));
80
		leftArm.setEnd(new Point(0,50));
81
		leftArm.setBounds(new Rectangle(0,0,40,130));
82
		
83
		PolylineShape rightArm = new PolylineShape();
84
		rightArm.setLineWidth(1);
85
		rightArm.setStart(new Point(20,60));
86
		rightArm.setEnd(new Point(40,50));
87
		rightArm.setBounds(new Rectangle(0,0,40,130));
88
		
89
		person.add(head);
90
		person.add(body);
91
		person.add(leftLeg);
92
		person.add(rightLeg);
93
		person.add(leftArm);
94
		person.add(rightArm);
95
		person.setSize(40,130);
96
		return person;
97
	}
98
99
	public static void main(String[] args) {
100
		final Display d = new Display();
101
		Shell shell = new Shell(d);
102
		shell.setText("GraphSnippet11");
103
		shell.setLayout(new FillLayout());
104
		shell.setSize(400, 400);
105
106
		
107
		final Graph g = new Graph(shell, SWT.NONE);
108
		g.addSelectionListener(new SelectionListener(){
109
		
110
			public void widgetSelected(SelectionEvent e) {
111
				Iterator iter = g.getSelection().iterator();
112
				while(iter.hasNext()) {
113
					Object o = iter.next();
114
					if ( o instanceof CGraphNode) {
115
						IFigure figure = ((CGraphNode)o).getFigure();
116
						figure.setBackgroundColor(ColorConstants.blue);
117
						figure.setForegroundColor(ColorConstants.blue);
118
					}
119
				}
120
				iter = g.getNodes().iterator();
121
				while ( iter.hasNext()) {
122
					Object o = iter.next();
123
					if ( o instanceof CGraphNode) {
124
						if ( !g.getSelection().contains(o)) {
125
							((CGraphNode)o).getFigure().setBackgroundColor(ColorConstants.black);
126
							((CGraphNode)o).getFigure().setForegroundColor(ColorConstants.black);
127
						}
128
					}
129
				}
130
			}
131
		
132
			public void widgetDefaultSelected(SelectionEvent e) {
133
				// TODO Auto-generated method stub
134
				
135
			}
136
		});
137
		
138
		Image zx = new Image(d, "zx.png");
139
		Image ibull = new Image(d, "ibull.jpg");
140
		CGraphNode n = new CGraphNode(g, SWT.NONE, createPersonFigure(zx));
141
		CGraphNode n2 = new CGraphNode(g, SWT.NONE,  createPersonFigure(ibull));
142
		GraphNode n3 = new GraphNode(g, SWT.NONE, "PDE");
143
		GraphNode n4 = new GraphNode(g, SWT.NONE, "Zest");
144
		GraphNode n5 = new GraphNode(g, SWT.NONE, "PDE Viz tool");
145
		
146
		new GraphConnection(g, SWT.NONE, n, n2);
147
		new GraphConnection(g, SWT.NONE, n, n3);
148
		new GraphConnection(g, SWT.NONE, n2, n4);
149
		new GraphConnection(g, SWT.NONE, n, n5);
150
		new GraphConnection(g, SWT.NONE, n2, n5);
151
		new GraphConnection(g, SWT.NONE, n3, n5);
152
		new GraphConnection(g, SWT.NONE, n4, n5);
153
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true);
154
155
		shell.open();
156
		while (!shell.isDisposed()) {
157
			while (!d.readAndDispatch()) {
158
				d.sleep();
159
			}
160
		}
161
		zx.dispose();
162
		ibull.dispose();
163
	}
164
165
}
(-)src/org/eclipse/zest/tests/swt/CustomPaintingGraphSnippet.java (+145 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 ******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import java.util.ArrayList;
15
import java.util.HashMap;
16
import java.util.Iterator;
17
import java.util.List;
18
import java.util.Map;
19
20
import org.eclipse.draw2d.ColorConstants;
21
import org.eclipse.swt.SWT;
22
import org.eclipse.swt.events.KeyAdapter;
23
import org.eclipse.swt.events.KeyEvent;
24
import org.eclipse.swt.events.PaintEvent;
25
import org.eclipse.swt.events.PaintListener;
26
import org.eclipse.swt.graphics.Font;
27
import org.eclipse.swt.graphics.FontData;
28
import org.eclipse.swt.graphics.Image;
29
import org.eclipse.swt.graphics.Region;
30
import org.eclipse.swt.layout.FillLayout;
31
import org.eclipse.swt.widgets.Display;
32
import org.eclipse.swt.widgets.Shell;
33
import org.eclipse.zest.core.widgets.Graph;
34
import org.eclipse.zest.core.widgets.GraphConnection;
35
import org.eclipse.zest.core.widgets.GraphItem;
36
import org.eclipse.zest.core.widgets.GraphNode;
37
import org.eclipse.zest.core.widgets.ZestStyles;
38
39
/**
40
 * This snippet shows how you can add a paint listener to a Zest graph to paint on top of
41
 * the widget.  This snippet allows you to type and it selects all the nodes that match 
42
 * what you type.
43
 * 
44
 * @author Ian Bull
45
 * 
46
 */
47
public class CustomPaintingGraphSnippet {
48
	public static final int BACKSPACE = 8;
49
	public static final int ENTER = 13;
50
51
	/**
52
	 * @param args
53
	 */
54
	public static void main(String[] args) {
55
		final Map figureListing = new HashMap();
56
		final StringBuffer stringBuffer = new StringBuffer();
57
		final Display d = new Display();
58
		FontData fontData = d.getSystemFont().getFontData()[0];
59
		fontData.height = 42;
60
61
		final Font font = new Font(d, fontData);
62
63
		Shell shell = new Shell(d);
64
		shell.setText("Graph Snippet 5");
65
		Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION);
66
		Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
67
		Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR);
68
		shell.setLayout(new FillLayout());
69
		shell.setSize(400, 400);
70
71
		final Graph g = new Graph(shell, SWT.NONE);
72
		g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED);
73
		GraphNode n1 = new GraphNode(g, SWT.NONE);
74
		n1.setText("org.eclipse.Information");
75
		n1.setImage(image1);
76
		GraphNode n2 = new GraphNode(g, SWT.NONE);
77
		n2.setText("org.eclipse.Warning");
78
		n2.setImage(image2);
79
		GraphNode n3 = new GraphNode(g, SWT.NONE);
80
		n3.setText("org.eclipse.Error");
81
		n3.setImage(image3);
82
		figureListing.put(n1.getText().toLowerCase(), n1);
83
		figureListing.put(n2.getText().toLowerCase(), n2);
84
		figureListing.put(n3.getText().toLowerCase(), n3);
85
86
		new GraphConnection(g, SWT.NONE, n1, n2);
87
		new GraphConnection(g, SWT.NONE, n2, n3);
88
		n1.setLocation(10, 10);
89
		n2.setLocation(200, 10);
90
		n3.setLocation(200, 200);
91
92
		g.addKeyListener(new KeyAdapter() {
93
94
			public void keyPressed(KeyEvent e) {
95
				boolean complete = false;
96
				if (e.keyCode == BACKSPACE) {
97
					if (stringBuffer.length() > 0) {
98
						stringBuffer.deleteCharAt(stringBuffer.length() - 1);
99
					}
100
				} else if (e.keyCode == ENTER) {
101
					complete = true;
102
				} else if ((e.character >= 'a' && e.character <= 'z') || (e.character >= 'A' && e.character <= 'Z') || (e.character == '.') || (e.character >= '0' && e.character <= '9')) {
103
					stringBuffer.append(e.character);
104
				}
105
				Iterator iterator = figureListing.keySet().iterator();
106
				List list = new ArrayList();
107
				if (stringBuffer.length() > 0) {
108
					while (iterator.hasNext()) {
109
						String string = (String) iterator.next();
110
						if (string.indexOf(stringBuffer.toString().toLowerCase()) >= 0) {
111
							list.add(figureListing.get(string));
112
						}
113
					}
114
				}
115
				g.setSelection((GraphItem[]) list.toArray(new GraphItem[list.size()]));
116
				if (complete && stringBuffer.length() > 0) {
117
					stringBuffer.delete(0, stringBuffer.length());
118
				}
119
120
				g.redraw();
121
			}
122
123
		});
124
125
		g.addPaintListener(new PaintListener() {
126
			public void paintControl(PaintEvent e) {
127
				e.gc.setFont(font);
128
				e.gc.setClipping((Region) null);
129
				e.gc.setForeground(ColorConstants.black);
130
				e.gc.drawText(stringBuffer.toString(), 50, 50, true);
131
			}
132
		});
133
134
		shell.open();
135
		while (!shell.isDisposed()) {
136
			while (!d.readAndDispatch()) {
137
				d.sleep();
138
			}
139
		}
140
		image1.dispose();
141
		image2.dispose();
142
		image3.dispose();
143
		font.dispose();
144
	}
145
}
(-)src/org/eclipse/zest/tests/swt/CurvedEdgeGraphSnippet.java (+79 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 ******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.swt.SWT;
15
import org.eclipse.swt.events.SelectionAdapter;
16
import org.eclipse.swt.events.SelectionEvent;
17
import org.eclipse.swt.layout.FillLayout;
18
import org.eclipse.swt.widgets.Button;
19
import org.eclipse.swt.widgets.Display;
20
import org.eclipse.swt.widgets.Shell;
21
import org.eclipse.zest.core.widgets.Graph;
22
import org.eclipse.zest.core.widgets.GraphConnection;
23
import org.eclipse.zest.core.widgets.GraphNode;
24
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
25
26
/**
27
 * 
28
 * This snippet shows how to create a curved connection using Zest.
29
 * Each time the Button is clicked, the curve changes.
30
 * 
31
 * @author Ian Bull
32
 * 
33
 */
34
public class CurvedEdgeGraphSnippet {
35
36
	public static void main(String[] args) {
37
		Display d = new Display();
38
		Shell shell = new Shell(d);
39
		shell.setText("GraphSnippet1");
40
		shell.setLayout(new FillLayout());
41
		shell.setSize(400, 400);
42
43
		final Graph g = new Graph(shell, SWT.NONE);
44
45
		GraphNode n = new GraphNode(g, SWT.NONE, "Paper");
46
		n.setBorderColor(org.eclipse.draw2d.ColorConstants.yellow);
47
		n.setBorderWidth(3);
48
		GraphNode n2 = new GraphNode(g, SWT.NONE, "Rock");
49
		GraphNode n3 = new GraphNode(g, SWT.NONE, "Scissors");
50
		final GraphConnection connection = new GraphConnection(g, SWT.NONE, n, n2);
51
		connection.setLineWidth(3);
52
		new GraphConnection(g, SWT.NONE, n2, n3);
53
		new GraphConnection(g, SWT.NONE, n3, n);
54
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true);
55
		
56
		Button button = new Button(shell, SWT.PUSH);
57
		button.setText("Change Curve");
58
		button.addSelectionListener(new SelectionAdapter() {
59
			int count = 0;
60
			public void widgetSelected(SelectionEvent e) {
61
				count = ++count % 16;
62
				if ( count > 8 ) {
63
					connection.setCurveDepth((-16 + count) * 10);
64
				}
65
				else {
66
					connection.setCurveDepth(count * 10);
67
				}
68
			}
69
		});
70
71
		shell.open();
72
		while (!shell.isDisposed()) {
73
			while (!d.readAndDispatch()) {
74
				d.sleep();
75
			}
76
		}
77
	}
78
79
}
(-)src/org/eclipse/zest/tests/jface/RefreshGraphJFaceSnippet.java (+143 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 ******************************************************************************/
12
package org.eclipse.zest.tests.jface;
13
14
import org.eclipse.jface.viewers.LabelProvider;
15
import org.eclipse.jface.viewers.Viewer;
16
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
17
import org.eclipse.zest.core.viewers.GraphViewer;
18
import org.eclipse.zest.core.viewers.IGraphContentProvider;
19
import org.eclipse.swt.SWT;
20
import org.eclipse.swt.events.SelectionAdapter;
21
import org.eclipse.swt.events.SelectionEvent;
22
import org.eclipse.swt.graphics.Image;
23
import org.eclipse.swt.layout.FillLayout;
24
import org.eclipse.swt.layout.GridData;
25
import org.eclipse.swt.layout.GridLayout;
26
import org.eclipse.swt.widgets.Button;
27
import org.eclipse.swt.widgets.Composite;
28
import org.eclipse.swt.widgets.Display;
29
import org.eclipse.swt.widgets.Shell;
30
31
/**
32
 * This snippet shows how the refresh works on a Zest viewer.
33
 */
34
public class RefreshGraphJFaceSnippet {
35
36
	static class MyContentProvider implements IGraphContentProvider {
37
38
		Object[] elements = new Object[] { "Rock2Paper", "Paper2Scissors", "Scissors2Rock" };
39
40
		public Object getDestination(Object rel) {
41
			if ("Rock2Paper".equals(rel)) {
42
				return "Rock";
43
			} else if ("Paper2Scissors".equals(rel) || "Scissors2Paper".equals(rel)) {
44
				return "Paper";
45
			} else if ("Scissors2Rock".equals(rel)) {
46
				return "Scissors";
47
			}
48
			return null;
49
		}
50
51
		public Object[] getElements(Object input) {
52
			return elements;
53
		}
54
55
		public Object getSource(Object rel) {
56
			if ("Rock2Paper".equals(rel)) {
57
				return "Paper";
58
			} else if ("Paper2Scissors".equals(rel) || "Scissors2Paper".equals(rel)) {
59
				return "Scissors";
60
			} else if ("Scissors2Rock".equals(rel)) {
61
				return "Rock";
62
			}
63
			return null;
64
		}
65
66
		public void setElements(Object[] elements) {
67
			this.elements = elements;
68
		}
69
70
		public double getWeight(Object connection) {
71
			return 0;
72
		}
73
74
		public void dispose() {
75
		}
76
77
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
78
		}
79
80
	}
81
82
	static class MyLabelProvider extends LabelProvider {
83
		final Image image = Display.getDefault().getSystemImage(SWT.ICON_WARNING);	
84
		
85
		public MyLabelProvider() {
86
			
87
		}
88
		
89
		public String getText(Object element) {
90
			return element.toString();
91
		}
92
		
93
		public Image getImage(Object element) {
94
			return image;
95
		}
96
	}
97
98
	static GraphViewer viewer = null;
99
	private static MyContentProvider contentProvider;
100
101
	/**
102
	 * @param args
103
	 */
104
	public static void main(String[] args) {
105
		Display d = new Display();
106
		Shell shell = new Shell(d);
107
		shell.setText("GraphJFaceSnippet2");
108
		shell.setLayout(new FillLayout(SWT.VERTICAL));
109
		shell.setSize(400, 400);
110
		Composite parent = new Composite(shell, SWT.NONE);
111
		parent.setLayout(new GridLayout(2, false));
112
		buildViewer(parent);
113
		buildButton(parent);
114
		shell.open();
115
		while (!shell.isDisposed()) {
116
			while (!d.readAndDispatch()) {
117
				d.sleep();
118
			}
119
		}
120
121
	}
122
123
	private static void buildButton(Composite parent) {
124
		Button button = new Button(parent, SWT.PUSH);
125
		button.setText("Refresh");
126
		button.addSelectionListener(new SelectionAdapter() {
127
			public void widgetSelected(SelectionEvent e) {
128
				contentProvider.setElements(new Object[] { "Rock2Paper", "Scissors2Paper", "Scissors2Rock" });
129
				viewer.refresh();
130
			}
131
		});
132
	}
133
134
	private static void buildViewer(Composite parent) {
135
		viewer = new GraphViewer(parent, SWT.NONE);
136
		viewer.getGraphControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
137
		contentProvider = new MyContentProvider();
138
		viewer.setContentProvider(contentProvider);
139
		viewer.setLabelProvider(new MyLabelProvider());
140
		viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm());
141
		viewer.setInput(new Object());
142
	}
143
}
(-)src/org/eclipse/zest/tests/swt/SelectionGraphSnippet.java (+78 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.zest.core.widgets.Graph;
15
import org.eclipse.zest.core.widgets.GraphConnection;
16
import org.eclipse.zest.core.widgets.GraphNode;
17
import org.eclipse.zest.core.widgets.ZestStyles;
18
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
19
import org.eclipse.swt.SWT;
20
import org.eclipse.swt.events.SelectionAdapter;
21
import org.eclipse.swt.events.SelectionEvent;
22
import org.eclipse.swt.graphics.Image;
23
import org.eclipse.swt.layout.FillLayout;
24
import org.eclipse.swt.widgets.Display;
25
import org.eclipse.swt.widgets.Shell;
26
27
/**
28
 * Adds a selection listener to the nodes to tell when a selection event has
29
 * happened.
30
 * 
31
 * @author Ian Bull
32
 * 
33
 */
34
public class SelectionGraphSnippet {
35
36
	public static void main(String[] args) {
37
		Display d = new Display();
38
		Shell shell = new Shell(d);
39
		Image image1 = Display.getDefault().getSystemImage(SWT.ICON_INFORMATION);
40
		Image image2 = Display.getDefault().getSystemImage(SWT.ICON_WARNING);
41
		Image image3 = Display.getDefault().getSystemImage(SWT.ICON_ERROR);
42
		shell.setLayout(new FillLayout());
43
		shell.setSize(400, 400);
44
45
		Graph g = new Graph(shell, SWT.NONE);
46
		g.addSelectionListener(new SelectionAdapter() {
47
			public void widgetSelected(SelectionEvent e) {
48
				System.out.println(((Graph) e.widget).getSelection());
49
			}
50
		});
51
		
52
		g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED);
53
		GraphNode n1 = new GraphNode(g, SWT.NONE);
54
		n1.setText("Information");
55
		n1.setImage(image1);
56
		GraphNode n2 = new GraphNode(g, SWT.NONE);
57
		n2.setText("Warning");
58
		n2.setImage(image2);
59
		GraphNode n3 = new GraphNode(g, SWT.NONE);
60
		n3.setText("Error");
61
		n3.setImage(image3);
62
		new GraphConnection(g, SWT.NONE, n1, n2);
63
		new GraphConnection(g, SWT.NONE, n2, n3);
64
65
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true);
66
67
		shell.open();
68
		while (!shell.isDisposed()) {
69
			while (!d.readAndDispatch()) {
70
				d.sleep();
71
			}
72
		}
73
		image1.dispose();
74
		image2.dispose();
75
		image3.dispose();
76
77
	}
78
}
(-)src/org/eclipse/zest/tests/swt/ContainersGraphSnippet.java (+88 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import org.eclipse.draw2d.Figure;
15
import org.eclipse.draw2d.FlowLayout;
16
import org.eclipse.draw2d.IFigure;
17
import org.eclipse.draw2d.ImageFigure;
18
import org.eclipse.draw2d.Label;
19
import org.eclipse.draw2d.MarginBorder;
20
import org.eclipse.swt.SWT;
21
import org.eclipse.swt.graphics.Image;
22
import org.eclipse.swt.layout.FillLayout;
23
import org.eclipse.swt.widgets.Display;
24
import org.eclipse.swt.widgets.Shell;
25
import org.eclipse.zest.core.widgets.Graph;
26
import org.eclipse.zest.core.widgets.GraphConnection;
27
import org.eclipse.zest.core.widgets.GraphContainer;
28
import org.eclipse.zest.core.widgets.GraphNode;
29
import org.eclipse.zest.core.widgets.ZestStyles;
30
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
31
32
/**
33
 * 
34
 * This snippet shows how to use graph containers.
35
 * 
36
 * @author Ian Bull
37
 * 
38
 */
39
public class ContainersGraphSnippet {
40
41
	public static void main(String[] args) {
42
		final Display d = new Display();
43
		Shell shell = new Shell(d);
44
		shell.setText("GraphSnippet11");
45
		shell.setLayout(new FillLayout());
46
		shell.setSize(400, 400);
47
		
48
		final Graph g = new Graph(shell, SWT.NONE);
49
		
50
		Image zx = new Image(d, "zxsnow.png");
51
		IFigure tooltip = new Figure();
52
		tooltip.setBorder(new MarginBorder(5,5,5,5));
53
		FlowLayout layout = new FlowLayout(false);
54
		layout.setMajorSpacing(3);
55
		layout.setMinorAlignment(3);
56
		tooltip.setLayoutManager(new FlowLayout(false));
57
		tooltip.add(new ImageFigure(zx));
58
		tooltip.add(new Label("Name: Chris Aniszczyk"));
59
		tooltip.add(new Label("Location: Austin, Texas"));
60
		
61
		GraphContainer c1 = new GraphContainer(g, SWT.NONE);
62
		c1.setText("Canada");
63
		GraphContainer c2 = new GraphContainer(g, SWT.NONE);
64
		c2.setText("USA");
65
		
66
		GraphNode n1 = new GraphNode(c1, SWT.NONE, "Ian B.");
67
		n1.setSize(200, 100);
68
		GraphNode n2 = new GraphNode(c2, SWT.NONE, "Chris A.");
69
		n2.setTooltip(tooltip);
70
		
71
		GraphConnection connection = new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, n1, n2);
72
		connection.setCurveDepth(-30);
73
		GraphConnection connection2 = new GraphConnection(g, ZestStyles.CONNECTIONS_DIRECTED, n2, n1);
74
		connection2.setCurveDepth(-30);
75
		
76
		
77
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(), true);
78
79
		shell.open();
80
		while (!shell.isDisposed()) {
81
			while (!d.readAndDispatch()) {
82
				d.sleep();
83
			}
84
		}
85
		zx.dispose();
86
	}
87
88
}
(-)src/org/eclipse/zest/tests/swt/SpaceTreeExample.java (+202 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 *******************************************************************************/
12
package org.eclipse.zest.tests.swt;
13
14
import java.util.List;
15
16
import org.eclipse.draw2d.ColorConstants;
17
import org.eclipse.jface.action.Action;
18
import org.eclipse.jface.action.IMenuListener;
19
import org.eclipse.jface.action.IMenuManager;
20
import org.eclipse.jface.action.MenuManager;
21
import org.eclipse.swt.SWT;
22
import org.eclipse.swt.layout.FillLayout;
23
import org.eclipse.swt.widgets.Display;
24
import org.eclipse.swt.widgets.Shell;
25
import org.eclipse.zest.core.widgets.DefaultSubgraph;
26
import org.eclipse.zest.core.widgets.Graph;
27
import org.eclipse.zest.core.widgets.GraphConnection;
28
import org.eclipse.zest.core.widgets.GraphNode;
29
import org.eclipse.zest.core.widgets.ZestStyles;
30
import org.eclipse.zest.core.widgets.DefaultSubgraph.TriangleSubgraphFactory;
31
import org.eclipse.zest.layouts.algorithms.SpaceTreeLayoutAlgorithm;
32
33
/**
34
 * This example lets you play with TreeLayoutAlgorithm in many ways - expanding
35
 * and collapsing nodes, moving them around, changing structure of the graph.
36
 */
37
public class SpaceTreeExample {
38
39
	static Graph g;
40
	
41
	static GraphNode source;
42
43
	static GraphNode target;
44
45
	static boolean changesSeries = false;
46
47
	public static void main(String[] args) {
48
		Display d = new Display();
49
		Shell shell = new Shell(d);
50
		shell.setText("Space Tree Layout Example");
51
		shell.setLayout(new FillLayout());
52
		shell.setSize(400, 400);
53
54
		g = new Graph(shell, SWT.NONE);
55
		g.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED);
56
		g.setNodeStyle(ZestStyles.NODES_FISHEYE);
57
		
58
		TriangleSubgraphFactory factory = new DefaultSubgraph.TriangleSubgraphFactory();
59
		factory.setColor(ColorConstants.green);
60
61
		g.setSubgraphFactory(factory);
62
		SpaceTreeLayoutAlgorithm spaceTreeLayoutAlgorithm = new SpaceTreeLayoutAlgorithm();
63
		g.setExpandCollapseManager(spaceTreeLayoutAlgorithm
64
				.getExpandCollapseManager());
65
66
		g.setLayoutAlgorithm(spaceTreeLayoutAlgorithm, false);
67
68
		createTree(g, "!", 5, 5);
69
70
71
		hookMenu(g);
72
73
		shell.open();
74
		while (!shell.isDisposed()) {
75
			while (!d.readAndDispatch()) {
76
				d.sleep();
77
			}
78
		}
79
	}
80
81
	private static GraphNode createTree(Graph g, String rootTitle, int depth, int breadth) {
82
		GraphNode root = new GraphNode(g, SWT.NONE, rootTitle);
83
		if (depth > 0) {
84
			for (int i = 0; i < breadth; i++) {
85
				GraphNode child = createTree(g, rootTitle + i, depth - 1 - i,
86
						breadth - i);
87
				new GraphConnection(g, SWT.NONE, root, child);
88
			}
89
		}
90
		return root;
91
	}
92
93
	private static void hookMenu(final Graph g) {
94
		MenuManager menuMgr = new MenuManager("#PopupMenu");
95
		menuMgr.setRemoveAllWhenShown(true);
96
		menuMgr.addMenuListener(new IMenuListener() {
97
			public void menuAboutToShow(IMenuManager manager) {
98
				fillContextMenu(manager);
99
			}
100
		});
101
		g.setMenu(menuMgr.createContextMenu(g));
102
	}
103
104
	private static void fillContextMenu(IMenuManager menuMgr) {
105
		List selection = g.getSelection();
106
		if (selection.size() == 1) {
107
			if (selection.get(0) instanceof GraphNode) {
108
				final GraphNode node = (GraphNode) selection.get(0);
109
				if (g.canExpand(node)) {
110
					Action expandAction = new Action() {
111
						public void run() {
112
							g.setExpanded(node, true);
113
						}
114
					};
115
					expandAction.setText("expand");
116
					menuMgr.add(expandAction);
117
				}
118
				if (g.canCollapse(node)) {
119
					Action collapseAction = new Action() {
120
						public void run() {
121
							g.setExpanded(node, false);
122
						}
123
					};
124
					collapseAction.setText("collapse");
125
					menuMgr.add(collapseAction);
126
				}
127
				Action disposeAction = new Action() {
128
					public void run() {
129
						node.dispose();
130
					}
131
				};
132
				disposeAction.setText("dispose");
133
				menuMgr.add(disposeAction);
134
135
				Action asSourceAction = new Action() {
136
					public void run() {
137
						source = node;
138
						addConnection();
139
					}
140
				};
141
				asSourceAction.setText("use as source");
142
				menuMgr.add(asSourceAction);
143
144
				Action asTargetAction = new Action() {
145
					public void run() {
146
						target = node;
147
						addConnection();
148
					}
149
				};
150
				asTargetAction.setText("use as target");
151
				menuMgr.add(asTargetAction);
152
			}
153
			if (selection.get(0) instanceof GraphConnection) {
154
				final GraphConnection connection = (GraphConnection) selection
155
						.get(0);
156
				Action removeAction = new Action() {
157
					public void run() {
158
						connection.dispose();
159
					}
160
				};
161
				removeAction.setText("remove");
162
				menuMgr.add(removeAction);
163
			}
164
		}
165
		if (selection.size() == 0) {
166
			Action addNode = new Action() {
167
				public void run() {
168
					new GraphNode(g, SWT.NONE, "new!");
169
				}
170
			};
171
			addNode.setText("add node");
172
			menuMgr.add(addNode);
173
174
			if (!changesSeries) {
175
				Action startChangesSeries = new Action() {
176
					public void run() {
177
						g.setDynamicLayout(false);
178
						changesSeries = true;
179
					}
180
				};
181
				startChangesSeries.setText("start changes");
182
				menuMgr.add(startChangesSeries);
183
			} else {
184
				Action endChangesSeries = new Action() {
185
					public void run() {
186
						g.setDynamicLayout(true);
187
						changesSeries = false;
188
					}
189
				};
190
				endChangesSeries.setText("end changes");
191
				menuMgr.add(endChangesSeries);
192
			}
193
		}
194
	}
195
196
	private static void addConnection() {
197
		if (source != null && target != null) {
198
			new GraphConnection(g, SWT.NONE, source, target);
199
			source = target = null;
200
		}
201
	};
202
}
(-)src/org/eclipse/zest/core/viewers/IGraphEntityRelationshipContentProvider.java (-9 / +16 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 14-31 Link Here
14
14
15
/**
15
/**
16
 * A content provider that is node-relationship centric. Call-backs return model
16
 * A content provider that is node-relationship centric. Call-backs return model
17
 * nodes to the user, and ask for relationships. Both nodes and relationships are
17
 * nodes to the user, and ask for relationships. Both nodes and relationships
18
 * represented by the user's model.
18
 * are represented by the user's model.
19
 * 
19
 * @author Del Myers
20
 * @author Del Myers
20
 *
21
 * 
21
 */
22
 */
22
//@tag bug.154580-Content.fix : new content provider that returns relationships for the given source and destination.
23
// @tag bug.154580-Content.fix : new content provider that returns relationships
23
public interface IGraphEntityRelationshipContentProvider extends IStructuredContentProvider {
24
// for the given source and destination.
25
public interface IGraphEntityRelationshipContentProvider extends
26
		IStructuredContentProvider {
24
	/**
27
	/**
25
	 * Gets the relationships between the given source and destination nodes.
28
	 * Gets the relationships between the given source and destination nodes.
26
	 * @param source the source node.
29
	 * 
27
	 * @param dest the destination node.
30
	 * @param source
28
	 * @return objects represtenting the different relationships between the nodes.
31
	 *            the source node.
32
	 * @param dest
33
	 *            the destination node.
34
	 * @return objects represtenting the different relationships between the
35
	 *         nodes.
29
	 */
36
	 */
30
	public Object[] getRelationships(Object source, Object dest);
37
	public Object[] getRelationships(Object source, Object dest);
31
38
(-)src/org/eclipse/zest/core/viewers/EntityConnectionData.java (-14 / +16 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 11-18 Link Here
11
package org.eclipse.zest.core.viewers;
11
package org.eclipse.zest.core.viewers;
12
12
13
/**
13
/**
14
 * A simple object that is used as the "external connection" in content providers that don't
14
 * A simple object that is used as the "external connection" in content
15
 * ask the user to create their own external connection. 
15
 * providers that don't ask the user to create their own external connection.
16
 * 
16
 * 
17
 * This is used whenever users don't specify a connection
17
 * This is used whenever users don't specify a connection
18
 * 
18
 * 
Lines 23-45 Link Here
23
	public final Object dest;
23
	public final Object dest;
24
24
25
	/**
25
	/**
26
	 * Creates a new entity connection data.  The source and dest
26
	 * Creates a new entity connection data. The source and dest are users
27
	 * are users nodes.
27
	 * nodes.
28
	 */
28
	 */
29
	public EntityConnectionData(Object source, Object dest) {
29
	public EntityConnectionData(Object source, Object dest) {
30
		/*
30
		/*
31
		if (source == null) {
31
		 * if (source == null) { throw new
32
			throw new RuntimeException("Creating relationship with null source object");
32
		 * RuntimeException("Creating relationship with null source object"); }
33
		}
33
		 * if (dest == null) { throw new
34
		if (dest == null) {
34
		 * RuntimeException("Creating relationship with null dest object"); }
35
			throw new RuntimeException("Creating relationship with null dest object");
35
		 */
36
		}
37
		*/
38
		this.source = source;
36
		this.source = source;
39
		this.dest = dest;
37
		this.dest = dest;
40
	}
38
	}
41
39
42
	/* (non-Javadoc)
40
	/*
41
	 * (non-Javadoc)
42
	 * 
43
	 * @see java.lang.Object#equals(java.lang.Object)
43
	 * @see java.lang.Object#equals(java.lang.Object)
44
	 */
44
	 */
45
	public boolean equals(Object obj) {
45
	public boolean equals(Object obj) {
Lines 50-56 Link Here
50
		return (this.source.equals(that.source) && this.dest.equals(that.dest));
50
		return (this.source.equals(that.source) && this.dest.equals(that.dest));
51
	}
51
	}
52
52
53
	/* (non-Javadoc)
53
	/*
54
	 * (non-Javadoc)
55
	 * 
54
	 * @see java.lang.Object#hashCode()
56
	 * @see java.lang.Object#hashCode()
55
	 */
57
	 */
56
	public int hashCode() {
58
	public int hashCode() {
(-)src/org/eclipse/zest/core/viewers/INestedContentProvider.java (-13 / +14 lines)
Lines 1-15 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others. All rights reserved.
2
 * Copyright (c) 2009 EclipseSource and others. All rights reserved. This
3
 * This program and the accompanying materials are made available under the
3
 * program and the accompanying materials are made available under the terms of
4
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * and is available at http://www.eclipse.org/legal/epl-v10.html
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
6
 * 
7
 * Contributors: IBM Corporation - initial API and implementation Chisel Group,
7
 * Contributors: EclipseSource - initial API and implementation
8
 * University of Victoria
9
 ******************************************************************************/
8
 ******************************************************************************/
10
package org.eclipse.zest.core.viewers;
9
package org.eclipse.zest.core.viewers;
11
10
12
/*
11
/**
13
 * A content provider for nested graphs. Any entity based content provider
12
 * A content provider for nested graphs. Any entity based content provider
14
 * (IGraphEntityContentProvider or IGraphEntityRelationshipContentProvider) can
13
 * (IGraphEntityContentProvider or IGraphEntityRelationshipContentProvider) can
15
 * also implement this interface. Any node that "hasChildren" will be rendered
14
 * also implement this interface. Any node that "hasChildren" will be rendered
Lines 22-41 Link Here
22
public interface INestedContentProvider {
21
public interface INestedContentProvider {
23
22
24
	/**
23
	/**
25
	 * Does the current node have children?  If so, it will be rendered as a
24
	 * Does the current node have children? If so, it will be rendered as a
26
	 * container.
25
	 * container.
27
	 * 
26
	 * 
28
	 * @param element The current node
27
	 * @param element
28
	 *            The current node
29
	 * @return True if it has children, false otherwise
29
	 * @return True if it has children, false otherwise
30
	 */
30
	 */
31
	public boolean hasChildren(Object element);
31
	public boolean hasChildren(Object element);
32
32
33
	/**
33
	/**
34
	 * Gets the children of this node.  This method will not be called
34
	 * Gets the children of this node. This method will not be called if
35
	 * if hasChildren returns false.
35
	 * hasChildren returns false.
36
	 * 
36
	 * 
37
	 * @param element The current node
37
	 * @param element
38
	 * @return The list of children for this node.  
38
	 *            The current node
39
	 * @return The list of children for this node.
39
	 */
40
	 */
40
	public Object[] getChildren(Object element);
41
	public Object[] getChildren(Object element);
41
}
42
}
(-)src/org/eclipse/zest/core/viewers/IEntityConnectionStyleProvider.java (-21 / +34 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 15-67 Link Here
15
import org.eclipse.ui.services.IDisposable;
15
import org.eclipse.ui.services.IDisposable;
16
16
17
/**
17
/**
18
 * An extension for label providers which allows users to set styles for connections
18
 * An extension for label providers which allows users to set styles for
19
 * that are based on entity end points.
19
 * connections that are based on entity end points.
20
 * 
20
 * @author Del Myers
21
 * @author Del Myers
21
 *
22
 * 
22
 */
23
 */
23
//@tag bug(151327-Styles) : fix
24
// @tag bug(151327-Styles) : fix
24
public interface IEntityConnectionStyleProvider extends IDisposable {
25
public interface IEntityConnectionStyleProvider extends IDisposable {
25
26
26
	/**
27
	/**
27
	 * Returns the style flags for this connection. Valid flags are those
28
	 * Returns the style flags for this connection. Valid flags are those that
28
	 * that begin with CONNECTION in @see org.eclipse.zest.core.ZestStyles. Check
29
	 * begin with CONNECTION in @see org.eclipse.zest.core.ZestStyles. Check
29
	 * ZestStyles for legal combinations.
30
	 * ZestStyles for legal combinations.
30
	 * @param src the source entity.
31
	 * 
31
	 * @param dest the destination entity.
32
	 * @param src
33
	 *            the source entity.
34
	 * @param dest
35
	 *            the destination entity.
32
	 * @return the style flags for this connection.
36
	 * @return the style flags for this connection.
33
	 * @see org.eclipse.zest.core.widgets.ZestStyles
37
	 * @see org.eclipse.zest.core.widgets.ZestStyles
34
	 */
38
	 */
35
	public int getConnectionStyle(Object src, Object dest);
39
	public int getConnectionStyle(Object src, Object dest);
36
	
40
37
	/**
41
	/**
38
	 * Returns the color for the connection. Null for default.
42
	 * Returns the color for the connection. Null for default.
39
	 * @param src the source entity.  Any resources created by this class must be disposed by
43
	 * 
40
	 * this class.
44
	 * @param src
41
	 * @param dest the destination entity.
45
	 *            the source entity. Any resources created by this class must be
46
	 *            disposed by this class.
47
	 * @param dest
48
	 *            the destination entity.
42
	 * @return the color.
49
	 * @return the color.
43
	 * @see #dispose()
50
	 * @see #dispose()
44
	 */
51
	 */
45
	public Color getColor(Object src, Object dest);
52
	public Color getColor(Object src, Object dest);
46
	
53
47
	/**
54
	/**
48
	 * Returns the highlighted color for this connection. Null for default.
55
	 * Returns the highlighted color for this connection. Null for default.
49
	 * @param src the source entity.  Any resources created by this class must be disposed by
56
	 * 
50
	 * this class.
57
	 * @param src
51
	 * @param dest the destination entity.
58
	 *            the source entity. Any resources created by this class must be
59
	 *            disposed by this class.
60
	 * @param dest
61
	 *            the destination entity.
52
	 * @return the highlighted color. Null for default.
62
	 * @return the highlighted color. Null for default.
53
	 * @see #dispose()
63
	 * @see #dispose()
54
	 */
64
	 */
55
	public Color getHighlightColor(Object src, Object dest);
65
	public Color getHighlightColor(Object src, Object dest);
56
	
66
57
	/**
67
	/**
58
	 * Returns the line width of the connection. -1 for default.
68
	 * Returns the line width of the connection. -1 for default.
59
	 * @param src the source entity.
69
	 * 
60
	 * @param dest the destination entity.
70
	 * @param src
71
	 *            the source entity.
72
	 * @param dest
73
	 *            the destination entity.
61
	 * @return the line width for the connection. -1 for default.
74
	 * @return the line width for the connection. -1 for default.
62
	 */
75
	 */
63
	public int getLineWidth(Object src, Object dest);
76
	public int getLineWidth(Object src, Object dest);
64
		
77
65
	/**
78
	/**
66
	 * Returns the tooltop for this node. If null is returned Zest will simply
79
	 * Returns the tooltop for this node. If null is returned Zest will simply
67
	 * use the default tooltip.
80
	 * use the default tooltip.
(-)src/org/eclipse/zest/core/viewers/IEntityConnectionStyleBezierExtension.java (-1 / +1 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
(-)src/org/eclipse/zest/core/viewers/IGraphEntityContentProvider.java (-2 / +3 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 15-21 Link Here
15
/**
15
/**
16
 * 
16
 * 
17
 * @author Ian Bull
17
 * @author Ian Bull
18
 *
18
 * 
19
 */
19
 */
20
public interface IGraphEntityContentProvider extends IStructuredContentProvider {
20
public interface IGraphEntityContentProvider extends IStructuredContentProvider {
21
21
Lines 23-28 Link Here
23
23
24
	/**
24
	/**
25
	 * Gets the elements this object is connected to
25
	 * Gets the elements this object is connected to
26
	 * 
26
	 * @param entity
27
	 * @param entity
27
	 * @return
28
	 * @return
28
	 */
29
	 */
(-)src/org/eclipse/zest/core/viewers/IConnectionStyleBezierExtension.java (-28 / +37 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 16-66 Link Here
16
 * 
16
 * 
17
 * Bezier curves are defined by a set of four points: two point in the layout
17
 * Bezier curves are defined by a set of four points: two point in the layout
18
 * (start and end), and two related control points (also start and end). The
18
 * (start and end), and two related control points (also start and end). The
19
 * control points are defined relative to their corresponding layout point.
19
 * control points are defined relative to their corresponding layout point. This
20
 * This definition includes an angle between the layout point and the line
20
 * definition includes an angle between the layout point and the line between
21
 * between the two layout points, as well as a ratio distance from the corresponding
21
 * the two layout points, as well as a ratio distance from the corresponding
22
 * layout point. The ratio distance is defined as a fraction between 0 and 1
22
 * layout point. The ratio distance is defined as a fraction between 0 and 1 of
23
 * of the distance between the two layout points. Using this definition
23
 * the distance between the two layout points. Using this definition allows
24
 * allows bezier curves to have a consistant look regardless of the actual
24
 * bezier curves to have a consistant look regardless of the actual positions of
25
 * positions of the nodes in the layouts. 
25
 * the nodes in the layouts.
26
 * 
26
 * @author Del Myers
27
 * @author Del Myers
27
 *
28
 * 
28
 */
29
 */
29
//@tag bug(152530-Bezier(fix)) : users can style bezier curves.
30
// @tag bug(152530-Bezier(fix)) : users can style bezier curves.
30
public interface IConnectionStyleBezierExtension {
31
public interface IConnectionStyleBezierExtension {
31
32
32
	/**
33
	/**
33
	 * Gets the angle between the start point, and the line between the start 
34
	 * Gets the angle between the start point, and the line between the start
34
	 * and end, which will define the position of the start control point.
35
	 * and end, which will define the position of the start control point. If
35
	 * If the start angle, and the end angle are the same sign, the two control
36
	 * the start angle, and the end angle are the same sign, the two control
36
	 * points are guaranteed to be on the same side of the line.
37
	 * points are guaranteed to be on the same side of the line.
37
	 * @param rel the relationship to base on.
38
	 * 
39
	 * @param rel
40
	 *            the relationship to base on.
38
	 * @return the start angle or <code>Double.NaN</code> for defaults.
41
	 * @return the start angle or <code>Double.NaN</code> for defaults.
39
	 */
42
	 */
40
	double getStartAngle(Object rel);
43
	double getStartAngle(Object rel);
41
	
44
42
	/**
45
	/**
43
	 * Gets the angle between the end point, and the line between the start 
46
	 * Gets the angle between the end point, and the line between the start and
44
	 * and end, which will define the position of the end control point.
47
	 * end, which will define the position of the end control point. If the
45
	 * If the start angle, and the end angle are the same sign, the two control
48
	 * start angle, and the end angle are the same sign, the two control points
46
	 * points are guaranteed to be on the same side of the line.
49
	 * are guaranteed to be on the same side of the line.
47
	 * @param rel the relationship to base on.
50
	 * 
51
	 * @param rel
52
	 *            the relationship to base on.
48
	 * @return the end angle or <code>Double.NaN</code> for defaults.
53
	 * @return the end angle or <code>Double.NaN</code> for defaults.
49
	 */
54
	 */
50
	double getEndAngle(Object rel);
55
	double getEndAngle(Object rel);
51
	
56
52
	/**
57
	/**
53
	 * Gets the distance between the start point and the start control point,
58
	 * Gets the distance between the start point and the start control point, as
54
	 * as a fraction of the distance between the start point and end point.
59
	 * a fraction of the distance between the start point and end point.
55
	 * @param rel the relationship to base on.
60
	 * 
61
	 * @param rel
62
	 *            the relationship to base on.
56
	 * @return the start distance or <code>Double.NaN</code> for defaults.
63
	 * @return the start distance or <code>Double.NaN</code> for defaults.
57
	 */
64
	 */
58
	double getStartDistance(Object rel);
65
	double getStartDistance(Object rel);
59
	
66
60
	/**
67
	/**
61
	 * Gets the distance between the end point and the end control point,
68
	 * Gets the distance between the end point and the end control point, as a
62
	 * as a fraction of the distance between the start point and end point.
69
	 * fraction of the distance between the start point and end point.
63
	 * @param rel the relationship to base on.
70
	 * 
71
	 * @param rel
72
	 *            the relationship to base on.
64
	 * @return the end distance or <code>Double.NaN</code> for defaults.
73
	 * @return the end distance or <code>Double.NaN</code> for defaults.
65
	 */
74
	 */
66
	double getEndDistance(Object rel);
75
	double getEndDistance(Object rel);
(-)src/org/eclipse/zest/core/viewers/GraphViewer.java (-20 / +100 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials are made
3
 * All rights reserved. This program and the accompanying materials are made
4
 * available under the terms of the Eclipse Public License v1.0 which
4
 * available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
Lines 27-52 Link Here
27
import org.eclipse.swt.widgets.Composite;
27
import org.eclipse.swt.widgets.Composite;
28
import org.eclipse.swt.widgets.Control;
28
import org.eclipse.swt.widgets.Control;
29
import org.eclipse.swt.widgets.Widget;
29
import org.eclipse.swt.widgets.Widget;
30
import org.eclipse.zest.core.viewers.internal.AbstractStructuredGraphViewer;
31
import org.eclipse.zest.core.viewers.internal.GraphModelEntityFactory;
30
import org.eclipse.zest.core.viewers.internal.GraphModelEntityFactory;
32
import org.eclipse.zest.core.viewers.internal.GraphModelEntityRelationshipFactory;
31
import org.eclipse.zest.core.viewers.internal.GraphModelEntityRelationshipFactory;
33
import org.eclipse.zest.core.viewers.internal.GraphModelFactory;
32
import org.eclipse.zest.core.viewers.internal.GraphModelFactory;
34
import org.eclipse.zest.core.viewers.internal.IStylingGraphModelFactory;
33
import org.eclipse.zest.core.viewers.internal.IStylingGraphModelFactory;
35
import org.eclipse.zest.core.viewers.internal.ZoomManager;
36
import org.eclipse.zest.core.widgets.Graph;
34
import org.eclipse.zest.core.widgets.Graph;
37
import org.eclipse.zest.core.widgets.GraphItem;
35
import org.eclipse.zest.core.widgets.GraphItem;
38
import org.eclipse.zest.core.widgets.ZestStyles;
36
import org.eclipse.zest.core.widgets.ZestStyles;
39
import org.eclipse.zest.layouts.LayoutAlgorithm;
37
import org.eclipse.zest.layouts.LayoutAlgorithm;
40
38
41
/*
39
/**
42
 * This view is used to represent a static graph. Static graphs can be layed
40
 * This view is used to represent a static graph. Static graphs can be layed
43
 * out, but do not continually update their layout locations.
41
 * out, but do not continually update their layout locations.
44
 * 
42
 * 
45
 * @author Ian Bull
43
 * @author Ian Bull
46
 * 
44
 * 
47
 * @author Chris Callendar
45
 * @author Chris Callendar
46
 * 
47
 * @noextend This class is not intended to be subclassed by clients.
48
 */
48
 */
49
public class GraphViewer extends AbstractStructuredGraphViewer implements ISelectionProvider {
49
public class GraphViewer extends AbstractStructuredGraphViewer implements
50
		ISelectionProvider {
50
51
51
	protected Graph graph = null;
52
	protected Graph graph = null;
52
	private IStylingGraphModelFactory modelFactory = null;
53
	private IStylingGraphModelFactory modelFactory = null;
Lines 89-98 Link Here
89
				Iterator iterator = selectionChangedListeners.iterator();
90
				Iterator iterator = selectionChangedListeners.iterator();
90
91
91
				ISelection structuredSelection = getSelection();
92
				ISelection structuredSelection = getSelection();
92
				SelectionChangedEvent event = new SelectionChangedEvent(GraphViewer.this, structuredSelection);
93
				SelectionChangedEvent event = new SelectionChangedEvent(
94
						GraphViewer.this, structuredSelection);
93
95
94
				while (iterator.hasNext()) {
96
				while (iterator.hasNext()) {
95
					ISelectionChangedListener listener = (ISelectionChangedListener) iterator.next();
97
					ISelectionChangedListener listener = (ISelectionChangedListener) iterator
98
							.next();
96
					listener.selectionChanged(event);
99
					listener.selectionChanged(event);
97
				}
100
				}
98
101
Lines 103-109 Link Here
103
		control.addMouseListener(new MouseListener() {
106
		control.addMouseListener(new MouseListener() {
104
107
105
			public void mouseDoubleClick(MouseEvent e) {
108
			public void mouseDoubleClick(MouseEvent e) {
106
				DoubleClickEvent doubleClickEvent = new DoubleClickEvent(GraphViewer.this, getSelection());
109
				DoubleClickEvent doubleClickEvent = new DoubleClickEvent(
110
						GraphViewer.this, getSelection());
107
				fireDoubleClick(doubleClickEvent);
111
				fireDoubleClick(doubleClickEvent);
108
			}
112
			}
109
113
Lines 118-123 Link Here
118
		});
122
		});
119
	}
123
	}
120
124
125
	protected void inputChanged(Object input, Object oldInput) {
126
		graph.setDynamicLayout(false);
127
		super.inputChanged(input, oldInput);
128
		graph.setDynamicLayout(true);
129
		graph.applyLayout();
130
	}
131
121
	/**
132
	/**
122
	 * Gets the styles for this structuredViewer
133
	 * Gets the styles for this structuredViewer
123
	 * 
134
	 * 
Lines 130-136 Link Here
130
	/*
141
	/*
131
	 * (non-Javadoc)
142
	 * (non-Javadoc)
132
	 * 
143
	 * 
133
	 * @see org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#getGraphControl()
144
	 * @seeorg.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#
145
	 * getGraphControl()
134
	 */
146
	 */
135
	public Graph getGraphControl() {
147
	public Graph getGraphControl() {
136
		return super.getGraphControl();
148
		return super.getGraphControl();
Lines 151-157 Link Here
151
	/*
163
	/*
152
	 * (non-Javadoc)
164
	 * (non-Javadoc)
153
	 * 
165
	 * 
154
	 * @see org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#setLayoutAlgorithm(org.eclipse.zest.layouts.LayoutAlgorithm)
166
	 * @seeorg.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#
167
	 * setLayoutAlgorithm(org.eclipse.zest.layouts.LayoutAlgorithm)
155
	 */
168
	 */
156
	public void setLayoutAlgorithm(LayoutAlgorithm algorithm) {
169
	public void setLayoutAlgorithm(LayoutAlgorithm algorithm) {
157
		super.setLayoutAlgorithm(algorithm);
170
		super.setLayoutAlgorithm(algorithm);
Lines 160-166 Link Here
160
	/*
173
	/*
161
	 * (non-Javadoc)
174
	 * (non-Javadoc)
162
	 * 
175
	 * 
163
	 * @see org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer#setNodeStyle(int)
176
	 * @see
177
	 * org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer#setNodeStyle
178
	 * (int)
164
	 */
179
	 */
165
	public void setNodeStyle(int nodeStyle) {
180
	public void setNodeStyle(int nodeStyle) {
166
		super.setNodeStyle(nodeStyle);
181
		super.setNodeStyle(nodeStyle);
Lines 175-181 Link Here
175
		} else if (contentProvider instanceof IGraphEntityRelationshipContentProvider) {
190
		} else if (contentProvider instanceof IGraphEntityRelationshipContentProvider) {
176
			super.setContentProvider(contentProvider);
191
			super.setContentProvider(contentProvider);
177
		} else {
192
		} else {
178
			throw new IllegalArgumentException("Invalid content provider, only IGraphContentProvider, IGraphEntityContentProvider, or IGraphEntityRelationshipContentProvider are supported.");
193
			throw new IllegalArgumentException(
194
					"Invalid content provider, only IGraphContentProvider, IGraphEntityContentProvider, or IGraphEntityRelationshipContentProvider are supported.");
179
		}
195
		}
180
	}
196
	}
181
197
Lines 195-201 Link Here
195
	 */
211
	 */
196
	public GraphItem findGraphItem(Object element) {
212
	public GraphItem findGraphItem(Object element) {
197
		Widget[] result = findItems(element);
213
		Widget[] result = findItems(element);
198
		return (result.length == 0 || !(result[0] instanceof GraphItem)) ? null : (GraphItem) result[0];
214
		return (result.length == 0 || !(result[0] instanceof GraphItem)) ? null
215
				: (GraphItem) result[0];
199
	}
216
	}
200
217
201
	/**
218
	/**
Lines 225-231 Link Here
225
	/*
242
	/*
226
	 * (non-Javadoc)
243
	 * (non-Javadoc)
227
	 * 
244
	 * 
228
	 * @see org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#reveal(java.lang.Object)
245
	 * @see
246
	 * org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#reveal
247
	 * (java.lang.Object)
229
	 */
248
	 */
230
	public void reveal(Object element) {
249
	public void reveal(Object element) {
231
		super.reveal(element);
250
		super.reveal(element);
Lines 234-240 Link Here
234
	/*
253
	/*
235
	 * (non-Javadoc)
254
	 * (non-Javadoc)
236
	 * 
255
	 * 
237
	 * @see org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#setConnectionStyle(int)
256
	 * @seeorg.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#
257
	 * setConnectionStyle(int)
238
	 */
258
	 */
239
	public void setConnectionStyle(int connectionStyle) {
259
	public void setConnectionStyle(int connectionStyle) {
240
		super.setConnectionStyle(connectionStyle);
260
		super.setConnectionStyle(connectionStyle);
Lines 243-249 Link Here
243
	/*
263
	/*
244
	 * (non-Javadoc)
264
	 * (non-Javadoc)
245
	 * 
265
	 * 
246
	 * @see org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#unReveal(java.lang.Object)
266
	 * @see
267
	 * org.eclipse.zest.core.viewer.internal.AbstractStructuredGraphViewer#unReveal
268
	 * (java.lang.Object)
247
	 */
269
	 */
248
	public void unReveal(Object element) {
270
	public void unReveal(Object element) {
249
		super.unReveal(element);
271
		super.unReveal(element);
Lines 255-279 Link Here
255
		}
277
		}
256
	}
278
	}
257
279
258
	public void removeSelectionChangedListener(ISelectionChangedListener listener) {
280
	public void removeSelectionChangedListener(
281
			ISelectionChangedListener listener) {
259
		if (selectionChangedListeners.contains(listener)) {
282
		if (selectionChangedListeners.contains(listener)) {
260
			selectionChangedListeners.remove(listener);
283
			selectionChangedListeners.remove(listener);
261
		}
284
		}
262
	}
285
	}
263
286
287
	/**
288
	 * {@inheritDoc}
289
	 * 
290
	 * NOTE: If a layout algorithm is set in the receiver, layout is performed
291
	 * after the refresh.
292
	 */
293
	public void refresh(Object element) {
294
		boolean dynamicLayoutEnabled = graph.isDynamicLayoutEnabled();
295
		graph.setDynamicLayout(false);
296
		super.refresh(element);
297
		graph.setDynamicLayout(dynamicLayoutEnabled);
298
	}
299
300
	/**
301
	 * {@inheritDoc}
302
	 * 
303
	 * NOTE: If a layout algorithm is set in the receiver, layout is performed
304
	 * after the refresh.
305
	 */
306
	public void refresh(Object element, boolean updateLabels) {
307
		boolean dynamicLayoutEnabled = graph.isDynamicLayoutEnabled();
308
		graph.setDynamicLayout(false);
309
		super.refresh(element, updateLabels);
310
		graph.setDynamicLayout(dynamicLayoutEnabled);
311
	}
312
313
	/**
314
	 * {@inheritDoc}
315
	 * 
316
	 * NOTE: If a layout algorithm is set in the receiver, layout is performed
317
	 * after the update.
318
	 */
319
	public void update(Object element, String[] properties) {
320
		boolean dynamicLayoutEnabled = graph.isDynamicLayoutEnabled();
321
		graph.setDynamicLayout(false);
322
		super.update(element, properties);
323
		graph.setDynamicLayout(dynamicLayoutEnabled);
324
	}
325
326
	/**
327
	 * {@inheritDoc}
328
	 * 
329
	 * NOTE: If a layout algorithm is set in the receiver, layout is performed
330
	 * after the update.
331
	 */
332
	public void update(Object[] elements, String[] properties) {
333
		boolean dynamicLayoutEnabled = graph.isDynamicLayoutEnabled();
334
		graph.setDynamicLayout(false);
335
		super.update(elements, properties);
336
		graph.setDynamicLayout(dynamicLayoutEnabled);
337
	}
338
264
	// @tag zest.bug.156286-Zooming.fix.experimental : expose the zoom manager
339
	// @tag zest.bug.156286-Zooming.fix.experimental : expose the zoom manager
265
	// for new actions.
340
	// for new actions.
266
	protected ZoomManager getZoomManager() {
341
	protected ZoomManager getZoomManager() {
267
		if (zoomManager == null) {
342
		if (zoomManager == null) {
268
			zoomManager = new ZoomManager(getGraphControl().getRootLayer(), getGraphControl().getViewport());
343
			zoomManager = new ZoomManager(getGraphControl().getRootLayer(),
344
					getGraphControl().getViewport());
269
		}
345
		}
270
		return zoomManager;
346
		return zoomManager;
271
	}
347
	}
272
348
273
	/*
349
	/**
274
	 * (non-Javadoc)
350
	 * (non-Javadoc)
275
	 * 
351
	 * 
276
	 * @see org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer#getFactory()
352
	 * @see org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer#getFactory()
353
	 * @noreference This method is not intended to be referenced by clients.
354
	 * @nooverride This method is not intended to be re-implemented or extended
355
	 *             by clients.
277
	 */
356
	 */
278
	protected IStylingGraphModelFactory getFactory() {
357
	protected IStylingGraphModelFactory getFactory() {
279
		if (modelFactory == null) {
358
		if (modelFactory == null) {
Lines 291-297 Link Here
291
	/*
370
	/*
292
	 * (non-Javadoc)
371
	 * (non-Javadoc)
293
	 * 
372
	 * 
294
	 * @see org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer#getLayoutAlgorithm()
373
	 * @seeorg.eclipse.zest.core.viewers.AbstractStructuredGraphViewer#
374
	 * getLayoutAlgorithm()
295
	 */
375
	 */
296
	protected LayoutAlgorithm getLayoutAlgorithm() {
376
	protected LayoutAlgorithm getLayoutAlgorithm() {
297
		return graph.getLayoutAlgorithm();
377
		return graph.getLayoutAlgorithm();
(-)src/org/eclipse/zest/core/viewers/IEntityStyleProvider.java (-3 / +3 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC,
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
Lines 88-94 Link Here
88
	 *         node is selected.
88
	 *         node is selected.
89
	 */
89
	 */
90
	// @tag ADJACENT : Removed highlight adjacent
90
	// @tag ADJACENT : Removed highlight adjacent
91
	//public boolean highlightAdjacentEntities(Object entity);
91
	// public boolean highlightAdjacentEntities(Object entity);
92
	/**
92
	/**
93
	 * Returns the color that adjacent entities will be drawn when this entity
93
	 * Returns the color that adjacent entities will be drawn when this entity
94
	 * is selected. Will be ignored if HighlightAdjacentEntities() returns
94
	 * is selected. Will be ignored if HighlightAdjacentEntities() returns
Lines 102-108 Link Here
102
	 * @see #dispose()
102
	 * @see #dispose()
103
	 */
103
	 */
104
	// @tag ADJACENT : Removed highlight adjacent
104
	// @tag ADJACENT : Removed highlight adjacent
105
	//public Color getAdjacentEntityHighlightColor(Object entity);
105
	// public Color getAdjacentEntityHighlightColor(Object entity);
106
	/**
106
	/**
107
	 * Returns the colour that this node should be coloured. This will be
107
	 * Returns the colour that this node should be coloured. This will be
108
	 * ignored if getNodeColour returns null. Any resources created by this
108
	 * ignored if getNodeColour returns null. Any resources created by this
(-)src/org/eclipse/zest/core/viewers/IFigureProvider.java (-3 / +12 lines)
Lines 1-11 Link Here
1
/******************************************************************************* 
2
 * Copyright (c) 2009 EclipseSource and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 *
7
 * Contributors:
8
 *   EclipseSource - initial API and implementation
9
 ******************************************************************************/
1
package org.eclipse.zest.core.viewers;
10
package org.eclipse.zest.core.viewers;
2
11
3
import org.eclipse.draw2d.IFigure;
12
import org.eclipse.draw2d.IFigure;
4
13
5
/**
14
/**
6
 * Allows a user to create a figure for an element in 
15
 * Allows a user to create a figure for an element in graph model. To use this
7
 * graph model.  To use this interface, it should 
16
 * interface, it should be implemented and passed to
8
 * be implemented and passed to {@link GraphViewer#setLabelProvider()}
17
 * {@link GraphViewer#setLabelProvider()}
9
 */
18
 */
10
public interface IFigureProvider {
19
public interface IFigureProvider {
11
20
(-)src/org/eclipse/zest/core/viewers/AbstractZoomableViewer.java (-12 / +17 lines)
Lines 1-8 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * All rights reserved. This program and the accompanying materials
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * which accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
Lines 12-35 Link Here
12
12
13
import org.eclipse.draw2d.geometry.Rectangle;
13
import org.eclipse.draw2d.geometry.Rectangle;
14
import org.eclipse.jface.viewers.StructuredViewer;
14
import org.eclipse.jface.viewers.StructuredViewer;
15
import org.eclipse.zest.core.viewers.internal.ZoomManager;
16
15
17
/**
16
/**
18
 * A simple interface that provides zooming capabilites. Not intended to be subclassed by clients.
17
 * A simple interface that provides zooming capabilites. Not intended to be
18
 * subclassed by clients.
19
 * 
19
 * @author Del Myers
20
 * @author Del Myers
20
 *
21
 * 
22
 * @noextend This class is not intended to be subclassed by clients.
23
 * 
21
 */
24
 */
22
//@tag bug.156286-Zooming.fix
25
// @tag bug.156286-Zooming.fix
23
public abstract class AbstractZoomableViewer extends StructuredViewer {
26
public abstract class AbstractZoomableViewer extends StructuredViewer {
24
	/**
27
	/**
25
	 * Returns a ZoomManager that zooming can be done on. May return null if none
28
	 * Returns a ZoomManager that zooming can be done on. May return null if
26
	 * is available.
29
	 * none is available.
30
	 * 
27
	 * @return a ZoomManager that zooming can be done on.
31
	 * @return a ZoomManager that zooming can be done on.
32
	 * @since 2.0
28
	 */
33
	 */
29
	protected abstract ZoomManager getZoomManager();
34
	protected abstract ZoomManager getZoomManager();
30
	
35
31
	public void zoomTo(int x, int y, int width, int height) {
36
	public void zoomTo(int x, int y, int width, int height) {
32
		Rectangle r = new Rectangle(x,y,width,height);
37
		Rectangle r = new Rectangle(x, y, width, height);
33
		if (r.isEmpty()) {
38
		if (r.isEmpty()) {
34
			getZoomManager().setZoomAsText("100%");
39
			getZoomManager().setZoomAsText("100%");
35
		} else {
40
		} else {
(-)src/org/eclipse/zest/core/viewers/ZoomContributionViewItem.java (-13 / +19 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC,
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
Lines 10-17 Link Here
10
package org.eclipse.zest.core.viewers;
10
package org.eclipse.zest.core.viewers;
11
11
12
import org.eclipse.jface.action.ContributionItem;
12
import org.eclipse.jface.action.ContributionItem;
13
import org.eclipse.zest.core.viewers.internal.ZoomListener;
14
import org.eclipse.zest.core.viewers.internal.ZoomManager;
15
import org.eclipse.swt.SWT;
13
import org.eclipse.swt.SWT;
16
import org.eclipse.swt.events.MenuAdapter;
14
import org.eclipse.swt.events.MenuAdapter;
17
import org.eclipse.swt.events.MenuEvent;
15
import org.eclipse.swt.events.MenuEvent;
Lines 37-44 Link Here
37
 * @author Del Myers
35
 * @author Del Myers
38
 * 
36
 * 
39
 */
37
 */
40
//@tag zest.bug.156286-Zooming.fix : create a contribution item that can set zooming on Zest views.
38
// @tag zest.bug.156286-Zooming.fix : create a contribution item that can set
41
public class ZoomContributionViewItem extends ContributionItem implements ZoomListener {
39
// zooming on Zest views.
40
public class ZoomContributionViewItem extends ContributionItem implements
41
		ZoomListener {
42
	/**
42
	/**
43
	 * Zooms to fit the width.
43
	 * Zooms to fit the width.
44
	 */
44
	 */
Lines 78-85 Link Here
78
	/*
78
	/*
79
	 * (non-Javadoc)
79
	 * (non-Javadoc)
80
	 * 
80
	 * 
81
	 * @see org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets.Menu,
81
	 * @see
82
	 *      int)
82
	 * org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets
83
	 * .Menu, int)
83
	 */
84
	 */
84
	public void fill(Menu menu, int index) {
85
	public void fill(Menu menu, int index) {
85
		if (this.fMenu == null || this.fMenu != menu) {
86
		if (this.fMenu == null || this.fMenu != menu) {
Lines 95-102 Link Here
95
	/*
96
	/*
96
	 * (non-Javadoc)
97
	 * (non-Javadoc)
97
	 * 
98
	 * 
98
	 * @see org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets.CoolBar,
99
	 * @see
99
	 *      int)
100
	 * org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets
101
	 * .CoolBar, int)
100
	 */
102
	 */
101
	public void fill(CoolBar parent, int index) {
103
	public void fill(CoolBar parent, int index) {
102
		CoolItem item = new CoolItem(parent, SWT.DROP_DOWN);
104
		CoolItem item = new CoolItem(parent, SWT.DROP_DOWN);
Lines 107-114 Link Here
107
	/*
109
	/*
108
	 * (non-Javadoc)
110
	 * (non-Javadoc)
109
	 * 
111
	 * 
110
	 * @see org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets.ToolBar,
112
	 * @see
111
	 *      int)
113
	 * org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets
114
	 * .ToolBar, int)
112
	 */
115
	 */
113
	public void fill(ToolBar parent, int index) {
116
	public void fill(ToolBar parent, int index) {
114
		ToolItem item = new ToolItem(parent, SWT.DROP_DOWN);
117
		ToolItem item = new ToolItem(parent, SWT.DROP_DOWN);
Lines 123-129 Link Here
123
			/*
126
			/*
124
			 * (non-Javadoc)
127
			 * (non-Javadoc)
125
			 * 
128
			 * 
126
			 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
129
			 * @see
130
			 * org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse
131
			 * .swt.events.SelectionEvent)
127
			 */
132
			 */
128
			public void widgetSelected(SelectionEvent e) {
133
			public void widgetSelected(SelectionEvent e) {
129
				int selection = combo.getSelectionIndex();
134
				int selection = combo.getSelectionIndex();
Lines 235-241 Link Here
235
		if (fMenu != null) {
240
		if (fMenu != null) {
236
			fMenu = null;
241
			fMenu = null;
237
		}
242
		}
238
		//		@tag zest.bug.159667-ZoomDispose : make sure that we no longer listen to the part service.
243
		// @tag zest.bug.159667-ZoomDispose : make sure that we no longer listen
244
		// to the part service.
239
		super.dispose();
245
		super.dispose();
240
	}
246
	}
241
}
247
}
(-)src/org/eclipse/zest/core/viewers/IGraphContentProvider.java (-14 / +21 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 13-48 Link Here
13
import org.eclipse.jface.viewers.IStructuredContentProvider;
13
import org.eclipse.jface.viewers.IStructuredContentProvider;
14
14
15
/**
15
/**
16
 * A graph content provider. 
16
 * A graph content provider.
17
 * 
17
 * 
18
 * @author Ian Bull
18
 * @author Ian Bull
19
 */
19
 */
20
public interface IGraphContentProvider extends IStructuredContentProvider {
20
public interface IGraphContentProvider extends IStructuredContentProvider {
21
21
22
	/**
22
	/**
23
	 * Gets the source Object for the given relationship. Note, at least one of the source
23
	 * Gets the source Object for the given relationship. Note, at least one of
24
	 * or destination must not be null. If both are null, then nothing can be displayed in
24
	 * the source or destination must not be null. If both are null, then
25
	 * the graph (a relationship cannot exist without nodes to be connected to). However,
25
	 * nothing can be displayed in the graph (a relationship cannot exist
26
	 * if one of getSource() or getDestination() returns null, then the resulting graph will
26
	 * without nodes to be connected to). However, if one of getSource() or
27
	 * contain an unconnected node for the non-null object returned from the other method.
27
	 * getDestination() returns null, then the resulting graph will contain an
28
	 * @param rel the relationship.
28
	 * unconnected node for the non-null object returned from the other method.
29
	 * 
30
	 * @param rel
31
	 *            the relationship.
29
	 * @return the source, or null for an unconnected destination.
32
	 * @return the source, or null for an unconnected destination.
30
	 */
33
	 */
31
	public Object getSource(Object rel);
34
	public Object getSource(Object rel);
32
35
33
	/**
36
	/**
34
	 * Gets the target Object for the given relationship. Note, at least one of the source
37
	 * Gets the target Object for the given relationship. Note, at least one of
35
	 * or destination must not be null. If both are null, then nothing can be displayed in
38
	 * the source or destination must not be null. If both are null, then
36
	 * the graph (a relationship cannot exist without nodes to be connected to). However,
39
	 * nothing can be displayed in the graph (a relationship cannot exist
37
	 * if one of getSource() or getDestination() returns null, then the resulting graph will
40
	 * without nodes to be connected to). However, if one of getSource() or
38
	 * contain an unconnected node for the non-null object returned from the other method.
41
	 * getDestination() returns null, then the resulting graph will contain an
39
	 * @param rel the relationship.
42
	 * unconnected node for the non-null object returned from the other method.
43
	 * 
44
	 * @param rel
45
	 *            the relationship.
40
	 * @return the destination, or null for an unconnected source.
46
	 * @return the destination, or null for an unconnected source.
41
	 */
47
	 */
42
	public Object getDestination(Object rel);
48
	public Object getDestination(Object rel);
43
49
44
	/**
50
	/**
45
	 * Returns all the relationships in the graph for the given input.
51
	 * Returns all the relationships in the graph for the given input.
52
	 * 
46
	 * @input the input model object.
53
	 * @input the input model object.
47
	 * @return all the relationships in the graph for the given input.
54
	 * @return all the relationships in the graph for the given input.
48
	 */
55
	 */
(-)src/org/eclipse/zest/core/viewers/IConnectionStyleProvider.java (-17 / +26 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 15-60 Link Here
15
import org.eclipse.ui.services.IDisposable;
15
import org.eclipse.ui.services.IDisposable;
16
16
17
/**
17
/**
18
 * An extension to label providers, to supply styles for connections based upon 
18
 * An extension to label providers, to supply styles for connections based upon
19
 * relationships, rather than on connected nodes.
19
 * relationships, rather than on connected nodes.
20
 * 
20
 * @author Del Myers
21
 * @author Del Myers
21
 * @see #IGraphContentProvider
22
 * @see #IGraphContentProvider
22
 * @see #IEntityStyleProvider
23
 * @see #IEntityStyleProvider
23
 *
24
 * 
24
 */
25
 */
25
//@tag bug(151327-Styles) : created to solve this bug
26
// @tag bug(151327-Styles) : created to solve this bug
26
public interface IConnectionStyleProvider extends IDisposable {
27
public interface IConnectionStyleProvider extends IDisposable {
27
	/**
28
	/**
28
	 * Returns the style flags for this connection. Valid flags are those
29
	 * Returns the style flags for this connection. Valid flags are those that
29
	 * that begin with CONNECTION in @see org.eclipse.zest.core.ZestStyles. Check
30
	 * begin with CONNECTION in @see org.eclipse.zest.core.ZestStyles. Check
30
	 * ZestStyles for legal combinations.
31
	 * ZestStyles for legal combinations.
31
	 * @param rel the relationship represented by this connection.
32
	 * 
33
	 * @param rel
34
	 *            the relationship represented by this connection.
32
	 * @return the style flags for this connection.
35
	 * @return the style flags for this connection.
33
	 * @see org.eclipse.zest.core.widgets.ZestStyles
36
	 * @see org.eclipse.zest.core.widgets.ZestStyles
34
	 */
37
	 */
35
	public int getConnectionStyle(Object rel);
38
	public int getConnectionStyle(Object rel);
36
	
39
37
	/**
40
	/**
38
	 * Returns the color for the connection. Null for default.  Any resources created by this class must be disposed by
41
	 * Returns the color for the connection. Null for default. Any resources
39
	 * this class.
42
	 * created by this class must be disposed by this class.
40
	 * @param rel the relationship represented by this connection.
43
	 * 
44
	 * @param rel
45
	 *            the relationship represented by this connection.
41
	 * @return the color.
46
	 * @return the color.
42
	 * @see #dispose()
47
	 * @see #dispose()
43
	 */
48
	 */
44
	public Color getColor(Object rel);
49
	public Color getColor(Object rel);
45
	
50
46
	/**
51
	/**
47
	 * Returns the highlighted color for this connection. Null for default.  Any resources created by this class must be disposed by
52
	 * Returns the highlighted color for this connection. Null for default. Any
48
	 * this class.
53
	 * resources created by this class must be disposed by this class.
49
	 * @param rel the relationship represented by this connection.
54
	 * 
55
	 * @param rel
56
	 *            the relationship represented by this connection.
50
	 * @return the highlighted color. Null for default.
57
	 * @return the highlighted color. Null for default.
51
	 * @see #dispose()
58
	 * @see #dispose()
52
	 */
59
	 */
53
	public Color getHighlightColor(Object rel);
60
	public Color getHighlightColor(Object rel);
54
	
61
55
	/**
62
	/**
56
	 * Returns the line width of the connection. -1 for default.
63
	 * Returns the line width of the connection. -1 for default.
57
	 * @param rel the relationship represented by this connection.
64
	 * 
65
	 * @param rel
66
	 *            the relationship represented by this connection.
58
	 * @return the line width for the connection. -1 for default.
67
	 * @return the line width for the connection. -1 for default.
59
	 */
68
	 */
60
	public int getLineWidth(Object rel);
69
	public int getLineWidth(Object rel);
(-)src/org/eclipse/zest/core/viewers/IZoomableWorkbenchPart.java (-6 / +7 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 10-26 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.zest.core.viewers;
11
package org.eclipse.zest.core.viewers;
12
12
13
14
/**
13
/**
15
 * An interface that can be added to IWorkbenchParts based on ZEST views so that zooming
14
 * An interface that can be added to IWorkbenchParts based on ZEST views so that
16
 * is supported.
15
 * zooming is supported.
16
 * 
17
 * @author Del Myers
17
 * @author Del Myers
18
 *
18
 * 
19
 */
19
 */
20
//@tag bug.156286-Zooming.fix : experimental
20
// @tag bug.156286-Zooming.fix : experimental
21
public interface IZoomableWorkbenchPart {
21
public interface IZoomableWorkbenchPart {
22
	/**
22
	/**
23
	 * Returns the viewer that is zoomable.
23
	 * Returns the viewer that is zoomable.
24
	 * 
24
	 * @return the viewer that is zoomable.
25
	 * @return the viewer that is zoomable.
25
	 */
26
	 */
26
	AbstractZoomableViewer getZoomableViewer();
27
	AbstractZoomableViewer getZoomableViewer();
(-)src/org/eclipse/zest/core/viewers/internal/GraphModelEntityFactory.java (-16 / +31 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials are made
3
 * All rights reserved. This program and the accompanying materials are made
4
 * available under the terms of the Eclipse Public License v1.0 which
4
 * available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
Lines 15-20 Link Here
15
import java.util.List;
15
import java.util.List;
16
import java.util.Set;
16
import java.util.Set;
17
17
18
import org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer;
18
import org.eclipse.zest.core.viewers.EntityConnectionData;
19
import org.eclipse.zest.core.viewers.EntityConnectionData;
19
import org.eclipse.zest.core.viewers.IFigureProvider;
20
import org.eclipse.zest.core.viewers.IFigureProvider;
20
import org.eclipse.zest.core.viewers.IGraphEntityContentProvider;
21
import org.eclipse.zest.core.viewers.IGraphEntityContentProvider;
Lines 39-45 Link Here
39
	/*
40
	/*
40
	 * (non-Javadoc)
41
	 * (non-Javadoc)
41
	 * 
42
	 * 
42
	 * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#createGraphModel()
43
	 * @seeorg.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#
44
	 * createGraphModel()
43
	 */
45
	 */
44
	public Graph createGraphModel(Graph model) {
46
	public Graph createGraphModel(Graph model) {
45
		doBuildGraph(model);
47
		doBuildGraph(model);
Lines 49-55 Link Here
49
	/*
51
	/*
50
	 * (non-Javadoc)
52
	 * (non-Javadoc)
51
	 * 
53
	 * 
52
	 * @see org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory#doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel)
54
	 * @see
55
	 * org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory
56
	 * #doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel)
53
	 */
57
	 */
54
	protected void doBuildGraph(Graph model) {
58
	protected void doBuildGraph(Graph model) {
55
		super.doBuildGraph(model);
59
		super.doBuildGraph(model);
Lines 73-80 Link Here
73
			}
77
			}
74
		}
78
		}
75
79
76
		// We may have other entities (such as children of containers) 
80
		// We may have other entities (such as children of containers)
77
		Set keySet = ((AbstractStructuredGraphViewer) getViewer()).getNodesMap().keySet();
81
		Set keySet = ((AbstractStructuredGraphViewer) getViewer())
82
				.getNodesMap().keySet();
78
		entities = keySet.toArray();
83
		entities = keySet.toArray();
79
84
80
		for (int i = 0; i < entities.length; i++) {
85
		for (int i = 0; i < entities.length; i++) {
Lines 84-90 Link Here
84
			if (filterElement(inputElement, data)) {
89
			if (filterElement(inputElement, data)) {
85
				continue;
90
				continue;
86
			}
91
			}
87
			Object[] related = ((IGraphEntityContentProvider) getContentProvider()).getConnectedTo(data);
92
			Object[] related = ((IGraphEntityContentProvider) getContentProvider())
93
					.getConnectedTo(data);
88
94
89
			if (related != null) {
95
			if (related != null) {
90
				for (int j = 0; j < related.length; j++) {
96
				for (int j = 0; j < related.length; j++) {
Lines 93-99 Link Here
93
					if (filterElement(inputElement, related[j])) {
99
					if (filterElement(inputElement, related[j])) {
94
						continue;
100
						continue;
95
					}
101
					}
96
					EntityConnectionData connectionData = new EntityConnectionData(data, related[j]);
102
					EntityConnectionData connectionData = new EntityConnectionData(
103
							data, related[j]);
97
					if (filterElement(inputElement, connectionData)) {
104
					if (filterElement(inputElement, connectionData)) {
98
						continue;
105
						continue;
99
					}
106
					}
Lines 106-113 Link Here
106
	/*
113
	/*
107
	 * (non-Javadoc)
114
	 * (non-Javadoc)
108
	 * 
115
	 * 
109
	 * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh(org.eclipse.zest.core.internal.graphmodel.GraphModel,
116
	 * @see
110
	 *      java.lang.Object)
117
	 * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh
118
	 * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object)
111
	 */
119
	 */
112
	public void refresh(Graph graph, Object element, boolean refreshLabels) {
120
	public void refresh(Graph graph, Object element, boolean refreshLabels) {
113
		if (element == null) {
121
		if (element == null) {
Lines 133-142 Link Here
133
141
134
		if (refreshLabels) {
142
		if (refreshLabels) {
135
			update(node);
143
			update(node);
136
			for (Iterator it = node.getSourceConnections().iterator(); it.hasNext();) {
144
			for (Iterator it = node.getSourceConnections().iterator(); it
145
					.hasNext();) {
137
				update((GraphItem) it.next());
146
				update((GraphItem) it.next());
138
			}
147
			}
139
			for (Iterator it = node.getTargetConnections().iterator(); it.hasNext();) {
148
			for (Iterator it = node.getTargetConnections().iterator(); it
149
					.hasNext();) {
140
				update((GraphItem) it.next());
150
				update((GraphItem) it.next());
141
			}
151
			}
142
		}
152
		}
Lines 149-155 Link Here
149
	 */
159
	 */
150
	private void reconnect(Graph graph, Object element, boolean refreshLabels) {
160
	private void reconnect(Graph graph, Object element, boolean refreshLabels) {
151
		GraphNode node = viewer.getGraphModelNode(element);
161
		GraphNode node = viewer.getGraphModelNode(element);
152
		Object[] related = ((IGraphEntityContentProvider) getContentProvider()).getConnectedTo(element);
162
		Object[] related = ((IGraphEntityContentProvider) getContentProvider())
163
				.getConnectedTo(element);
153
		List connections = node.getSourceConnections();
164
		List connections = node.getSourceConnections();
154
		LinkedList toAdd = new LinkedList();
165
		LinkedList toAdd = new LinkedList();
155
		LinkedList toDelete = new LinkedList();
166
		LinkedList toDelete = new LinkedList();
Lines 157-166 Link Here
157
		HashSet oldExternalConnections = new HashSet();
168
		HashSet oldExternalConnections = new HashSet();
158
		HashSet newExternalConnections = new HashSet();
169
		HashSet newExternalConnections = new HashSet();
159
		for (Iterator it = connections.iterator(); it.hasNext();) {
170
		for (Iterator it = connections.iterator(); it.hasNext();) {
160
			oldExternalConnections.add(((GraphConnection) it.next()).getExternalConnection());
171
			oldExternalConnections.add(((GraphConnection) it.next())
172
					.getExternalConnection());
161
		}
173
		}
162
		for (int i = 0; i < related.length; i++) {
174
		for (int i = 0; i < related.length; i++) {
163
			newExternalConnections.add(new EntityConnectionData(element, related[i]));
175
			newExternalConnections.add(new EntityConnectionData(element,
176
					related[i]));
164
		}
177
		}
165
		for (Iterator it = oldExternalConnections.iterator(); it.hasNext();) {
178
		for (Iterator it = oldExternalConnections.iterator(); it.hasNext();) {
166
			Object next = it.next();
179
			Object next = it.next();
Lines 204-211 Link Here
204
	/*
217
	/*
205
	 * (non-Javadoc)
218
	 * (non-Javadoc)
206
	 * 
219
	 * 
207
	 * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh(org.eclipse.zest.core.internal.graphmodel.GraphModel,
220
	 * @see
208
	 *      java.lang.Object, boolean)
221
	 * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh
222
	 * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object,
223
	 * boolean)
209
	 */
224
	 */
210
	public void refresh(Graph graph, Object element) {
225
	public void refresh(Graph graph, Object element) {
211
		refresh(graph, element, false);
226
		refresh(graph, element, false);
(-)src/org/eclipse/zest/core/viewers/internal/AbstractStylingModelFactory.java (-15 / +8 lines)
Lines 5-15 Link Here
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 ******************************************************************************/
11
 ******************************************************************************/
10
package org.eclipse.zest.core.viewers.internal;
12
package org.eclipse.zest.core.viewers.internal;
11
13
12
import java.util.ArrayList;
13
import java.util.HashMap;
14
import java.util.HashMap;
14
import java.util.Iterator;
15
import java.util.Iterator;
15
import java.util.LinkedList;
16
import java.util.LinkedList;
Lines 22-36 Link Here
22
import org.eclipse.jface.viewers.StructuredViewer;
23
import org.eclipse.jface.viewers.StructuredViewer;
23
import org.eclipse.jface.viewers.ViewerFilter;
24
import org.eclipse.jface.viewers.ViewerFilter;
24
import org.eclipse.swt.SWT;
25
import org.eclipse.swt.SWT;
26
import org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer;
25
import org.eclipse.zest.core.viewers.IFigureProvider;
27
import org.eclipse.zest.core.viewers.IFigureProvider;
26
import org.eclipse.zest.core.viewers.INestedContentProvider;
28
import org.eclipse.zest.core.viewers.INestedContentProvider;
27
import org.eclipse.zest.core.widgets.Graph;
29
import org.eclipse.zest.core.widgets.Graph;
28
import org.eclipse.zest.core.widgets.GraphConnection;
30
import org.eclipse.zest.core.widgets.GraphConnection;
31
import org.eclipse.zest.core.widgets.GraphContainer;
29
import org.eclipse.zest.core.widgets.GraphItem;
32
import org.eclipse.zest.core.widgets.GraphItem;
30
import org.eclipse.zest.core.widgets.GraphNode;
33
import org.eclipse.zest.core.widgets.GraphNode;
31
import org.eclipse.zest.core.widgets.IContainer;
32
34
33
/*
35
/**
34
 * Base class that can be used for model factories. Offers facilities to style
36
 * Base class that can be used for model factories. Offers facilities to style
35
 * the items that have been created by the factory.
37
 * the items that have been created by the factory.
36
 * 
38
 * 
Lines 42-48 Link Here
42
	private AbstractStructuredGraphViewer viewer;
44
	private AbstractStructuredGraphViewer viewer;
43
	private int connectionStyle;
45
	private int connectionStyle;
44
	private int nodeStyle;
46
	private int nodeStyle;
45
	private List /* ConstraintAdapater */constraintAdapters = new ArrayList();
46
47
47
	/**
48
	/**
48
	 * 
49
	 * 
Lines 51-59 Link Here
51
		this.viewer = viewer;
52
		this.viewer = viewer;
52
		this.connectionStyle = SWT.NONE;
53
		this.connectionStyle = SWT.NONE;
53
		this.nodeStyle = SWT.NONE;
54
		this.nodeStyle = SWT.NONE;
54
		if (viewer instanceof AbstractStructuredGraphViewer) {
55
			this.constraintAdapters = (viewer).getConstraintAdapters();
56
		}
57
	}
55
	}
58
56
59
	public void styleConnection(GraphConnection conn) {
57
	public void styleConnection(GraphConnection conn) {
Lines 208-217 Link Here
208
					return node;
206
					return node;
209
				}
207
				}
210
				for (int i = 0; i < childNodes.length; i++) {
208
				for (int i = 0; i < childNodes.length; i++) {
211
					GraphNode childNode = viewer.addGraphModelNode((IContainer) node, childNodes[i]);
209
					GraphNode childNode = viewer.addGraphModelNode((GraphContainer) node, childNodes[i]);
212
					styleItem(childNode);
210
					styleItem(childNode);
213
				}
211
				}
214
				((IContainer) node).applyLayout();
212
				((GraphContainer) node).applyLayout();
215
				return node;
213
				return node;
216
			}
214
			}
217
		}
215
		}
Lines 243-252 Link Here
243
		this.nodeStyle = style;
241
		this.nodeStyle = style;
244
	}
242
	}
245
243
246
	public List /* ConstraintAdapter */getConstraintAdapters() {
247
		return this.constraintAdapters;
248
	}
249
250
	/**
244
	/**
251
	 * @return the nodeStyle
245
	 * @return the nodeStyle
252
	 */
246
	 */
Lines 345-351 Link Here
345
		clearGraph(model);
339
		clearGraph(model);
346
		model.setConnectionStyle(getConnectionStyle());
340
		model.setConnectionStyle(getConnectionStyle());
347
		model.setNodeStyle(getNodeStyle());
341
		model.setNodeStyle(getNodeStyle());
348
		model.setConstraintAdapters(getConstraintAdapters());
349
	}
342
	}
350
343
351
	/**
344
	/**
(-)src/org/eclipse/zest/core/viewers/internal/IStylingGraphModelFactory.java (-2 / +3 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 93-99 Link Here
93
	 *            the user model data used for the destination node.
93
	 *            the user model data used for the destination node.
94
	 * @return the created or retrieved connection for the given graph.
94
	 * @return the created or retrieved connection for the given graph.
95
	 */
95
	 */
96
	public GraphConnection createConnection(Graph graph, Object element, Object source, Object dest);
96
	public GraphConnection createConnection(Graph graph, Object element,
97
			Object source, Object dest);
97
98
98
	/**
99
	/**
99
	 * Restyles the given graph items according to the label provider supplied
100
	 * Restyles the given graph items according to the label provider supplied
(-)src/org/eclipse/zest/core/viewers/internal/AbstractStructuredGraphViewer.java (-756 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.core.viewers.internal;
11
12
import java.util.ArrayList;
13
import java.util.Comparator;
14
import java.util.HashMap;
15
import java.util.Iterator;
16
import java.util.LinkedList;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.TreeSet;
20
21
import org.eclipse.draw2d.IFigure;
22
import org.eclipse.swt.SWT;
23
import org.eclipse.swt.SWTError;
24
import org.eclipse.swt.events.DisposeEvent;
25
import org.eclipse.swt.widgets.Widget;
26
import org.eclipse.zest.core.viewers.AbstractZoomableViewer;
27
import org.eclipse.zest.core.viewers.IGraphContentProvider;
28
import org.eclipse.zest.core.widgets.CGraphNode;
29
import org.eclipse.zest.core.widgets.ConstraintAdapter;
30
import org.eclipse.zest.core.widgets.Graph;
31
import org.eclipse.zest.core.widgets.GraphConnection;
32
import org.eclipse.zest.core.widgets.GraphContainer;
33
import org.eclipse.zest.core.widgets.GraphItem;
34
import org.eclipse.zest.core.widgets.GraphNode;
35
import org.eclipse.zest.core.widgets.IContainer;
36
import org.eclipse.zest.core.widgets.ZestStyles;
37
import org.eclipse.zest.layouts.LayoutAlgorithm;
38
39
/*
40
 * Abstraction of graph viewers to implement functionality used by all of them.
41
 * Not intended to be implemented by clients. Use one of the provided children
42
 * instead.
43
 * 
44
 * @author Del Myers
45
 */
46
public abstract class AbstractStructuredGraphViewer extends AbstractZoomableViewer {
47
	/**
48
	 * Contains top-level styles for the entire graph. Set in the constructor. *
49
	 */
50
	private int graphStyle;
51
52
	/**
53
	 * Contains node-level styles for the graph. Set in setNodeStyle(). Defaults
54
	 * are used in the constructor.
55
	 */
56
	private int nodeStyle;
57
58
	/**
59
	 * Contains arc-level styles for the graph. Set in setConnectionStyle().
60
	 * Defaults are used in the constructor.
61
	 */
62
	private int connectionStyle;
63
64
	private HashMap nodesMap = new HashMap();
65
	private HashMap connectionsMap = new HashMap();
66
67
	/**
68
	 * The constraint adatpers
69
	 */
70
	private List constraintAdapters = new ArrayList();
71
72
	/**
73
	 * A simple graph comparator that orders graph elements based on thier type
74
	 * (connection or node), and their unique object identification.
75
	 */
76
	private class SimpleGraphComparator implements Comparator {
77
		TreeSet storedStrings;
78
79
		/**
80
		 * 
81
		 */
82
		public SimpleGraphComparator() {
83
			this.storedStrings = new TreeSet();
84
		}
85
86
		/*
87
		 * (non-Javadoc)
88
		 * 
89
		 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
90
		 */
91
		public int compare(Object arg0, Object arg1) {
92
			if (arg0 instanceof GraphNode && arg1 instanceof GraphConnection) {
93
				return 1;
94
			} else if (arg0 instanceof GraphConnection && arg1 instanceof GraphNode) {
95
				return -1;
96
			}
97
			if (arg0.equals(arg1)) {
98
				return 0;
99
			}
100
			return getObjectString(arg0).compareTo(getObjectString(arg1));
101
		}
102
103
		private String getObjectString(Object o) {
104
			String s = o.getClass().getName() + "@" + Integer.toHexString(o.hashCode());
105
			while (storedStrings.contains(s)) {
106
				s = s + 'X';
107
			}
108
			return s;
109
		}
110
	}
111
112
	protected AbstractStructuredGraphViewer(int graphStyle) {
113
		this.graphStyle = graphStyle;
114
		this.connectionStyle = SWT.NONE;
115
		this.nodeStyle = SWT.NONE;
116
117
	}
118
119
	/**
120
	 * Sets the default style for nodes in this graph. Note: if an input is set
121
	 * on the viewer, a ZestException will be thrown.
122
	 * 
123
	 * @param nodeStyle
124
	 *            the style for the nodes.
125
	 * @see #ZestStyles
126
	 */
127
	public void setNodeStyle(int nodeStyle) {
128
		if (getInput() != null) {
129
			throw new SWTError(SWT.ERROR_UNSPECIFIED);
130
		}
131
		this.nodeStyle = nodeStyle;
132
	}
133
134
	/**
135
	 * Sets the default style for connections in this graph. Note: if an input
136
	 * is set on the viewer, a ZestException will be thrown.
137
	 * 
138
	 * @param connectionStyle
139
	 *            the style for the connections.
140
	 * @see #ZestStyles
141
	 */
142
	public void setConnectionStyle(int connectionStyle) {
143
		if (getInput() != null) {
144
			throw new SWTError(SWT.ERROR_UNSPECIFIED);
145
		}
146
		if (!ZestStyles.validateConnectionStyle(connectionStyle)) {
147
			throw new SWTError(SWT.ERROR_INVALID_ARGUMENT);
148
		}
149
		this.connectionStyle = connectionStyle;
150
	}
151
152
	/**
153
	 * Returns the style set for the graph
154
	 * 
155
	 * @return The style set of the graph
156
	 */
157
	public int getGraphStyle() {
158
		return graphStyle;
159
	}
160
161
	/**
162
	 * Returns the style set for the nodes.
163
	 * 
164
	 * @return the style set for the nodes.
165
	 */
166
	public int getNodeStyle() {
167
		return nodeStyle;
168
	}
169
170
	public Graph getGraphControl() {
171
		return (Graph) getControl();
172
	}
173
174
	/**
175
	 * @return the connection style.
176
	 */
177
	public int getConnectionStyle() {
178
		return connectionStyle;
179
	}
180
181
	/**
182
	 * Adds a new constraint adapter to the list of constraints
183
	 * 
184
	 * @param constraintAdapter
185
	 */
186
	public void addConstraintAdapter(ConstraintAdapter constraintAdapter) {
187
		this.constraintAdapters.add(constraintAdapter);
188
	}
189
190
	/**
191
	 * Gets all the constraint adapters currently on the viewer
192
	 * 
193
	 * @return
194
	 */
195
	public List getConstraintAdapters() {
196
		return this.constraintAdapters;
197
	}
198
199
	/**
200
	 * Sets the layout algorithm for this viewer. Subclasses may place
201
	 * restrictions on the algorithms that it accepts.
202
	 * 
203
	 * @param algorithm
204
	 *            the layout algorithm
205
	 * @param run
206
	 *            true if the layout algorithm should be run immediately. This
207
	 *            is a hint.
208
	 */
209
	public abstract void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean run);
210
211
	/**
212
	 * Gets the current layout algorithm.
213
	 * 
214
	 * @return the current layout algorithm.
215
	 */
216
	protected abstract LayoutAlgorithm getLayoutAlgorithm();
217
218
	/**
219
	 * Equivalent to setLayoutAlgorithm(algorithm, false).
220
	 * 
221
	 * @param algorithm
222
	 */
223
	public void setLayoutAlgorithm(LayoutAlgorithm algorithm) {
224
		setLayoutAlgorithm(algorithm, false);
225
	}
226
227
	public Object[] getNodeElements() {
228
		return this.nodesMap.keySet().toArray();
229
	}
230
231
	public Object[] getConnectionElements() {
232
		return this.connectionsMap.keySet().toArray();
233
	}
234
235
	HashMap getNodesMap() {
236
		return this.nodesMap;
237
	}
238
239
	GraphNode addGraphModelContainer(Object element) {
240
		GraphNode node = this.getGraphModelNode(element);
241
		if (node == null) {
242
			node = new GraphContainer((Graph) getControl(), SWT.NONE);
243
			this.nodesMap.put(element, node);
244
			node.setData(element);
245
		}
246
		return node;
247
	}
248
249
	GraphNode addGraphModelNode(IContainer container, Object element) {
250
		GraphNode node = this.getGraphModelNode(element);
251
		if (node == null) {
252
			node = new GraphNode(container, SWT.NONE);
253
			this.nodesMap.put(element, node);
254
			node.setData(element);
255
		}
256
		return node;
257
	}
258
259
	GraphNode addGraphModelNode(Object element, IFigure figure) {
260
		GraphNode node = this.getGraphModelNode(element);
261
		if (node == null) {
262
			if (figure != null) {
263
				node = new CGraphNode((Graph) getControl(), SWT.NONE, figure);
264
				this.nodesMap.put(element, node);
265
				node.setData(element);
266
			} else {
267
				node = new GraphNode((Graph) getControl(), SWT.NONE);
268
				this.nodesMap.put(element, node);
269
				node.setData(element);
270
			}
271
		}
272
		return node;
273
	}
274
275
	GraphConnection addGraphModelConnection(Object element, GraphNode source, GraphNode target) {
276
		GraphConnection connection = this.getGraphModelConnection(element);
277
		if (connection == null) {
278
			connection = new GraphConnection((Graph) getControl(), SWT.NONE, source, target);
279
			this.connectionsMap.put(element, connection);
280
			connection.setData(element);
281
		}
282
		return connection;
283
284
	}
285
286
	GraphConnection getGraphModelConnection(Object obj) {
287
		return (GraphConnection) this.connectionsMap.get(obj);
288
	}
289
290
	GraphNode getGraphModelNode(Object obj) {
291
		return (GraphNode) this.nodesMap.get(obj);
292
	}
293
294
	void removeGraphModelConnection(Object obj) {
295
		GraphConnection connection = (GraphConnection) connectionsMap.get(obj);
296
		if (connection != null) {
297
			connectionsMap.remove(obj);
298
			if (!connection.isDisposed()) {
299
				connection.dispose();
300
			}
301
		}
302
	}
303
304
	void removeGraphModelNode(Object obj) {
305
		GraphNode node = (GraphNode) nodesMap.get(obj);
306
		if (node != null) {
307
			nodesMap.remove(obj);
308
			if (!node.isDisposed()) {
309
				node.dispose();
310
			}
311
		}
312
	}
313
314
	protected void handleDispose(DisposeEvent event) {
315
316
		if (getControl() != null && !getControl().isDisposed()) {
317
			getControl().dispose();
318
		}
319
		super.handleDispose(event);
320
	}
321
322
	/*
323
	 * (non-Javadoc)
324
	 * 
325
	 * @see org.eclipse.jface.viewers.StructuredViewer#internalRefresh(java.lang.Object)
326
	 */
327
	protected void internalRefresh(Object element) {
328
		if (getInput() == null) {
329
			return;
330
		}
331
		if (element == getInput()) {
332
			getFactory().refreshGraph(getGraphControl());
333
		} else {
334
			getFactory().refresh(getGraphControl(), element);
335
		}
336
		// After all the items are loaded, we call update to ensure drawing.
337
		// This way the damaged area does not get too big if we start
338
		// adding and removing more nodes
339
		getGraphControl().getLightweightSystem().getUpdateManager().performUpdate();
340
	}
341
342
	protected void doUpdateItem(Widget item, Object element, boolean fullMap) {
343
		if (item == getGraphControl()) {
344
			getFactory().update(getNodesArray(getGraphControl()));
345
			getFactory().update(getConnectionsArray(getGraphControl()));
346
		} else if (item instanceof GraphItem) {
347
			getFactory().update((GraphItem) item);
348
		}
349
	}
350
351
	/*
352
	 * (non-Javadoc)
353
	 * 
354
	 * @see org.eclipse.jface.viewers.StructuredViewer#doFindInputItem(java.lang.Object)
355
	 */
356
	protected Widget doFindInputItem(Object element) {
357
358
		if (element == getInput() && element instanceof Widget) {
359
			return (Widget) element;
360
		}
361
		return null;
362
	}
363
364
	/*
365
	 * (non-Javadoc)
366
	 * 
367
	 * @see org.eclipse.jface.viewers.StructuredViewer#doFindItem(java.lang.Object)
368
	 */
369
	protected Widget doFindItem(Object element) {
370
		Widget node = (Widget) nodesMap.get(element);
371
		Widget connection = (Widget) connectionsMap.get(element);
372
		return (node != null) ? node : connection;
373
	}
374
375
	/*
376
	 * (non-Javadoc)
377
	 * 
378
	 * @see org.eclipse.jface.viewers.StructuredViewer#getSelectionFromWidget()
379
	 */
380
	protected List getSelectionFromWidget() {
381
		List internalSelection = getWidgetSelection();
382
		LinkedList externalSelection = new LinkedList();
383
		for (Iterator i = internalSelection.iterator(); i.hasNext();) {
384
			// @tag zest.todo : should there be a method on IGraphItem to get
385
			// the external data?
386
			GraphItem item = (GraphItem) i.next();
387
			if (item instanceof GraphNode) {
388
				externalSelection.add(((GraphNode) item).getData());
389
			} else if (item instanceof GraphConnection) {
390
				externalSelection.add(((GraphConnection) item).getExternalConnection());
391
			} else if (item instanceof Widget) {
392
				externalSelection.add(((Widget) item).getData());
393
			}
394
		}
395
		return externalSelection;
396
	}
397
398
	protected GraphItem[] /* GraphItem */findItems(List l) {
399
		if (l == null) {
400
			return new GraphItem[0];
401
		}
402
403
		ArrayList list = new ArrayList();
404
		Iterator iterator = l.iterator();
405
406
		while (iterator.hasNext()) {
407
			GraphItem w = (GraphItem) findItem(iterator.next());
408
			list.add(w);
409
		}
410
		return (GraphItem[]) list.toArray(new GraphItem[list.size()]);
411
	}
412
413
	/*
414
	 * (non-Javadoc)
415
	 * 
416
	 * @see org.eclipse.jface.viewers.StructuredViewer#setSelectionToWidget(java.util.List,
417
	 *      boolean)
418
	 */
419
	protected void setSelectionToWidget(List l, boolean reveal) {
420
		Graph control = (Graph) getControl();
421
		List selection = new LinkedList();
422
		for (Iterator i = l.iterator(); i.hasNext();) {
423
			Object obj = i.next();
424
			GraphNode node = (GraphNode) nodesMap.get(obj);
425
			GraphConnection conn = (GraphConnection) connectionsMap.get(obj);
426
			if (node != null) {
427
				selection.add(node);
428
			}
429
			if (conn != null) {
430
				selection.add(conn);
431
			}
432
		}
433
		control.setSelection((GraphNode[]) selection.toArray(new GraphNode[selection.size()]));
434
	}
435
436
	/**
437
	 * Gets the internal model elements that are selected.
438
	 * 
439
	 * @return
440
	 */
441
	protected List getWidgetSelection() {
442
		Graph control = (Graph) getControl();
443
		return control.getSelection();
444
	}
445
446
	/*
447
	 * (non-Javadoc)
448
	 * 
449
	 * @see org.eclipse.jface.viewers.Viewer#inputChanged(java.lang.Object,
450
	 *      java.lang.Object)
451
	 */
452
	protected void inputChanged(Object input, Object oldInput) {
453
		IStylingGraphModelFactory factory = getFactory();
454
		factory.setConnectionStyle(getConnectionStyle());
455
		factory.setNodeStyle(getNodeStyle());
456
457
		// Save the old map so we can set the size and position of any nodes
458
		// that are the same
459
		Map oldNodesMap = nodesMap;
460
		Graph graph = (Graph) getControl();
461
		graph.setSelection(new GraphNode[0]);
462
463
		Iterator iterator = nodesMap.values().iterator();
464
		while (iterator.hasNext()) {
465
			GraphNode node = (GraphNode) iterator.next();
466
			if (!node.isDisposed()) {
467
				node.dispose();
468
			}
469
		}
470
471
		iterator = connectionsMap.values().iterator();
472
		while (iterator.hasNext()) {
473
			GraphConnection connection = (GraphConnection) iterator.next();
474
			if (!connection.isDisposed()) {
475
				connection.dispose();
476
			}
477
		}
478
479
		nodesMap = new HashMap();
480
		connectionsMap = new HashMap();
481
482
		graph = factory.createGraphModel(graph);
483
484
		((Graph) getControl()).setNodeStyle(getNodeStyle());
485
		((Graph) getControl()).setConnectionStyle(getConnectionStyle());
486
487
		// check if any of the pre-existing nodes are still present
488
		// in this case we want them to keep the same location & size
489
		for (Iterator iter = oldNodesMap.keySet().iterator(); iter.hasNext();) {
490
			Object data = iter.next();
491
			GraphNode newNode = (GraphNode) nodesMap.get(data);
492
			if (newNode != null) {
493
				GraphNode oldNode = (GraphNode) oldNodesMap.get(data);
494
				newNode.setLocation(oldNode.getLocation().x, oldNode.getLocation().y);
495
				if (oldNode.isSizeFixed()) {
496
					newNode.setSize(oldNode.getSize().width, oldNode.getSize().height);
497
				}
498
			}
499
		}
500
501
		applyLayout();
502
	}
503
504
	/**
505
	 * Returns the factory used to create the model. This must not be called
506
	 * before the content provider is set.
507
	 * 
508
	 * @return
509
	 */
510
	protected abstract IStylingGraphModelFactory getFactory();
511
512
	protected void filterVisuals() {
513
		if (getGraphControl() == null) {
514
			return;
515
		}
516
		Object[] filtered = getFilteredChildren(getInput());
517
		SimpleGraphComparator comparator = new SimpleGraphComparator();
518
		TreeSet filteredElements = new TreeSet(comparator);
519
		TreeSet unfilteredElements = new TreeSet(comparator);
520
		List connections = getGraphControl().getConnections();
521
		List nodes = getGraphControl().getNodes();
522
		if (filtered.length == 0) {
523
			// set everything to invisible.
524
			// @tag zest.bug.156528-Filters.check : should we only filter out
525
			// the nodes?
526
			for (Iterator i = connections.iterator(); i.hasNext();) {
527
				GraphConnection c = (GraphConnection) i.next();
528
				c.setVisible(false);
529
			}
530
			for (Iterator i = nodes.iterator(); i.hasNext();) {
531
				GraphNode n = (GraphNode) i.next();
532
				n.setVisible(false);
533
			}
534
			return;
535
		}
536
		for (Iterator i = connections.iterator(); i.hasNext();) {
537
			GraphConnection c = (GraphConnection) i.next();
538
			if (c.getExternalConnection() != null) {
539
				unfilteredElements.add(c);
540
			}
541
		}
542
		for (Iterator i = nodes.iterator(); i.hasNext();) {
543
			GraphNode n = (GraphNode) i.next();
544
			if (n.getData() != null) {
545
				unfilteredElements.add(n);
546
			}
547
		}
548
		for (int i = 0; i < filtered.length; i++) {
549
			Object modelElement = connectionsMap.get(filtered[i]);
550
			if (modelElement == null) {
551
				modelElement = nodesMap.get(filtered[i]);
552
			}
553
			if (modelElement != null) {
554
				filteredElements.add(modelElement);
555
			}
556
		}
557
		unfilteredElements.removeAll(filteredElements);
558
		// set all the elements that did not pass the filters to invisible, and
559
		// all the elements that passed to visible.
560
		while (unfilteredElements.size() > 0) {
561
			GraphItem i = (GraphItem) unfilteredElements.first();
562
			i.setVisible(false);
563
			unfilteredElements.remove(i);
564
		}
565
		while (filteredElements.size() > 0) {
566
			GraphItem i = (GraphItem) filteredElements.first();
567
			i.setVisible(true);
568
			filteredElements.remove(i);
569
		}
570
	}
571
572
	/*
573
	 * (non-Javadoc)
574
	 * 
575
	 * @see org.eclipse.jface.viewers.StructuredViewer#getRawChildren(java.lang.Object)
576
	 */
577
	protected Object[] getRawChildren(Object parent) {
578
		if (parent == getInput()) {
579
			// get the children from the model.
580
			LinkedList children = new LinkedList();
581
			if (getGraphControl() != null) {
582
				List connections = getGraphControl().getConnections();
583
				List nodes = getGraphControl().getNodes();
584
				for (Iterator i = connections.iterator(); i.hasNext();) {
585
					GraphConnection c = (GraphConnection) i.next();
586
					if (c.getExternalConnection() != null) {
587
						children.add(c.getExternalConnection());
588
					}
589
				}
590
				for (Iterator i = nodes.iterator(); i.hasNext();) {
591
					GraphNode n = (GraphNode) i.next();
592
					if (n.getData() != null) {
593
						children.add(n.getData());
594
					}
595
				}
596
				return children.toArray();
597
			}
598
		}
599
		return super.getRawChildren(parent);
600
	}
601
602
	/**
603
	 * 
604
	 */
605
	public void reveal(Object element) {
606
		Widget[] items = this.findItems(element);
607
		for (int i = 0; i < items.length; i++) {
608
			Widget item = items[i];
609
			if (item instanceof GraphNode) {
610
				GraphNode graphModelNode = (GraphNode) item;
611
				graphModelNode.highlight();
612
			} else if (item instanceof GraphConnection) {
613
				GraphConnection graphModelConnection = (GraphConnection) item;
614
				graphModelConnection.highlight();
615
			}
616
		}
617
	}
618
619
	public void unReveal(Object element) {
620
		Widget[] items = this.findItems(element);
621
		for (int i = 0; i < items.length; i++) {
622
			Widget item = items[i];
623
			if (item instanceof GraphNode) {
624
				GraphNode graphModelNode = (GraphNode) item;
625
				graphModelNode.unhighlight();
626
			} else if (item instanceof GraphConnection) {
627
				GraphConnection graphModelConnection = (GraphConnection) item;
628
				graphModelConnection.unhighlight();
629
			}
630
		}
631
	}
632
633
	/**
634
	 * Applies the viewers layouts.
635
	 * 
636
	 */
637
	public abstract void applyLayout();
638
639
	/**
640
	 * Removes the given connection object from the layout algorithm and the
641
	 * model.
642
	 * 
643
	 * @param connection
644
	 */
645
	public void removeRelationship(Object connection) {
646
		GraphConnection relationship = (GraphConnection) connectionsMap.get(connection);
647
648
		if (relationship != null) {
649
			// remove the relationship from the layout algorithm
650
			if (getLayoutAlgorithm() != null) {
651
				getLayoutAlgorithm().removeRelationship(relationship.getLayoutRelationship());
652
			}
653
			// remove the relationship from the model
654
			relationship.dispose();
655
		}
656
	}
657
658
	/**
659
	 * Creates a new node and adds it to the graph. If it already exists nothing
660
	 * happens.
661
	 * 
662
	 * @param newNode
663
	 */
664
	public void addNode(Object element) {
665
		if (nodesMap.get(element) == null) {
666
			// create the new node
667
			getFactory().createNode(getGraphControl(), element);
668
669
		}
670
	}
671
672
	/**
673
	 * Removes the given element from the layout algorithm and the model.
674
	 * 
675
	 * @param element
676
	 *            The node element to remove.
677
	 */
678
	public void removeNode(Object element) {
679
		GraphNode node = (GraphNode) nodesMap.get(element);
680
681
		if (node != null) {
682
			// remove the node from the layout algorithm and all the connections
683
			if (getLayoutAlgorithm() != null) {
684
				getLayoutAlgorithm().removeEntity(node.getLayoutEntity());
685
				getLayoutAlgorithm().removeRelationships(node.getSourceConnections());
686
				getLayoutAlgorithm().removeRelationships(node.getTargetConnections());
687
			}
688
			// remove the node and it's connections from the model
689
			node.dispose();
690
		}
691
	}
692
693
	/**
694
	 * Creates a new relationship between the source node and the destination
695
	 * node. If either node doesn't exist then it will be created.
696
	 * 
697
	 * @param connection
698
	 *            The connection data object.
699
	 * @param srcNode
700
	 *            The source node data object.
701
	 * @param destNode
702
	 *            The destination node data object.
703
	 */
704
	public void addRelationship(Object connection, Object srcNode, Object destNode) {
705
		// create the new relationship
706
		IStylingGraphModelFactory modelFactory = getFactory();
707
		modelFactory.createConnection(getGraphControl(), connection, srcNode, destNode);
708
709
	}
710
711
	/**
712
	 * Adds a new relationship given the connection. It will use the content
713
	 * provider to determine the source and destination nodes.
714
	 * 
715
	 * @param connection
716
	 *            The connection data object.
717
	 */
718
	public void addRelationship(Object connection) {
719
		IStylingGraphModelFactory modelFactory = getFactory();
720
		if (connectionsMap.get(connection) == null) {
721
			if (modelFactory.getContentProvider() instanceof IGraphContentProvider) {
722
				IGraphContentProvider content = ((IGraphContentProvider) modelFactory.getContentProvider());
723
				Object source = content.getSource(connection);
724
				Object dest = content.getDestination(connection);
725
				// create the new relationship
726
				modelFactory.createConnection(getGraphControl(), connection, source, dest);
727
			} else {
728
				throw new UnsupportedOperationException();
729
			}
730
		}
731
	}
732
733
	/**
734
	 * Converts the list of GraphModelConnection objects into an array and
735
	 * returns it.
736
	 * 
737
	 * @return GraphModelConnection[]
738
	 */
739
	protected GraphConnection[] getConnectionsArray(Graph graph) {
740
		GraphConnection[] connsArray = new GraphConnection[graph.getConnections().size()];
741
		connsArray = (GraphConnection[]) graph.getConnections().toArray(connsArray);
742
		return connsArray;
743
	}
744
745
	/**
746
	 * Converts the list of GraphModelNode objects into an array an returns it.
747
	 * 
748
	 * @return GraphModelNode[]
749
	 */
750
	protected GraphNode[] getNodesArray(Graph graph) {
751
		GraphNode[] nodesArray = new GraphNode[graph.getNodes().size()];
752
		nodesArray = (GraphNode[]) graph.getNodes().toArray(nodesArray);
753
		return nodesArray;
754
	}
755
756
}
(-)src/org/eclipse/zest/core/viewers/internal/ZoomManager.java (-598 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others. All rights reserved.
3
 * This program and the accompanying materials are made available under the
4
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
5
 * and is available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: IBM Corporation - initial API and implementation
8
 ******************************************************************************/
9
package org.eclipse.zest.core.viewers.internal;
10
11
import java.util.ArrayList;
12
import java.util.Collections;
13
import java.util.Iterator;
14
import java.util.List;
15
16
import org.eclipse.draw2d.FreeformFigure;
17
import org.eclipse.draw2d.IFigure;
18
import org.eclipse.draw2d.ScalableFigure;
19
import org.eclipse.draw2d.ScalableFreeformLayeredPane;
20
import org.eclipse.draw2d.Viewport;
21
import org.eclipse.draw2d.geometry.Dimension;
22
import org.eclipse.draw2d.geometry.Point;
23
import org.eclipse.draw2d.geometry.Rectangle;
24
import org.eclipse.swt.widgets.Display;
25
26
/**
27
 * Manage the primary zoom function in a graphical viewer. This class is used by
28
 * the zoom contribution items, including:
29
 * <UL>
30
 * <LI>{@link org.eclipse.gef.ui.actions.ZoomInAction}
31
 * <LI>{@link org.eclipse.gef.ui.actions.ZoomOutAction}
32
 * <LI> and {@link org.eclipse.gef.ui.actions.ZoomComboContributionItem}
33
 * </UL>
34
 * <P>
35
 * A ZoomManager controls how zoom in and zoom out are performed. It also
36
 * determines the list of choices the user sees in the drop-down Combo on the
37
 * toolbar. The zoom manager controls a <code>ScalableFigure</code>, which
38
 * performs the actual zoom, and also a <code>Viewport</code>. The viewport
39
 * is needed so that the scrolled location is preserved as the zoom level
40
 * changes.
41
 * <p>
42
 * <b>NOTE:</b> For the settings of {@link #FIT_ALL Page},
43
 * {@link #FIT_WIDTH Width} and {@link #FIT_HEIGHT Height} to work properly, the
44
 * given <code>Viewport</code> should have its scrollbars always visible or
45
 * never visible. Otherwise, these settings may cause undesired effects.
46
 * 
47
 * @author Dan Lee
48
 * @author Eric Bordeau
49
 */
50
public class ZoomManager {
51
52
	/** Style bit meaning don't animate any zooms */
53
	public static final int ANIMATE_NEVER = 0;
54
	/** Style bit meaning animate during {@link #zoomIn()} and {@link #zoomOut()} */
55
	public static final int ANIMATE_ZOOM_IN_OUT = 1;
56
57
	private List listeners = new ArrayList();
58
59
	private double multiplier = 1.0;
60
	private ScalableFigure pane;
61
	private Viewport viewport;
62
	private double zoom = 1.0;
63
	//private int zoomAnimationStyle = ANIMATE_NEVER;
64
	private String currentZoomContant = null;
65
	private double[] zoomLevels = { .5, .75, 1.0, 1.5, 2.0, 2.5, 3, 4 };
66
67
	/**
68
	 * String constant for the "Height" zoom level. At this zoom level, the zoom
69
	 * manager will adopt a zoom setting such that the entire height of the
70
	 * diagram will be visible on the screen.
71
	 */
72
	public static final String FIT_HEIGHT = SharedMessages.FitHeightAction_Label;
73
	/**
74
	 * String constant for the "Width" zoom level. At this zoom level, the zoom
75
	 * manager will adopt a zoom setting such that the entire width of the
76
	 * diagram will be visible on the screen.
77
	 */
78
	public static final String FIT_WIDTH = SharedMessages.FitWidthAction_Label;
79
	/**
80
	 * String constant for the "Page" zoom level. At this zoom level, the zoom
81
	 * manager will adopt a zoom setting such that the entire diagram will be
82
	 * visible on the screen.
83
	 */
84
	public static final String FIT_ALL = SharedMessages.FitAllAction_Label;
85
	private List zoomLevelContributions = Collections.EMPTY_LIST;
86
87
	//DecimalFormat format = new DecimalFormat("####%"); //$NON-NLS-1$
88
89
	/**
90
	 * Creates a new ZoomManager.
91
	 * 
92
	 * @param pane
93
	 *            The ScalableFigure associated with this ZoomManager
94
	 * @param viewport
95
	 *            The Viewport assoicated with this ZoomManager
96
	 */
97
	public ZoomManager(ScalableFigure pane, Viewport viewport) {
98
		this.pane = pane;
99
		this.viewport = viewport;
100
		zoomLevelContributions = new ArrayList();
101
		zoomLevelContributions.add(FIT_ALL);
102
	}
103
104
	/**
105
	 * @deprecated Use {@link #ZoomManager(ScalableFigure, Viewport)} instead.
106
	 *             Creates a new ZoomManager
107
	 * @param pane
108
	 *            The ScalableFreeformLayeredPane associated with this
109
	 *            ZoomManager
110
	 * @param viewport
111
	 *            The Viewport assoicated with this viewport
112
	 */
113
	public ZoomManager(ScalableFreeformLayeredPane pane, Viewport viewport) {
114
		this.pane = pane;
115
		this.viewport = viewport;
116
	}
117
118
	/**
119
	 * Adds the given ZoomListener to this ZoomManager's list of listeners.
120
	 * 
121
	 * @param listener
122
	 *            the ZoomListener to be added
123
	 */
124
	public void addZoomListener(ZoomListener listener) {
125
		listeners.add(listener);
126
	}
127
128
	/**
129
	 * returns <code>true</code> if the zoommanager can perform
130
	 * <code>zoomIn()</code>.
131
	 * 
132
	 * @return boolean true if zoomIn can be called
133
	 */
134
	public boolean canZoomIn() {
135
		return getZoom() < getMaxZoom();
136
	}
137
138
	/**
139
	 * returns <code>true</code> if the zoommanager can perform
140
	 * <code>zoomOut()</code>.
141
	 * 
142
	 * @return boolean true if zoomOut can be called
143
	 */
144
	public boolean canZoomOut() {
145
		return getZoom() > getMinZoom();
146
	}
147
148
	/**
149
	 * Notifies listeners that the zoom level has changed.
150
	 */
151
	protected void fireZoomChanged() {
152
		Iterator iter = listeners.iterator();
153
		while (iter.hasNext()) {
154
			((ZoomListener) iter.next()).zoomChanged(zoom);
155
		}
156
	}
157
158
	private double getFitXZoomLevel(int which) {
159
		IFigure fig = getScalableFigure();
160
161
		Dimension available = getViewport().getClientArea().getSize();
162
		Dimension desired;
163
		if (fig instanceof FreeformFigure) {
164
			desired = ((FreeformFigure) fig).getFreeformExtent().getCopy().union(0, 0).getSize();
165
		} else {
166
			desired = fig.getPreferredSize().getCopy();
167
		}
168
169
		desired.width -= fig.getInsets().getWidth();
170
		desired.height -= fig.getInsets().getHeight();
171
172
		while (fig != getViewport()) {
173
			available.width -= fig.getInsets().getWidth();
174
			available.height -= fig.getInsets().getHeight();
175
			fig = fig.getParent();
176
		}
177
178
		double scaleX = Math.min(available.width * zoom / desired.width, getMaxZoom());
179
		double scaleY = Math.min(available.height * zoom / desired.height, getMaxZoom());
180
		if (which == 0) {
181
			return scaleX;
182
		}
183
		if (which == 1) {
184
			return scaleY;
185
		}
186
		return Math.min(scaleX, scaleY);
187
	}
188
189
	/**
190
	 * Calculates and returns the zoom percent required so that the entire
191
	 * height of the {@link #getScalableFigure() scalable figure} is visible on
192
	 * the screen. This is the zoom level associated with {@link #FIT_HEIGHT}.
193
	 * 
194
	 * @return zoom setting required to fit the scalable figure vertically on
195
	 *         the screen
196
	 */
197
	protected double getFitHeightZoomLevel() {
198
		return getFitXZoomLevel(1);
199
	}
200
201
	/**
202
	 * Calculates and returns the zoom percentage required to fit the entire
203
	 * {@link #getScalableFigure() scalable figure} on the screen. This is the
204
	 * zoom setting associated with {@link #FIT_ALL}. It is the minimum of
205
	 * {@link #getFitHeightZoomLevel()} and {@link #getFitWidthZoomLevel()}.
206
	 * 
207
	 * @return zoom setting required to fit the entire scalable figure on the
208
	 *         screen
209
	 */
210
	protected double getFitPageZoomLevel() {
211
		return getFitXZoomLevel(2);
212
	}
213
214
	/**
215
	 * Calculates and returns the zoom percentage required so that the entire
216
	 * width of the {@link #getScalableFigure() scalable figure} is visible on
217
	 * the screen. This is the zoom setting associated with {@link #FIT_WIDTH}.
218
	 * 
219
	 * @return zoom setting required to fit the scalable figure horizontally on
220
	 *         the screen
221
	 */
222
	protected double getFitWidthZoomLevel() {
223
		return getFitXZoomLevel(0);
224
	}
225
226
	/**
227
	 * Returns the maxZoom.
228
	 * 
229
	 * @return double
230
	 */
231
	public double getMaxZoom() {
232
		return getZoomLevels()[getZoomLevels().length - 1];
233
	}
234
235
	/**
236
	 * Returns the minZoom.
237
	 * 
238
	 * @return double
239
	 */
240
	public double getMinZoom() {
241
		return getZoomLevels()[0];
242
	}
243
244
	/**
245
	 * Returns the mutltiplier. This value is used to use zoom levels internally
246
	 * that are proportionally different than those displayed to the user. e.g.
247
	 * with a multiplier value of 2.0, the zoom level 1.0 will be displayed as
248
	 * "200%".
249
	 * 
250
	 * @return double The multiplier
251
	 */
252
	public double getUIMultiplier() {
253
		return multiplier;
254
	}
255
256
	/**
257
	 * Returns the zoom level that is one level higher than the current level.
258
	 * If zoom level is at maximum, returns the maximum.
259
	 * 
260
	 * @return double The next zoom level
261
	 */
262
	public double getNextZoomLevel() {
263
		for (int i = 0; i < zoomLevels.length; i++) {
264
			if (zoomLevels[i] > zoom) {
265
				return zoomLevels[i];
266
			}
267
		}
268
		return getMaxZoom();
269
	}
270
271
	/**
272
	 * Returns the zoom level that is one level higher than the current level.
273
	 * If zoom level is at maximum, returns the maximum.
274
	 * 
275
	 * @return double The previous zoom level
276
	 */
277
	public double getPreviousZoomLevel() {
278
		for (int i = 1; i < zoomLevels.length; i++) {
279
			if (zoomLevels[i] >= zoom) {
280
				return zoomLevels[i - 1];
281
			}
282
		}
283
		return getMinZoom();
284
	}
285
286
	/**
287
	 * Returns the figure which performs the actual zooming.
288
	 * 
289
	 * @return the scalable figure
290
	 */
291
	public ScalableFigure getScalableFigure() {
292
		return pane;
293
	}
294
295
	/**
296
	 * Returns the viewport.
297
	 * 
298
	 * @return Viewport
299
	 */
300
	public Viewport getViewport() {
301
		return viewport;
302
	}
303
304
	/**
305
	 * Returns the current zoom level.
306
	 * 
307
	 * @return double the zoom level
308
	 */
309
	public double getZoom() {
310
		return zoom;
311
	}
312
313
	private String format(double d) {
314
		return "" + ((int) (d * 100)) + "%";
315
	}
316
317
	/**
318
	 * Returns the current zoom level as a percentage formatted String
319
	 * 
320
	 * @return String The current zoom level as a String
321
	 */
322
	public String getZoomAsText() {
323
		if (currentZoomContant != null) {
324
			return currentZoomContant;
325
		}
326
327
		//String newItem = format.format(zoom * multiplier);
328
		String newItem = format(zoom * multiplier);
329
		return newItem;
330
	}
331
332
	/**
333
	 * Returns the list of strings that should be appended to the list of
334
	 * numerical zoom levels. These could be things such as Fit Width, Fit Page,
335
	 * etc. May return <code>null</code>.
336
	 * 
337
	 * @return the list of contributed zoom levels
338
	 */
339
	public List getZoomLevelContributions() {
340
		return zoomLevelContributions;
341
	}
342
343
	/**
344
	 * Returns the zoomLevels.
345
	 * 
346
	 * @return double[]
347
	 */
348
	public double[] getZoomLevels() {
349
		return zoomLevels;
350
	}
351
352
	/**
353
	 * Returns the list of zoom levels as Strings in percent notation, plus any
354
	 * additional zoom levels that were contributed using
355
	 * {@link #setZoomLevelContributions(List)}.
356
	 * 
357
	 * @return List The list of zoom levels
358
	 */
359
	public String[] getZoomLevelsAsText() {
360
		String[] zoomLevelStrings = new String[zoomLevels.length + zoomLevelContributions.size()];
361
362
		if (zoomLevelContributions != null) {
363
			for (int i = 0; i < zoomLevelContributions.size(); i++) {
364
				zoomLevelStrings[i] = (String) zoomLevelContributions.get(i);
365
			}
366
		}
367
		for (int i = 0; i < zoomLevels.length; i++) {
368
			//zoomLevelStrings[i + zoomLevelContributions.size()] = format.format(zoomLevels[i] * multiplier);
369
			zoomLevelStrings[i + zoomLevelContributions.size()] = format(zoomLevels[i] * multiplier);
370
		}
371
372
		return zoomLevelStrings;
373
	}
374
375
	/**
376
	 * Sets the zoom level to the given value. Min-max range check is not done.
377
	 * 
378
	 * @param zoom
379
	 *            the new zoom level
380
	 */
381
	protected void primSetZoom(double zoom) {
382
		Point p1 = getViewport().getClientArea().getCenter();
383
		Point p2 = p1.getCopy();
384
		Point p = getViewport().getViewLocation();
385
		double prevZoom = this.zoom;
386
		this.zoom = zoom;
387
		pane.setScale(zoom);
388
		fireZoomChanged();
389
		getViewport().validate();
390
391
		p2.scale(zoom / prevZoom);
392
		Dimension dif = p2.getDifference(p1);
393
		p.x += dif.width;
394
		p.y += dif.height;
395
		setViewLocation(p);
396
	}
397
398
	/**
399
	 * Removes the given ZoomListener from this ZoomManager's list of listeners.
400
	 * 
401
	 * @param listener
402
	 *            the ZoomListener to be removed
403
	 */
404
	public void removeZoomListener(ZoomListener listener) {
405
		listeners.remove(listener);
406
	}
407
408
	/**
409
	 * Sets the UI multiplier. The UI multiplier is applied to all zoom settings
410
	 * when they are presented to the user ({@link #getZoomAsText()}).
411
	 * Similarly, the multiplier is inversely applied when the user specifies a
412
	 * zoom level ({@link #setZoomAsText(String)}).
413
	 * <P>
414
	 * When the UI multiplier is <code>1.0</code>, the User will see the
415
	 * exact zoom level that is being applied. If the value is <code>2.0</code>,
416
	 * then a scale of <code>0.5</code> will be labeled "100%" to the User.
417
	 * 
418
	 * @param multiplier
419
	 *            The mutltiplier to set
420
	 */
421
	public void setUIMultiplier(double multiplier) {
422
		this.multiplier = multiplier;
423
	}
424
425
	/**
426
	 * Sets the Viewport's view associated with this ZoomManager to the passed
427
	 * Point
428
	 * 
429
	 * @param p
430
	 *            The new location for the Viewport's view.
431
	 */
432
	public void setViewLocation(Point p) {
433
		viewport.setViewLocation(p.x, p.y);
434
435
	}
436
437
	/**
438
	 * Sets the zoom level to the given value. If the zoom is out of the min-max
439
	 * range, it will be ignored.
440
	 * 
441
	 * @param zoom
442
	 *            the new zoom level
443
	 */
444
	public void setZoom(double zoom) {
445
		currentZoomContant = null;
446
		zoom = Math.min(getMaxZoom(), zoom);
447
		zoom = Math.max(getMinZoom(), zoom);
448
		if (this.zoom != zoom) {
449
			primSetZoom(zoom);
450
		}
451
	}
452
453
	/**
454
	 * Sets which zoom methods get animated.
455
	 * 
456
	 * @param style
457
	 *            the style bits determining the zoom methods to be animated.
458
	 */
459
	public void setZoomAnimationStyle(int style) {
460
		//zoomAnimationStyle = style;
461
	}
462
463
	/**
464
	 * Sets zoom to the passed string. The string must be composed of numeric
465
	 * characters only with the exception of a decimal point and a '%' as the
466
	 * last character. If the zoom level contribution list has been set, this
467
	 * method should be overridden to provide the appropriate zoom
468
	 * implementation for the new zoom levels.
469
	 * 
470
	 * @param zoomString
471
	 *            The new zoom level
472
	 */
473
	public void setZoomAsText(String zoomString) {
474
		currentZoomContant = null;
475
		if (zoomString.equalsIgnoreCase(FIT_HEIGHT)) {
476
			currentZoomContant = FIT_HEIGHT;
477
			primSetZoom(getFitHeightZoomLevel());
478
			viewport.getUpdateManager().performUpdate();
479
			viewport.setViewLocation(viewport.getHorizontalRangeModel().getValue(), viewport.getVerticalRangeModel().getMinimum());
480
		} else if (zoomString.equalsIgnoreCase(FIT_ALL)) {
481
			currentZoomContant = FIT_ALL;
482
			primSetZoom(getFitPageZoomLevel());
483
			viewport.getUpdateManager().performUpdate();
484
			viewport.setViewLocation(viewport.getHorizontalRangeModel().getMinimum(), viewport.getVerticalRangeModel().getMinimum());
485
		} else if (zoomString.equalsIgnoreCase(FIT_WIDTH)) {
486
			currentZoomContant = FIT_WIDTH;
487
			primSetZoom(getFitWidthZoomLevel());
488
			viewport.getUpdateManager().performUpdate();
489
			viewport.setViewLocation(viewport.getHorizontalRangeModel().getMinimum(), viewport.getVerticalRangeModel().getValue());
490
		} else {
491
			try {
492
				//Trim off the '%'
493
				if (zoomString.charAt(zoomString.length() - 1) == '%') {
494
					zoomString = zoomString.substring(0, zoomString.length() - 1);
495
				}
496
				double newZoom = Double.parseDouble(zoomString) / 100;
497
				setZoom(newZoom / multiplier);
498
			} catch (Exception e) {
499
				Display.getCurrent().beep();
500
			}
501
		}
502
	}
503
504
	/**
505
	 * Sets the list of zoom level contributions (as strings). If you contribute
506
	 * something <b>other than</b> {@link #FIT_HEIGHT}, {@link #FIT_WIDTH} and
507
	 * {@link #FIT_ALL} you must subclass this class and override this method to
508
	 * implement your contributed zoom function.
509
	 * 
510
	 * @param contributions
511
	 *            the list of contributed zoom levels
512
	 */
513
	public void setZoomLevelContributions(List contributions) {
514
		zoomLevelContributions = contributions;
515
	}
516
517
	/**
518
	 * Sets the zoomLevels.
519
	 * 
520
	 * @param zoomLevels
521
	 *            The zoomLevels to set
522
	 */
523
	public void setZoomLevels(double[] zoomLevels) {
524
		this.zoomLevels = zoomLevels;
525
	}
526
527
	/**
528
	 * Sets the zoom level to be one level higher
529
	 */
530
	public void zoomIn() {
531
		setZoom(getNextZoomLevel());
532
	}
533
534
	/**
535
	 * Currently does nothing.
536
	 * 
537
	 * @param rect
538
	 *            a rectangle
539
	 */
540
	public void zoomTo(Rectangle rect) {
541
	}
542
543
	//private void performAnimatedZoom(Rectangle rect, boolean zoomIn, int iterationCount) {
544
	//	double finalRatio;
545
	//	double zoomIncrement;
546
	//	
547
	//	if (zoomIn) {
548
	//		finalRatio = zoom / getNextZoomLevel();
549
	//		zoomIncrement = (getNextZoomLevel() - zoom) / iterationCount;
550
	//	} else {
551
	//		finalRatio = zoom / getPreviousZoomLevel();
552
	//		zoomIncrement = (getPreviousZoomLevel() - zoom) / iterationCount;
553
	//	}
554
	//	
555
	//	getScalableFigure().translateToRelative(rect);
556
	//	Point originalViewLocation = getViewport().getViewLocation();
557
	//	Point finalViewLocation = calculateViewLocation(rect, finalRatio);
558
	//	
559
	//	double xIncrement =
560
	//		(double) (finalViewLocation.x - originalViewLocation.x) / iterationCount;
561
	//	double yIncrement =
562
	//		(double) (finalViewLocation.y - originalViewLocation.y) / iterationCount;
563
	//	
564
	//	double originalZoom = zoom;
565
	//	Point currentViewLocation = new Point();
566
	//	for (int i = 1; i < iterationCount; i++) {
567
	//		currentViewLocation.x = (int)(originalViewLocation.x + (xIncrement * i));
568
	//		currentViewLocation.y = (int)(originalViewLocation.y + (yIncrement * i));
569
	//		setZoom(originalZoom + zoomIncrement * i);
570
	//		getViewport().validate();
571
	//		setViewLocation(currentViewLocation);
572
	//		getViewport().getUpdateManager().performUpdate();
573
	//	}
574
	//	
575
	//	if (zoomIn)
576
	//		setZoom(getNextZoomLevel());
577
	//	else
578
	//		setZoom(getPreviousZoomLevel());
579
	//	
580
	//	getViewport().validate();
581
	//	setViewLocation(finalViewLocation);	
582
	//}
583
	//
584
	//private Point calculateViewLocation(Rectangle zoomRect, double ratio) {
585
	//	Point viewLocation = new Point();
586
	//	viewLocation.x = (int)(zoomRect.x / ratio);
587
	//	viewLocation.y = (int)(zoomRect.y / ratio);
588
	//	return viewLocation;
589
	//}
590
591
	/**
592
	 * Sets the zoom level to be one level lower
593
	 */
594
	public void zoomOut() {
595
		setZoom(getPreviousZoomLevel());
596
	}
597
598
}
(-)src/org/eclipse/zest/core/viewers/internal/ZoomListener.java (-25 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.zest.core.viewers.internal;
12
13
/**
14
 * Listens to zoom level changes.
15
 * @author Eric Bordeau
16
 */
17
public interface ZoomListener {
18
19
/**
20
 * Called whenever the ZoomManager's zoom level changes.
21
 * @param zoom the new zoom level.
22
 */
23
void zoomChanged(double zoom);
24
25
}
(-)src/org/eclipse/zest/core/viewers/internal/SharedMessages.java (-4 / +4 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2003, 2005 IBM Corporation and others. All rights reserved.
2
 * Copyright (c) 2003, 2005-2009 IBM Corporation and others. All rights reserved.
3
 * This program and the accompanying materials are made available under the
3
 * This program and the accompanying materials are made available under the
4
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
4
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
5
 * and is available at http://www.eclipse.org/legal/epl-v10.html
5
 * and is available at http://www.eclipse.org/legal/epl-v10.html
Lines 19-32 Link Here
19
	/**
19
	/**
20
	 * The string "Page".
20
	 * The string "Page".
21
	 */
21
	 */
22
	public static String FitAllAction_Label = "Page"; //GEFMessages.FitAllAction_Label;
22
	public static String FitAllAction_Label = "Page"; // GEFMessages.FitAllAction_Label;
23
	/**
23
	/**
24
	 * The string "Width".
24
	 * The string "Width".
25
	 */
25
	 */
26
	public static String FitWidthAction_Label = "Width"; //GEFMessages.FitWidthAction_Label;
26
	public static String FitWidthAction_Label = "Width"; // GEFMessages.FitWidthAction_Label;
27
	/**
27
	/**
28
	 * The string "Height".
28
	 * The string "Height".
29
	 */
29
	 */
30
	public static String FitHeightAction_Label = "Height"; //GEFMessages.FitHeightAction_Label;
30
	public static String FitHeightAction_Label = "Height"; // GEFMessages.FitHeightAction_Label;
31
31
32
}
32
}
(-)src/org/eclipse/zest/core/viewers/internal/GraphModelFactory.java (-17 / +27 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials are made
3
 * All rights reserved. This program and the accompanying materials are made
4
 * available under the terms of the Eclipse Public License v1.0 which
4
 * available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
Lines 12-17 Link Here
12
import java.util.Iterator;
12
import java.util.Iterator;
13
import java.util.List;
13
import java.util.List;
14
14
15
import org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer;
15
import org.eclipse.zest.core.viewers.IFigureProvider;
16
import org.eclipse.zest.core.viewers.IFigureProvider;
16
import org.eclipse.zest.core.viewers.IGraphContentProvider;
17
import org.eclipse.zest.core.viewers.IGraphContentProvider;
17
import org.eclipse.zest.core.widgets.Graph;
18
import org.eclipse.zest.core.widgets.Graph;
Lines 46-57 Link Here
46
	/*
47
	/*
47
	 * (non-Javadoc)
48
	 * (non-Javadoc)
48
	 * 
49
	 * 
49
	 * @see org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory#doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel)
50
	 * @see
51
	 * org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory
52
	 * #doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel)
50
	 */
53
	 */
51
	protected void doBuildGraph(Graph model) {
54
	protected void doBuildGraph(Graph model) {
52
		super.doBuildGraph(model);
55
		super.doBuildGraph(model);
53
		// make the model have the same styles as the viewer
56
		// make the model have the same styles as the viewer
54
		Object rels[] = getContentProvider().getElements(getViewer().getInput());
57
		Object rels[] = getContentProvider()
58
				.getElements(getViewer().getInput());
55
		if (rels != null) {
59
		if (rels != null) {
56
			IFigureProvider figureProvider = null;
60
			IFigureProvider figureProvider = null;
57
			if (getLabelProvider() instanceof IFigureProvider) {
61
			if (getLabelProvider() instanceof IFigureProvider) {
Lines 63-79 Link Here
63
			for (int i = 0; i < rels.length; i++) {
67
			for (int i = 0; i < rels.length; i++) {
64
				// Check the filter on the source
68
				// Check the filter on the source
65
				Object source = getCastedContent().getSource(rels[i]);
69
				Object source = getCastedContent().getSource(rels[i]);
66
				source = filterElement(getViewer().getInput(), source) ? null : source;
70
				source = filterElement(getViewer().getInput(), source) ? null
71
						: source;
67
72
68
				// Check hte filter on the dest
73
				// Check hte filter on the dest
69
				Object dest = getCastedContent().getDestination(rels[i]);
74
				Object dest = getCastedContent().getDestination(rels[i]);
70
				dest = filterElement(getViewer().getInput(), dest) ? null : dest;
75
				dest = filterElement(getViewer().getInput(), dest) ? null
76
						: dest;
71
77
72
				if (source == null) {
78
				if (source == null) {
73
					// just create the node for the destination
79
					// just create the node for the destination
74
					if (dest != null) {
80
					if (dest != null) {
75
						if (figureProvider != null) {
81
						if (figureProvider != null) {
76
							createNode(model, dest, figureProvider.getFigure(dest));
82
							createNode(model, dest, figureProvider
83
									.getFigure(dest));
77
						} else {
84
						} else {
78
							createNode(model, dest);
85
							createNode(model, dest);
79
						}
86
						}
Lines 83-89 Link Here
83
					// just create the node for the source
90
					// just create the node for the source
84
					if (source != null) {
91
					if (source != null) {
85
						if (figureProvider != null) {
92
						if (figureProvider != null) {
86
							createNode(model, source, figureProvider.getFigure(dest));
93
							createNode(model, source, figureProvider
94
									.getFigure(dest));
87
						} else {
95
						} else {
88
							createNode(model, source);
96
							createNode(model, source);
89
						}
97
						}
Lines 92-99 Link Here
92
				}
100
				}
93
				// If any of the source, dest is null or the edge is filtered,
101
				// If any of the source, dest is null or the edge is filtered,
94
				// don't create the graph.
102
				// don't create the graph.
95
				if (source != null && dest != null && !filterElement(getViewer().getInput(), rels[i])) {
103
				if (source != null && dest != null
96
					createConnection(model, rels[i], getCastedContent().getSource(rels[i]), getCastedContent().getDestination(rels[i]));
104
						&& !filterElement(getViewer().getInput(), rels[i])) {
105
					createConnection(model, rels[i], getCastedContent()
106
							.getSource(rels[i]), getCastedContent()
107
							.getDestination(rels[i]));
97
				}
108
				}
98
			}
109
			}
99
		}
110
		}
Lines 107-114 Link Here
107
	/*
118
	/*
108
	 * (non-Javadoc)
119
	 * (non-Javadoc)
109
	 * 
120
	 * 
110
	 * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh(org.eclipse.zest.core.internal.graphmodel.GraphModel,
121
	 * @see
111
	 *      java.lang.Object)
122
	 * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh
123
	 * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object)
112
	 */
124
	 */
113
	public void refresh(Graph graph, Object element) {
125
	public void refresh(Graph graph, Object element) {
114
		refresh(graph, element, false);
126
		refresh(graph, element, false);
Lines 117-124 Link Here
117
	/*
129
	/*
118
	 * (non-Javadoc)
130
	 * (non-Javadoc)
119
	 * 
131
	 * 
120
	 * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh(org.eclipse.zest.core.internal.graphmodel.GraphModel,
132
	 * @see
121
	 *      java.lang.Object, boolean)
133
	 * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh
134
	 * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object,
135
	 * boolean)
122
	 */
136
	 */
123
	public void refresh(Graph graph, Object element, boolean updateLabels) {
137
	public void refresh(Graph graph, Object element, boolean updateLabels) {
124
		GraphConnection conn = viewer.getGraphModelConnection(element);
138
		GraphConnection conn = viewer.getGraphModelConnection(element);
Lines 157-166 Link Here
157
			} else if (updateLabels) {
171
			} else if (updateLabels) {
158
				styleItem(internalDest);
172
				styleItem(internalDest);
159
			}
173
			}
160
161
			// @tag TODO: Remove these lines
162
			// conn.disconnect();
163
			// conn.reconnect(internalSource, internalDest);
164
			if (updateLabels) {
174
			if (updateLabels) {
165
				styleItem(conn);
175
				styleItem(conn);
166
			}
176
			}
(-)src/org/eclipse/zest/core/viewers/internal/GraphModelEntityRelationshipFactory.java (-14 / +29 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC,
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
Lines 12-17 Link Here
12
import java.util.ArrayList;
12
import java.util.ArrayList;
13
import java.util.List;
13
import java.util.List;
14
14
15
import org.eclipse.zest.core.viewers.AbstractStructuredGraphViewer;
15
import org.eclipse.zest.core.viewers.IGraphEntityRelationshipContentProvider;
16
import org.eclipse.zest.core.viewers.IGraphEntityRelationshipContentProvider;
16
import org.eclipse.zest.core.widgets.Graph;
17
import org.eclipse.zest.core.widgets.Graph;
17
import org.eclipse.zest.core.widgets.GraphContainer;
18
import org.eclipse.zest.core.widgets.GraphContainer;
Lines 25-43 Link Here
25
// @tag bug.154580-Content.fix
26
// @tag bug.154580-Content.fix
26
// @tag bug.160367-Refreshing.fix : updated to use new
27
// @tag bug.160367-Refreshing.fix : updated to use new
27
// AbstractStylingModelFactory
28
// AbstractStylingModelFactory
28
public class GraphModelEntityRelationshipFactory extends AbstractStylingModelFactory {
29
public class GraphModelEntityRelationshipFactory extends
30
		AbstractStylingModelFactory {
29
31
30
	public GraphModelEntityRelationshipFactory(AbstractStructuredGraphViewer viewer) {
32
	public GraphModelEntityRelationshipFactory(
33
			AbstractStructuredGraphViewer viewer) {
31
		super(viewer);
34
		super(viewer);
32
		if (!(viewer.getContentProvider() instanceof IGraphEntityRelationshipContentProvider)) {
35
		if (!(viewer.getContentProvider() instanceof IGraphEntityRelationshipContentProvider)) {
33
			throw new IllegalArgumentException("Expected IGraphEntityRelationshipContentProvider");
36
			throw new IllegalArgumentException(
37
					"Expected IGraphEntityRelationshipContentProvider");
34
		}
38
		}
35
	}
39
	}
36
40
37
	/*
41
	/*
38
	 * (non-Javadoc)
42
	 * (non-Javadoc)
39
	 * 
43
	 * 
40
	 * @see org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory#createGraphModel()
44
	 * @see
45
	 * org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory
46
	 * #createGraphModel()
41
	 */
47
	 */
42
	public Graph createGraphModel(Graph model) {
48
	public Graph createGraphModel(Graph model) {
43
		doBuildGraph(model);
49
		doBuildGraph(model);
Lines 47-57 Link Here
47
	/*
53
	/*
48
	 * (non-Javadoc)
54
	 * (non-Javadoc)
49
	 * 
55
	 * 
50
	 * @see org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory#doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel)
56
	 * @see
57
	 * org.eclipse.zest.core.internal.graphmodel.AbstractStylingModelFactory
58
	 * #doBuildGraph(org.eclipse.zest.core.internal.graphmodel.GraphModel)
51
	 */
59
	 */
52
	protected void doBuildGraph(Graph model) {
60
	protected void doBuildGraph(Graph model) {
53
		super.doBuildGraph(model);
61
		super.doBuildGraph(model);
54
		Object[] nodes = getContentProvider().getElements(getViewer().getInput());
62
		Object[] nodes = getContentProvider().getElements(
63
				getViewer().getInput());
55
		nodes = filter(getViewer().getInput(), nodes);
64
		nodes = filter(getViewer().getInput(), nodes);
56
		createModelNodes(model, nodes);
65
		createModelNodes(model, nodes);
57
		createModelRelationships(model);
66
		createModelRelationships(model);
Lines 78-93 Link Here
78
				listOfNodes.addAll(childNodes);
87
				listOfNodes.addAll(childNodes);
79
			}
88
			}
80
		}
89
		}
81
		modelNodes = (GraphNode[]) listOfNodes.toArray(new GraphNode[listOfNodes.size()]);
90
		modelNodes = (GraphNode[]) listOfNodes
91
				.toArray(new GraphNode[listOfNodes.size()]);
82
92
83
		IGraphEntityRelationshipContentProvider content = getCastedContent();
93
		IGraphEntityRelationshipContentProvider content = getCastedContent();
84
		for (int i = 0; i < modelNodes.length; i++) {
94
		for (int i = 0; i < modelNodes.length; i++) {
85
			for (int j = 0; j < modelNodes.length; j++) {
95
			for (int j = 0; j < modelNodes.length; j++) {
86
				Object[] rels = content.getRelationships(modelNodes[i].getData(), modelNodes[j].getData());
96
				Object[] rels = content.getRelationships(modelNodes[i]
97
						.getData(), modelNodes[j].getData());
87
				if (rels != null) {
98
				if (rels != null) {
88
					rels = filter(getViewer().getInput(), rels);
99
					rels = filter(getViewer().getInput(), rels);
89
					for (int r = 0; r < rels.length; r++) {
100
					for (int r = 0; r < rels.length; r++) {
90
						createConnection(model, rels[r], modelNodes[i].getData(), modelNodes[j].getData());
101
						createConnection(model, rels[r], modelNodes[i]
102
								.getData(), modelNodes[j].getData());
91
					}
103
					}
92
				}
104
				}
93
			}
105
			}
Lines 111-118 Link Here
111
	/*
123
	/*
112
	 * (non-Javadoc)
124
	 * (non-Javadoc)
113
	 * 
125
	 * 
114
	 * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh(org.eclipse.zest.core.internal.graphmodel.GraphModel,
126
	 * @see
115
	 *      java.lang.Object)
127
	 * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh
128
	 * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object)
116
	 */
129
	 */
117
	public void refresh(Graph graph, Object element) {
130
	public void refresh(Graph graph, Object element) {
118
		refresh(graph, element, false);
131
		refresh(graph, element, false);
Lines 121-128 Link Here
121
	/*
134
	/*
122
	 * (non-Javadoc)
135
	 * (non-Javadoc)
123
	 * 
136
	 * 
124
	 * @see org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh(org.eclipse.zest.core.internal.graphmodel.GraphModel,
137
	 * @see
125
	 *      java.lang.Object, boolean)
138
	 * org.eclipse.zest.core.internal.graphmodel.IStylingGraphModelFactory#refresh
139
	 * (org.eclipse.zest.core.internal.graphmodel.GraphModel, java.lang.Object,
140
	 * boolean)
126
	 */
141
	 */
127
	public void refresh(Graph graph, Object element, boolean updateLabels) {
142
	public void refresh(Graph graph, Object element, boolean updateLabels) {
128
		// with this kind of graph, it is just as easy and cost-effective to
143
		// with this kind of graph, it is just as easy and cost-effective to
(-)src/org/eclipse/zest/core/viewers/internal/GraphItemStyler.java (-21 / +31 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC,
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
Lines 33-39 Link Here
33
 */
33
 */
34
// @tag bug(151327-Styles) : created to help resolve this bug
34
// @tag bug(151327-Styles) : created to help resolve this bug
35
public class GraphItemStyler {
35
public class GraphItemStyler {
36
	public static void styleItem(GraphItem item, final IBaseLabelProvider labelProvider) {
36
	public static void styleItem(GraphItem item,
37
			final IBaseLabelProvider labelProvider) {
37
38
38
		if (item instanceof GraphNode) {
39
		if (item instanceof GraphNode) {
39
			GraphNode node = (GraphNode) item;
40
			GraphNode node = (GraphNode) item;
Lines 57-68 Link Here
57
				node.setFont(fontProvider.getFont(entity));
58
				node.setFont(fontProvider.getFont(entity));
58
			}
59
			}
59
			if (labelProvider instanceof ILabelProvider) {
60
			if (labelProvider instanceof ILabelProvider) {
60
				String text = ((ILabelProvider) labelProvider).getText(node.getData());
61
				String text = ((ILabelProvider) labelProvider).getText(node
62
						.getData());
61
				node.setText((text != null) ? text : "");
63
				node.setText((text != null) ? text : "");
62
				node.setImage(((ILabelProvider) labelProvider).getImage(node.getData()));
64
				node.setImage(((ILabelProvider) labelProvider).getImage(node
65
						.getData()));
63
			}
66
			}
64
			if (labelProvider instanceof ISelfStyleProvider) {
67
			if (labelProvider instanceof ISelfStyleProvider) {
65
				((ISelfStyleProvider) labelProvider).selfStyleNode(entity, node);
68
				((ISelfStyleProvider) labelProvider)
69
						.selfStyleNode(entity, node);
66
			}
70
			}
67
		} else if (item instanceof GraphConnection) {
71
		} else if (item instanceof GraphConnection) {
68
			GraphConnection conn = (GraphConnection) item;
72
			GraphConnection conn = (GraphConnection) item;
Lines 75-93 Link Here
75
				conn.setConnectionStyle(SWT.NONE);
79
				conn.setConnectionStyle(SWT.NONE);
76
			}
80
			}
77
			if (labelProvider instanceof ILabelProvider) {
81
			if (labelProvider instanceof ILabelProvider) {
78
				String text = ((ILabelProvider) labelProvider).getText(conn.getExternalConnection());
82
				String text = ((ILabelProvider) labelProvider).getText(conn
83
						.getExternalConnection());
79
				conn.setText((text != null) ? text : "");
84
				conn.setText((text != null) ? text : "");
80
				conn.setImage(((ILabelProvider) labelProvider).getImage(conn.getExternalConnection()));
85
				conn.setImage(((ILabelProvider) labelProvider).getImage(conn
86
						.getExternalConnection()));
81
			}
87
			}
82
			if (labelProvider instanceof IEntityConnectionStyleProvider) {
88
			if (labelProvider instanceof IEntityConnectionStyleProvider) {
83
				styleEntityConnection(conn, (IEntityConnectionStyleProvider) labelProvider);
89
				styleEntityConnection(conn,
90
						(IEntityConnectionStyleProvider) labelProvider);
84
			} else if (labelProvider instanceof IConnectionStyleProvider) {
91
			} else if (labelProvider instanceof IConnectionStyleProvider) {
85
				styleConnection(conn, (IConnectionStyleProvider) labelProvider);
92
				styleConnection(conn, (IConnectionStyleProvider) labelProvider);
86
			}
93
			}
87
			int swt = getLineStyleForZestStyle(conn.getConnectionStyle());
94
			int swt = getLineStyleForZestStyle(conn.getConnectionStyle());
88
			conn.setLineStyle(swt);
95
			conn.setLineStyle(swt);
89
			if (labelProvider instanceof ISelfStyleProvider) {
96
			if (labelProvider instanceof ISelfStyleProvider) {
90
				((ISelfStyleProvider) labelProvider).selfStyleConnection(conn.getData(), conn);
97
				((ISelfStyleProvider) labelProvider).selfStyleConnection(conn
98
						.getData(), conn);
91
			}
99
			}
92
		}
100
		}
93
	}
101
	}
Lines 96-102 Link Here
96
	 * @param conn
104
	 * @param conn
97
	 * @param provider
105
	 * @param provider
98
	 */
106
	 */
99
	private static void styleConnection(GraphConnection conn, IConnectionStyleProvider provider) {
107
	private static void styleConnection(GraphConnection conn,
108
			IConnectionStyleProvider provider) {
100
		Object rel = conn.getExternalConnection();
109
		Object rel = conn.getExternalConnection();
101
		Color c;
110
		Color c;
102
		int style = provider.getConnectionStyle(rel);
111
		int style = provider.getConnectionStyle(rel);
Lines 147-153 Link Here
147
	 * @param conn
156
	 * @param conn
148
	 * @param provider
157
	 * @param provider
149
	 */
158
	 */
150
	private static void styleEntityConnection(GraphConnection conn, IEntityConnectionStyleProvider provider) {
159
	private static void styleEntityConnection(GraphConnection conn,
160
			IEntityConnectionStyleProvider provider) {
151
		Object src = conn.getSource().getData();
161
		Object src = conn.getSource().getData();
152
		Object dest = conn.getDestination().getData();
162
		Object dest = conn.getDestination().getData();
153
		Color c;
163
		Color c;
Lines 159-165 Link Here
159
			conn.setConnectionStyle(style);
169
			conn.setConnectionStyle(style);
160
		}
170
		}
161
		// @tag bug(152530-Bezier(fisx))
171
		// @tag bug(152530-Bezier(fisx))
162
		// @tag TODO curved connections bezier : add back the bezier connection stuff
172
		// @tag TODO curved connections bezier : add back the bezier connection
173
		// stuff
163
		// if (ZestStyles.checkStyle(conn.getConnectionStyle(),
174
		// if (ZestStyles.checkStyle(conn.getConnectionStyle(),
164
		// ZestStyles.CONNECTIONS_BEZIER)
175
		// ZestStyles.CONNECTIONS_BEZIER)
165
		// && provider instanceof IEntityConnectionStyleBezierExtension) {
176
		// && provider instanceof IEntityConnectionStyleBezierExtension) {
Lines 205-221 Link Here
205
	private static void styleNode(GraphNode node, IEntityStyleProvider provider) {
216
	private static void styleNode(GraphNode node, IEntityStyleProvider provider) {
206
		Object entity = node.getData();
217
		Object entity = node.getData();
207
		// @tag ADJACENT : Removed highlight adjacent
218
		// @tag ADJACENT : Removed highlight adjacent
208
		//node.setHighlightAdjacentNodes(provider.highlightAdjacentEntities(entity));
219
		// node.setHighlightAdjacentNodes(provider.highlightAdjacentEntities(entity));
209
220
210
		// @tag ADJACENT : Removed highlight adjacent
221
		// @tag ADJACENT : Removed highlight adjacent
211
		/*
222
		/*
212
		if (provider.highlightAdjacentEntities(entity)) {
223
		 * if (provider.highlightAdjacentEntities(entity)) { Color c =
213
			Color c = provider.getAdjacentEntityHighlightColor(entity);
224
		 * provider.getAdjacentEntityHighlightColor(entity); if (c != null) {
214
			if (c != null) {
225
		 * node.setHighlightAdjacentColor(c); } }
215
				node.setHighlightAdjacentColor(c);
226
		 */
216
			}
217
		}
218
		*/
219
		Color c;
227
		Color c;
220
		IFigure figure;
228
		IFigure figure;
221
		int width = -1;
229
		int width = -1;
Lines 251-257 Link Here
251
	 * 
259
	 * 
252
	 */
260
	 */
253
	public static int getLineStyleForZestStyle(int style) {
261
	public static int getLineStyleForZestStyle(int style) {
254
		int lineStyles = ZestStyles.CONNECTIONS_DASH_DOT | ZestStyles.CONNECTIONS_DASH | ZestStyles.CONNECTIONS_DOT | ZestStyles.CONNECTIONS_SOLID;
262
		int lineStyles = ZestStyles.CONNECTIONS_DASH_DOT
263
				| ZestStyles.CONNECTIONS_DASH | ZestStyles.CONNECTIONS_DOT
264
				| ZestStyles.CONNECTIONS_SOLID;
255
		style = style & lineStyles;
265
		style = style & lineStyles;
256
		if (style == 0) {
266
		if (style == 0) {
257
			style = ZestStyles.CONNECTIONS_SOLID;
267
			style = ZestStyles.CONNECTIONS_SOLID;
(-)src/org/eclipse/zest/core/widgets/Graph.java (-517 / +528 lines)
Lines 1-22 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * All rights reserved. This program and the accompanying materials are made
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
8
 * Contributors: The Chisel Group, University of Victoria 
9
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 ******************************************************************************/
10
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
package org.eclipse.zest.core.widgets;
11
12
12
import java.util.ArrayList;
13
import java.util.ArrayList;
13
import java.util.HashMap;
14
import java.util.HashMap;
15
import java.util.HashSet;
14
import java.util.Iterator;
16
import java.util.Iterator;
15
import java.util.LinkedList;
16
import java.util.List;
17
import java.util.List;
17
18
18
import org.eclipse.draw2d.Animation;
19
import org.eclipse.draw2d.Animation;
19
import org.eclipse.draw2d.ColorConstants;
20
import org.eclipse.draw2d.ColorConstants;
21
import org.eclipse.draw2d.CoordinateListener;
20
import org.eclipse.draw2d.FigureCanvas;
22
import org.eclipse.draw2d.FigureCanvas;
21
import org.eclipse.draw2d.FreeformLayer;
23
import org.eclipse.draw2d.FreeformLayer;
22
import org.eclipse.draw2d.FreeformLayout;
24
import org.eclipse.draw2d.FreeformLayout;
Lines 34-39 Link Here
34
import org.eclipse.draw2d.geometry.Point;
36
import org.eclipse.draw2d.geometry.Point;
35
import org.eclipse.draw2d.geometry.Rectangle;
37
import org.eclipse.draw2d.geometry.Rectangle;
36
import org.eclipse.swt.SWT;
38
import org.eclipse.swt.SWT;
39
import org.eclipse.swt.events.ControlEvent;
40
import org.eclipse.swt.events.ControlListener;
37
import org.eclipse.swt.events.PaintEvent;
41
import org.eclipse.swt.events.PaintEvent;
38
import org.eclipse.swt.events.PaintListener;
42
import org.eclipse.swt.events.PaintListener;
39
import org.eclipse.swt.events.SelectionAdapter;
43
import org.eclipse.swt.events.SelectionAdapter;
Lines 41-67 Link Here
41
import org.eclipse.swt.events.SelectionListener;
45
import org.eclipse.swt.events.SelectionListener;
42
import org.eclipse.swt.graphics.Color;
46
import org.eclipse.swt.graphics.Color;
43
import org.eclipse.swt.widgets.Composite;
47
import org.eclipse.swt.widgets.Composite;
44
import org.eclipse.swt.widgets.Control;
45
import org.eclipse.swt.widgets.Display;
48
import org.eclipse.swt.widgets.Display;
46
import org.eclipse.swt.widgets.Event;
49
import org.eclipse.swt.widgets.Event;
47
import org.eclipse.swt.widgets.Item;
50
import org.eclipse.swt.widgets.Item;
51
import org.eclipse.swt.widgets.Widget;
48
import org.eclipse.zest.core.widgets.internal.ContainerFigure;
52
import org.eclipse.zest.core.widgets.internal.ContainerFigure;
49
import org.eclipse.zest.core.widgets.internal.RevealListener;
50
import org.eclipse.zest.core.widgets.internal.ZestRootLayer;
53
import org.eclipse.zest.core.widgets.internal.ZestRootLayer;
51
import org.eclipse.zest.layouts.InvalidLayoutConfiguration;
52
import org.eclipse.zest.layouts.LayoutAlgorithm;
54
import org.eclipse.zest.layouts.LayoutAlgorithm;
53
import org.eclipse.zest.layouts.LayoutEntity;
55
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
54
import org.eclipse.zest.layouts.LayoutRelationship;
56
import org.eclipse.zest.layouts.interfaces.ExpandCollapseManager;
55
import org.eclipse.zest.layouts.LayoutStyles;
56
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
57
import org.eclipse.zest.layouts.constraints.LayoutConstraint;
58
57
59
/*
58
/**
60
 * Holds the nodes and connections for the graph.
59
 * @since 1.0
61
 * 
62
 * @author Chris Callendar
63
 * 
64
 * @author Ian Bull
65
 */
60
 */
66
public class Graph extends FigureCanvas implements IContainer {
61
public class Graph extends FigureCanvas implements IContainer {
67
62
Lines 85-107 Link Here
85
	 * These are all the children of this graph. These lists contains all nodes
80
	 * These are all the children of this graph. These lists contains all nodes
86
	 * and connections that have added themselves to this graph.
81
	 * and connections that have added themselves to this graph.
87
	 */
82
	 */
88
	private final List nodes;
83
	private List nodes;
89
	protected List connections;
84
	protected List connections;
85
	HashSet subgraphFigures;
90
	private List selectedItems = null;
86
	private List selectedItems = null;
91
	IFigure fisheyedFigure = null;
87
	private ArrayList fisheyeListeners = new ArrayList();
92
	private List /* SelectionListener */selectionListeners = null;
88
	private List selectionListeners = null;
93
89
94
	/** This maps all visible nodes to their model element. */
90
	/** This maps all visible nodes to their model element. */
95
	private HashMap figure2ItemMap = null;
91
	private HashMap figure2ItemMap = null;
96
92
97
	/** Maps user nodes to internal nodes */
98
	private int connectionStyle;
93
	private int connectionStyle;
99
	private int nodeStyle;
94
	private int nodeStyle;
100
	private List constraintAdapters;
101
	private List revealListeners = null;
102
103
	private ScalableFreeformLayeredPane fishEyeLayer = null;
95
	private ScalableFreeformLayeredPane fishEyeLayer = null;
104
	LayoutAlgorithm layoutAlgorithm = null;
96
	private InternalLayoutContext layoutContext = null;
97
	private volatile boolean shouldSheduleLayout;
98
	private volatile Runnable scheduledLayoutRunnable = null;
99
	private volatile boolean scheduledLayoutClean = false;
105
	private Dimension preferredSize = null;
100
	private Dimension preferredSize = null;
106
	int style = 0;
101
	int style = 0;
107
102
Lines 120-131 Link Here
120
		this.style = style;
115
		this.style = style;
121
		this.setBackground(ColorConstants.white);
116
		this.setBackground(ColorConstants.white);
122
117
123
		LIGHT_BLUE = new Color(Display.getDefault(), 216, 228, 248);
124
		LIGHT_BLUE_CYAN = new Color(Display.getDefault(), 213, 243, 255);
125
		GREY_BLUE = new Color(Display.getDefault(), 139, 150, 171);
126
		DARK_BLUE = new Color(Display.getDefault(), 1, 70, 122);
127
		LIGHT_YELLOW = new Color(Display.getDefault(), 255, 255, 206);
128
129
		this.setViewport(new FreeformViewport());
118
		this.setViewport(new FreeformViewport());
130
119
131
		this.getVerticalBar().addSelectionListener(new SelectionAdapter() {
120
		this.getVerticalBar().addSelectionListener(new SelectionAdapter() {
Lines 142-208 Link Here
142
131
143
		// @tag CGraph.workaround : this allows me to handle mouse events
132
		// @tag CGraph.workaround : this allows me to handle mouse events
144
		// outside of the canvas
133
		// outside of the canvas
145
		this.getLightweightSystem().setEventDispatcher(new SWTEventDispatcher() {
134
		this.getLightweightSystem().setEventDispatcher(
146
			public void dispatchMouseMoved(org.eclipse.swt.events.MouseEvent me) {
135
				new SWTEventDispatcher() {
147
				super.dispatchMouseMoved(me);
136
					public void dispatchMouseMoved(
148
137
							org.eclipse.swt.events.MouseEvent me) {
149
				// If the current event is null, return
138
						super.dispatchMouseMoved(me);
150
				if (getCurrentEvent() == null) {
139
151
					return;
140
						// If the current event is null, return
152
				}
141
						if (getCurrentEvent() == null) {
142
							return;
143
						}
153
144
154
				if (getMouseTarget() == null) {
145
						if (getMouseTarget() == null) {
155
					setMouseTarget(getRoot());
146
							setMouseTarget(getRoot());
156
				}
147
						}
157
				if ((me.stateMask & SWT.BUTTON_MASK) != 0) {
148
						if ((me.stateMask & SWT.BUTTON_MASK) != 0) {
158
					// Sometimes getCurrentEvent() returns null
149
							// Sometimes getCurrentEvent() returns null
159
					getMouseTarget().handleMouseDragged(getCurrentEvent());
150
							getMouseTarget().handleMouseDragged(
160
				} else {
151
									getCurrentEvent());
161
					getMouseTarget().handleMouseMoved(getCurrentEvent());
152
						} else {
162
				}
153
							getMouseTarget()
163
			}
154
									.handleMouseMoved(getCurrentEvent());
164
		});
155
						}
156
					}
157
				});
165
158
166
		this.setContents(createLayers());
159
		this.setContents(createLayers());
167
		DragSupport dragSupport = new DragSupport(this);
160
		DragSupport dragSupport = new DragSupport();
168
		this.getLightweightSystem().getRootFigure().addMouseListener(dragSupport);
161
		this.getLightweightSystem().getRootFigure().addMouseListener(
169
		this.getLightweightSystem().getRootFigure().addMouseMotionListener(dragSupport);
162
				dragSupport);
163
		this.getLightweightSystem().getRootFigure().addMouseMotionListener(
164
				dragSupport);
170
165
171
		this.nodes = new ArrayList();
166
		this.nodes = new ArrayList();
172
		this.preferredSize = new Dimension(-1, -1);
167
		this.preferredSize = new Dimension(-1, -1);
173
		this.connectionStyle = ZestStyles.NONE;
168
		this.connectionStyle = ZestStyles.NONE;
174
		this.nodeStyle = ZestStyles.NONE;
169
		this.nodeStyle = ZestStyles.NONE;
175
		this.connections = new ArrayList();
170
		this.connections = new ArrayList();
176
		this.constraintAdapters = new ArrayList();
171
		this.subgraphFigures = new HashSet();
177
		this.selectedItems = new ArrayList();
172
		this.selectedItems = new ArrayList();
178
		this.selectionListeners = new ArrayList();
173
		this.selectionListeners = new ArrayList();
179
		this.figure2ItemMap = new HashMap();
174
		this.figure2ItemMap = new HashMap();
180
175
181
		revealListeners = new ArrayList(1);
182
		this.addPaintListener(new PaintListener() {
176
		this.addPaintListener(new PaintListener() {
183
			public void paintControl(PaintEvent e) {
177
			public void paintControl(PaintEvent e) {
184
				if (!revealListeners.isEmpty()) {
178
				if (shouldSheduleLayout) {
185
					// Go through the reveal list and let everyone know that the
179
					applyLayoutInternal(true);
186
					// view is now available. Remove the listeners so they are
180
					shouldSheduleLayout = false;
187
					// only
188
					// called once!
189
					Iterator iterator = revealListeners.iterator();
190
					while (iterator.hasNext()) {
191
						RevealListener reveallisetner = (RevealListener) iterator.next();
192
						reveallisetner.revealed(Graph.this);
193
						iterator.remove();
194
					}
195
				}
196
				/*
197
				Iterator iterator = getNodes().iterator();
198
				while (iterator.hasNext()) {
199
					GraphNode node = (GraphNode) iterator.next();
200
					node.paint();
201
				}
181
				}
202
				*/
203
			}
182
			}
204
		});
183
		});
205
184
185
		this.addControlListener(new ControlListener() {
186
187
			public void controlResized(ControlEvent e) {
188
				if (preferredSize.width == -1 || preferredSize.height == -1) {
189
					getLayoutContext().fireBoundsChangedEvent();
190
				}
191
			}
192
193
			public void controlMoved(ControlEvent e) {
194
				// do nothing
195
			}
196
		});
206
	}
197
	}
207
198
208
	/**
199
	/**
Lines 235-257 Link Here
235
	}
226
	}
236
227
237
	/**
228
	/**
238
	 * Adds a new constraint adapter to the list of constraint adapters 
239
	 * @param constraintAdapter
240
	 */
241
	public void addConstraintAdapter(ConstraintAdapter constraintAdapter) {
242
		this.constraintAdapters.add(constraintAdapter);
243
	}
244
245
	/**
246
	 * Sets the constraint adapters on this model
247
	 * 
248
	 * @param constraintAdapters
249
	 */
250
	public void setConstraintAdapters(List /* ConstraintAdapters */constraintAdapters) {
251
		this.constraintAdapters = constraintAdapters;
252
	}
253
254
	/**
255
	 * Gets the root layer for this graph
229
	 * Gets the root layer for this graph
256
	 * 
230
	 * 
257
	 * @return
231
	 * @return
Lines 326-331 Link Here
326
				}
300
				}
327
			}
301
			}
328
		}
302
		}
303
		// TODO shouldn't this method fire a selection event?
329
	}
304
	}
330
305
331
	public void selectAll() {
306
	public void selectAll() {
Lines 334-339 Link Here
334
			selectedItems.add(nodes.get(i));
309
			selectedItems.add(nodes.get(i));
335
			((GraphNode) nodes.get(i)).highlight();
310
			((GraphNode) nodes.get(i)).highlight();
336
		}
311
		}
312
		// TODO shouldn't this method fire a selection event?
337
	}
313
	}
338
314
339
	/**
315
	/**
Lines 351-366 Link Here
351
	 * @see org.eclipse.swt.widgets.Widget#toString()
327
	 * @see org.eclipse.swt.widgets.Widget#toString()
352
	 */
328
	 */
353
	public String toString() {
329
	public String toString() {
354
		return "GraphModel {" + nodes.size() + " nodes, " + connections.size() + " connections}";
330
		return "GraphModel {" + nodes.size() + " nodes, " + connections.size()
355
	}
331
				+ " connections}";
356
357
	/*
358
	 * (non-Javadoc)
359
	 * 
360
	 * @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphItem#getGraphModel()
361
	 */
362
	public Graph getGraphModel() {
363
		return this;
364
	}
332
	}
365
333
366
	/**
334
	/**
Lines 389-409 Link Here
389
	}
357
	}
390
358
391
	/**
359
	/**
392
	 * Runs the layout on this graph. It uses the reveal listner to run the
360
	 * Runs the layout on this graph. If the view is not visible layout will be
393
	 * layout only if the view is visible. Otherwise it will be deferred until
361
	 * deferred until after the view is available.
394
	 * after the view is available.
395
	 */
362
	 */
396
	public void applyLayout() {
363
	public void applyLayout() {
397
		this.addRevealListener(new RevealListener() {
364
		scheduleLayoutOnReveal(true);
398
			public void revealed(Control c) {
365
	}
399
				Display.getDefault().asyncExec(new Runnable() {
400
366
401
					public void run() {
367
	/**
402
						applyLayoutInternal();
368
	 * Enables or disables dynamic layout (that is layout algorithm performing
403
					}
369
	 * layout in background or when certain events occur). Dynamic layout should
404
				});
370
	 * be disabled before doing a long series of changes in the graph to make
371
	 * sure that layout algorithm won't interfere with these changes.
372
	 * 
373
	 * Enabling dynamic layout causes the layout algorithm to be applied even if
374
	 * it's not actually a dynamic algorithm.
375
	 * 
376
	 * @param enabled
377
	 * 
378
	 * @since 2.0
379
	 */
380
	public void setDynamicLayout(boolean enabled) {
381
		if (getLayoutContext().isBackgroundLayoutEnabled() != enabled) {
382
			layoutContext.setBackgroundLayoutEnabled(enabled);
383
			if (enabled) {
384
				scheduleLayoutOnReveal(false);
405
			}
385
			}
406
		});
386
		}
387
	}
388
389
	/**
390
	 * 
391
	 * @return true if dynamic layout is enabled (see
392
	 *         {@link #setDynamicLayout(boolean)})
393
	 * @since 2.0
394
	 */
395
	public boolean isDynamicLayoutEnabled() {
396
		return getLayoutContext().isBackgroundLayoutEnabled();
397
	}
398
399
	private void applyLayoutInternal(boolean clean) {
400
		if (getLayoutContext().getLayoutAlgorithm() == null) {
401
			return;
402
		}
403
		scheduledLayoutClean = scheduledLayoutClean || clean;
404
		synchronized (this) {
405
			if (scheduledLayoutRunnable == null) {
406
				Display.getDefault().asyncExec(
407
						scheduledLayoutRunnable = new Runnable() {
408
							public void run() {
409
								Animation.markBegin();
410
								getLayoutContext().applyLayout(
411
										scheduledLayoutClean);
412
								layoutContext.flushChanges(false);
413
								Animation.run(ANIMATION_TIME);
414
								getLightweightSystem().getUpdateManager()
415
										.performUpdate();
416
								synchronized (Graph.this) {
417
									scheduledLayoutRunnable = null;
418
									scheduledLayoutClean = false;
419
								}
420
							}
421
						});
422
			}
423
		}
407
	}
424
	}
408
425
409
	/**
426
	/**
Lines 415-434 Link Here
415
	 */
432
	 */
416
	public void setPreferredSize(int width, int height) {
433
	public void setPreferredSize(int width, int height) {
417
		this.preferredSize = new Dimension(width, height);
434
		this.preferredSize = new Dimension(width, height);
435
		getLayoutContext().fireBoundsChangedEvent();
436
	}
437
438
	/**
439
	 * @return the preferred size of the layout area.
440
	 * @since 2.0
441
	 */
442
	public Dimension getPreferredSize() {
443
		if (preferredSize.width < 0 || preferredSize.height < 0) {
444
			org.eclipse.swt.graphics.Point size = getSize();
445
			double scale = getRootLayer().getScale();
446
			return new Dimension((int) (size.x / scale + 0.5), (int) (size.y
447
					/ scale + 0.5));
448
		}
449
		return preferredSize;
450
	}
451
452
	/**
453
	 * @noreference This method is not intended to be referenced by clients.
454
	 */
455
	public InternalLayoutContext getLayoutContext() {
456
		if (layoutContext == null) {
457
			layoutContext = new InternalLayoutContext(this);
458
		}
459
		return layoutContext;
418
	}
460
	}
419
461
420
	/**
462
	/**
421
	 * @param algorithm
463
	 * @param algorithm
464
	 * @since 2.0
422
	 */
465
	 */
423
	public void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean applyLayout) {
466
	public void setLayoutAlgorithm(LayoutAlgorithm algorithm,
424
		this.layoutAlgorithm = algorithm;
467
			boolean applyLayout) {
468
		getLayoutContext().setLayoutAlgorithm(algorithm);
425
		if (applyLayout) {
469
		if (applyLayout) {
426
			applyLayout();
470
			applyLayout();
427
		}
471
		}
428
	}
472
	}
429
473
474
	/**
475
	 * @since 2.0
476
	 */
430
	public LayoutAlgorithm getLayoutAlgorithm() {
477
	public LayoutAlgorithm getLayoutAlgorithm() {
431
		return this.layoutAlgorithm;
478
		return getLayoutContext().getLayoutAlgorithm();
479
	}
480
481
	/**
482
	 * @since 2.0
483
	 */
484
	public void setSubgraphFactory(SubgraphFactory factory) {
485
		getLayoutContext().setSubgraphFactory(factory);
486
	}
487
488
	/**
489
	 * @since 2.0
490
	 */
491
	public SubgraphFactory getSubgraphFactory() {
492
		return getLayoutContext().getSubgraphFactory();
493
	}
494
495
	/**
496
	 * @since 2.0
497
	 */
498
	public void setExpandCollapseManager(
499
			ExpandCollapseManager expandCollapseManager) {
500
		getLayoutContext().setExpandCollapseManager(expandCollapseManager);
501
	}
502
503
	/**
504
	 * @since 2.0
505
	 */
506
	public ExpandCollapseManager getExpandCollapseManager() {
507
		return getLayoutContext().getExpandCollapseManager();
508
	}
509
510
	/**
511
	 * Adds a filter used for hiding elements from layout algorithm.
512
	 * 
513
	 * NOTE: If a node or subgraph if filtered out, all connections adjacent to
514
	 * it should also be filtered out. Otherwise layout algorithm may behave in
515
	 * an unexpected way.
516
	 * 
517
	 * @param filter
518
	 *            filter to add
519
	 * @since 2.0
520
	 */
521
	public void addLayoutFilter(LayoutFilter filter) {
522
		getLayoutContext().addFilter(filter);
523
	}
524
525
	/**
526
	 * Removes given layout filter. If it had not been added to this graph, this
527
	 * method does nothing.
528
	 * 
529
	 * @param filter
530
	 *            filter to remove
531
	 * @since 2.0
532
	 */
533
	public void removeLayoutFilter(LayoutFilter filter) {
534
		getLayoutContext().removeFilter(filter);
432
	}
535
	}
433
536
434
	/**
537
	/**
Lines 437-548 Link Here
437
	 * This point should be translated to relative before calling findFigureAt
540
	 * This point should be translated to relative before calling findFigureAt
438
	 */
541
	 */
439
	public IFigure getFigureAt(int x, int y) {
542
	public IFigure getFigureAt(int x, int y) {
440
		IFigure figureUnderMouse = this.getContents().findFigureAt(x, y, new TreeSearch() {
543
		IFigure figureUnderMouse = this.getContents().findFigureAt(x, y,
544
				new TreeSearch() {
441
545
442
			public boolean accept(IFigure figure) {
546
					public boolean accept(IFigure figure) {
443
				return true;
547
						return true;
444
			}
548
					}
445
446
			public boolean prune(IFigure figure) {
447
				IFigure parent = figure.getParent();
448
				// @tag TODO Zest : change these to from getParent to their actual layer names
449
549
450
				if (parent == fishEyeLayer) {
550
					public boolean prune(IFigure figure) {
451
					// If it node is on the fish eye layer, don't worry about it.
551
						IFigure parent = figure.getParent();
452
					return true;
552
						// @tag TODO Zest : change these to from getParent to
453
				}
553
						// their
454
				if (parent instanceof ContainerFigure && figure instanceof PolylineConnection) {
554
						// actual layer names
455
					return false;
555
456
				}
556
						if (parent == fishEyeLayer) {
457
				if (parent == zestRootLayer || parent == zestRootLayer.getParent() || parent == zestRootLayer.getParent().getParent()) {
557
							// If it node is on the fish eye layer, don't worry
458
					return false;
558
							// about
459
				}
559
							// it.
460
				GraphItem item = (GraphItem) figure2ItemMap.get(figure);
560
							return true;
461
				if (item != null && item.getItemType() == GraphItem.CONTAINER) {
561
						}
462
					return false;
562
						if (parent instanceof ContainerFigure
463
				} else if (figure instanceof FreeformLayer || parent instanceof FreeformLayer || figure instanceof ScrollPane || parent instanceof ScrollPane || parent instanceof ScalableFreeformLayeredPane || figure instanceof ScalableFreeformLayeredPane || figure instanceof FreeformViewport ||
563
								&& figure instanceof PolylineConnection) {
464
						parent instanceof FreeformViewport) {
564
							return false;
465
					return false;
565
						}
466
				}
566
						if (parent == zestRootLayer
467
				return true;
567
								|| parent == zestRootLayer.getParent()
468
			}
568
								|| parent == zestRootLayer.getParent()
569
										.getParent()) {
570
							return false;
571
						}
572
						GraphItem item = (GraphItem) figure2ItemMap.get(figure);
573
						if (item != null
574
								&& item.getItemType() == GraphItem.CONTAINER) {
575
							return false;
576
						} else if (figure instanceof FreeformLayer
577
								|| parent instanceof FreeformLayer
578
								|| figure instanceof ScrollPane
579
								|| parent instanceof ScrollPane
580
								|| parent instanceof ScalableFreeformLayeredPane
581
								|| figure instanceof ScalableFreeformLayeredPane
582
								|| figure instanceof FreeformViewport
583
								|| parent instanceof FreeformViewport) {
584
							return false;
585
						}
586
						return true;
587
					}
469
588
470
		});
589
				});
471
		return figureUnderMouse;
590
		return figureUnderMouse;
472
591
473
	}
592
	}
474
593
475
	// /////////////////////////////////////////////////////////////////////////////////
594
	private class DragSupport implements MouseMotionListener,
476
	// PRIVATE METHODS. These are NON API
595
			org.eclipse.draw2d.MouseListener {
477
	// /////////////////////////////////////////////////////////////////////////////////
596
478
	class DragSupport implements MouseMotionListener, org.eclipse.draw2d.MouseListener {
597
		Point dragStartLocation = null;
479
		/**
598
		IFigure draggedSubgraphFigure = null;
480
		 * 
599
		/** locations of dragged items relative to cursor position */
481
		 */
600
		ArrayList relativeLocations = new ArrayList();
482
		Graph graph = null;
483
		Point lastLocation = null;
484
		GraphItem fisheyedItem = null;
601
		GraphItem fisheyedItem = null;
485
		boolean isDragging = false;
602
		boolean isDragging = false;
486
603
487
		DragSupport(Graph graph) {
488
			this.graph = graph;
489
		}
490
491
		public void mouseDragged(org.eclipse.draw2d.MouseEvent me) {
604
		public void mouseDragged(org.eclipse.draw2d.MouseEvent me) {
492
			if (!isDragging) {
605
			if (!isDragging) {
493
				return;
606
				return;
494
			}
607
			}
495
			Point mousePoint = new Point(me.x, me.y);
608
			if (selectedItems.isEmpty()) {
496
			Point tempPoint = mousePoint.getCopy();
609
				IFigure figureUnderMouse = getFigureAt(dragStartLocation.x,
497
			if (selectedItems.size() > 0) {
610
						dragStartLocation.y);
498
				Iterator iterator = selectedItems.iterator();
611
				if (subgraphFigures.contains(figureUnderMouse)) {
499
				while (iterator.hasNext()) {
612
					draggedSubgraphFigure = figureUnderMouse;
500
					GraphItem item = (GraphItem) iterator.next();
613
				}
501
					if ((item.getItemType() == GraphItem.NODE) || (item.getItemType() == GraphItem.CONTAINER)) {
614
			}
502
						// @tag Zest.selection Zest.move : This is where the node movement is tracked
503
						Point pointCopy = mousePoint.getCopy();
504
615
505
						Point tempLastLocation = lastLocation.getCopy();
616
			Point mousePoint = new Point(me.x, me.y);
506
						item.getFigure().getParent().translateToRelative(tempLastLocation);
617
			if (!selectedItems.isEmpty() || draggedSubgraphFigure != null) {
507
						item.getFigure().getParent().translateFromParent(tempLastLocation);
508
509
						item.getFigure().getParent().translateToRelative(pointCopy);
510
						item.getFigure().getParent().translateFromParent(pointCopy);
511
						Point delta = new Point(pointCopy.x - tempLastLocation.x, pointCopy.y - tempLastLocation.y);
512
						if (item.getItemType() == GraphItem.NODE || item.getItemType() == GraphItem.CONTAINER) {
513
							GraphNode node = (GraphNode) item;
514
							node.setLocation(node.getLocation().x + delta.x, node.getLocation().y + delta.y);
515
618
619
				if (relativeLocations.isEmpty()) {
620
					for (Iterator iterator = selectedItems.iterator(); iterator
621
							.hasNext();) {
622
						GraphItem item = (GraphItem) iterator.next();
623
						if ((item.getItemType() == GraphItem.NODE)
624
								|| (item.getItemType() == GraphItem.CONTAINER)) {
625
							relativeLocations.add(getRelativeLocation(item
626
									.getFigure()));
516
						}
627
						}
517
						/*
628
					}
518
						else if (item.getItemType() == GraphItem.CONTAINER) {
629
					if (draggedSubgraphFigure != null) {
519
							GraphContainer container = (GraphContainer) item;
630
						relativeLocations
520
							container.setLocation(container.getLocation().x + delta.x, container.getLocation().y + delta.y);
631
								.add(getRelativeLocation(draggedSubgraphFigure));
521
						}
632
					}
522
						*/
633
				}
634
635
				Iterator locationsIterator = relativeLocations.iterator();
636
				for (Iterator selectionIterator = selectedItems.iterator(); selectionIterator
637
						.hasNext();) {
638
					GraphItem item = (GraphItem) selectionIterator.next();
639
					if ((item.getItemType() == GraphItem.NODE)
640
							|| (item.getItemType() == GraphItem.CONTAINER)) {
641
						Point pointCopy = mousePoint.getCopy();
642
						Point relativeLocation = (Point) locationsIterator
643
								.next();
644
645
						item.getFigure().getParent().translateToRelative(
646
								pointCopy);
647
						item.getFigure().getParent().translateFromParent(
648
								pointCopy);
649
650
						((GraphNode) item)
651
								.setLocation(relativeLocation.x + pointCopy.x,
652
										relativeLocation.y + pointCopy.y);
523
					} else {
653
					} else {
524
						// There is no movement for connection
654
						// There is no movement for connection
525
					}
655
					}
526
				}
656
				}
527
				if (fisheyedFigure != null) {
657
				if (draggedSubgraphFigure != null) {
528
					Point pointCopy = mousePoint.getCopy();
658
					Point pointCopy = mousePoint.getCopy();
529
659
					draggedSubgraphFigure.getParent().translateToRelative(
530
					Point tempLastLocation = lastLocation.getCopy();
660
							pointCopy);
531
					fisheyedFigure.translateToRelative(tempLastLocation);
661
					draggedSubgraphFigure.getParent().translateFromParent(
532
					fisheyedFigure.translateFromParent(tempLastLocation);
662
							pointCopy);
533
663
					Point relativeLocation = (Point) locationsIterator.next();
534
					fisheyedFigure.translateToRelative(pointCopy);
664
					pointCopy.x += relativeLocation.x;
535
					fisheyedFigure.translateFromParent(pointCopy);
665
					pointCopy.y += relativeLocation.y;
536
					Point delta = new Point(pointCopy.x - tempLastLocation.x, pointCopy.y - tempLastLocation.y);
666
537
					Point point = new Point(fisheyedFigure.getBounds().x + delta.x, fisheyedFigure.getBounds().y + delta.y);
667
					draggedSubgraphFigure.setLocation(pointCopy);
538
					fishEyeLayer.setConstraint(fisheyedFigure, new Rectangle(point, fisheyedFigure.getSize()));
539
					fishEyeLayer.getUpdateManager().performUpdate();
540
					//fisheyedFigure.setBounds(new Rectangle(point2, fisheyedFigure.getSize()));
541
					//fisheyedFigure.setLocation(new Point(fisheyedFigure.getBounds().x + delta.x, fisheyedFigure.getBounds().y + delta.y));
542
				}
668
				}
543
			}
669
			}
544
			lastLocation = tempPoint;
670
		}
545
			//oldLocation = mousePoint;
671
672
		private Point getRelativeLocation(IFigure figure) {
673
			Point location = figure.getBounds().getTopLeft();
674
			Point mousePointCopy = dragStartLocation.getCopy();
675
			figure.getParent().translateToRelative(mousePointCopy);
676
			figure.getParent().translateFromParent(mousePointCopy);
677
			location.x -= mousePointCopy.x;
678
			location.y -= mousePointCopy.y;
679
			return location;
546
		}
680
		}
547
681
548
		public void mouseEntered(org.eclipse.draw2d.MouseEvent me) {
682
		public void mouseEntered(org.eclipse.draw2d.MouseEvent me) {
Lines 559-565 Link Here
559
693
560
		/**
694
		/**
561
		 * This tracks whenever a mouse moves. The only thing we care about is
695
		 * This tracks whenever a mouse moves. The only thing we care about is
562
		 * fisheye(ing) nodes.  This means whenever the mouse moves we check if
696
		 * fisheye(ing) nodes. This means whenever the mouse moves we check if
563
		 * we need to fisheye on a node or not.
697
		 * we need to fisheye on a node or not.
564
		 */
698
		 */
565
		public void mouseMoved(org.eclipse.draw2d.MouseEvent me) {
699
		public void mouseMoved(org.eclipse.draw2d.MouseEvent me) {
Lines 569-595 Link Here
569
703
570
			if (figureUnderMouse != null) {
704
			if (figureUnderMouse != null) {
571
				// There is a figure under this mouse
705
				// There is a figure under this mouse
572
				GraphItem itemUnderMouse = (GraphItem) figure2ItemMap.get(figureUnderMouse);
706
				GraphItem itemUnderMouse = (GraphItem) figure2ItemMap
707
						.get(figureUnderMouse);
573
				if (itemUnderMouse == fisheyedItem) {
708
				if (itemUnderMouse == fisheyedItem) {
574
709
					return;
575
				} else if (itemUnderMouse != null && itemUnderMouse.getItemType() == GraphItem.NODE) {
710
				}
711
				if (fisheyedItem != null) {
712
					((GraphNode) fisheyedItem).fishEye(false, true);
713
					fisheyedItem = null;
714
				}
715
				if (itemUnderMouse != null
716
						&& itemUnderMouse.getItemType() == GraphItem.NODE) {
576
					fisheyedItem = itemUnderMouse;
717
					fisheyedItem = itemUnderMouse;
577
					fisheyedFigure = ((GraphNode) itemUnderMouse).fishEye(true, true);
718
					IFigure fisheyedFigure = ((GraphNode) itemUnderMouse)
719
							.fishEye(true, true);
578
					if (fisheyedFigure == null) {
720
					if (fisheyedFigure == null) {
579
						// If there is no fisheye figure (this means that the node does not support a fish eye)
721
						// If there is no fisheye figure (this means that the
722
						// node does not support a fish eye)
580
						// then remove the fisheyed item
723
						// then remove the fisheyed item
581
						fisheyedItem = null;
724
						fisheyedItem = null;
582
					}
725
					}
583
				} else if (fisheyedItem != null) {
584
					((GraphNode) fisheyedItem).fishEye(false, true);
585
					fisheyedItem = null;
586
					fisheyedFigure = null;
587
				}
726
				}
588
			} else {
727
			} else {
589
				if (fisheyedItem != null) {
728
				if (fisheyedItem != null) {
590
					((GraphNode) fisheyedItem).fishEye(false, true);
729
					((GraphNode) fisheyedItem).fishEye(false, true);
591
					fisheyedItem = null;
730
					fisheyedItem = null;
592
					fisheyedFigure = null;
593
				}
731
				}
594
			}
732
			}
595
		}
733
		}
Lines 601-607 Link Here
601
		public void mousePressed(org.eclipse.draw2d.MouseEvent me) {
739
		public void mousePressed(org.eclipse.draw2d.MouseEvent me) {
602
			isDragging = true;
740
			isDragging = true;
603
			Point mousePoint = new Point(me.x, me.y);
741
			Point mousePoint = new Point(me.x, me.y);
604
			lastLocation = mousePoint.getCopy();
742
			dragStartLocation = mousePoint.getCopy();
605
743
606
			getRootLayer().translateToRelative(mousePoint);
744
			getRootLayer().translateToRelative(mousePoint);
607
745
Lines 610-619 Link Here
610
				scale *= 1.05;
748
				scale *= 1.05;
611
				getRootLayer().setScale(scale);
749
				getRootLayer().setScale(scale);
612
				Point newMousePoint = mousePoint.getCopy().scale(1.05);
750
				Point newMousePoint = mousePoint.getCopy().scale(1.05);
613
				Point delta = new Point(newMousePoint.x - mousePoint.x, newMousePoint.y - mousePoint.y);
751
				Point delta = new Point(newMousePoint.x - mousePoint.x,
614
				Point newViewLocation = getViewport().getViewLocation().getCopy().translate(delta);
752
						newMousePoint.y - mousePoint.y);
753
				Point newViewLocation = getViewport().getViewLocation()
754
						.getCopy().translate(delta);
615
				getViewport().setViewLocation(newViewLocation);
755
				getViewport().setViewLocation(newViewLocation);
616
				lastLocation.scale(scale);
617
756
618
				clearSelection();
757
				clearSelection();
619
				return;
758
				return;
Lines 623-644 Link Here
623
				getRootLayer().setScale(scale);
762
				getRootLayer().setScale(scale);
624
763
625
				Point newMousePoint = mousePoint.getCopy().scale(1 / 1.05);
764
				Point newMousePoint = mousePoint.getCopy().scale(1 / 1.05);
626
				Point delta = new Point(newMousePoint.x - mousePoint.x, newMousePoint.y - mousePoint.y);
765
				Point delta = new Point(newMousePoint.x - mousePoint.x,
627
				Point newViewLocation = getViewport().getViewLocation().getCopy().translate(delta);
766
						newMousePoint.y - mousePoint.y);
767
				Point newViewLocation = getViewport().getViewLocation()
768
						.getCopy().translate(delta);
628
				getViewport().setViewLocation(newViewLocation);
769
				getViewport().setViewLocation(newViewLocation);
629
				clearSelection();
770
				clearSelection();
630
				return;
771
				return;
631
			} else {
772
			} else {
632
				boolean hasSelection = selectedItems.size() > 0;
773
				boolean hasSelection = selectedItems.size() > 0;
633
				IFigure figureUnderMouse = getFigureAt(mousePoint.x, mousePoint.y);
774
				IFigure figureUnderMouse = getFigureAt(mousePoint.x,
775
						mousePoint.y);
634
				getRootLayer().translateFromParent(mousePoint);
776
				getRootLayer().translateFromParent(mousePoint);
635
777
636
				if (figureUnderMouse != null) {
778
				if (figureUnderMouse != null) {
637
					figureUnderMouse.getParent().translateFromParent(mousePoint);
779
					figureUnderMouse.getParent()
780
							.translateFromParent(mousePoint);
638
				}
781
				}
639
				// If the figure under the mouse is the canvas, and CTRL is not being held down, then select
782
				// If the figure under the mouse is the canvas, and CTRL is not
783
				// being held down, then select
640
				// nothing
784
				// nothing
641
				if (figureUnderMouse == null || figureUnderMouse == graph) {
785
				if (figureUnderMouse == null || figureUnderMouse == Graph.this) {
642
					if (me.getState() != org.eclipse.draw2d.MouseEvent.CONTROL) {
786
					if (me.getState() != org.eclipse.draw2d.MouseEvent.CONTROL) {
643
						clearSelection();
787
						clearSelection();
644
						if (hasSelection) {
788
						if (hasSelection) {
Lines 649-655 Link Here
649
					return;
793
					return;
650
				}
794
				}
651
795
652
				GraphItem itemUnderMouse = (GraphItem) figure2ItemMap.get(figureUnderMouse);
796
				GraphItem itemUnderMouse = (GraphItem) figure2ItemMap
797
						.get(figureUnderMouse);
653
				if (itemUnderMouse == null) {
798
				if (itemUnderMouse == null) {
654
					if (me.getState() != org.eclipse.draw2d.MouseEvent.CONTROL) {
799
					if (me.getState() != org.eclipse.draw2d.MouseEvent.CONTROL) {
655
						clearSelection();
800
						clearSelection();
Lines 661-668 Link Here
661
					return;
806
					return;
662
				}
807
				}
663
				if (selectedItems.contains(itemUnderMouse)) {
808
				if (selectedItems.contains(itemUnderMouse)) {
664
					// We have already selected this node, and CTRL is being held down, remove this selection
809
					// We have already selected this node, and CTRL is being
665
					// @tag Zest.selection : This deselects when you have CTRL pressed
810
					// held down, remove this selection
811
					// @tag Zest.selection : This deselects when you have CTRL
812
					// pressed
666
					if (me.getState() == org.eclipse.draw2d.MouseEvent.CONTROL) {
813
					if (me.getState() == org.eclipse.draw2d.MouseEvent.CONTROL) {
667
						selectedItems.remove(itemUnderMouse);
814
						selectedItems.remove(itemUnderMouse);
668
						(itemUnderMouse).unhighlight();
815
						(itemUnderMouse).unhighlight();
Lines 676-682 Link Here
676
				}
823
				}
677
824
678
				if (itemUnderMouse.getItemType() == GraphItem.NODE) {
825
				if (itemUnderMouse.getItemType() == GraphItem.NODE) {
679
					// @tag Zest.selection : This is where the nodes are selected
826
					// @tag Zest.selection : This is where the nodes are
827
					// selected
680
					selectedItems.add(itemUnderMouse);
828
					selectedItems.add(itemUnderMouse);
681
					((GraphNode) itemUnderMouse).highlight();
829
					((GraphNode) itemUnderMouse).highlight();
682
					fireWidgetSelectedEvent(itemUnderMouse);
830
					fireWidgetSelectedEvent(itemUnderMouse);
Lines 696-702 Link Here
696
844
697
		public void mouseReleased(org.eclipse.draw2d.MouseEvent me) {
845
		public void mouseReleased(org.eclipse.draw2d.MouseEvent me) {
698
			isDragging = false;
846
			isDragging = false;
699
847
			relativeLocations.clear();
848
			draggedSubgraphFigure = null;
700
		}
849
		}
701
850
702
	}
851
	}
Lines 715-721 Link Here
715
	private void fireWidgetSelectedEvent(Item item) {
864
	private void fireWidgetSelectedEvent(Item item) {
716
		Iterator iterator = selectionListeners.iterator();
865
		Iterator iterator = selectionListeners.iterator();
717
		while (iterator.hasNext()) {
866
		while (iterator.hasNext()) {
718
			SelectionListener selectionListener = (SelectionListener) iterator.next();
867
			SelectionListener selectionListener = (SelectionListener) iterator
868
					.next();
719
			Event swtEvent = new Event();
869
			Event swtEvent = new Event();
720
			swtEvent.item = item;
870
			swtEvent.item = item;
721
			swtEvent.widget = this;
871
			swtEvent.widget = this;
Lines 726-804 Link Here
726
	}
876
	}
727
877
728
	/**
878
	/**
729
	 * Moves the edge to the highlight layer. This moves the edge above the
730
	 * nodes
731
	 * 
732
	 * @param connection
733
	 */
734
	void highlightEdge(GraphConnection connection) {
735
		IFigure figure = connection.getConnectionFigure();
736
		if (figure != null && !connection.isHighlighted()) {
737
			zestRootLayer.highlightConnection(figure);
738
		}
739
	}
740
741
	/**
742
	 * Moves the edge from the edge feedback layer back to the edge layer
743
	 * 
744
	 * @param graphConnection
745
	 */
746
	void unhighlightEdge(GraphConnection connection) {
747
		IFigure figure = connection.getConnectionFigure();
748
		if (figure != null && connection.isHighlighted()) {
749
			zestRootLayer.unHighlightConnection(figure);
750
		}
751
	}
752
753
	/**
754
	 * Moves the node onto the node feedback layer
755
	 * 
756
	 * @param node
757
	 */
758
	void highlightNode(GraphNode node) {
759
		IFigure figure = node.getNodeFigure();
760
		if (figure != null && !node.isHighlighted()) {
761
			zestRootLayer.highlightNode(figure);
762
		}
763
	}
764
765
	/**
766
	 * Moves the node onto the node feedback layer
767
	 * 
768
	 * @param node
769
	 */
770
	void highlightNode(GraphContainer node) {
771
		IFigure figure = node.getNodeFigure();
772
		if (figure != null && !node.isHighlighted()) {
773
			zestRootLayer.highlightNode(figure);
774
		}
775
	}
776
777
	/**
778
	 * Moves the node off the node feedback layer
779
	 * 
780
	 * @param node
781
	 */
782
	void unhighlightNode(GraphContainer node) {
783
		IFigure figure = node.getNodeFigure();
784
		if (figure != null && node.isHighlighted()) {
785
			zestRootLayer.unHighlightNode(figure);
786
		}
787
	}
788
789
	/**
790
	 * Moves the node off the node feedback layer
791
	 * 
792
	 * @param node
793
	 */
794
	void unhighlightNode(GraphNode node) {
795
		IFigure figure = node.getNodeFigure();
796
		if (figure != null && node.isHighlighted()) {
797
			zestRootLayer.unHighlightNode(figure);
798
		}
799
	}
800
801
	/**
802
	 * Converts the list of GraphModelConnection objects into an array and
879
	 * Converts the list of GraphModelConnection objects into an array and
803
	 * returns it.
880
	 * returns it.
804
	 * 
881
	 * 
Lines 810-871 Link Here
810
		return connsArray;
887
		return connsArray;
811
	}
888
	}
812
889
813
	LayoutRelationship[] getConnectionsToLayout(List nodesToLayout) {
814
		// @tag zest.bug.156528-Filters.follows : make sure not to layout
815
		// filtered connections, if the style says so.
816
		LayoutRelationship[] entities;
817
		if (ZestStyles.checkStyle(style, ZestStyles.IGNORE_INVISIBLE_LAYOUT)) {
818
			LinkedList connectionList = new LinkedList();
819
			for (Iterator i = this.getConnections().iterator(); i.hasNext();) {
820
				GraphConnection next = (GraphConnection) i.next();
821
				if (next.isVisible() && nodesToLayout.contains(next.getSource()) && nodesToLayout.contains(next.getDestination())) {
822
					connectionList.add(next.getLayoutRelationship());
823
				}
824
			}
825
			entities = (LayoutRelationship[]) connectionList.toArray(new LayoutRelationship[] {});
826
		} else {
827
			LinkedList nodeList = new LinkedList();
828
			for (Iterator i = this.getConnections().iterator(); i.hasNext();) {
829
				GraphConnection next = (GraphConnection) i.next();
830
				if (nodesToLayout.contains(next.getSource()) && nodesToLayout.contains(next.getDestination())) {
831
					nodeList.add(next.getLayoutRelationship());
832
				}
833
			}
834
			entities = (LayoutRelationship[]) nodeList.toArray(new LayoutRelationship[] {});
835
		}
836
		return entities;
837
	}
838
839
	LayoutEntity[] getNodesToLayout(List nodes) {
840
		// @tag zest.bug.156528-Filters.follows : make sure not to layout
841
		// filtered nodes, if the style says so.
842
		LayoutEntity[] entities;
843
		if (ZestStyles.checkStyle(style, ZestStyles.IGNORE_INVISIBLE_LAYOUT)) {
844
			LinkedList nodeList = new LinkedList();
845
			for (Iterator i = nodes.iterator(); i.hasNext();) {
846
				GraphNode next = (GraphNode) i.next();
847
				if (next.isVisible()) {
848
					nodeList.add(next.getLayoutEntity());
849
				}
850
			}
851
			entities = (LayoutEntity[]) nodeList.toArray(new LayoutEntity[] {});
852
		} else {
853
			LinkedList nodeList = new LinkedList();
854
			for (Iterator i = nodes.iterator(); i.hasNext();) {
855
				GraphNode next = (GraphNode) i.next();
856
				nodeList.add(next.getLayoutEntity());
857
			}
858
			entities = (LayoutEntity[]) nodeList.toArray(new LayoutEntity[] {});
859
		}
860
		return entities;
861
	}
862
863
	void removeConnection(GraphConnection connection) {
890
	void removeConnection(GraphConnection connection) {
864
		IFigure figure = connection.getConnectionFigure();
891
		IFigure figure = connection.getConnectionFigure();
865
		PolylineConnection sourceContainerConnectionFigure = connection.getSourceContainerConnectionFigure();
892
		PolylineConnection sourceContainerConnectionFigure = connection
866
		PolylineConnection targetContainerConnectionFigure = connection.getTargetContainerConnectionFigure();
893
				.getSourceContainerConnectionFigure();
894
		PolylineConnection targetContainerConnectionFigure = connection
895
				.getTargetContainerConnectionFigure();
867
		connection.removeFigure();
896
		connection.removeFigure();
868
		this.getConnections().remove(connection);
897
		this.getConnections().remove(connection);
898
		this.selectedItems.remove(connection);
869
		figure2ItemMap.remove(figure);
899
		figure2ItemMap.remove(figure);
870
		if (sourceContainerConnectionFigure != null) {
900
		if (sourceContainerConnectionFigure != null) {
871
			figure2ItemMap.remove(sourceContainerConnectionFigure);
901
			figure2ItemMap.remove(sourceContainerConnectionFigure);
Lines 873-891 Link Here
873
		if (targetContainerConnectionFigure != null) {
903
		if (targetContainerConnectionFigure != null) {
874
			figure2ItemMap.remove(targetContainerConnectionFigure);
904
			figure2ItemMap.remove(targetContainerConnectionFigure);
875
		}
905
		}
906
		getLayoutContext().fireConnectionRemovedEvent(connection.getLayout());
876
	}
907
	}
877
908
878
	void removeNode(GraphNode node) {
909
	void removeNode(GraphNode node) {
879
		IFigure figure = node.getNodeFigure();
910
		IFigure figure = node.getNodeFigure();
880
		if (figure.getParent() != null) {
911
		if (figure.getParent() != null) {
881
			if (figure.getParent() instanceof ZestRootLayer) {
912
			figure.getParent().remove(figure);
882
				((ZestRootLayer) figure.getParent()).removeNode(figure);
883
			} else {
884
				figure.getParent().remove(figure);
885
			}
886
		}
913
		}
887
		this.getNodes().remove(node);
914
		this.getNodes().remove(node);
915
		this.selectedItems.remove(node);
888
		figure2ItemMap.remove(figure);
916
		figure2ItemMap.remove(figure);
917
		node.getLayout().dispose();
889
	}
918
	}
890
919
891
	void addConnection(GraphConnection connection, boolean addToEdgeLayer) {
920
	void addConnection(GraphConnection connection, boolean addToEdgeLayer) {
Lines 893-936 Link Here
893
		if (addToEdgeLayer) {
922
		if (addToEdgeLayer) {
894
			zestRootLayer.addConnection(connection.getFigure());
923
			zestRootLayer.addConnection(connection.getFigure());
895
		}
924
		}
925
		getLayoutContext().fireConnectionAddedEvent(connection.getLayout());
896
	}
926
	}
897
927
898
	/*
928
	/**
899
	public void redraw() {
929
	 * @noreference This method is not intended to be referenced by clients.
900
930
	 */
901
		Iterator iterator = this.getConnections().iterator();
931
	public void addNode(GraphNode node) {
902
		while (iterator.hasNext()) {
903
			GraphConnection connection = (GraphConnection) iterator.next();
904
			IFigure figure = connection.getFigure();
905
			if (!zestRootLayer.getChildren().contains(figure)) {
906
				if (true || false || false) {
907
					zestRootLayer.addConnection(connection.getFigure());
908
				}
909
			}
910
		}
911
		iterator = this.getNodes().iterator();
912
		while (iterator.hasNext()) {
913
			GraphNode graphNode = (GraphNode) iterator.next();
914
			IFigure figure = graphNode.getFigure();
915
			if (!zestRootLayer.getChildren().contains(figure)) {
916
				zestRootLayer.addNode(graphNode.getFigure());
917
			}
918
		}
919
920
		super.redraw();
921
922
	}
923
	*/
924
925
	void addNode(GraphNode node) {
926
		this.getNodes().add(node);
932
		this.getNodes().add(node);
927
		zestRootLayer.addNode(node.getFigure());
933
		zestRootLayer.addNode(node.getFigure());
934
		getLayoutContext().fireNodeAddedEvent(node.getLayout());
928
	}
935
	}
929
936
930
	void addNode(GraphContainer graphContainer) {
937
	/**
931
		this.getNodes().add(graphContainer);
938
	 * @noreference This method is not intended to be referenced by clients.
932
		zestRootLayer.addNode(graphContainer.getFigure());
939
	 */
940
	public void addSubgraphFigure(IFigure figure) {
941
		zestRootLayer.addSubgraph(figure);
942
		subgraphFigures.add(figure);
943
	}
933
944
945
	void removeSubgraphFigure(IFigure figure) {
946
		subgraphFigures.remove(figure);
947
		figure.getParent().remove(figure);
934
	}
948
	}
935
949
936
	void registerItem(GraphItem item) {
950
	void registerItem(GraphItem item) {
Lines 941-1071 Link Here
941
			IFigure figure = item.getFigure();
955
			IFigure figure = item.getFigure();
942
			figure2ItemMap.put(figure, item);
956
			figure2ItemMap.put(figure, item);
943
			if (((GraphConnection) item).getSourceContainerConnectionFigure() != null) {
957
			if (((GraphConnection) item).getSourceContainerConnectionFigure() != null) {
944
				figure2ItemMap.put(((GraphConnection) item).getSourceContainerConnectionFigure(), item);
958
				figure2ItemMap.put(((GraphConnection) item)
959
						.getSourceContainerConnectionFigure(), item);
945
			}
960
			}
946
			if (((GraphConnection) item).getTargetContainerConnectionFigure() != null) {
961
			if (((GraphConnection) item).getTargetContainerConnectionFigure() != null) {
947
				figure2ItemMap.put(((GraphConnection) item).getTargetContainerConnectionFigure(), item);
962
				figure2ItemMap.put(((GraphConnection) item)
963
						.getTargetContainerConnectionFigure(), item);
948
			}
964
			}
949
		} else if (item.getItemType() == GraphItem.CONTAINER) {
965
		} else if (item.getItemType() == GraphItem.CONTAINER) {
950
			IFigure figure = item.getFigure();
966
			IFigure figure = item.getFigure();
951
			figure2ItemMap.put(figure, item);
967
			figure2ItemMap.put(figure, item);
952
		} else {
968
		} else {
953
			throw new RuntimeException("Unknown item type: " + item.getItemType());
969
			throw new RuntimeException("Unknown item type: "
954
		}
970
					+ item.getItemType());
955
	}
956
957
	/*
958
959
960
	/**
961
	 * Changes the figure for a particular node
962
	 */
963
	void changeNodeFigure(IFigure oldValue, IFigure newFigure, GraphNode graphItem) {
964
		if (zestRootLayer.getChildren().contains(oldValue)) {
965
			zestRootLayer.remove(oldValue);
966
			figure2ItemMap.remove(oldValue);
967
		}
968
		figure2ItemMap.put(newFigure, graphItem);
969
		zestRootLayer.add(newFigure);
970
	}
971
972
	/**
973
	 * Invoke all the constraint adapaters for this constraints
974
	 * 
975
	 * @param object
976
	 * @param constraint
977
	 */
978
	void invokeConstraintAdapters(Object object, LayoutConstraint constraint) {
979
		if (constraintAdapters == null) {
980
			return;
981
		}
971
		}
982
		Iterator iterator = this.constraintAdapters.iterator();
983
		while (iterator.hasNext()) {
984
			ConstraintAdapter constraintAdapter = (ConstraintAdapter) iterator.next();
985
			constraintAdapter.populateConstraint(object, constraint);
986
		}
987
	}
988
989
	private void applyLayoutInternal() {
990
991
		if ((this.getNodes().size() == 0)) {
992
			return;
993
		}
994
995
		int layoutStyle = 0;
996
997
		if ((nodeStyle & ZestStyles.NODES_NO_LAYOUT_RESIZE) > 0) {
998
			layoutStyle = LayoutStyles.NO_LAYOUT_NODE_RESIZING;
999
		}
1000
1001
		if (layoutAlgorithm == null) {
1002
			layoutAlgorithm = new TreeLayoutAlgorithm(layoutStyle);
1003
		}
1004
1005
		layoutAlgorithm.setStyle(layoutAlgorithm.getStyle() | layoutStyle);
1006
1007
		// calculate the size for the layout algorithm
1008
		Dimension d = this.getViewport().getSize();
1009
		d.width = d.width - 10;
1010
		d.height = d.height - 10;
1011
1012
		if (this.preferredSize.width >= 0) {
1013
			d.width = preferredSize.width;
1014
		}
1015
		if (this.preferredSize.height >= 0) {
1016
			d.height = preferredSize.height;
1017
		}
1018
1019
		if (d.isEmpty()) {
1020
			return;
1021
		}
1022
		LayoutRelationship[] connectionsToLayout = getConnectionsToLayout(nodes);
1023
		LayoutEntity[] nodesToLayout = getNodesToLayout(getNodes());
1024
1025
		try {
1026
			Animation.markBegin();
1027
			layoutAlgorithm.applyLayout(nodesToLayout, connectionsToLayout, 0, 0, d.width, d.height, false, false);
1028
			Animation.run(ANIMATION_TIME);
1029
			getLightweightSystem().getUpdateManager().performUpdate();
1030
1031
		} catch (InvalidLayoutConfiguration e) {
1032
			e.printStackTrace();
1033
		}
1034
1035
	}
1036
1037
	interface MyRunnable extends Runnable {
1038
		public boolean isVisible();
1039
	}
972
	}
1040
973
1041
	/**
974
	/**
1042
	 * Adds a reveal listener to the view. Note: A reveal listener will only
975
	 * Schedules a layout to be performed after the view is revealed (or
1043
	 * every be called ONCE!!! even if a view comes and goes. There is no remove
976
	 * immediately, if the view is already revealed).
1044
	 * reveal listener. This is used to defer some events until after the view
1045
	 * is revealed.
1046
	 * 
977
	 * 
1047
	 * @param revealListener
978
	 * @param clean
1048
	 */
979
	 */
1049
	private void addRevealListener(final RevealListener revealListener) {
980
	private void scheduleLayoutOnReveal(final boolean clean) {
1050
1051
		MyRunnable myRunnable = new MyRunnable() {
1052
			boolean isVisible;
1053
1054
			public boolean isVisible() {
1055
				return this.isVisible;
1056
			}
1057
981
982
		final boolean[] isVisibleSync = new boolean[1];
983
		Display.getDefault().syncExec(new Runnable() {
1058
			public void run() {
984
			public void run() {
1059
				isVisible = Graph.this.isVisible();
985
				isVisibleSync[0] = isVisible();
1060
			}
986
			}
987
		});
1061
988
1062
		};
989
		if (isVisibleSync[0]) {
1063
		Display.getDefault().syncExec(myRunnable);
990
			applyLayoutInternal(clean);
1064
1065
		if (myRunnable.isVisible()) {
1066
			revealListener.revealed(this);
1067
		} else {
991
		} else {
1068
			revealListeners.add(revealListener);
992
			shouldSheduleLayout = true;
1069
		}
993
		}
1070
	}
994
	}
1071
995
Lines 1084-1101 Link Here
1084
1008
1085
		zestRootLayer.addLayoutListener(LayoutAnimator.getDefault());
1009
		zestRootLayer.addLayoutListener(LayoutAnimator.getDefault());
1086
		fishEyeLayer.addLayoutListener(LayoutAnimator.getDefault());
1010
		fishEyeLayer.addLayoutListener(LayoutAnimator.getDefault());
1011
1012
		rootlayer.addCoordinateListener(new CoordinateListener() {
1013
			public void coordinateSystemChanged(IFigure source) {
1014
				if (preferredSize.width == -1 && preferredSize.height == -1) {
1015
					getLayoutContext().fireBoundsChangedEvent();
1016
				}
1017
			}
1018
		});
1019
1087
		return rootlayer;
1020
		return rootlayer;
1088
	}
1021
	}
1089
1022
1090
	/**
1023
	/**
1091
	 * This removes the fisheye from the graph. It uses an animation to make the fisheye
1024
	 * This removes the fisheye from the graph. It uses an animation to make the
1092
	 * shrink, and then it finally clears the fisheye layer.  This assumes that there
1025
	 * fisheye shrink, and then it finally clears the fisheye layer. This
1093
	 * is ever only 1 node on the fisheye layer at any time.  
1026
	 * assumes that there is ever only 1 node on the fisheye layer at any time.
1094
	 * 
1027
	 * 
1095
	 * @param fishEyeFigure The fisheye figure
1028
	 * @param fishEyeFigure
1096
	 * @param regularFigure The regular figure (i.e. the non fisheye version)
1029
	 *            The fisheye figure
1030
	 * @param regularFigure
1031
	 *            The regular figure (i.e. the non fisheye version)
1097
	 */
1032
	 */
1098
	void removeFishEye(final IFigure fishEyeFigure, final IFigure regularFigure, boolean animate) {
1033
	void removeFishEye(final IFigure fishEyeFigure,
1034
			final IFigure regularFigure, boolean animate) {
1099
1035
1100
		if (!fishEyeLayer.getChildren().contains(fishEyeFigure)) {
1036
		if (!fishEyeLayer.getChildren().contains(fishEyeFigure)) {
1101
			return;
1037
			return;
Lines 1114-1130 Link Here
1114
1050
1115
		fishEyeLayer.setConstraint(fishEyeFigure, bounds);
1051
		fishEyeLayer.setConstraint(fishEyeFigure, bounds);
1116
1052
1053
		for (Iterator iterator = fisheyeListeners.iterator(); iterator
1054
				.hasNext();) {
1055
			FisheyeListener listener = (FisheyeListener) iterator.next();
1056
			listener.fisheyeRemoved(this, regularFigure, fishEyeFigure);
1057
		}
1058
1117
		if (animate) {
1059
		if (animate) {
1118
			Animation.run(FISHEYE_ANIMATION_TIME * 2);
1060
			Animation.run(FISHEYE_ANIMATION_TIME * 2);
1119
		}
1061
		}
1120
		this.getRootLayer().getUpdateManager().performUpdate();
1062
		this.getRootLayer().getUpdateManager().performUpdate();
1121
		fishEyeLayer.removeAll();
1063
		fishEyeLayer.removeAll();
1122
		this.fisheyedFigure = null;
1123
1064
1124
	}
1065
	}
1125
1066
1126
	/**
1067
	/**
1127
	 * Replaces the old fisheye figure with a new one.
1068
	 * Replaces the old fisheye figure with a new one.
1069
	 * 
1128
	 * @param oldFigure
1070
	 * @param oldFigure
1129
	 * @param newFigure
1071
	 * @param newFigure
1130
	 */
1072
	 */
Lines 1132-1160 Link Here
1132
		if (this.fishEyeLayer.getChildren().contains(oldFigure)) {
1074
		if (this.fishEyeLayer.getChildren().contains(oldFigure)) {
1133
			Rectangle bounds = oldFigure.getBounds();
1075
			Rectangle bounds = oldFigure.getBounds();
1134
			newFigure.setBounds(bounds);
1076
			newFigure.setBounds(bounds);
1135
			//this.fishEyeLayer.getChildren().remove(oldFigure);
1136
			this.fishEyeLayer.remove(oldFigure);
1077
			this.fishEyeLayer.remove(oldFigure);
1137
			this.fishEyeLayer.add(newFigure);
1078
			this.fishEyeLayer.add(newFigure);
1138
			//this.fishEyeLayer.getChildren().add(newFigure);
1079
1139
			//this.fishEyeLayer.invalidate();
1080
			for (Iterator iterator = fisheyeListeners.iterator(); iterator
1140
			//this.fishEyeLayer.repaint();
1081
					.hasNext();) {
1141
			this.fisheyedFigure = newFigure;
1082
				FisheyeListener listener = (FisheyeListener) iterator.next();
1083
				listener.fisheyeReplaced(this, oldFigure, newFigure);
1084
			}
1085
1142
			return true;
1086
			return true;
1143
		}
1087
		}
1144
		return false;
1088
		return false;
1145
	}
1089
	}
1146
1090
1147
	/**
1091
	/**
1148
	 * Add a fisheye version of the node.  This works by animating the change from the original node
1092
	 * Add a fisheye version of the node. This works by animating the change
1149
	 * to the fisheyed one, and then placing the fisheye node on the fisheye layer.
1093
	 * from the original node to the fisheyed one, and then placing the fisheye
1150
	 * @param startFigure The original node
1094
	 * node on the fisheye layer.
1151
	 * @param endFigure The fisheye figure
1095
	 * 
1152
	 * @param newBounds The final size of the fisheyed figure
1096
	 * @param startFigure
1097
	 *            The original node
1098
	 * @param endFigure
1099
	 *            The fisheye figure
1100
	 * @param newBounds
1101
	 *            The final size of the fisheyed figure
1153
	 */
1102
	 */
1154
	void fishEye(IFigure startFigure, IFigure endFigure, Rectangle newBounds, boolean animate) {
1103
	void fishEye(IFigure startFigure, IFigure endFigure, Rectangle newBounds,
1104
			boolean animate) {
1155
1105
1156
		fishEyeLayer.removeAll();
1106
		fishEyeLayer.removeAll();
1157
		fisheyedFigure = null;
1107
1158
		if (animate) {
1108
		if (animate) {
1159
			Animation.markBegin();
1109
			Animation.markBegin();
1160
		}
1110
		}
Lines 1167-1173 Link Here
1167
1117
1168
		Rectangle bounds = startFigure.getBounds().getCopy();
1118
		Rectangle bounds = startFigure.getBounds().getCopy();
1169
		startFigure.translateToAbsolute(bounds);
1119
		startFigure.translateToAbsolute(bounds);
1170
		//startFigure.translateToRelative(bounds);
1120
		// startFigure.translateToRelative(bounds);
1171
		fishEyeLayer.translateToRelative(bounds);
1121
		fishEyeLayer.translateToRelative(bounds);
1172
		fishEyeLayer.translateFromParent(bounds);
1122
		fishEyeLayer.translateFromParent(bounds);
1173
1123
Lines 1176-1190 Link Here
1176
		fishEyeLayer.add(endFigure);
1126
		fishEyeLayer.add(endFigure);
1177
		fishEyeLayer.setConstraint(endFigure, newBounds);
1127
		fishEyeLayer.setConstraint(endFigure, newBounds);
1178
1128
1129
		for (Iterator iterator = fisheyeListeners.iterator(); iterator
1130
				.hasNext();) {
1131
			FisheyeListener listener = (FisheyeListener) iterator.next();
1132
			listener.fisheyeAdded(this, startFigure, endFigure);
1133
		}
1134
1179
		if (animate) {
1135
		if (animate) {
1180
			Animation.run(FISHEYE_ANIMATION_TIME);
1136
			Animation.run(FISHEYE_ANIMATION_TIME);
1181
		}
1137
		}
1182
		this.getRootLayer().getUpdateManager().performUpdate();
1138
		this.getRootLayer().getUpdateManager().performUpdate();
1183
	}
1139
	}
1184
1140
1185
	public Graph getGraph() {
1141
	/**
1186
		// @tag refactor : Is this method really needed
1142
	 * Adds a listener that will be notified when fisheyed figures change in
1187
		return this.getGraphModel();
1143
	 * this graph.
1144
	 * 
1145
	 * @param listener
1146
	 *            listener to add
1147
	 * @since 2.0
1148
	 */
1149
	public void addFisheyeListener(FisheyeListener listener) {
1150
		fisheyeListeners.add(listener);
1151
	}
1152
1153
	/**
1154
	 * @since 2.0
1155
	 */
1156
	public void removeFisheyeListener(FisheyeListener listener) {
1157
		fisheyeListeners.remove(listener);
1188
	}
1158
	}
1189
1159
1190
	public int getItemType() {
1160
	public int getItemType() {
Lines 1195-1198 Link Here
1195
		return (GraphItem) figure2ItemMap.get(figure);
1165
		return (GraphItem) figure2ItemMap.get(figure);
1196
	}
1166
	}
1197
1167
1168
	/**
1169
	 * @since 2.0
1170
	 */
1171
	public void setExpanded(GraphNode node, boolean expanded) {
1172
		layoutContext.setExpanded(node.getLayout(), expanded);
1173
		rootlayer.invalidate();
1174
	}
1175
1176
	/**
1177
	 * @since 2.0
1178
	 */
1179
	public boolean canExpand(GraphNode node) {
1180
		return layoutContext.canExpand(node.getLayout());
1181
	}
1182
1183
	/**
1184
	 * @since 2.0
1185
	 */
1186
	public boolean canCollapse(GraphNode node) {
1187
		return layoutContext.canCollapse(node.getLayout());
1188
	}
1189
1190
	public Graph getGraph() {
1191
		return this;
1192
	}
1193
1194
	/**
1195
	 * @since 2.0
1196
	 */
1197
	public Widget getItem() {
1198
		return this;
1199
	}
1200
1201
	/**
1202
	 * @since 2.0
1203
	 */
1204
	public DisplayIndependentRectangle getLayoutBounds() {
1205
		Dimension preferredSize = this.getPreferredSize();
1206
		return new DisplayIndependentRectangle(0, 0, preferredSize.width,
1207
				preferredSize.height);
1208
	}
1198
}
1209
}
(-)src/org/eclipse/zest/core/widgets/GraphContainer.java (-317 / +445 lines)
Lines 1-11 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC,
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
8
 * Contributors: The Chisel Group, University of Victoria 
9
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 ******************************************************************************/
10
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
package org.eclipse.zest.core.widgets;
11
12
Lines 14-46 Link Here
14
import java.util.LinkedList;
15
import java.util.LinkedList;
15
import java.util.List;
16
import java.util.List;
16
17
18
import org.eclipse.draw2d.ActionEvent;
19
import org.eclipse.draw2d.ActionListener;
17
import org.eclipse.draw2d.Animation;
20
import org.eclipse.draw2d.Animation;
21
import org.eclipse.draw2d.Clickable;
18
import org.eclipse.draw2d.ColorConstants;
22
import org.eclipse.draw2d.ColorConstants;
23
import org.eclipse.draw2d.Figure;
19
import org.eclipse.draw2d.FreeformLayout;
24
import org.eclipse.draw2d.FreeformLayout;
20
import org.eclipse.draw2d.FreeformViewport;
25
import org.eclipse.draw2d.FreeformViewport;
26
import org.eclipse.draw2d.Graphics;
21
import org.eclipse.draw2d.IFigure;
27
import org.eclipse.draw2d.IFigure;
28
import org.eclipse.draw2d.Label;
22
import org.eclipse.draw2d.LayoutAnimator;
29
import org.eclipse.draw2d.LayoutAnimator;
23
import org.eclipse.draw2d.LineBorder;
30
import org.eclipse.draw2d.LineBorder;
24
import org.eclipse.draw2d.PolylineConnection;
25
import org.eclipse.draw2d.ScrollPane;
31
import org.eclipse.draw2d.ScrollPane;
32
import org.eclipse.draw2d.ToolbarLayout;
33
import org.eclipse.draw2d.Triangle;
26
import org.eclipse.draw2d.Viewport;
34
import org.eclipse.draw2d.Viewport;
27
import org.eclipse.draw2d.geometry.Dimension;
35
import org.eclipse.draw2d.geometry.Dimension;
28
import org.eclipse.draw2d.geometry.Point;
36
import org.eclipse.draw2d.geometry.Point;
29
import org.eclipse.draw2d.geometry.Rectangle;
37
import org.eclipse.draw2d.geometry.Rectangle;
38
import org.eclipse.swt.events.SelectionEvent;
39
import org.eclipse.swt.events.SelectionListener;
40
import org.eclipse.swt.graphics.Color;
30
import org.eclipse.swt.graphics.Image;
41
import org.eclipse.swt.graphics.Image;
42
import org.eclipse.swt.graphics.RGB;
43
import org.eclipse.swt.widgets.Display;
44
import org.eclipse.swt.widgets.Widget;
31
import org.eclipse.zest.core.widgets.internal.AspectRatioFreeformLayer;
45
import org.eclipse.zest.core.widgets.internal.AspectRatioFreeformLayer;
32
import org.eclipse.zest.core.widgets.internal.ContainerFigure;
46
import org.eclipse.zest.core.widgets.internal.ContainerFigure;
33
import org.eclipse.zest.core.widgets.internal.ExpandGraphLabel;
34
import org.eclipse.zest.core.widgets.internal.ZestRootLayer;
47
import org.eclipse.zest.core.widgets.internal.ZestRootLayer;
35
import org.eclipse.zest.layouts.InvalidLayoutConfiguration;
36
import org.eclipse.zest.layouts.LayoutAlgorithm;
48
import org.eclipse.zest.layouts.LayoutAlgorithm;
37
import org.eclipse.zest.layouts.LayoutEntity;
38
import org.eclipse.zest.layouts.LayoutRelationship;
39
import org.eclipse.zest.layouts.LayoutStyles;
40
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
49
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
50
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
41
51
42
/*
52
/**
43
 * A Container than can be added to a Graph. Nodes can be added to this
53
 * A Container that can be added to a Graph. Nodes can be added to this
44
 * container. The container supports collapsing and expanding and has the same
54
 * container. The container supports collapsing and expanding and has the same
45
 * properties as the nodes. Containers cannot have custom figures.
55
 * properties as the nodes. Containers cannot have custom figures.
46
 * 
56
 * 
Lines 48-121 Link Here
48
 */
58
 */
49
public class GraphContainer extends GraphNode implements IContainer {
59
public class GraphContainer extends GraphNode implements IContainer {
50
60
51
	//private static final double CONTAINER_SCALE = 0.75;
61
	static class ExpandGraphLabel extends Figure implements ActionListener {
52
	private static final double scaledWidth = 300;
62
53
	private static final double scaledHeight = 200;
63
		private boolean isExpanded;
64
		private Expander expander = new Expander();
65
		private Color darkerBackground;
66
67
		class Expander extends Clickable {
68
			private Triangle triangle;
69
70
			public Expander() {
71
				setStyle(Clickable.STYLE_TOGGLE);
72
				triangle = new Triangle();
73
				triangle.setSize(10, 10);
74
				triangle.setBackgroundColor(ColorConstants.black);
75
				triangle.setForegroundColor(ColorConstants.black);
76
				triangle.setFill(true);
77
				triangle.setDirection(Triangle.EAST);
78
				triangle.setLocation(new Point(5, 3));
79
				this.setLayoutManager(new FreeformLayout());
80
				this.add(triangle);
81
				this.setPreferredSize(15, 15);
82
				this.addActionListener(ExpandGraphLabel.this);
83
			}
84
85
			public void open() {
86
				triangle.setDirection(Triangle.SOUTH);
87
			}
88
89
			public void close() {
90
				triangle.setDirection(Triangle.EAST);
91
			}
92
93
		}
94
95
		/**
96
		 * Sets the expander state (the little triangle) to
97
		 * ExpanderGraphLabel.OPEN or ExpanderGraphLabel.CLOSED
98
		 * 
99
		 * @param state
100
		 */
101
		public void setExpandedState(boolean expanded) {
102
			if (expanded) {
103
				expander.open();
104
			} else {
105
				expander.close();
106
			}
107
			this.isExpanded = expanded;
108
		}
109
110
		/*
111
		 * (non-Javadoc)
112
		 * 
113
		 * @see
114
		 * org.eclipse.draw2d.ActionListener#actionPerformed(org.eclipse.draw2d
115
		 * .ActionEvent)
116
		 */
117
		public void actionPerformed(ActionEvent event) {
118
			if (isExpanded) {
119
				container.close(true);
120
			} else {
121
				container.open(true);
122
			}
123
		}
124
125
		private final int arcWidth = 8;
126
		private final Label label;
127
		private final GraphContainer container;
128
		private final ToolbarLayout layout;
129
130
		public ExpandGraphLabel(GraphContainer container, String text,
131
				Image image, boolean cacheLabel) {
132
			this.label = new Label(text) {
133
134
				/**
135
				 * <b>This method is overwritten so that the text is not
136
				 * truncated.</b><br>
137
				 * 
138
				 * {@inheritDoc}
139
				 * 
140
				 */
141
				protected void paintFigure(Graphics graphics) {
142
					if (isOpaque()) {
143
						super.paintFigure(graphics);
144
					}
145
					Rectangle bounds = getBounds();
146
					graphics.translate(bounds.x, bounds.y);
147
					if (getIcon() != null) {
148
						graphics.drawImage(getIcon(), getIconLocation());
149
					}
150
					if (!isEnabled()) {
151
						graphics.translate(1, 1);
152
						graphics
153
								.setForegroundColor(ColorConstants.buttonLightest);
154
						graphics
155
								.drawText(getSubStringText(), getTextLocation());
156
						graphics.translate(-1, -1);
157
						graphics
158
								.setForegroundColor(ColorConstants.buttonDarker);
159
					}
160
					graphics.drawText(getText(), getTextLocation());
161
					graphics.translate(-bounds.x, -bounds.y);
162
				}
163
			};
164
			this.setText(text);
165
			this.setImage(image);
166
			this.container = container;
167
			this.setFont(Display.getDefault().getSystemFont());
168
			layout = new ToolbarLayout(true);
169
			layout.setSpacing(5);
170
			layout.setMinorAlignment(ToolbarLayout.ALIGN_CENTER);
171
			this.setLayoutManager(layout);
172
			this.add(this.expander);
173
			this.add(this.label);
174
		}
175
176
		private Color getDarkerBackgroundColor() {
177
			if (darkerBackground == null) {
178
				Color baseColor = getBackgroundColor();
179
				int blue = (int) (baseColor.getBlue() * 0.8 + 0.5);
180
				int red = (int) (baseColor.getRed() * 0.8 + 0.5);
181
				int green = (int) (baseColor.getGreen() * 0.8 + 0.5);
182
				darkerBackground = new Color(Display.getCurrent(), new RGB(red,
183
						green, blue));
184
			}
185
			return darkerBackground;
186
		}
187
188
		/*
189
		 * (non-Javadoc)
190
		 * 
191
		 * @see
192
		 * org.eclipse.draw2d.Label#paintFigure(org.eclipse.draw2d.Graphics)
193
		 */
194
		public void paint(Graphics graphics) {
195
196
			graphics.setForegroundColor(getDarkerBackgroundColor());
197
			graphics.setBackgroundColor(getBackgroundColor());
198
199
			graphics.pushState();
200
201
			// fill in the background
202
			Rectangle bounds = getBounds().getCopy();
203
			Rectangle r = bounds.getCopy();
204
			r.y += arcWidth / 2;
205
			r.height -= arcWidth;
206
207
			Rectangle top = bounds.getCopy();
208
			top.height /= 2;
209
			graphics.setForegroundColor(getBackgroundColor());
210
			graphics.setBackgroundColor(getBackgroundColor());
211
			graphics.fillRoundRectangle(top, arcWidth, arcWidth);
212
213
			top.y = top.y + top.height;
214
			graphics.setForegroundColor(darkerBackground);
215
			graphics.setBackgroundColor(darkerBackground);
216
			graphics.fillRoundRectangle(top, arcWidth, arcWidth);
217
218
			graphics.setBackgroundColor(darkerBackground);
219
			graphics.setForegroundColor(getBackgroundColor());
220
			graphics.fillGradient(r, true);
221
222
			super.paint(graphics);
223
			graphics.popState();
224
			graphics.setForegroundColor(darkerBackground);
225
			graphics.setBackgroundColor(darkerBackground);
226
			// paint the border
227
			bounds.setSize(bounds.width - 1, bounds.height - 1);
228
			graphics.drawRoundRectangle(bounds, arcWidth, arcWidth);
229
		}
230
231
		public void setBackgroundColor(Color bg) {
232
			super.setBackgroundColor(bg);
233
			if (darkerBackground != null) {
234
				darkerBackground.dispose();
235
			}
236
			darkerBackground = null;
237
		}
238
239
		public void setTextT(String string) {
240
			this.setPreferredSize(null);
241
			this.label.setText(string);
242
			this.add(label);
243
			this.layout.layout(this);
244
			this.invalidate();
245
			this.revalidate();
246
			this.validate();
247
		}
248
249
		public void setText(String string) {
250
			this.label.setText(string);
251
		}
252
253
		public void setImage(Image image) {
254
			this.label.setIcon(image);
255
		}
256
257
		public void setFocus() {
258
			expander.requestFocus();
259
		}
260
261
	}
262
263
	static final double SCALED_WIDTH = 250;
264
	static final double SCALED_HEIGHT = 200;
54
	private static final int CONTAINER_HEIGHT = 200;
265
	private static final int CONTAINER_HEIGHT = 200;
55
	private static final int MIN_WIDTH = 250;
266
	private static final int MIN_WIDTH = 250;
267
	private static final int MIN_HEIGHT = 30;
56
	private static final int ANIMATION_TIME = 100;
268
	private static final int ANIMATION_TIME = 100;
57
	private static final int SUBLAYER_OFFSET = 2;
269
	private static final int SUBLAYER_OFFSET = 2;
58
270
271
	private static SelectionListener selectionListener;
272
59
	private ExpandGraphLabel expandGraphLabel;
273
	private ExpandGraphLabel expandGraphLabel;
60
274
61
	//private FreeformLayer container;
62
	//private FreeformLayer edgeLayer;
63
	private List childNodes = null;
275
	private List childNodes = null;
64
	private int childAreaHeight = CONTAINER_HEIGHT;
276
	private int childAreaHeight = CONTAINER_HEIGHT;
65
277
66
	public ZestRootLayer zestLayer;
278
	private ZestRootLayer zestLayer;
67
	private ScrollPane scrollPane;
279
	private ScrollPane scrollPane;
68
	private LayoutAlgorithm layoutAlgorithm;
280
	private LayoutAlgorithm layoutAlgorithm;
69
	private boolean isExpanded = false;
281
	private boolean isExpanded = false;
70
	//private ScalableFreeformLayeredPane scalledLayer;
282
	private boolean isLayoutScheduled = false;
71
	private AspectRatioFreeformLayer scalledLayer;
283
	private AspectRatioFreeformLayer scalledLayer;
284
	private InternalLayoutContext layoutContext;
72
285
73
	/**
286
	/**
74
	 * Creates a new GraphContainer.  A GraphContainer may contain nodes,
287
	 * Creates a new GraphContainer. A GraphContainer may contain nodes, and has
75
	 * and has many of the same properties as a graph node.
288
	 * many of the same properties as a graph node.
76
	 * @param graph The graph that the container is being added to
289
	 * 
77
	 * @param style 
290
	 * @param graph
291
	 *            The graph that the container is being added to
292
	 * @param style
293
	 * 
294
	 * @since 2.0
78
	 */
295
	 */
79
	public GraphContainer(IContainer graph, int style) {
296
	public GraphContainer(Graph graph, int style) {
80
		this(graph, style, "");
297
		super(graph, style, "");
81
298
		initModel(graph, "", null);
82
	}
83
84
	public GraphContainer(IContainer graph, int style, String text) {
85
		this(graph, style, text, null);
86
87
	}
88
89
	public GraphContainer(IContainer graph, int style, String text, Image image) {
90
		super(graph, style, text, image);
91
		initModel(graph, text, image);
92
		close(false);
299
		close(false);
93
		childNodes = new ArrayList();
300
		childNodes = new ArrayList();
301
		registerToParent(graph);
94
	}
302
	}
95
303
96
	/**
304
	/**
97
	 * Custom figures cannot be set on a GraphContainer.
305
	 * Custom figures cannot be set on a GraphContainer.
98
	 */
306
	 */
99
	public void setCustomFigure(IFigure nodeFigure) {
307
	public void setCustomFigure(IFigure nodeFigure) {
100
		throw new RuntimeException("Operation not supported:  Containers cannot have custom figures");
308
		throw new RuntimeException(
101
	}
309
				"Operation not supported:  Containers cannot have custom figures");
102
103
	/*
104
	 * (non-Javadoc)
105
	 * @see org.eclipse.mylar.zest.core.widgets.GraphItem#getItemType()
106
	public int getItemType() {
107
		return GraphItem.CONTAINER;
108
	}
109
110
	/**
111
	 * Gets the figure for this container.
112
	 */
113
	public IFigure getNodeFigure() {
114
		return this.nodeFigure;
115
	}
310
	}
116
311
117
	/**
312
	/**
118
	 * Close this node.
313
	 * Close this node.
314
	 * 
119
	 * @param animate
315
	 * @param animate
120
	 */
316
	 */
121
	public void close(boolean animate) {
317
	public void close(boolean animate) {
Lines 124-161 Link Here
124
		}
320
		}
125
		isExpanded = false;
321
		isExpanded = false;
126
322
127
		expandGraphLabel.setExpandedState(ExpandGraphLabel.CLOSED);
323
		expandGraphLabel.setExpandedState(false);
128
		Rectangle newBounds = scrollPane.getBounds().getCopy();
324
		Rectangle newBounds = scrollPane.getBounds().getCopy();
129
		newBounds.height = 0;
325
		newBounds.height = 0;
130
326
131
		//this.nodeFigure.setConstraint(scrollPane, newBounds);
132
		//this.nodeFigure.revalidate();
133
		scrollPane.setSize(scrollPane.getSize().width, 0);
327
		scrollPane.setSize(scrollPane.getSize().width, 0);
134
		updateFigureForModel(this.zestLayer);
328
		updateFigureForModel(this.zestLayer);
135
		scrollPane.setVisible(false);
329
		scrollPane.setVisible(false);
136
		//setSize(expandGraphLabel.getSize().width, expandGraphLabel.getSize().height);
137
		List children = this.zestLayer.getChildren();
330
		List children = this.zestLayer.getChildren();
138
		for (Iterator iterator = children.iterator(); iterator.hasNext();) {
331
		for (Iterator iterator = children.iterator(); iterator.hasNext();) {
139
			IFigure child = (IFigure) iterator.next();
332
			IFigure child = (IFigure) iterator.next();
140
			GraphItem item = getGraph().getGraphItem(child);
333
			GraphItem item = getGraph().getGraphItem(child);
141
			item.setVisible(false);
334
			item.setVisible(false);
142
		}
335
		}
143
		Rectangle containerBounds = new Rectangle(this.getLocation(), new Dimension(this.getSize().width, CONTAINER_HEIGHT + this.expandGraphLabel.getSize().height));
336
		Rectangle containerBounds = new Rectangle(this.getLocation(),
337
				new Dimension(this.getSize().width, CONTAINER_HEIGHT
338
						+ this.expandGraphLabel.getSize().height));
144
		moveNodesUp(containerBounds, this);
339
		moveNodesUp(containerBounds, this);
145
		if (animate) {
340
		if (animate) {
146
			Animation.run(ANIMATION_TIME);
341
			Animation.run(ANIMATION_TIME);
147
		}
342
		}
148
		//this.nodeFigure.getUpdateManager().performUpdate();
149
		updateFigureForModel(nodeFigure);
343
		updateFigureForModel(nodeFigure);
150
	}
344
	}
151
345
152
	private static void addNodeToOrderedList(List orderedNodeList, GraphNode node) {
346
	private static void addNodeToOrderedList(List orderedNodeList,
347
			GraphNode node) {
153
		Iterator orderedNodeIterator = orderedNodeList.iterator();
348
		Iterator orderedNodeIterator = orderedNodeList.iterator();
154
		int counter = 0;
349
		int counter = 0;
155
		while (orderedNodeIterator.hasNext()) {
350
		while (orderedNodeIterator.hasNext()) {
156
			// Look through the list of nodes below and find the right spot for this
351
			// Look through the list of nodes below and find the right spot for
352
			// this
157
			GraphNode nextOrderedNode = (GraphNode) orderedNodeIterator.next();
353
			GraphNode nextOrderedNode = (GraphNode) orderedNodeIterator.next();
158
			if (nextOrderedNode.getLocation().y + nextOrderedNode.getBounds().height > node.getLocation().y + node.getBounds().height) {
354
			if (nextOrderedNode.getLocation().y
355
					+ nextOrderedNode.getBounds().height > node.getLocation().y
356
					+ node.getBounds().height) {
159
				break;
357
				break;
160
			}
358
			}
161
			counter++;
359
			counter++;
Lines 165-176 Link Here
165
	}
363
	}
166
364
167
	/**
365
	/**
168
	 * Gets all the nodes below the yValue.  The nodes are returned in order.
366
	 * Gets all the nodes below the yValue. The nodes are returned in order.
367
	 * 
169
	 * @param nodes
368
	 * @param nodes
170
	 * @param yValue
369
	 * @param yValue
171
	 * @return
370
	 * @return
172
	 */
371
	 */
173
	private static List getOrderedNodesBelowY(List nodes, int yValue, GraphNode yValueNode) {
372
	private static List getOrderedNodesBelowY(List nodes, int yValue,
373
			GraphNode yValueNode) {
174
		Iterator iterator = nodes.iterator();
374
		Iterator iterator = nodes.iterator();
175
		LinkedList orderedNode = new LinkedList();
375
		LinkedList orderedNode = new LinkedList();
176
		while (iterator.hasNext()) {
376
		while (iterator.hasNext()) {
Lines 194-206 Link Here
194
394
195
	/**
395
	/**
196
	 * Checks if the node intersects the stripe between left and right
396
	 * Checks if the node intersects the stripe between left and right
397
	 * 
197
	 * @param left
398
	 * @param left
198
	 * @param right
399
	 * @param right
199
	 * @param node
400
	 * @param node
200
	 * @return
401
	 * @return
201
	 */
402
	 */
202
	private static boolean nodeInStripe(int left, int right, GraphNode node) {
403
	private static boolean nodeInStripe(int left, int right, GraphNode node) {
203
		return (node.getBounds().x < right && node.getBounds().x + node.getBounds().width > left);
404
		return (node.getBounds().x < right && node.getBounds().x
405
				+ node.getBounds().width > left);
204
	}
406
	}
205
407
206
	void pack(Graph g) {
408
	void pack(Graph g) {
Lines 229-241 Link Here
229
431
230
	/**
432
	/**
231
	 * Move the nodes below this node up
433
	 * Move the nodes below this node up
434
	 * 
232
	 * @param containerBounds
435
	 * @param containerBounds
233
	 * @param graphContainer
436
	 * @param graphContainer
234
	 */
437
	 */
235
	private void moveNodesUp(Rectangle containerBounds, GraphNode graphContainer) {
438
	private void moveNodesUp(Rectangle containerBounds, GraphNode graphContainer) {
236
439
237
		// Get all nodes below this container, in order
440
		// Get all nodes below this container, in order
238
		List orderedNodesBelowY = getOrderedNodesBelowY(parent.getNodes(), containerBounds.y, graphContainer);
441
		List orderedNodesBelowY = getOrderedNodesBelowY(parent.getGraph()
442
				.getNodes(), containerBounds.y, graphContainer);
239
		int leftSide = containerBounds.x;
443
		int leftSide = containerBounds.x;
240
		int rightSide = containerBounds.x + containerBounds.width;
444
		int rightSide = containerBounds.x + containerBounds.width;
241
		List nodesToConsider = new LinkedList();
445
		List nodesToConsider = new LinkedList();
Lines 248-255 Link Here
248
			GraphNode node = (GraphNode) nodesToConsider.get(0);
452
			GraphNode node = (GraphNode) nodesToConsider.get(0);
249
			if (nodeInStripe(leftSide, rightSide, node)) {
453
			if (nodeInStripe(leftSide, rightSide, node)) {
250
				leftSide = Math.min(leftSide, node.getBounds().x);
454
				leftSide = Math.min(leftSide, node.getBounds().x);
251
				rightSide = Math.max(rightSide, node.getBounds().x + node.getBounds().width);
455
				rightSide = Math.max(rightSide, node.getBounds().x
252
				// If this node is in the stripe, move it up 
456
						+ node.getBounds().width);
457
				// If this node is in the stripe, move it up
253
				// the previous node
458
				// the previous node
254
				GraphNode previousNode = null;
459
				GraphNode previousNode = null;
255
				int i = 0;
460
				int i = 0;
Lines 261-268 Link Here
261
				int j = i - 1;
466
				int j = i - 1;
262
				while (j >= 0) {
467
				while (j >= 0) {
263
					GraphNode pastNode = (GraphNode) orderedNodesBelowY.get(j);
468
					GraphNode pastNode = (GraphNode) orderedNodesBelowY.get(j);
264
					//if (nodeInStripe(leftSide, rightSide, pastNode)) {
469
					// if (nodeInStripe(leftSide, rightSide, pastNode)) {
265
					if (nodeInStripe(node.getBounds().x, node.getBounds().x + node.getBounds().width, pastNode)) {
470
					if (nodeInStripe(node.getBounds().x, node.getBounds().x
471
							+ node.getBounds().width, pastNode)) {
266
						previousNode = pastNode;
472
						previousNode = pastNode;
267
						break;
473
						break;
268
					}
474
					}
Lines 271-277 Link Here
271
				if (previousNode == null) {
477
				if (previousNode == null) {
272
					previousNode = graphContainer;
478
					previousNode = graphContainer;
273
				}
479
				}
274
				int previousLocation = previousNode.getBounds().y + previousNode.getBounds().height + 2;
480
				int previousLocation = previousNode.getBounds().y
481
						+ previousNode.getBounds().height + 2;
275
482
276
				orderedNodesBelowY.remove(i);
483
				orderedNodesBelowY.remove(i);
277
				node.setLocation(node.getLocation().x, previousLocation);
484
				node.setLocation(node.getLocation().x, previousLocation);
Lines 283-302 Link Here
283
	}
490
	}
284
491
285
	/**
492
	/**
286
	 * Open the container.  This opens the graph container to 
493
	 * Open the container. This opens the graph container to show the nodes
287
	 * show the nodes within and update the twistie
494
	 * within and update the twistie
288
	 */
495
	 */
289
	public void open(boolean animate) {
496
	public void open(boolean animate) {
497
		if (isLayoutScheduled) {
498
			internalApplyLayout();
499
		}
500
290
		if (animate) {
501
		if (animate) {
291
			Animation.markBegin();
502
			Animation.markBegin();
292
		}
503
		}
293
		isExpanded = true;
504
		isExpanded = true;
294
505
295
		expandGraphLabel.setExpandedState(ExpandGraphLabel.OPEN);
506
		expandGraphLabel.setExpandedState(true);
296
507
297
		scrollPane.setSize(computeChildArea());
508
		scrollPane.setSize(computeChildArea());
298
		scrollPane.setVisible(true);
509
		scrollPane.setVisible(true);
299
		//setSize(expandGraphLabel.getSize().width, expandGraphLabel.getSize().height + expandedHeight - SUBLAYER_OFFSET);
300
510
301
		List children = this.zestLayer.getChildren();
511
		List children = this.zestLayer.getChildren();
302
		for (Iterator iterator = children.iterator(); iterator.hasNext();) {
512
		for (Iterator iterator = children.iterator(); iterator.hasNext();) {
Lines 307-323 Link Here
307
517
308
		updateFigureForModel(nodeFigure);
518
		updateFigureForModel(nodeFigure);
309
519
310
		Rectangle containerBounds = new Rectangle(this.getLocation(), new Dimension(this.getSize().width, CONTAINER_HEIGHT + this.expandGraphLabel.getSize().height));
520
		Rectangle containerBounds = new Rectangle(this.getLocation(),
311
		//moveIntersectedNodes(containerBounds, this);
521
				new Dimension(this.getSize().width, CONTAINER_HEIGHT
522
						+ this.expandGraphLabel.getSize().height));
312
		moveNodesDown(containerBounds, this);
523
		moveNodesDown(containerBounds, this);
313
		moveNodesUp(containerBounds, this);
524
		moveNodesUp(containerBounds, this);
314
		//pack(graph);
315
		if (animate) {
525
		if (animate) {
316
			Animation.run(ANIMATION_TIME);
526
			Animation.run(ANIMATION_TIME);
317
		}
527
		}
318
		this.getFigure().getUpdateManager().performValidation();
528
		this.getFigure().getUpdateManager().performValidation();
319
		//this.nodeFigure.getUpdateManager().performUpdate();
320
321
	}
529
	}
322
530
323
	/**
531
	/**
Lines 325-334 Link Here
325
	 * @param containerBounds
533
	 * @param containerBounds
326
	 * @param graphContainer
534
	 * @param graphContainer
327
	 */
535
	 */
328
	private void moveNodesDown(Rectangle containerBounds, GraphContainer graphContainer) {
536
	private void moveNodesDown(Rectangle containerBounds,
537
			GraphContainer graphContainer) {
329
538
330
		// Find all nodes below here
539
		// Find all nodes below here
331
		List nodesBelowHere = getOrderedNodesBelowY(parent.getNodes(), containerBounds.y, graphContainer);
540
		List nodesBelowHere = getOrderedNodesBelowY(parent.getGraph()
541
				.getNodes(), containerBounds.y, graphContainer);
332
		Iterator nodesBelowHereIterator = nodesBelowHere.iterator();
542
		Iterator nodesBelowHereIterator = nodesBelowHere.iterator();
333
		List nodesToMove = new LinkedList();
543
		List nodesToMove = new LinkedList();
334
		int left = containerBounds.x;
544
		int left = containerBounds.x;
Lines 338-347 Link Here
338
			if (nodeInStripe(left, right, node)) {
548
			if (nodeInStripe(left, right, node)) {
339
				nodesToMove.add(node);
549
				nodesToMove.add(node);
340
				left = Math.min(left, node.getBounds().x);
550
				left = Math.min(left, node.getBounds().x);
341
				right = Math.max(right, node.getBounds().x + node.getBounds().width);
551
				right = Math.max(right, node.getBounds().x
552
						+ node.getBounds().width);
342
			}
553
			}
343
		}
554
		}
344
		List intersectingNodes = intersectingNodes(containerBounds, nodesToMove, graphContainer);
555
		List intersectingNodes = intersectingNodes(containerBounds,
556
				nodesToMove, graphContainer);
345
		int delta = getMaxMovement(containerBounds, intersectingNodes);
557
		int delta = getMaxMovement(containerBounds, intersectingNodes);
346
		if (delta > 0) {
558
		if (delta > 0) {
347
			shiftNodesDown(nodesToMove, delta);
559
			shiftNodesDown(nodesToMove, delta);
Lines 349-398 Link Here
349
561
350
	}
562
	}
351
563
352
	void highlightNode(GraphNode node) {
353
354
	}
355
356
	void highlightEdge(GraphConnection connection) {
357
	}
358
359
	void highlightNode(GraphContainer container) {
360
361
	}
362
363
	void unhighlightNode(GraphNode node) {
364
365
	}
366
367
	void unhighlightNode(GraphContainer container) {
368
369
	}
370
371
//	/**
372
//	 * Gets a list of nodes below the given node
373
//	 * @param node
374
//	 * @return
375
//	 */
376
//	private List getNodesBelow(int y, List nodes) {
377
//		Iterator allNodes = nodes.iterator();
378
//		LinkedList result = new LinkedList();
379
//		while (allNodes.hasNext()) {
380
//			GraphNode nextNode = (GraphNode) allNodes.next();
381
//			int top = nextNode.getLocation().y;
382
//			if (top > y) {
383
//				result.add(nextNode);
384
//			}
385
//		}
386
//		return result;
387
//	}
388
389
	/**
564
	/**
390
	 * Checks all the nodes in the list of nodesToCheck to see if they intersect with the bounds set
565
	 * Checks all the nodes in the list of nodesToCheck to see if they intersect
566
	 * with the bounds set
567
	 * 
391
	 * @param node
568
	 * @param node
392
	 * @param nodesToCheck
569
	 * @param nodesToCheck
393
	 * @return
570
	 * @return
394
	 */
571
	 */
395
	private List intersectingNodes(Rectangle bounds, List nodesToCheck, GraphNode node) {
572
	private List intersectingNodes(Rectangle bounds, List nodesToCheck,
573
			GraphNode node) {
396
		List result = new LinkedList();
574
		List result = new LinkedList();
397
		Iterator nodes = nodesToCheck.iterator();
575
		Iterator nodes = nodesToCheck.iterator();
398
		while (nodes.hasNext()) {
576
		while (nodes.hasNext()) {
Lines 408-414 Link Here
408
	}
586
	}
409
587
410
	/**
588
	/**
411
	 * Gets the max distance the intersecting nodes need to be shifted to make room for the expanding node
589
	 * Gets the max distance the intersecting nodes need to be shifted to make
590
	 * room for the expanding node
591
	 * 
412
	 * @param bounds
592
	 * @param bounds
413
	 * @param nodesToMove
593
	 * @param nodesToMove
414
	 * @return
594
	 * @return
Lines 427-432 Link Here
427
607
428
	/**
608
	/**
429
	 * Shifts a collection of nodes down.
609
	 * Shifts a collection of nodes down.
610
	 * 
430
	 * @param nodesToShift
611
	 * @param nodesToShift
431
	 * @param amount
612
	 * @param amount
432
	 */
613
	 */
Lines 435-498 Link Here
435
		while (iterator.hasNext()) {
616
		while (iterator.hasNext()) {
436
			GraphNode node = (GraphNode) iterator.next();
617
			GraphNode node = (GraphNode) iterator.next();
437
618
438
			node.setLocation(node.getLocation().x, node.getLocation().y + amount);
619
			node.setLocation(node.getLocation().x, node.getLocation().y
620
					+ amount);
439
		}
621
		}
440
	}
622
	}
441
623
442
//	/**
443
//	 * This finds the highest Y Value of a set of nodes.
444
//	 * @param nodes
445
//	 * @return
446
//	 */
447
//	private int findSmallestYValue(List nodes) {
448
//		Iterator iterator = nodes.iterator();
449
//		int lowestNode /*highest on the screen*/= Integer.MAX_VALUE - 100; // Subtract 100 so we don't overflow
450
//		while (iterator.hasNext()) {
451
//			GraphNode node = (GraphNode) iterator.next();
452
//			int y = node.getLocation().y;
453
//			lowestNode = Math.min(lowestNode, y);
454
//		}
455
//		return lowestNode;
456
//	}
457
458
//	/**
459
//	 * Clears the nodes that the container intersects as it expands
460
//	 * @param containerBounds
461
//	 * @param graphContainer
462
//	 */
463
//	private void moveIntersectedNodes(Rectangle containerBounds, GraphNode graphContainer) {
464
//
465
//		List nodesBelowHere = getNodesBelow(this.getLocation().y, graphContainer.getGraphModel().getNodes());
466
//		List intersectingNodes = intersectingNodes(containerBounds, nodesBelowHere, graphContainer);
467
//		int delta = getMaxMovement(containerBounds, intersectingNodes);
468
//		shiftNodesDown(intersectingNodes, delta);
469
//
470
//		int lowestNode /*highest on the screen*/= findSmallestYValue(intersectingNodes);
471
//		nodesBelowHere = getNodesBelow(lowestNode, nodesBelowHere);
472
//
473
//		while (nodesBelowHere.size() > 0) {
474
//			Iterator intersectingNodeIterator = intersectingNodes.iterator();
475
//			List nodesMovedInLastIteration = new LinkedList();
476
//			while (intersectingNodeIterator.hasNext()) {
477
//				GraphNode node = (GraphNode) intersectingNodeIterator.next();
478
//				intersectingNodes = intersectingNodes(node.getBounds(), nodesBelowHere, node);
479
//				delta = getMaxMovement(node.getBounds(), intersectingNodes);
480
//				if (delta > 0) {
481
//					shiftNodesDown(intersectingNodes, delta);
482
//					nodesMovedInLastIteration.addAll(intersectingNodes);
483
//				}
484
//			}
485
//			lowestNode /*highest on the screen*/= findSmallestYValue(nodesMovedInLastIteration);
486
//			nodesBelowHere = getNodesBelow(lowestNode, nodesBelowHere);
487
//			intersectingNodes = nodesMovedInLastIteration;
488
//		}
489
//	}
490
491
	/**
624
	/**
492
	 * Gets the graph that this container has been added to.
625
	 * Gets the graph that this container has been added to.
493
	 */
626
	 */
494
	public Graph getGraph() {
627
	public Graph getGraph() {
495
		return this.graph.getGraph();
628
		return this.graph;
629
	}
630
631
	/**
632
	 * @since 2.0
633
	 */
634
	public Widget getItem() {
635
		return this;
496
	}
636
	}
497
637
498
	public int getItemType() {
638
	public int getItemType() {
Lines 500-565 Link Here
500
	}
640
	}
501
641
502
	/**
642
	/**
503
	 * 
643
	 * @since 2.0
504
	 */
644
	 */
505
	public void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean applyLayout) {
645
	public void setLayoutAlgorithm(LayoutAlgorithm algorithm,
646
			boolean applyLayout) {
647
		if (this.layoutAlgorithm != null) {
648
			this.layoutAlgorithm.setLayoutContext(null);
649
		}
650
506
		this.layoutAlgorithm = algorithm;
651
		this.layoutAlgorithm = algorithm;
652
		this.layoutAlgorithm.setLayoutContext(getLayoutContext());
507
		if (applyLayout) {
653
		if (applyLayout) {
508
			applyLayout();
654
			applyLayout();
509
		}
655
		}
510
511
	}
656
	}
512
657
513
	public void applyLayout() {
658
	/**
514
		if ((this.getNodes().size() == 0)) {
659
	 * @noreference This method is not intended to be referenced by clients.
515
			return;
660
	 */
661
	public InternalLayoutContext getLayoutContext() {
662
		if (layoutContext == null) {
663
			layoutContext = new InternalLayoutContext(this);
516
		}
664
		}
665
		return layoutContext;
666
	}
517
667
518
		int layoutStyle = 0;
668
	/**
669
	 * @since 2.0
670
	 */
671
	public DisplayIndependentRectangle getLayoutBounds() {
672
		double width = GraphContainer.SCALED_WIDTH;
673
		double height = GraphContainer.SCALED_HEIGHT;
674
		return new DisplayIndependentRectangle(0, 0, width, height);
675
	}
519
676
520
		if (checkStyle(ZestStyles.NODES_NO_LAYOUT_RESIZE)) {
677
	public void applyLayout() {
521
			layoutStyle = LayoutStyles.NO_LAYOUT_NODE_RESIZING;
678
		if (isExpanded) {
679
			internalApplyLayout();
680
		} else {
681
			isLayoutScheduled = true;
522
		}
682
		}
683
	}
523
684
685
	private void internalApplyLayout() {
686
		isLayoutScheduled = false;
524
		if (layoutAlgorithm == null) {
687
		if (layoutAlgorithm == null) {
525
			layoutAlgorithm = new TreeLayoutAlgorithm(layoutStyle);
688
			setLayoutAlgorithm(new TreeLayoutAlgorithm(), false);
526
		}
527
528
		layoutAlgorithm.setStyle(layoutAlgorithm.getStyle() | layoutStyle);
529
530
		// calculate the size for the layout algorithm
531
		//Dimension d = this.scalledLayer.getSize();
532
		Dimension d = new Dimension();
533
		d.width = (int) scaledWidth;
534
		d.height = (int) scaledHeight;
535
536
		d.width = d.width - 10;
537
		d.height = d.height - 10;
538
		//if (d.height <= 0) {
539
		//d.height = (CONTAINER_HEIGHT);
540
		//}
541
		//d.scale(1 / this.scalledLayer.getScale());
542
543
		if (d.isEmpty()) {
544
			return;
545
		}
546
		LayoutRelationship[] connectionsToLayout = getGraph().getConnectionsToLayout(getNodes());
547
		LayoutEntity[] nodesToLayout = getGraph().getNodesToLayout(getNodes());
548
549
		try {
550
			Animation.markBegin();
551
			layoutAlgorithm.applyLayout(nodesToLayout, connectionsToLayout, 25, 25, d.width - 50, d.height - 50, false, false);
552
			Animation.run(ANIMATION_TIME);
553
			getFigure().getUpdateManager().performUpdate();
554
555
		} catch (InvalidLayoutConfiguration e) {
556
			e.printStackTrace();
557
		}
689
		}
558
690
		Animation.markBegin();
691
		layoutAlgorithm.applyLayout(true);
692
		layoutContext.flushChanges(false);
693
		Animation.run(ANIMATION_TIME);
694
		getFigure().getUpdateManager().performUpdate();
559
	}
695
	}
560
696
561
	/**
697
	/**
562
	 * Get the scale for this container. This is the scale applied to the children contained within
698
	 * Get the scale for this container. This is the scale applied to the
699
	 * children contained within
700
	 * 
563
	 * @return
701
	 * @return
564
	 */
702
	 */
565
	public double getScale() {
703
	public double getScale() {
Lines 567-573 Link Here
567
	}
705
	}
568
706
569
	/**
707
	/**
570
	 * Set the scale for this container. This is the scale applied to the children contained within.
708
	 * Set the scale for this container. This is the scale applied to the
709
	 * children contained within.
710
	 * 
571
	 * @param scale
711
	 * @param scale
572
	 */
712
	 */
573
	public void setScale(double scale) {
713
	public void setScale(double scale) {
Lines 582-589 Link Here
582
	}
722
	}
583
723
584
	/**
724
	/**
585
	 * This is a small class to help represent the size of the container.  It should only be
725
	 * This is a small class to help represent the size of the container. It
586
	 * used in the computeContainerSize method.
726
	 * should only be used in the computeContainerSize method.
587
	 */
727
	 */
588
	class ContainerDimension {
728
	class ContainerDimension {
589
		int width;
729
		int width;
Lines 593-611 Link Here
593
733
594
	/**
734
	/**
595
	 * Computes size of the scroll pane that the child nodes will be placed in.
735
	 * Computes size of the scroll pane that the child nodes will be placed in.
736
	 * 
596
	 * @return
737
	 * @return
597
	 */
738
	 */
598
	private Dimension computeChildArea() {
739
	private Dimension computeChildArea() {
599
		ContainerDimension containerDimension = computeContainerSize();
740
		ContainerDimension containerDimension = computeContainerSize();
600
		Dimension dimension = new Dimension();
741
		Dimension dimension = new Dimension();
601
		dimension.width = containerDimension.width;
742
		dimension.width = containerDimension.width;
602
		dimension.height = containerDimension.expandedHeight - containerDimension.labelHeight + SUBLAYER_OFFSET;
743
		dimension.height = containerDimension.expandedHeight
744
				- containerDimension.labelHeight + SUBLAYER_OFFSET;
603
		return dimension;
745
		return dimension;
604
	}
746
	}
605
747
606
	/**
748
	/**
607
	 * Computes the desired size of the container.  This method uses the 
749
	 * Computes the desired size of the container. This method uses the minimum
608
	 * minimum size, label size and setSize to compute the size.
750
	 * size, label size and setSize to compute the size.
751
	 * 
609
	 * @return
752
	 * @return
610
	 */
753
	 */
611
	private ContainerDimension computeContainerSize() {
754
	private ContainerDimension computeContainerSize() {
Lines 616-651 Link Here
616
			labelWidth = MIN_WIDTH;
759
			labelWidth = MIN_WIDTH;
617
			expandGraphLabel.setPreferredSize(labelWidth, labelHeight);
760
			expandGraphLabel.setPreferredSize(labelWidth, labelHeight);
618
		}
761
		}
619
		if (labelHeight < 30) {
620
			labelHeight = 30;
621
		}
622
762
623
		dimension.labelHeight = labelHeight;
763
		dimension.labelHeight = Math.max(labelHeight, MIN_HEIGHT);
624
		dimension.width = labelWidth;
764
		dimension.width = Math.max(labelWidth, this.size.width);
625
		dimension.width = Math.max(dimension.width, this.size.width);
765
		dimension.expandedHeight = Math.max(dimension.labelHeight
626
		dimension.expandedHeight = dimension.labelHeight + childAreaHeight - SUBLAYER_OFFSET;
766
				+ childAreaHeight - SUBLAYER_OFFSET, this.size.height);
627
		dimension.expandedHeight = Math.max(dimension.expandedHeight, this.size.height);
628
767
629
		return dimension;
768
		return dimension;
630
	}
769
	}
631
770
632
	/*
633
	private double computeChildScale() {
634
		Dimension childArea = computeChildArea();
635
		double widthScale = childArea.width / scaledWidth;
636
		double heightScale = childArea.height / scaledHeight;
637
		return Math.min(widthScale, heightScale);
638
	}
639
	*/
640
	private double computeHeightScale() {
771
	private double computeHeightScale() {
641
		Dimension childArea = computeChildArea();
772
		Dimension childArea = computeChildArea();
642
		double heightScale = childArea.height / scaledHeight;
773
		double heightScale = childArea.height / SCALED_HEIGHT;
643
		return heightScale;
774
		return heightScale;
644
	}
775
	}
645
776
646
	private double computeWidthScale() {
777
	private double computeWidthScale() {
647
		Dimension childArea = computeChildArea();
778
		Dimension childArea = computeChildArea();
648
		double widthScale = childArea.width / scaledWidth;
779
		double widthScale = childArea.width / SCALED_WIDTH;
649
		return widthScale;
780
		return widthScale;
650
	}
781
	}
651
782
Lines 657-663 Link Here
657
		containerFigure.addLayoutListener(LayoutAnimator.getDefault());
788
		containerFigure.addLayoutListener(LayoutAnimator.getDefault());
658
789
659
		containerFigure.setLayoutManager(new FreeformLayout());
790
		containerFigure.setLayoutManager(new FreeformLayout());
660
		expandGraphLabel = new ExpandGraphLabel(this, node.getText(), node.getImage(), false);
791
		expandGraphLabel = new ExpandGraphLabel(this, node.getText(), node
792
				.getImage(), false);
661
		expandGraphLabel.setText(getText());
793
		expandGraphLabel.setText(getText());
662
		expandGraphLabel.setImage(getImage());
794
		expandGraphLabel.setImage(getImage());
663
		ContainerDimension containerDimension = computeContainerSize();
795
		ContainerDimension containerDimension = computeContainerSize();
Lines 666-718 Link Here
666
		scrollPane.addLayoutListener(LayoutAnimator.getDefault());
798
		scrollPane.addLayoutListener(LayoutAnimator.getDefault());
667
799
668
		Viewport viewport = new FreeformViewport();
800
		Viewport viewport = new FreeformViewport();
669
		/*
670
		 * This is the code that helps remove the scroll bars moving when the nodes
671
		 * are dragged.  
672
		 *
673
		viewport.setHorizontalRangeModel(new DefaultRangeModel() {
674
			public void setAll(int min, int ext, int max) {
675
				System.out.println("Max: " + max + " : current Max:  " + getMaximum());
676
				if (max < getMaximum()) {
677
					max = getMaximum();
678
				}
679
				super.setAll(min, ext, max);
680
			}
681
682
			public void setMaximum(int maximum) {
683
				// TODO Auto-generated method stub
684
				System.out.println("Max: " + maximum + " : current Max:  " + getMaximum());
685
				if (maximum < getMaximum()) {
686
					return;
687
				}
688
				super.setMaximum(maximum);
689
			}
690
		});
691
		*/
692
801
693
		scrollPane.setViewport(viewport);
802
		scrollPane.setViewport(viewport);
694
		viewport.addLayoutListener(LayoutAnimator.getDefault());
803
		viewport.addLayoutListener(LayoutAnimator.getDefault());
695
		scrollPane.setScrollBarVisibility(ScrollPane.AUTOMATIC);
804
		scrollPane.setScrollBarVisibility(ScrollPane.AUTOMATIC);
696
805
697
		//scalledLayer = new ScalableFreeformLayeredPane();
698
		scalledLayer = new AspectRatioFreeformLayer("debug label");
806
		scalledLayer = new AspectRatioFreeformLayer("debug label");
699
		scalledLayer.addLayoutListener(LayoutAnimator.getDefault());
807
		scalledLayer.addLayoutListener(LayoutAnimator.getDefault());
700
		//scalledLayer.setScale(computeChildScale());
701
		scalledLayer.setScale(computeWidthScale(), computeHeightScale());
808
		scalledLayer.setScale(computeWidthScale(), computeHeightScale());
702
		//container = new FreeformLayer();
703
		//edgeLayer = new FreeformLayer();
704
		zestLayer = new ZestRootLayer();
809
		zestLayer = new ZestRootLayer();
705
		zestLayer.addLayoutListener(LayoutAnimator.getDefault());
810
		zestLayer.addLayoutListener(LayoutAnimator.getDefault());
706
		//container.addLayoutListener(LayoutAnimator.getDefault());
707
		//edgeLayer.addLayoutListener(LayoutAnimator.getDefault());
708
		//scalledLayer.add(edgeLayer);
709
		//scalledLayer.add(container);
710
		scalledLayer.add(zestLayer);
811
		scalledLayer.add(zestLayer);
711
812
712
		//container.setLayoutManager(new FreeformLayout());
713
		zestLayer.setLayoutManager(new FreeformLayout());
813
		zestLayer.setLayoutManager(new FreeformLayout());
714
		scrollPane.setSize(computeChildArea());
814
		scrollPane.setSize(computeChildArea());
715
		scrollPane.setLocation(new Point(0, containerDimension.labelHeight - SUBLAYER_OFFSET));
815
		scrollPane.setLocation(new Point(0, containerDimension.labelHeight
816
				- SUBLAYER_OFFSET));
716
		scrollPane.setForegroundColor(ColorConstants.gray);
817
		scrollPane.setForegroundColor(ColorConstants.gray);
717
818
718
		expandGraphLabel.setBackgroundColor(getBackgroundColor());
819
		expandGraphLabel.setBackgroundColor(getBackgroundColor());
Lines 728-735 Link Here
728
		return containerFigure;
829
		return containerFigure;
729
	}
830
	}
730
831
832
	private void registerToParent(IContainer parent) {
833
		if (parent.getItemType() == GRAPH) {
834
			createSelectionListener();
835
			parent.getGraph().addSelectionListener(selectionListener);
836
		}
837
	}
838
839
	private void createSelectionListener() {
840
		if (selectionListener == null) {
841
			selectionListener = new SelectionListener() {
842
				public void widgetSelected(SelectionEvent e) {
843
					if (e.item instanceof GraphContainer) {
844
						// set focus to expand label so that pressing space
845
						// opens/closes the last selected container
846
						((GraphContainer) e.item).expandGraphLabel.setFocus();
847
					}
848
				}
849
850
				public void widgetDefaultSelected(SelectionEvent e) {
851
					// ignore
852
				}
853
			};
854
855
		}
856
	}
857
731
	protected void updateFigureForModel(IFigure currentFigure) {
858
	protected void updateFigureForModel(IFigure currentFigure) {
732
859
860
		if (expandGraphLabel == null) {
861
			initFigure();
862
		}
733
		expandGraphLabel.setTextT(getText());
863
		expandGraphLabel.setTextT(getText());
734
		expandGraphLabel.setImage(getImage());
864
		expandGraphLabel.setImage(getImage());
735
		expandGraphLabel.setFont(getFont());
865
		expandGraphLabel.setFont(getFont());
Lines 737-783 Link Here
737
		if (highlighted == HIGHLIGHT_ON) {
867
		if (highlighted == HIGHLIGHT_ON) {
738
			expandGraphLabel.setForegroundColor(getForegroundColor());
868
			expandGraphLabel.setForegroundColor(getForegroundColor());
739
			expandGraphLabel.setBackgroundColor(getHighlightColor());
869
			expandGraphLabel.setBackgroundColor(getHighlightColor());
740
		}
870
		} else {
741
		// @tag ADJACENT : Removed highlight adjacent
742
		/*
743
		else if (highlighted == HIGHLIGHT_ADJACENT) {
744
			expandGraphLabel.setForegroundColor(getForegroundColor());
745
			expandGraphLabel.setBackgroundColor(getHighlightAdjacentColor());
746
		}
747
		*/
748
		else {
749
			expandGraphLabel.setForegroundColor(getForegroundColor());
871
			expandGraphLabel.setForegroundColor(getForegroundColor());
750
			expandGraphLabel.setBackgroundColor(getBackgroundColor());
872
			expandGraphLabel.setBackgroundColor(getBackgroundColor());
751
		}
873
		}
752
874
753
		ContainerDimension containerDimension = computeContainerSize();
875
		ContainerDimension containerDimension = computeContainerSize();
754
876
755
		expandGraphLabel.setSize(containerDimension.width, containerDimension.labelHeight);
877
		expandGraphLabel.setSize(containerDimension.width,
878
				containerDimension.labelHeight);
756
		if (isExpanded) {
879
		if (isExpanded) {
757
			//setSize(expandGraphLabel.getSize().width, expandGraphLabel.getSize().height + expandedHeight - SUBLAYER_OFFSET);
758
			setSize(containerDimension.width, containerDimension.expandedHeight);
880
			setSize(containerDimension.width, containerDimension.expandedHeight);
759
		} else {
881
		} else {
760
			setSize(containerDimension.width, containerDimension.labelHeight);
882
			setSize(containerDimension.width, containerDimension.labelHeight);
761
		}
883
		}
762
		scrollPane.setLocation(new Point(expandGraphLabel.getLocation().x, expandGraphLabel.getLocation().y + containerDimension.labelHeight - SUBLAYER_OFFSET));
884
		scrollPane.setLocation(new Point(expandGraphLabel.getLocation().x,
763
		//scrollPane.setLocation(new Point(0, labelHeight - SUBLAYER_OFFSET));
885
				expandGraphLabel.getLocation().y
764
		//Rectangle bounds = expandGraphLabel.getBounds().getCopy();
886
						+ containerDimension.labelHeight - SUBLAYER_OFFSET));
765
		//Rectangle newBounds = new Rectangle(new Point(bounds.x, bounds.y + labelHeight - SUBLAYER_OFFSET), scrollPane.getSize());
766
		//figure.setConstraint(scrollPane, newBounds);
767
		/*
768
		size.width = labelWidth;
769
		if (scrollPane.getSize().height > 0) {
770
			size.height = labelHeight + scrollPane.getSize().height - SUBLAYER_OFFSET;
771
		} else {
772
			size.height = labelHeight;
773
		}
774
		refreshLocation();
775
		figure.getUpdateManager().performValidation();
776
		*/
777
887
778
	}
888
	}
779
889
780
	protected void refreshLocation() {
890
	void refreshBounds() {
781
		if (nodeFigure == null || nodeFigure.getParent() == null) {
891
		if (nodeFigure == null || nodeFigure.getParent() == null) {
782
			return; // node figure has not been created yet
892
			return; // node figure has not been created yet
783
		}
893
		}
Lines 787-793 Link Here
787
		ContainerDimension containerDimension = computeContainerSize();
897
		ContainerDimension containerDimension = computeContainerSize();
788
		Dimension size = new Dimension();
898
		Dimension size = new Dimension();
789
899
790
		expandGraphLabel.setSize(containerDimension.width, containerDimension.labelHeight);
900
		expandGraphLabel.setSize(containerDimension.width,
901
				containerDimension.labelHeight);
791
		this.childAreaHeight = computeChildArea().height;
902
		this.childAreaHeight = computeChildArea().height;
792
		if (isExpanded) {
903
		if (isExpanded) {
793
			size.width = containerDimension.width;
904
			size.width = containerDimension.width;
Lines 798-835 Link Here
798
		}
909
		}
799
		Rectangle bounds = new Rectangle(loc, size);
910
		Rectangle bounds = new Rectangle(loc, size);
800
		nodeFigure.getParent().setConstraint(nodeFigure, bounds);
911
		nodeFigure.getParent().setConstraint(nodeFigure, bounds);
801
		scrollPane.setLocation(new Point(expandGraphLabel.getLocation().x, expandGraphLabel.getLocation().y + containerDimension.labelHeight - SUBLAYER_OFFSET));
912
		scrollPane.setLocation(new Point(expandGraphLabel.getLocation().x,
913
				expandGraphLabel.getLocation().y
914
						+ containerDimension.labelHeight - SUBLAYER_OFFSET));
802
		scrollPane.setSize(computeChildArea());
915
		scrollPane.setSize(computeChildArea());
803
		scalledLayer.setScale(computeWidthScale(), computeHeightScale());
916
		scalledLayer.setScale(computeWidthScale(), computeHeightScale());
804
	}
917
	}
805
918
806
	void addConnectionFigure(PolylineConnection connection) {
919
	/**
807
		nodeFigure.add(connection);
920
	 * @noreference This method is not intended to be referenced by clients.
808
		//zestLayer.addConnection(connection);
921
	 */
922
	public void addSubgraphFigure(IFigure figure) {
923
		zestLayer.addSubgraph(figure);
924
		graph.subgraphFigures.add(figure);
809
	}
925
	}
810
926
811
	void addNode(GraphNode node) {
927
	void addConnectionFigure(IFigure figure) {
812
		zestLayer.addNode(node.getNodeFigure());
928
		nodeFigure.add(figure);
813
		this.childNodes.add(node);
814
		//container.add(node.getNodeFigure());
815
		//graph.registerItem(node);
816
	}
929
	}
817
930
818
	void addNode(GraphContainer container) {
931
	/**
819
		// Containers cannot be added to other containers (yet)
932
	 * @noreference This method is not intended to be referenced by clients.
933
	 */
934
	public void addNode(GraphNode node) {
935
		zestLayer.addNode(node.getNodeFigure());
936
		this.childNodes.add(node);
937
		node.setVisible(isExpanded);
820
	}
938
	}
821
939
822
	public List getNodes() {
940
	public List getNodes() {
823
		return this.childNodes;
941
		return this.childNodes;
824
	}
942
	}
825
943
826
	void paint() {
944
	/**
827
		Iterator iterator = getNodes().iterator();
945
	 * @since 2.0
946
	 */
947
	public List getConnections() {
948
		return filterConnections(getGraph().getConnections());
828
949
829
		while (iterator.hasNext()) {
830
			GraphNode node = (GraphNode) iterator.next();
831
			node.paint();
832
		}
833
	}
950
	}
834
951
952
	private List filterConnections(List connections) {
953
		List result = new ArrayList();
954
		for (Iterator iterator = connections.iterator(); iterator.hasNext();) {
955
			GraphConnection connection = (GraphConnection) iterator.next();
956
			if (connection.getSource().getParent() == this
957
					&& connection.getDestination().getParent() == this) {
958
				result.add(connection);
959
			}
960
		}
961
		return result;
962
	}
835
}
963
}
(-)src/org/eclipse/zest/core/widgets/GraphNode.java (-328 / +168 lines)
Lines 1-11 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * All rights reserved. This program and the accompanying materials are made
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
8
 * Contributors: The Chisel Group, University of Victoria 
9
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 ******************************************************************************/
10
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
package org.eclipse.zest.core.widgets;
11
12
Lines 13-19 Link Here
13
import java.util.Iterator;
14
import java.util.Iterator;
14
import java.util.List;
15
import java.util.List;
15
16
17
import org.eclipse.draw2d.Animation;
16
import org.eclipse.draw2d.ColorConstants;
18
import org.eclipse.draw2d.ColorConstants;
19
import org.eclipse.draw2d.FigureListener;
17
import org.eclipse.draw2d.IFigure;
20
import org.eclipse.draw2d.IFigure;
18
import org.eclipse.draw2d.Label;
21
import org.eclipse.draw2d.Label;
19
import org.eclipse.draw2d.geometry.Dimension;
22
import org.eclipse.draw2d.geometry.Dimension;
Lines 21-37 Link Here
21
import org.eclipse.draw2d.geometry.Point;
24
import org.eclipse.draw2d.geometry.Point;
22
import org.eclipse.draw2d.geometry.PrecisionPoint;
25
import org.eclipse.draw2d.geometry.PrecisionPoint;
23
import org.eclipse.draw2d.geometry.Rectangle;
26
import org.eclipse.draw2d.geometry.Rectangle;
24
import org.eclipse.swt.SWT;
25
import org.eclipse.swt.graphics.Color;
27
import org.eclipse.swt.graphics.Color;
26
import org.eclipse.swt.graphics.Font;
28
import org.eclipse.swt.graphics.Font;
27
import org.eclipse.swt.graphics.FontData;
28
import org.eclipse.swt.graphics.Image;
29
import org.eclipse.swt.graphics.Image;
29
import org.eclipse.swt.widgets.Display;
30
import org.eclipse.swt.widgets.Display;
30
import org.eclipse.zest.core.widgets.internal.GraphLabel;
31
import org.eclipse.zest.core.widgets.internal.GraphLabel;
31
import org.eclipse.zest.layouts.LayoutEntity;
32
import org.eclipse.zest.core.widgets.internal.ZestRootLayer;
32
import org.eclipse.zest.layouts.constraints.LayoutConstraint;
33
33
34
/*
34
/**
35
 * Simple node class which has the following properties: color, size, location,
35
 * Simple node class which has the following properties: color, size, location,
36
 * and a label. It also has a list of connections and anchors.
36
 * and a label. It also has a list of connections and anchors.
37
 * 
37
 * 
Lines 44-51 Link Here
44
public class GraphNode extends GraphItem {
44
public class GraphNode extends GraphItem {
45
	public static final int HIGHLIGHT_NONE = 0;
45
	public static final int HIGHLIGHT_NONE = 0;
46
	public static final int HIGHLIGHT_ON = 1;
46
	public static final int HIGHLIGHT_ON = 1;
47
	// @tag ADJACENT : Removed highlight adjacent
48
	//public static final int HIGHLIGHT_ADJACENT = 2;
49
47
50
	private int nodeStyle;
48
	private int nodeStyle;
51
49
Lines 55-71 Link Here
55
	private Color foreColor;
53
	private Color foreColor;
56
	private Color backColor;
54
	private Color backColor;
57
	private Color highlightColor;
55
	private Color highlightColor;
58
	// @tag ADJACENT : Removed highlight adjacent
59
	//private Color highlightAdjacentColor;
60
	private Color borderColor;
56
	private Color borderColor;
61
	private Color borderHighlightColor;
57
	private Color borderHighlightColor;
62
	private int borderWidth;
58
	private int borderWidth;
63
	private Point currentLocation;
59
	private PrecisionPoint currentLocation;
64
	protected Dimension size;
60
	protected Dimension size;
65
	private Font font;
61
	private Font font;
66
	private boolean cacheLabel;
62
	private boolean cacheLabel;
67
	private boolean visible = true;
63
	private boolean visible = true;
68
	private LayoutEntity layoutEntity;
69
64
70
	protected Graph graph;
65
	protected Graph graph;
71
	protected IContainer parent;
66
	protected IContainer parent;
Lines 84-120 Link Here
84
		this(graphModel, style, null);
79
		this(graphModel, style, null);
85
	}
80
	}
86
81
87
	public GraphNode(IContainer graphModel, int style, Object data) {
88
		this(graphModel.getGraph(), style, "" /*text*/, null /*image*/, data);
89
	}
90
91
	public GraphNode(IContainer graphModel, int style, String text) {
82
	public GraphNode(IContainer graphModel, int style, String text) {
92
		this(graphModel, style, text, null);
83
		this(graphModel, style, text, null, null);
93
	}
94
95
	public GraphNode(IContainer graphModel, int style, String text, Object data) {
96
		this(graphModel.getGraph(), style, text, null /*image*/, data);
97
	}
84
	}
98
85
99
	public GraphNode(IContainer graphModel, int style, String text, Image image) {
86
	public GraphNode(IContainer graphModel, int style, Object data) {
100
		this(graphModel, style, text, image, null);
87
		this(graphModel, style, "" /* text */, null /* image */, data);
101
	}
88
	}
102
89
103
	public GraphNode(IContainer graphModel, int style, String text, Image image, Object data) {
90
	private GraphNode(IContainer graphModel, int style, String text,
91
			Image image, Object data) {
104
		super(graphModel.getGraph(), style, data);
92
		super(graphModel.getGraph(), style, data);
105
		initModel(graphModel, text, image);
93
		initModel(graphModel, text, image);
106
		if (nodeFigure == null) {
94
		if (nodeFigure == null) {
107
			initFigure();
95
			initFigure();
108
		}
96
		}
109
97
110
		// This is a hack because JAVA sucks!
98
		this.parent.addNode(this);
111
		// I don't want to expose addNode so I can't put it in the
112
		// IContainer interface.  
113
		if (this.parent.getItemType() == GRAPH) {
114
			((Graph) this.parent).addNode(this);
115
		} else if (this.parent.getItemType() == CONTAINER) {
116
			((GraphContainer) this.parent).addNode(this);
117
		}
118
		this.parent.getGraph().registerItem(this);
99
		this.parent.getGraph().registerItem(this);
119
	}
100
	}
120
101
Lines 124-150 Link Here
124
105
125
	static int count = 0;
106
	static int count = 0;
126
107
127
	protected void initModel(IContainer parent, String text, Image image) {
108
	protected void initModel(IContainer graphModel, String text, Image image) {
128
		this.nodeStyle |= parent.getGraph().getNodeStyle();
109
		this.nodeStyle |= graphModel.getGraph().getNodeStyle();
129
		this.parent = parent;
110
		this.parent = graphModel;
130
		this.sourceConnections = new ArrayList();
111
		this.sourceConnections = new ArrayList();
131
		this.targetConnections = new ArrayList();
112
		this.targetConnections = new ArrayList();
132
		this.foreColor = parent.getGraph().DARK_BLUE;
113
		this.foreColor = graphModel.getGraph().DARK_BLUE;
133
		this.backColor = parent.getGraph().LIGHT_BLUE;
114
		this.backColor = graphModel.getGraph().LIGHT_BLUE;
134
		this.highlightColor = parent.getGraph().HIGHLIGHT_COLOR;
115
		this.highlightColor = graphModel.getGraph().HIGHLIGHT_COLOR;
135
		// @tag ADJACENT : Removed highlight adjacent
136
		//this.highlightAdjacentColor = ColorConstants.orange;
137
		this.nodeStyle = SWT.NONE;
138
		this.borderColor = ColorConstants.lightGray;
116
		this.borderColor = ColorConstants.lightGray;
139
		this.borderHighlightColor = ColorConstants.blue;
117
		this.borderHighlightColor = ColorConstants.blue;
140
		this.borderWidth = 1;
118
		this.borderWidth = 1;
141
		this.currentLocation = new PrecisionPoint(0, 0);
119
		this.currentLocation = new PrecisionPoint(0, 0);
142
		this.size = new Dimension(-1, -1);
120
		this.size = new Dimension(-1, -1);
143
		this.font = Display.getDefault().getSystemFont();
121
		this.font = Display.getDefault().getSystemFont();
144
		this.graph = parent.getGraph();
122
		this.graph = graphModel.getGraph();
145
		this.cacheLabel = false;
123
		this.cacheLabel = false;
146
		this.setText(text);
124
		this.setText(text);
147
		this.layoutEntity = new LayoutGraphNode();
148
		if (image != null) {
125
		if (image != null) {
149
			this.setImage(image);
126
			this.setImage(image);
150
		}
127
		}
Lines 162-171 Link Here
162
		return "GraphModelNode: " + getText();
139
		return "GraphModelNode: " + getText();
163
	}
140
	}
164
141
165
	public LayoutEntity getLayoutEntity() {
166
		return layoutEntity;
167
	}
168
169
	/*
142
	/*
170
	 * (non-Javadoc)
143
	 * (non-Javadoc)
171
	 * 
144
	 * 
Lines 178-184 Link Here
178
		super.dispose();
151
		super.dispose();
179
		this.isDisposed = true;
152
		this.isDisposed = true;
180
		while (getSourceConnections().size() > 0) {
153
		while (getSourceConnections().size() > 0) {
181
			GraphConnection connection = (GraphConnection) getSourceConnections().get(0);
154
			GraphConnection connection = (GraphConnection) getSourceConnections()
155
					.get(0);
182
			if (!connection.isDisposed()) {
156
			if (!connection.isDisposed()) {
183
				connection.dispose();
157
				connection.dispose();
184
			} else {
158
			} else {
Lines 186-192 Link Here
186
			}
160
			}
187
		}
161
		}
188
		while (getTargetConnections().size() > 0) {
162
		while (getTargetConnections().size() > 0) {
189
			GraphConnection connection = (GraphConnection) getTargetConnections().get(0);
163
			GraphConnection connection = (GraphConnection) getTargetConnections()
164
					.get(0);
190
			if (!connection.isDisposed()) {
165
			if (!connection.isDisposed()) {
191
				connection.dispose();
166
				connection.dispose();
192
			} else {
167
			} else {
Lines 206-213 Link Here
206
	}
181
	}
207
182
208
	/**
183
	/**
209
	 * Determines if this node has a fixed size or if it is packed to the size of its contents.
184
	 * Determines if this node has a fixed size or if it is packed to the size
210
	 * To set a node to pack, set its size (-1, -1)  
185
	 * of its contents. To set a node to pack, set its size (-1, -1)
186
	 * 
211
	 * @return
187
	 * @return
212
	 */
188
	 */
213
	public boolean isSizeFixed() {
189
	public boolean isSizeFixed() {
Lines 256-262 Link Here
256
	/*
232
	/*
257
	 * (non-Javadoc)
233
	 * (non-Javadoc)
258
	 * 
234
	 * 
259
	 * @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#isSelected()
235
	 * @see
236
	 * org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#isSelected
237
	 * ()
260
	 */
238
	 */
261
	public boolean isSelected() {
239
	public boolean isSelected() {
262
		return selected;
240
		return selected;
Lines 266-274 Link Here
266
	 * Sets the current location for this node.
244
	 * Sets the current location for this node.
267
	 */
245
	 */
268
	public void setLocation(double x, double y) {
246
	public void setLocation(double x, double y) {
269
		currentLocation.x = (int) x;
247
		if (currentLocation.preciseX != x || currentLocation.preciseY != y) {
270
		currentLocation.y = (int) y;
248
			currentLocation.preciseX = x;
271
		refreshLocation();
249
			currentLocation.preciseY = y;
250
			currentLocation.updateInts();
251
			refreshBounds();
252
		}
272
	}
253
	}
273
254
274
	/**
255
	/**
Lines 374-401 Link Here
374
	}
355
	}
375
356
376
	/**
357
	/**
377
	 * Get the highlight adjacent colour for this node. This is the colour that
378
	 * adjacent nodes will get
379
	 */
380
	// @tag ADJACENT : Removed highlight adjacent
381
	/*
382
	public Color getHighlightAdjacentColor() {
383
		return highlightAdjacentColor;
384
	}
385
	*/
386
387
	/**
388
	 * Set the highlight adjacent colour for this node. This is the colour that
389
	 * adjacent node will get.
390
	 */
391
	// @tag ADJACENT : Removed highlight adjacent
392
	/*
393
	public void setHighlightAdjacentColor(Color c) {
394
		this.highlightAdjacentColor = c;
395
	}
396
	*/
397
398
	/**
399
	 * Highlights the node changing the background color and border color. The
358
	 * Highlights the node changing the background color and border color. The
400
	 * source and destination connections are also highlighted, and the adjacent
359
	 * source and destination connections are also highlighted, and the adjacent
401
	 * nodes are highlighted too in a different color.
360
	 * nodes are highlighted too in a different color.
Lines 404-428 Link Here
404
		if (highlighted == HIGHLIGHT_ON) {
363
		if (highlighted == HIGHLIGHT_ON) {
405
			return;
364
			return;
406
		}
365
		}
407
		// @tag ADJACENT : Removed highlight adjacent
366
		IFigure parentFigure = nodeFigure.getParent();
408
		/*
367
		if (parentFigure instanceof ZestRootLayer) {
409
		if (ZestStyles.checkStyle(getNodeStyle(), ZestStyles.NODES_HIGHLIGHT_ADJACENT)) {
368
			((ZestRootLayer) parentFigure).highlightNode(nodeFigure);
410
			for (Iterator iter = sourceConnections.iterator(); iter.hasNext();) {
411
				GraphConnection conn = (GraphConnection) iter.next();
412
				conn.highlight();
413
				conn.getDestination().highlightAdjacent();
414
			}
415
			for (Iterator iter = targetConnections.iterator(); iter.hasNext();) {
416
				GraphConnection conn = (GraphConnection) iter.next();
417
				conn.highlight();
418
				conn.getSource().highlightAdjacent();
419
			}
420
		}
421
		*/
422
		if (parent.getItemType() == GraphItem.CONTAINER) {
423
			((GraphContainer) parent).highlightNode(this);
424
		} else {
425
			((Graph) parent).highlightNode(this);
426
		}
369
		}
427
		highlighted = HIGHLIGHT_ON;
370
		highlighted = HIGHLIGHT_ON;
428
		updateFigureForModel(getNodeFigure());
371
		updateFigureForModel(getNodeFigure());
Lines 433-478 Link Here
433
	 */
376
	 */
434
	public void unhighlight() {
377
	public void unhighlight() {
435
378
436
		// @tag ADJACENT : Removed highlight adjacent
437
		//boolean highlightedAdjacently = (highlighted == HIGHLIGHT_ADJACENT);
438
		if (highlighted == HIGHLIGHT_NONE) {
379
		if (highlighted == HIGHLIGHT_NONE) {
439
			return;
380
			return;
440
		}
381
		}
441
		// @tag ADJACENT : Removed highlight adjacent
382
442
		/*
383
		IFigure parentFigure = nodeFigure.getParent();
443
		if (!highlightedAdjacently) {
384
		if (parentFigure instanceof ZestRootLayer) {
444
			// IF we are highlighted as an adjacent node, we don't need to deal
385
			((ZestRootLayer) parentFigure).unHighlightNode(nodeFigure);
445
			// with our connections.
446
			if (ZestStyles.checkStyle(getNodeStyle(), ZestStyles.NODES_HIGHLIGHT_ADJACENT)) {
447
				// unhighlight the adjacent edges
448
				for (Iterator iter = sourceConnections.iterator(); iter.hasNext();) {
449
					GraphConnection conn = (GraphConnection) iter.next();
450
					conn.unhighlight();
451
					if (conn.getDestination() != this) {
452
						conn.getDestination().unhighlight();
453
					}
454
				}
455
				for (Iterator iter = targetConnections.iterator(); iter.hasNext();) {
456
					GraphConnection conn = (GraphConnection) iter.next();
457
					conn.unhighlight();
458
					if (conn.getSource() != this) {
459
						conn.getSource().unhighlight();
460
					}
461
				}
462
			}
463
		}
464
		*/
465
		if (parent.getItemType() == GraphItem.CONTAINER) {
466
			((GraphContainer) parent).unhighlightNode(this);
467
		} else {
468
			((Graph) parent).unhighlightNode(this);
469
		}
386
		}
387
470
		highlighted = HIGHLIGHT_NONE;
388
		highlighted = HIGHLIGHT_NONE;
471
		updateFigureForModel(nodeFigure);
389
		updateFigureForModel(nodeFigure);
472
390
473
	}
391
	}
474
392
475
	protected void refreshLocation() {
393
	void refreshBounds() {
476
		Point loc = this.getLocation();
394
		Point loc = this.getLocation();
477
		Dimension size = this.getSize();
395
		Dimension size = this.getSize();
478
		Rectangle bounds = new Rectangle(loc, size);
396
		Rectangle bounds = new Rectangle(loc, size);
Lines 480-543 Link Here
480
		if (nodeFigure == null || nodeFigure.getParent() == null) {
398
		if (nodeFigure == null || nodeFigure.getParent() == null) {
481
			return; // node figure has not been created yet
399
			return; // node figure has not been created yet
482
		}
400
		}
483
		//nodeFigure.setBounds(bounds);
484
		nodeFigure.getParent().setConstraint(nodeFigure, bounds);
401
		nodeFigure.getParent().setConstraint(nodeFigure, bounds);
485
	}
486
402
487
	/**
403
		if (isFisheyeEnabled) {
488
	 * Highlights this node using the adjacent highlight color. This only does
404
			Rectangle fishEyeBounds = calculateFishEyeBounds();
489
	 * something if highlighAdjacentNodes is set to true and if the node isn't
405
			if (fishEyeBounds != null) {
490
	 * already highlighted.
406
				fishEyeFigure.getParent().translateToRelative(fishEyeBounds);
491
	 * 
407
				fishEyeFigure.getParent().translateFromParent(fishEyeBounds);
492
	 * @see #setHighlightAdjacentNodes(boolean)
408
				fishEyeFigure.getParent().setConstraint(fishEyeFigure,
493
	 */
409
						fishEyeBounds);
494
	// @tag ADJACENT : removed highlight adjacent
410
			}
495
	/*
496
	public void highlightAdjacent() {
497
		if (highlighted > 0) {
498
			return;
499
		}
500
		highlighted = HIGHLIGHT_ADJACENT;
501
		updateFigureForModel(nodeFigure);
502
		if (parent.getItemType() == GraphItem.CONTAINER) {
503
			((GraphContainer) parent).highlightNode(this);
504
		} else {
505
			((Graph) parent).highlightNode(this);
506
		}
507
	}
508
	*/
509
510
	/**
511
	 * Returns if the nodes adjacent to this node will be highlighted when this
512
	 * node is selected.
513
	 * 
514
	 * @return GraphModelNode
515
	 */
516
	// @tag ADJACENT : Removed highlight adjacent
517
	/*
518
	public boolean isHighlightAdjacentNodes() {
519
		return ZestStyles.checkStyle(nodeStyle, ZestStyles.NODES_HIGHLIGHT_ADJACENT);
520
	}
521
	*/
522
523
	/**
524
	 * Sets if the adjacent nodes to this one should be highlighted when this
525
	 * node is selected.
526
	 * 
527
	 * @param highlightAdjacentNodes
528
	 *            The highlightAdjacentNodes to set.
529
	 */
530
	// @tag ADJACENT : Removed highlight adjacent
531
	/*
532
	public void setHighlightAdjacentNodes(boolean highlightAdjacentNodes) {
533
		if (!highlightAdjacentNodes) {
534
			this.nodeStyle |= ZestStyles.NODES_HIGHLIGHT_ADJACENT;
535
			this.nodeStyle ^= ZestStyles.NODES_HIGHLIGHT_ADJACENT;
536
			return;
537
		}
411
		}
538
		this.nodeStyle |= ZestStyles.NODES_HIGHLIGHT_ADJACENT;
539
	}
412
	}
540
	*/
541
413
542
	public Color getBorderColor() {
414
	public Color getBorderColor() {
543
		return borderColor;
415
		return borderColor;
Lines 572-592 Link Here
572
		}
444
		}
573
		super.setText(string);
445
		super.setText(string);
574
446
575
		if (nodeFigure != null) {
447
		updateFigureForModel(this.nodeFigure);
576
			updateFigureForModel(this.nodeFigure);
577
		}
578
	}
448
	}
579
449
580
	/*
450
	/*
581
	 * (non-Javadoc)
451
	 * (non-Javadoc)
582
	 * 
452
	 * 
583
	 * @see org.eclipse.swt.widgets.Item#setImage(org.eclipse.swt.graphics.Image)
453
	 * @see
454
	 * org.eclipse.swt.widgets.Item#setImage(org.eclipse.swt.graphics.Image)
584
	 */
455
	 */
585
	public void setImage(Image image) {
456
	public void setImage(Image image) {
586
		super.setImage(image);
457
		super.setImage(image);
587
		if (nodeFigure != null) {
458
		updateFigureForModel(nodeFigure);
588
			updateFigureForModel(nodeFigure);
589
		}
590
	}
459
	}
591
460
592
	/**
461
	/**
Lines 611-638 Link Here
611
	 */
480
	 */
612
	public void setNodeStyle(int nodeStyle) {
481
	public void setNodeStyle(int nodeStyle) {
613
		this.nodeStyle = nodeStyle;
482
		this.nodeStyle = nodeStyle;
614
		this.cacheLabel = ((this.nodeStyle & ZestStyles.NODES_CACHE_LABEL) > 0) ? true : false;
483
		this.cacheLabel = ((this.nodeStyle & ZestStyles.NODES_CACHE_LABEL) > 0) ? true
484
				: false;
615
	}
485
	}
616
486
617
	/*
618
	 * (non-Javadoc)
619
	 * 
620
	 * @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setSize(double,
621
	 *      double)
622
	 */
623
	public void setSize(double width, double height) {
487
	public void setSize(double width, double height) {
624
		if ((width != size.width) || (height != size.height)) {
488
		if ((width != size.width) || (height != size.height)) {
625
			size.width = (int) width;
489
			size.width = (int) width;
626
			size.height = (int) height;
490
			size.height = (int) height;
627
			refreshLocation();
491
			refreshBounds();
628
		}
492
		}
629
	}
493
	}
630
494
631
	/*
632
	 * (non-Javadoc)
633
	 * 
634
	 * @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getBorderHighlightColor()
635
	 */
636
	public Color getBorderHighlightColor() {
495
	public Color getBorderHighlightColor() {
637
		return borderHighlightColor;
496
		return borderHighlightColor;
638
	}
497
	}
Lines 645-671 Link Here
645
		this.cacheLabel = cacheLabel;
504
		this.cacheLabel = cacheLabel;
646
	}
505
	}
647
506
648
	public IFigure getNodeFigure() {
507
	IFigure getNodeFigure() {
649
		return this.nodeFigure;
508
		return this.nodeFigure;
650
	}
509
	}
651
510
652
	public void setVisible(boolean visible) {
511
	public void setVisible(boolean visible) {
653
		// graph.addRemoveFigure(this, visible);
654
		this.visible = visible;
512
		this.visible = visible;
655
		this.getFigure().setVisible(visible);
513
		this.getFigure().setVisible(visible);
656
		List sConnections = (this).getSourceConnections();
514
		for (Iterator iterator2 = sourceConnections.iterator(); iterator2
657
		List tConnections = (this).getTargetConnections();
515
				.hasNext();) {
658
		for (Iterator iterator2 = sConnections.iterator(); iterator2.hasNext();) {
659
			GraphConnection connection = (GraphConnection) iterator2.next();
516
			GraphConnection connection = (GraphConnection) iterator2.next();
660
			connection.setVisible(visible);
517
			connection.setVisible(visible);
661
		}
518
		}
662
519
663
		for (Iterator iterator2 = tConnections.iterator(); iterator2.hasNext();) {
520
		for (Iterator iterator2 = targetConnections.iterator(); iterator2
521
				.hasNext();) {
664
			GraphConnection connection = (GraphConnection) iterator2.next();
522
			GraphConnection connection = (GraphConnection) iterator2.next();
665
			connection.setVisible(visible);
523
			connection.setVisible(visible);
666
		}
524
		}
667
	}
525
	}
668
526
527
	public boolean isVisible() {
528
		return visible;
529
	}
530
669
	public int getStyle() {
531
	public int getStyle() {
670
		return super.getStyle() | this.getNodeStyle();
532
		return super.getStyle() | this.getNodeStyle();
671
	}
533
	}
Lines 675-687 Link Here
675
	 **************************************************************************/
537
	 **************************************************************************/
676
538
677
	private IFigure fishEyeFigure = null;
539
	private IFigure fishEyeFigure = null;
678
	private Font fishEyeFont = null;
679
	private boolean isFisheyeEnabled;
540
	private boolean isFisheyeEnabled;
680
541
681
	protected IFigure fishEye(boolean enable, boolean animate) {
542
	protected IFigure fishEye(boolean enable, boolean animate) {
682
		if (isDisposed) {
543
		if (isDisposed) {
683
			// If a fisheyed figure is still left on the canvas, we could get
544
			// If a fisheyed figure is still left on the canvas, we could get
684
			// called once more after the dispose is called.  Since we cleaned
545
			// called once more after the dispose is called. Since we cleaned
685
			// up everything on dispose, we can just return null here.
546
			// up everything on dispose, we can just return null here.
686
			return null;
547
			return null;
687
		}
548
		}
Lines 692-733 Link Here
692
			// Create the fish eye label
553
			// Create the fish eye label
693
			fishEyeFigure = createFishEyeFigure();
554
			fishEyeFigure = createFishEyeFigure();
694
555
695
			// Get the current Bounds
556
			Rectangle rectangle = calculateFishEyeBounds();
696
			Rectangle rectangle = nodeFigure.getBounds().getCopy();
697
557
698
			// Calculate how much we have to expand the current bounds to get to the new bounds
558
			if (rectangle == null) {
699
			Dimension newSize = fishEyeFigure.getPreferredSize();
700
			Rectangle currentSize = rectangle.getCopy();
701
			nodeFigure.translateToAbsolute(currentSize);
702
			int expandedH = (newSize.height - currentSize.height) / 2 + 1;
703
			int expandedW = (newSize.width - currentSize.width) / 2 + 1;
704
			Dimension expandAmount = new Dimension(expandedW, expandedH);
705
			nodeFigure.translateToAbsolute(rectangle);
706
			rectangle.expand(new Insets(expandAmount.height, expandAmount.width, expandAmount.height, expandAmount.width));
707
			if (expandedH <= 0 && expandedW <= 0) {
708
				return null;
559
				return null;
709
			}
560
			}
710
561
711
			FontData fontData = Display.getCurrent().getSystemFont().getFontData()[0];
562
			// Add the fisheye
712
			fontData.height = 12;
563
			this.getGraphModel().fishEye(nodeFigure, fishEyeFigure, rectangle,
713
			fishEyeFont = new Font(Display.getCurrent(), fontData);
564
					true);
714
			fishEyeFigure.setFont(fishEyeFont);
715
716
			//Add the fisheye
717
			this.getGraphModel().fishEye(nodeFigure, fishEyeFigure, rectangle, true);
718
			if (fishEyeFigure != null) {
565
			if (fishEyeFigure != null) {
719
				isFisheyeEnabled = true;
566
				isFisheyeEnabled = true;
720
			}
567
			}
721
			return fishEyeFigure;
568
			return fishEyeFigure;
722
569
723
		} else {
570
		} else {
724
			// Remove the fisheye and dispose the font
725
			this.getGraphModel().removeFishEye(fishEyeFigure, nodeFigure, animate);
726
			if (fishEyeFont != null) {
727
				this.fishEyeFont.dispose();
728
				this.fishEyeFont = null;
729
			}
730
			isFisheyeEnabled = false;
571
			isFisheyeEnabled = false;
572
			this.getGraphModel().removeFishEye(fishEyeFigure, nodeFigure,
573
					animate);
731
			return null;
574
			return null;
732
		}
575
		}
733
	}
576
	}
Lines 740-749 Link Here
740
		return highlighted > 0;
583
		return highlighted > 0;
741
	}
584
	}
742
585
743
	void invokeLayoutListeners(LayoutConstraint constraint) {
744
		graph.invokeConstraintAdapters(this, constraint);
745
	}
746
747
	protected void updateFigureForModel(IFigure currentFigure) {
586
	protected void updateFigureForModel(IFigure currentFigure) {
748
		if (currentFigure == null) {
587
		if (currentFigure == null) {
749
			return;
588
			return;
Lines 755-764 Link Here
755
		GraphLabel figure = (GraphLabel) currentFigure;
594
		GraphLabel figure = (GraphLabel) currentFigure;
756
		IFigure toolTip;
595
		IFigure toolTip;
757
596
758
		if (!checkStyle(ZestStyles.NODES_HIDE_TEXT)) {
597
		if (!checkStyle(ZestStyles.NODES_HIDE_TEXT)
598
				&& !figure.getText().equals(this.getText())) {
759
			figure.setText(this.getText());
599
			figure.setText(this.getText());
760
		}
600
		}
761
		figure.setIcon(getImage());
601
		if (figure.getIcon() != getImage()) {
602
			figure.setIcon(getImage());
603
		}
762
604
763
		if (highlighted == HIGHLIGHT_ON) {
605
		if (highlighted == HIGHLIGHT_ON) {
764
			figure.setForegroundColor(getForegroundColor());
606
			figure.setForegroundColor(getForegroundColor());
Lines 772-778 Link Here
772
614
773
		figure.setBorderWidth(getBorderWidth());
615
		figure.setBorderWidth(getBorderWidth());
774
616
775
		figure.setFont(getFont());
617
		if (figure.getFont() != getFont()) {
618
			figure.setFont(getFont());
619
		}
776
620
777
		if (this.getTooltip() == null && hasCustomTooltip == false) {
621
		if (this.getTooltip() == null && hasCustomTooltip == false) {
778
			// if we have a custom tooltip, don't try and create our own.
622
			// if we have a custom tooltip, don't try and create our own.
Lines 783-836 Link Here
783
		}
627
		}
784
		figure.setToolTip(toolTip);
628
		figure.setToolTip(toolTip);
785
629
786
		refreshLocation();
787
788
		if (isFisheyeEnabled) {
630
		if (isFisheyeEnabled) {
789
			IFigure newFisheyeFigure = createFishEyeFigure();
631
			IFigure newFisheyeFigure = createFishEyeFigure();
790
			if (graph.replaceFishFigure(this.fishEyeFigure, newFisheyeFigure)) {
632
			if (graph.replaceFishFigure(this.fishEyeFigure, newFisheyeFigure)) {
791
				this.fishEyeFigure = newFisheyeFigure;
633
				this.fishEyeFigure = newFisheyeFigure;
792
			}
634
			}
793
		}
635
		}
636
		refreshBounds();
794
	}
637
	}
795
638
796
	protected IFigure createFigureForModel() {
639
	protected IFigure createFigureForModel() {
797
		GraphNode node = this;
640
		GraphNode node = this;
798
		boolean cacheLabel = (this).cacheLabel();
641
		boolean cacheLabel = (this).cacheLabel();
799
		GraphLabel label = new GraphLabel(node.getText(), node.getImage(), cacheLabel);
642
		final GraphLabel label = new GraphLabel(node.getText(),
643
				node.getImage(), cacheLabel);
800
		label.setFont(this.font);
644
		label.setFont(this.font);
801
		if (checkStyle(ZestStyles.NODES_HIDE_TEXT)) {
645
		if (checkStyle(ZestStyles.NODES_HIDE_TEXT)) {
802
			label.setText("");
646
			label.setText("");
803
		}
647
		}
804
		updateFigureForModel(label);
648
		updateFigureForModel(label);
649
		label.addFigureListener(new FigureListener() {
650
			private Dimension previousSize = label.getBounds().getSize();
651
			private PrecisionPoint previousLocation = new PrecisionPoint(
652
					currentLocation);
653
654
			public void figureMoved(IFigure source) {
655
				if (Animation.isAnimating() || getLayout().isMinimized()) {
656
					return;
657
				}
658
				getLayout().refreshSize();
659
				getLayout().refreshLocation();
660
661
				Rectangle newBounds = nodeFigure.getBounds();
662
				if (!newBounds.getSize().equals(previousSize)) {
663
					previousSize = newBounds.getSize();
664
					if (size.width >= 0 && size.height >= 0) {
665
						size = newBounds.getSize();
666
					}
667
					currentLocation = new PrecisionPoint(nodeFigure.getBounds()
668
							.getTopLeft());
669
					parent.getLayoutContext().fireEntityResizedEvent(
670
							getLayout());
671
				} else if (previousLocation.x != newBounds.x
672
						|| previousLocation.y != newBounds.y) {
673
					currentLocation = new PrecisionPoint(nodeFigure.getBounds()
674
							.getTopLeft());
675
					previousLocation = new PrecisionPoint(currentLocation);
676
					parent.getLayoutContext().fireEntityMovedEvent(getLayout());
677
				}
678
			}
679
		});
805
		return label;
680
		return label;
806
	}
681
	}
807
682
808
	private IFigure createFishEyeFigure() {
683
	private IFigure createFishEyeFigure() {
809
		GraphNode node = this;
684
		GraphNode node = this;
810
		boolean cacheLabel = this.cacheLabel();
685
		boolean cacheLabel = this.cacheLabel();
811
		GraphLabel label = new GraphLabel(node.getText(), node.getImage(), cacheLabel);
686
		GraphLabel label = new GraphLabel(node.getText(), node.getImage(),
687
				cacheLabel);
812
688
813
		if (!checkStyle(ZestStyles.NODES_HIDE_TEXT)) {
814
			label.setText(this.getText());
815
		}
816
		label.setIcon(getImage());
817
818
		// @tag TODO: Add border and foreground colours to highlight
819
		// (this.borderColor)
820
		if (highlighted == HIGHLIGHT_ON) {
689
		if (highlighted == HIGHLIGHT_ON) {
821
			label.setForegroundColor(getForegroundColor());
690
			label.setForegroundColor(getForegroundColor());
822
			label.setBackgroundColor(getHighlightColor());
691
			label.setBackgroundColor(getHighlightColor());
692
			label.setBorderColor(getBorderHighlightColor());
823
		} else {
693
		} else {
824
			label.setForegroundColor(getForegroundColor());
694
			label.setForegroundColor(getForegroundColor());
825
			label.setBackgroundColor(getBackgroundColor());
695
			label.setBackgroundColor(getBackgroundColor());
696
			label.setBorderColor(getBorderColor());
826
		}
697
		}
827
698
699
		label.setBorderWidth(getBorderWidth());
828
		label.setFont(getFont());
700
		label.setFont(getFont());
701
829
		return label;
702
		return label;
830
	}
703
	}
831
704
832
	public boolean isVisible() {
705
	private Rectangle calculateFishEyeBounds() {
833
		return visible;
706
		// Get the current Bounds
707
		Rectangle rectangle = nodeFigure.getBounds().getCopy();
708
709
		// Calculate how much we have to expand the current bounds to get to the
710
		// new bounds
711
		Dimension newSize = fishEyeFigure.getPreferredSize();
712
		Rectangle currentSize = rectangle.getCopy();
713
		nodeFigure.translateToAbsolute(currentSize);
714
		int expandedH = Math.max((newSize.height - currentSize.height) / 2 + 1,
715
				0);
716
		int expandedW = Math
717
				.max((newSize.width - currentSize.width) / 2 + 1, 0);
718
		Dimension expandAmount = new Dimension(expandedW, expandedH);
719
		nodeFigure.translateToAbsolute(rectangle);
720
		rectangle.expand(new Insets(expandAmount.height, expandAmount.width,
721
				expandAmount.height, expandAmount.width));
722
		if (expandedH <= 0 && expandedW <= 0) {
723
			return null;
724
		}
725
		return rectangle;
834
	}
726
	}
835
727
836
	void addSourceConnection(GraphConnection connection) {
728
	void addSourceConnection(GraphConnection connection) {
Lines 873-955 Link Here
873
		return NODE;
765
		return NODE;
874
	}
766
	}
875
767
876
	class LayoutGraphNode implements LayoutEntity {
768
	/**
877
		Object layoutInformation = null;
769
	 * @noreference This method is not intended to be referenced by clients.
878
770
	 */
879
		public double getHeightInLayout() {
771
	public IFigure getFigure() {
880
			return getSize().height;
881
		}
882
883
		public Object getLayoutInformation() {
884
			return layoutInformation;
885
		}
886
887
		public String toString() {
888
			return getText();
889
		}
890
891
		public double getWidthInLayout() {
892
			return getSize().width;
893
		}
894
895
		public double getXInLayout() {
896
			return getLocation().x;
897
		}
898
899
		public double getYInLayout() {
900
			return getLocation().y;
901
		}
902
903
		public void populateLayoutConstraint(LayoutConstraint constraint) {
904
			invokeLayoutListeners(constraint);
905
		}
906
907
		public void setLayoutInformation(Object internalEntity) {
908
			this.layoutInformation = internalEntity;
909
910
		}
911
912
		public void setLocationInLayout(double x, double y) {
913
			setLocation(x, y);
914
		}
915
916
		public void setSizeInLayout(double width, double height) {
917
			setSize(width, height);
918
		}
919
920
		/**
921
		 * Compares two nodes.
922
		 */
923
		public int compareTo(Object otherNode) {
924
			int rv = 0;
925
			if (otherNode instanceof GraphNode) {
926
				GraphNode node = (GraphNode) otherNode;
927
				if (getText() != null) {
928
					rv = getText().compareTo(node.getText());
929
				}
930
			}
931
			return rv;
932
		}
933
934
		public Object getGraphData() {
935
			return GraphNode.this;
936
		}
937
938
		public void setGraphData(Object o) {
939
			// TODO Auto-generated method stub
940
941
		}
942
943
	}
944
945
	IFigure getFigure() {
946
		if (this.nodeFigure == null) {
772
		if (this.nodeFigure == null) {
947
			initFigure();
773
			initFigure();
948
		}
774
		}
949
		return this.getNodeFigure();
775
		return this.getNodeFigure();
950
	}
776
	}
951
777
952
	void paint() {
778
	private InternalNodeLayout layout;
779
780
	/**
781
	 * @noreference This method is not intended to be referenced by clients.
782
	 */
783
	public InternalNodeLayout getLayout() {
784
		if (layout == null) {
785
			layout = new InternalNodeLayout(this);
786
		}
787
		return layout;
788
	}
953
789
790
	void applyLayoutChanges() {
791
		if (layout != null) {
792
			layout.applyLayout();
793
		}
954
	}
794
	}
955
}
795
}
(-)src/org/eclipse/zest/core/widgets/ConstraintAdapter.java (-31 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *******************************************************************************/
11
package org.eclipse.zest.core.widgets;
12
13
import org.eclipse.zest.layouts.constraints.LayoutConstraint;
14
15
/**
16
 * 
17
 * This interface is used to populate layout constraints on Zest nodes.
18
 * Constraint will be a instance of LayoutConstraint (look at the heirarchy for an up-to-date list).
19
 * 
20
 * @author Ian Bull
21
 */
22
public interface ConstraintAdapter {
23
	
24
	/**
25
	 * 
26
	 * @param object
27
	 * @param constraint
28
	 */
29
	public void populateConstraint(Object object, LayoutConstraint constraint);
30
31
}
(-)src/org/eclipse/zest/core/widgets/GraphConnection.java (-126 / +148 lines)
Lines 1-11 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * All rights reserved. This program and the accompanying materials are made
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
8
 * Contributors: The Chisel Group, University of Victoria 
9
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 ******************************************************************************/
10
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
package org.eclipse.zest.core.widgets;
11
12
Lines 28-37 Link Here
28
import org.eclipse.zest.core.widgets.internal.PolylineArcConnection;
29
import org.eclipse.zest.core.widgets.internal.PolylineArcConnection;
29
import org.eclipse.zest.core.widgets.internal.RoundedChopboxAnchor;
30
import org.eclipse.zest.core.widgets.internal.RoundedChopboxAnchor;
30
import org.eclipse.zest.core.widgets.internal.ZestRootLayer;
31
import org.eclipse.zest.core.widgets.internal.ZestRootLayer;
31
import org.eclipse.zest.layouts.LayoutBendPoint;
32
import org.eclipse.zest.layouts.interfaces.ConnectionLayout;
32
import org.eclipse.zest.layouts.LayoutEntity;
33
import org.eclipse.zest.layouts.interfaces.NodeLayout;
33
import org.eclipse.zest.layouts.LayoutRelationship;
34
import org.eclipse.zest.layouts.constraints.LayoutConstraint;
35
34
36
/*
35
/*
37
 * This is the graph connection model which stores the source and destination
36
 * This is the graph connection model which stores the source and destination
Lines 44-51 Link Here
44
public class GraphConnection extends GraphItem {
43
public class GraphConnection extends GraphItem {
45
44
46
	private Font font;
45
	private Font font;
47
	private GraphNode sourceNode;
46
	private final GraphNode sourceNode;
48
	private GraphNode destinationNode;
47
	private final GraphNode destinationNode;
49
48
50
	private double weight;
49
	private double weight;
51
	private Color color;
50
	private Color color;
Lines 53-59 Link Here
53
	private Color foreground;
52
	private Color foreground;
54
	private int lineWidth;
53
	private int lineWidth;
55
	private int lineStyle;
54
	private int lineStyle;
56
	private final Graph graphModel;
55
	private final Graph graph;
57
56
58
	private int connectionStyle;
57
	private int connectionStyle;
59
	private int curveDepth;
58
	private int curveDepth;
Lines 72-81 Link Here
72
	private IFigure tooltip;
71
	private IFigure tooltip;
73
72
74
	private boolean highlighted;
73
	private boolean highlighted;
75
	private GraphLayoutConnection layoutConnection = null;
76
	private boolean hasCustomTooltip;
74
	private boolean hasCustomTooltip;
77
75
78
	public GraphConnection(Graph graphModel, int style, GraphNode source, GraphNode destination) {
76
	public GraphConnection(Graph graphModel, int style, GraphNode source,
77
			GraphNode destination) {
79
		super(graphModel, style);
78
		super(graphModel, style);
80
79
81
		this.connectionStyle |= graphModel.getConnectionStyle();
80
		this.connectionStyle |= graphModel.getConnectionStyle();
Lines 88-97 Link Here
88
		this.highlightColor = graphModel.DARK_BLUE;
87
		this.highlightColor = graphModel.DARK_BLUE;
89
		this.lineWidth = 1;
88
		this.lineWidth = 1;
90
		this.lineStyle = Graphics.LINE_SOLID;
89
		this.lineStyle = Graphics.LINE_SOLID;
91
		setWeight(weight);
90
		this.weight = 1.0;
92
		this.graphModel = graphModel;
91
		this.graph = graphModel;
93
		this.curveDepth = 0;
92
		this.curveDepth = 0;
94
		this.layoutConnection = new GraphLayoutConnection();
95
		this.font = Display.getDefault().getSystemFont();
93
		this.font = Display.getDefault().getSystemFont();
96
		registerConnection(source, destination);
94
		registerConnection(source, destination);
97
	}
95
	}
Lines 106-152 Link Here
106
		(source).addSourceConnection(this);
104
		(source).addSourceConnection(this);
107
		(destination).addTargetConnection(this);
105
		(destination).addTargetConnection(this);
108
106
109
		if (source.getParent().getItemType() == GraphItem.CONTAINER && destination.getParent().getItemType() == GraphItem.CONTAINER && (source.getParent() == destination.getParent())) {
107
		if (source.getParent().getItemType() == GraphItem.CONTAINER
110
			// 196189: Edges should not draw on the edge layer if both the src and dest are in the same container
108
				&& destination.getParent().getItemType() == GraphItem.CONTAINER
109
				&& (source.getParent() == destination.getParent())) {
110
			// 196189: Edges should not draw on the edge layer if both the src
111
			// and dest are in the same container
111
			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=196189
112
			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=196189
112
			graphModel.addConnection(this, ZestRootLayer.EDGES_ON_TOP);
113
			graph.addConnection(this, false);
113
		} else {
114
		} else {
114
			graphModel.addConnection(this, true);
115
			graph.addConnection(this, true);
115
		}
116
		}
116
117
117
		if ((source.getParent()).getItemType() == GraphItem.CONTAINER) {
118
		if ((source.getParent()).getItemType() == GraphItem.CONTAINER) {
118
			// If the container of the source is a container, we need to draw another
119
			// If the container of the source is a container, we need to draw
119
			// arc on that arc layer
120
			// another arc on that arc layer
120
			sourceContainerConnectionFigure = doCreateFigure();
121
			sourceContainerConnectionFigure = doCreateFigure();
121
			((GraphContainer) source.getParent()).addConnectionFigure((PolylineConnection) sourceContainerConnectionFigure);
122
			((GraphContainer) source.getParent())
123
					.addConnectionFigure(sourceContainerConnectionFigure);
122
			this.setVisible(false);
124
			this.setVisible(false);
123
		}
125
		}
124
126
125
		if ((destination.getParent()).getItemType() == GraphItem.CONTAINER) { //&& src_destSameContainer == false) {
127
		if ((destination.getParent()).getItemType() == GraphItem.CONTAINER) {
126
			// If the container of the source is a container, we need to draw another
128
			// If the container of the source is a container, we need to draw
127
			// arc on that arc layer
129
			// another arc on that arc layer
128
			targetContainerConnectionFigure = doCreateFigure();
130
			targetContainerConnectionFigure = doCreateFigure();
129
			((GraphContainer) destination.getParent()).addConnectionFigure((PolylineConnection) targetContainerConnectionFigure);
131
			((GraphContainer) destination.getParent())
132
					.addConnectionFigure(targetContainerConnectionFigure);
130
			this.setVisible(false);
133
			this.setVisible(false);
131
		}
134
		}
132
		graphModel.getGraph().registerItem(this);
135
		graph.registerItem(this);
133
	}
136
	}
134
137
135
	void removeFigure() {
138
	void removeFigure() {
136
		if (connectionFigure.getParent() != null) {
139
		if (connectionFigure.getParent() != null) {
137
			if (connectionFigure.getParent() instanceof ZestRootLayer) {
140
			connectionFigure.getParent().remove(connectionFigure);
138
				((ZestRootLayer) connectionFigure.getParent()).removeConnection(connectionFigure);
139
			} else {
140
				connectionFigure.getParent().remove(connectionFigure);
141
			}
142
		}
141
		}
143
		connectionFigure = null;
142
		connectionFigure = null;
144
		if (sourceContainerConnectionFigure != null) {
143
		if (sourceContainerConnectionFigure != null) {
145
			sourceContainerConnectionFigure.getParent().remove(sourceContainerConnectionFigure);
144
			sourceContainerConnectionFigure.getParent().remove(
145
					sourceContainerConnectionFigure);
146
			sourceContainerConnectionFigure = null;
146
			sourceContainerConnectionFigure = null;
147
		}
147
		}
148
		if (targetContainerConnectionFigure != null) {
148
		if (targetContainerConnectionFigure != null) {
149
			targetContainerConnectionFigure.getParent().remove(targetContainerConnectionFigure);
149
			targetContainerConnectionFigure.getParent().remove(
150
					targetContainerConnectionFigure);
150
			targetContainerConnectionFigure = null;
151
			targetContainerConnectionFigure = null;
151
		}
152
		}
152
153
Lines 157-168 Link Here
157
		this.isDisposed = true;
158
		this.isDisposed = true;
158
		(getSource()).removeSourceConnection(this);
159
		(getSource()).removeSourceConnection(this);
159
		(getDestination()).removeTargetConnection(this);
160
		(getDestination()).removeTargetConnection(this);
160
		graphModel.removeConnection(this);
161
		graph.removeConnection(this);
161
		if (sourceContainerConnectionFigure != null) {
162
		if (sourceContainerConnectionFigure != null) {
162
			sourceContainerConnectionFigure.getParent().remove(sourceContainerConnectionFigure);
163
			sourceContainerConnectionFigure.getParent().remove(
164
					sourceContainerConnectionFigure);
163
		}
165
		}
164
		if (targetContainerConnectionFigure != null) {
166
		if (targetContainerConnectionFigure != null) {
165
			targetContainerConnectionFigure.getParent().remove(targetContainerConnectionFigure);
167
			targetContainerConnectionFigure.getParent().remove(
168
					targetContainerConnectionFigure);
166
		}
169
		}
167
	}
170
	}
168
171
Lines 172-193 Link Here
172
175
173
	public Connection getConnectionFigure() {
176
	public Connection getConnectionFigure() {
174
		if (connectionFigure == null) {
177
		if (connectionFigure == null) {
175
			connectionFigure = createFigure();
178
			connectionFigure = doCreateFigure();
176
		}
179
		}
177
		return connectionFigure;
180
		return connectionFigure;
178
	}
181
	}
179
182
180
	/**
183
	/**
181
	 * Gets a proxy to this connection that can be used with the Zest layout
182
	 * engine
183
	 * 
184
	 * @return
185
	 */
186
	public LayoutRelationship getLayoutRelationship() {
187
		return this.layoutConnection;
188
	}
189
190
	/**
191
	 * Gets the external connection object.
184
	 * Gets the external connection object.
192
	 * 
185
	 * 
193
	 * @return Object
186
	 * @return Object
Lines 202-212 Link Here
202
	 * @return String
195
	 * @return String
203
	 */
196
	 */
204
	public String toString() {
197
	public String toString() {
205
		String arrow = (isBidirectionalInLayout() ? " <--> " : " --> ");
198
		StringBuffer buffer = new StringBuffer("GraphModelConnection: ");
206
		String src = (sourceNode != null ? sourceNode.getText() : "null");
199
		buffer.append(sourceNode != null ? sourceNode.getText() : "null");
207
		String dest = (destinationNode != null ? destinationNode.getText() : "null");
200
		buffer.append(isDirected() ? " --> " : " --- ");
208
		String weight = "  (weight=" + getWeightInLayout() + ")";
201
		buffer.append(destinationNode != null ? destinationNode.getText()
209
		return ("GraphModelConnection: " + src + arrow + dest + weight);
202
				: "null");
203
		buffer.append("  (weight=").append(getWeightInLayout()).append(")");
204
		return buffer.toString();
210
	}
205
	}
211
206
212
	/**
207
	/**
Lines 228-235 Link Here
228
	 * @see #ZestStyles
223
	 * @see #ZestStyles
229
	 */
224
	 */
230
	public void setConnectionStyle(int style) {
225
	public void setConnectionStyle(int style) {
226
		boolean directed = isDirected();
231
		this.connectionStyle = style;
227
		this.connectionStyle = style;
232
		updateFigure(this.connectionFigure);
228
		updateFigure(this.connectionFigure);
229
		if (directed != isDirected()) {
230
			graph.getLayoutContext().fireConnectionDirectedChanged(getLayout());
231
		}
233
	}
232
	}
234
233
235
	/**
234
	/**
Lines 272-277 Link Here
272
	 * 
271
	 * 
273
	 */
272
	 */
274
	public void setWeight(double weight) {
273
	public void setWeight(double weight) {
274
		double previousWeight = this.weight;
275
		if (weight < 0) {
275
		if (weight < 0) {
276
			this.weight = -1;
276
			this.weight = -1;
277
		} else if (weight > 1) {
277
		} else if (weight > 1) {
Lines 279-284 Link Here
279
		} else {
279
		} else {
280
			this.weight = weight;
280
			this.weight = weight;
281
		}
281
		}
282
		if (previousWeight != this.weight) {
283
			graph.getLayoutContext().fireConnectionWeightChanged(getLayout());
284
		}
282
	}
285
	}
283
286
284
	/**
287
	/**
Lines 413-421 Link Here
413
		if (highlighted) {
416
		if (highlighted) {
414
			return;
417
			return;
415
		}
418
		}
419
		IFigure parentFigure = connectionFigure.getParent();
420
		if (parentFigure instanceof ZestRootLayer) {
421
			((ZestRootLayer) parentFigure)
422
					.highlightConnection(connectionFigure);
423
		}
416
		highlighted = true;
424
		highlighted = true;
417
		updateFigure(connectionFigure);
425
		updateFigure(connectionFigure);
418
		graphModel.highlightEdge(this);
419
	}
426
	}
420
427
421
	/**
428
	/**
Lines 425-433 Link Here
425
		if (!highlighted) {
432
		if (!highlighted) {
426
			return;
433
			return;
427
		}
434
		}
435
		IFigure parentFigure = connectionFigure.getParent();
436
		if (parentFigure instanceof ZestRootLayer) {
437
			((ZestRootLayer) parentFigure)
438
					.unHighlightConnection(connectionFigure);
439
		}
428
		highlighted = false;
440
		highlighted = false;
429
		updateFigure(connectionFigure);
441
		updateFigure(connectionFigure);
430
		graphModel.unhighlightEdge(this);
431
	}
442
	}
432
443
433
	/**
444
	/**
Lines 445-469 Link Here
445
	 * @return The graph model that this connection is contained in
456
	 * @return The graph model that this connection is contained in
446
	 */
457
	 */
447
	public Graph getGraphModel() {
458
	public Graph getGraphModel() {
448
		return this.graphModel;
459
		return this.graph;
449
	}
460
	}
450
461
451
	/**
462
	/**
452
	 * Sets the curve depth of the arc.  The curve depth is defined as 
463
	 * Sets the curve depth of the arc. The curve depth is defined as the
453
	 * the maximum distance from any point on the chord (i.e. a vector
464
	 * maximum distance from any point on the chord (i.e. a vector normal to the
454
	 * normal to the chord with magnitude d).
465
	 * chord with magnitude d).
455
	 * 
466
	 * 
456
	 * If 0 is set, a Polyline Connection will be used, otherwise a 
467
	 * If 0 is set, a Polyline Connection will be used, otherwise a
457
	 * PolylineArcConnectoin will be used.  Negative depths are also supported.
468
	 * PolylineArcConnectoin will be used. Negative depths are also supported.
458
	 * @param depth The depth of the curve
469
	 * 
470
	 * @param depth
471
	 *            The depth of the curve
459
	 */
472
	 */
460
	public void setCurveDepth(int depth) {
473
	public void setCurveDepth(int depth) {
461
		if (this.curveDepth == 0 && depth != 0 || this.curveDepth != 0 && depth == 0) {
474
		if (this.curveDepth == 0 && depth != 0 || this.curveDepth != 0
475
				&& depth == 0) {
462
			// There is currently no curve, so we have to create
476
			// There is currently no curve, so we have to create
463
			// a curved connection
477
			// a curved connection
464
			graphModel.removeConnection(this);
478
			graph.removeConnection(this);
465
			this.curveDepth = depth;
479
			this.curveDepth = depth;
466
			this.connectionFigure = createFigure();
480
			this.connectionFigure = doCreateFigure();
467
			registerConnection(sourceNode, destinationNode);
481
			registerConnection(sourceNode, destinationNode);
468
			updateFigure(this.connectionFigure);
482
			updateFigure(this.connectionFigure);
469
		} else {
483
		} else {
Lines 484-493 Link Here
484
	/*
498
	/*
485
	 * (non-Javadoc)
499
	 * (non-Javadoc)
486
	 * 
500
	 * 
487
	 * @see org.eclipse.mylar.zest.core.internal.graphmodel.GraphItem#setVisible(boolean)
501
	 * @see
502
	 * org.eclipse.mylar.zest.core.internal.graphmodel.GraphItem#setVisible(
503
	 * boolean)
488
	 */
504
	 */
489
	public void setVisible(boolean visible) {
505
	public void setVisible(boolean visible) {
490
		//graphModel.addRemoveFigure(this, visible);
491
		if (getSource().isVisible() && getDestination().isVisible() && visible) {
506
		if (getSource().isVisible() && getDestination().isVisible() && visible) {
492
			this.getFigure().setVisible(visible);
507
			this.getFigure().setVisible(visible);
493
			if (sourceContainerConnectionFigure != null) {
508
			if (sourceContainerConnectionFigure != null) {
Lines 532-537 Link Here
532
		}
547
		}
533
	}
548
	}
534
549
550
	/**
551
	 * @since 2.0
552
	 */
553
	public boolean isDirected() {
554
		return ZestStyles.checkStyle(connectionStyle,
555
				ZestStyles.CONNECTIONS_DIRECTED);
556
	}
557
558
	/**
559
	 * @since 2.0
560
	 */
561
	public void setDirected(boolean directed) {
562
		if (directed) {
563
			setConnectionStyle(connectionStyle
564
					| ZestStyles.CONNECTIONS_DIRECTED);
565
		} else {
566
			setConnectionStyle(connectionStyle
567
					& (-1 - ZestStyles.CONNECTIONS_DIRECTED));
568
		}
569
	}
570
535
	PolylineConnection getSourceContainerConnectionFigure() {
571
	PolylineConnection getSourceContainerConnectionFigure() {
536
		return (PolylineConnection) sourceContainerConnectionFigure;
572
		return (PolylineConnection) sourceContainerConnectionFigure;
537
	}
573
	}
Lines 559-565 Link Here
559
		connectionShape.setLineStyle(getLineStyle());
595
		connectionShape.setLineStyle(getLineStyle());
560
596
561
		if (this.getText() != null || this.getImage() != null) {
597
		if (this.getText() != null || this.getImage() != null) {
562
			//Label l = new Label(this.getText(), this.getImage());
563
			if (this.getImage() != null) {
598
			if (this.getImage() != null) {
564
				this.connectionLabel.setIcon(this.getImage());
599
				this.connectionLabel.setIcon(this.getImage());
565
			}
600
			}
Lines 593-599 Link Here
593
		}
628
		}
594
629
595
		IFigure toolTip;
630
		IFigure toolTip;
596
		if (this.getTooltip() == null && getText() != null && getText().length() > 0 && hasCustomTooltip == false) {
631
		if (this.getTooltip() == null && getText() != null
632
				&& getText().length() > 0 && hasCustomTooltip == false) {
597
			toolTip = new Label();
633
			toolTip = new Label();
598
			((Label) toolTip).setText(getText());
634
			((Label) toolTip).setText(getText());
599
		} else {
635
		} else {
Lines 602-625 Link Here
602
		connection.setToolTip(toolTip);
638
		connection.setToolTip(toolTip);
603
	}
639
	}
604
640
605
	private Connection createFigure() {
606
		/*
607
		if ((sourceNode.getParent()).getItemType() == GraphItem.CONTAINER) {
608
			GraphContainer container = (GraphContainer) sourceNode.getParent();
609
			sourceContainerConnectionFigure = doCreateFigure();
610
			container.addConnectionFigure((PolylineConnection) sourceContainerConnectionFigure);
611
		}
612
		if ((destinationNode.getParent()).getItemType() == GraphItem.CONTAINER) {
613
			GraphContainer container = (GraphContainer) destinationNode.getParent();
614
			targetContainerConnectionFigure = doCreateFigure();
615
			container.addConnectionFigure((PolylineConnection) targetContainerConnectionFigure);
616
		}
617
		*/
618
619
		return doCreateFigure();
620
621
	}
622
623
	private Connection doCreateFigure() {
641
	private Connection doCreateFigure() {
624
		Connection connectionFigure = null;
642
		Connection connectionFigure = null;
625
		ChopboxAnchor sourceAnchor = null;
643
		ChopboxAnchor sourceAnchor = null;
Lines 628-635 Link Here
628
		Locator labelLocator = null;
646
		Locator labelLocator = null;
629
647
630
		if (getSource() == getDestination()) {
648
		if (getSource() == getDestination()) {
631
			// If this is a self loop, create a looped arc and put the locator at the top
649
			// If this is a self loop, create a looped arc and put the locator
632
			// of the connection
650
			// at the top of the connection
633
			connectionFigure = new PolylineArcConnection();
651
			connectionFigure = new PolylineArcConnection();
634
			sourceAnchor = new LoopAnchor(getSource().getNodeFigure());
652
			sourceAnchor = new LoopAnchor(getSource().getNodeFigure());
635
			targetAnchor = new LoopAnchor(getDestination().getNodeFigure());
653
			targetAnchor = new LoopAnchor(getDestination().getNodeFigure());
Lines 637-655 Link Here
637
				protected Point getReferencePoint() {
655
				protected Point getReferencePoint() {
638
					Point p = Point.SINGLETON;
656
					Point p = Point.SINGLETON;
639
					p.x = getConnection().getPoints().getPoint(getIndex()).x;
657
					p.x = getConnection().getPoints().getPoint(getIndex()).x;
640
					p.y = (int) (getConnection().getPoints().getPoint(getIndex()).y - (curveDepth * 1.5));
658
					p.y = (int) (getConnection().getPoints().getPoint(
659
							getIndex()).y - (curveDepth * 1.5));
641
					return p;
660
					return p;
642
				}
661
				}
643
			};
662
			};
644
		} else {
663
		} else {
645
			if (curveDepth != 0) {
664
			if (curveDepth != 0) {
646
				connectionFigure = new PolylineArcConnection();
665
				connectionFigure = new PolylineArcConnection();
647
				((PolylineArcConnection) connectionFigure).setDepth(this.curveDepth);
666
				((PolylineArcConnection) connectionFigure)
667
						.setDepth(this.curveDepth);
648
			} else {
668
			} else {
649
				connectionFigure = new PolylineConnection();
669
				connectionFigure = new PolylineConnection();
650
			}
670
			}
651
			sourceAnchor = new RoundedChopboxAnchor(getSource().getNodeFigure(), 8);
671
			sourceAnchor = new RoundedChopboxAnchor(
652
			targetAnchor = new RoundedChopboxAnchor(getDestination().getNodeFigure(), 8);
672
					getSource().getNodeFigure(), 8);
673
			targetAnchor = new RoundedChopboxAnchor(getDestination()
674
					.getNodeFigure(), 8);
653
			labelLocator = new MidpointLocator(connectionFigure, 0);
675
			labelLocator = new MidpointLocator(connectionFigure, 0);
654
		}
676
		}
655
677
Lines 661-718 Link Here
661
		return connectionFigure;
683
		return connectionFigure;
662
	}
684
	}
663
685
664
	/*
686
	IFigure getFigure() {
665
	 * (non-Javadoc)
687
		return this.getConnectionFigure();
666
	 * 
667
	 * @see org.eclipse.mylar.zest.layouts.LayoutRelationship#isBidirectionalInLayout()
668
	 */
669
	private boolean isBidirectionalInLayout() {
670
		return !ZestStyles.checkStyle(connectionStyle, ZestStyles.CONNECTIONS_DIRECTED);
671
	}
688
	}
672
689
673
	class GraphLayoutConnection implements LayoutRelationship {
690
	private InternalConnectionLayout layout;
674
675
		Object layoutInformation = null;
676
691
677
		public void clearBendPoints() {
692
	InternalConnectionLayout getLayout() {
678
			// @tag TODO : add bendpoints
693
		if (layout == null) {
694
			layout = new InternalConnectionLayout();
679
		}
695
		}
696
		return layout;
697
	}
680
698
681
		public LayoutEntity getDestinationInLayout() {
699
	class InternalConnectionLayout implements ConnectionLayout {
682
			return getDestination().getLayoutEntity();
700
		private boolean visible = GraphConnection.this.isVisible();
683
		}
684
701
685
		public Object getLayoutInformation() {
702
		public NodeLayout getSource() {
686
			return layoutInformation;
703
			return sourceNode.getLayout();
687
		}
704
		}
688
705
689
		public LayoutEntity getSourceInLayout() {
706
		public NodeLayout getTarget() {
690
			return getSource().getLayoutEntity();
707
			return destinationNode.getLayout();
691
		}
708
		}
692
709
693
		public void populateLayoutConstraint(LayoutConstraint constraint) {
710
		public double getWeight() {
694
			graphModel.invokeConstraintAdapters(GraphConnection.this, constraint);
711
			return GraphConnection.this.getWeightInLayout();
695
		}
712
		}
696
713
697
		public void setBendPoints(LayoutBendPoint[] bendPoints) {
714
		public boolean isDirected() {
698
			// @tag TODO : add bendpoints
715
			return ZestStyles.checkStyle(getConnectionStyle(),
716
					ZestStyles.CONNECTIONS_DIRECTED);
699
		}
717
		}
700
718
701
		public void setLayoutInformation(Object layoutInformation) {
719
		public boolean isVisible() {
702
			this.layoutInformation = layoutInformation;
720
			return visible;
703
		}
721
		}
704
722
705
		public Object getGraphData() {
723
		public void setVisible(boolean visible) {
706
			return GraphConnection.this;
724
			graph.getLayoutContext().checkChangesAllowed();
725
			this.visible = visible;
707
		}
726
		}
708
727
709
		public void setGraphData(Object o) {
728
		void applyLayout() {
710
729
			if (GraphConnection.this.isVisible() != this.visible) {
730
				GraphConnection.this.setVisible(this.visible);
731
			}
711
		}
732
		}
712
713
	}
733
	}
714
734
715
	IFigure getFigure() {
735
	void applyLayoutChanges() {
716
		return this.getConnectionFigure();
736
		if (layout != null) {
737
			layout.applyLayout();
738
		}
717
	}
739
	}
718
}
740
}
(-)src/org/eclipse/zest/core/widgets/CGraphNode.java (-51 lines)
Removed Link Here
1
package org.eclipse.zest.core.widgets;
2
3
import org.eclipse.draw2d.IFigure;
4
import org.eclipse.swt.graphics.Color;
5
import org.eclipse.swt.graphics.Font;
6
7
/**
8
 * A Custom Graph Node
9
 */
10
public class CGraphNode extends GraphNode {
11
12
	IFigure figure = null;
13
14
	public CGraphNode(IContainer graphModel, int style, IFigure figure) {
15
		super(graphModel, style, figure);
16
	}
17
18
	public IFigure getFigure() {
19
		return super.getFigure();
20
	}
21
22
	protected IFigure createFigureForModel() {
23
		this.figure = (IFigure) this.getData();
24
		return this.figure;
25
	}
26
27
	public void setBackgroundColor(Color c) {
28
		getFigure().setBackgroundColor(c);
29
	}
30
31
	public void setFont(Font font) {
32
		getFigure().setFont(font);
33
	}
34
35
	public Color getBackgroundColor() {
36
		return getFigure().getBackgroundColor();
37
	}
38
39
	public Font getFont() {
40
		return getFigure().getFont();
41
	}
42
43
	public Color getForegroundColor() {
44
		return getFigure().getForegroundColor();
45
	}
46
47
	protected void updateFigureForModel(IFigure currentFigure) {
48
		// Undefined
49
	}
50
51
}
(-)src/org/eclipse/zest/core/widgets/IContainer.java (-37 / +47 lines)
Lines 1-64 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * All rights reserved. This program and the accompanying materials
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * which accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
7
 * 
8
 * Contributors:
8
 * Contributors: The Chisel Group, University of Victoria 
9
 *     The Chisel Group, University of Victoria
9
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
10
 *******************************************************************************/
10
 ******************************************************************************/
11
package org.eclipse.zest.core.widgets;
11
package org.eclipse.zest.core.widgets;
12
12
13
import java.util.List;
13
import java.util.List;
14
14
15
import org.eclipse.draw2d.IFigure;
16
import org.eclipse.swt.widgets.Widget;
15
import org.eclipse.zest.layouts.LayoutAlgorithm;
17
import org.eclipse.zest.layouts.LayoutAlgorithm;
18
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
16
19
17
/**
20
/**
18
 * This interface describes all Zest components that are Containers. This is an internal interface
21
 * @noimplement This interface is not intended to be implemented by clients.
19
 * and thus should not be used outside of Zest.  Implementors of this interface must include the 
20
 * following two methods
21
 *   o addNode(GraphNode)
22
 *   o addNode(GraphContainer)
23
 *   
24
 * These are not actually listed here because Java does not allow protected methods in
25
 * interfaces.
26
 * 
22
 * 
27
 * @author Ian Bull
28
 */
23
 */
29
public interface IContainer {
24
public interface IContainer {
30
25
31
	public Graph getGraph();
26
	public abstract Graph getGraph();
32
33
	// All implementers must include this method
34
	/* protected void addNode(GraphNode node); */
35
27
36
	// All implementers must include this method
28
	/**
37
	/* protected void addNode(GraphContainer container); */
29
	 * @since 2.0
30
	 */
31
	public Widget getItem();
38
32
39
	public int getItemType();
33
	public abstract List getNodes();
40
34
41
	/**
35
	/**
42
	 * Re-applies the current layout algorithm
36
	 * Returns list of connections laying inside this container. Only
37
	 * connections which both source and target nodes lay directly in this
38
	 * container are returned.
39
	 * 
40
	 * @return
41
	 * @since 2.0
43
	 */
42
	 */
44
	public void applyLayout();
43
	public abstract List getConnections();
45
44
46
	/**
45
	/**
47
	 * Sets the LayoutAlgorithm for this container and optionally applies it.
46
	 * @noreference This method is not intended to be referenced by clients.
48
	 *  
47
	 * @param graphNode
49
	 * @param algorithm The layout algorithm to set
50
	 * @param applyLayout 
51
	 */
48
	 */
52
	public void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean applyLayout);
49
	public abstract void addNode(GraphNode graphNode);
53
50
54
	public List getNodes();
51
	/**
52
	 * @noreference This method is not intended to be referenced by clients.
53
	 * @param figure
54
	 */
55
	public abstract void addSubgraphFigure(IFigure figure);
55
56
56
	/* protected void highlightNode(GraphNode node); */
57
	public abstract int getItemType();
57
58
58
	/* protected void highlightNode(GraphContainer container);*/
59
	/**
60
	 * @return
61
	 * @since 2.0
62
	 */
63
	public abstract DisplayIndependentRectangle getLayoutBounds();
59
64
60
	/* protected void unhighlightNode(GraphNode node); */
65
	/**
66
	 * @noreference This method is not intended to be referenced by clients.
67
	 * @return
68
	 */
69
	public abstract InternalLayoutContext getLayoutContext();
61
70
62
	/* protected void unhighlightNode(GraphContainer container);*/
71
	public void applyLayout();
63
72
64
} // end of IContainer
73
	public void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean apply);
74
}
(-)src/org/eclipse/zest/core/widgets/GraphItem.java (-10 / +13 lines)
Lines 1-11 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * All rights reserved. This program and the accompanying materials are made
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
8
 * Contributors: The Chisel Group, University of Victoria 
9
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 ******************************************************************************/
10
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
package org.eclipse.zest.core.widgets;
11
12
Lines 89-103 Link Here
89
	public abstract Graph getGraphModel();
90
	public abstract Graph getGraphModel();
90
91
91
	/**
92
	/**
92
	 * Highlights the current GraphItem.  A graph item is either a graph node or 
93
	 * Highlights the current GraphItem. A graph item is either a graph node or
93
	 * graph connection, and highlighting them will set the appropriate highlight
94
	 * graph connection, and highlighting them will set the appropriate
94
	 * color.
95
	 * highlight color.
95
	 */
96
	 */
96
	public abstract void highlight();
97
	public abstract void highlight();
97
98
98
	/**
99
	/**
99
	 * Unhighlight sets the graphItem (either a graphNode or graphConnection) back
100
	 * Unhighlight sets the graphItem (either a graphNode or graphConnection)
100
	 * to the unhighlight figure or color.
101
	 * back to the unhighlight figure or color.
101
	 */
102
	 */
102
	public abstract void unhighlight();
103
	public abstract void unhighlight();
103
104
Lines 105-111 Link Here
105
106
106
	/**
107
	/**
107
	 * Checks a style to see if it is set on the given graph item
108
	 * Checks a style to see if it is set on the given graph item
108
	 * @param styleToCheck The style to check
109
	 * 
110
	 * @param styleToCheck
111
	 *            The style to check
109
	 * @return
112
	 * @return
110
	 */
113
	 */
111
	protected boolean checkStyle(int styleToCheck) {
114
	protected boolean checkStyle(int styleToCheck) {
(-)META-INF/MANIFEST.MF (-15 / +16 lines)
Lines 1-15 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
Bundle-ManifestVersion: 2
2
Bundle-ManifestVersion: 2
3
Bundle-Name: %Plugin.name
3
Bundle-Name: %Plugin.name
4
Bundle-SymbolicName: org.eclipse.zest.core;singleton:=true
4
Bundle-SymbolicName: org.eclipse.zest.core;singleton:=true
5
Bundle-Vendor: %Plugin.providerName
5
Bundle-Vendor: %Plugin.providerName
6
Bundle-Localization: plugin
6
Bundle-Localization: plugin
7
Bundle-Version: 1.2.0.qualifier
7
Bundle-Version: 2.0.0.qualifier
8
Require-Bundle: org.eclipse.zest.layouts,
8
Require-Bundle: org.eclipse.zest.layouts,
9
 org.eclipse.ui,
9
 org.eclipse.ui,
10
 org.eclipse.draw2d;visibility:=reexport
10
 org.eclipse.draw2d;visibility:=reexport
11
Eclipse-LazyStart: false
11
Eclipse-LazyStart: false
12
Export-Package: org.eclipse.zest.core.viewers,
12
Export-Package: org.eclipse.zest.core.viewers,
13
 org.eclipse.zest.core.widgets
13
 org.eclipse.zest.core.widgets,
14
Import-Package: com.ibm.icu.text;version="[3.8.1,5.0.0)"
14
 org.eclipse.zest.core.widgets.custom
15
Bundle-RequiredExecutionEnvironment: J2SE-1.4
15
Import-Package: com.ibm.icu.text;version="[3.8.1,5.0.0)"
16
Bundle-RequiredExecutionEnvironment: J2SE-1.4
(-)src/org/eclipse/zest/core/widgets/internal/AligningBendpointLocator.java (-43 / +60 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 20-34 Link Here
20
20
21
/**
21
/**
22
 * A locator that finds the middle of a connection based on the bendpoints.
22
 * A locator that finds the middle of a connection based on the bendpoints.
23
 * 
23
 * @author Del Myers
24
 * @author Del Myers
24
 *
25
 * 
25
 */
26
 */
26
//@tag zest(bug(154391-ArcEnds(fix))) : use this locator to ensure that labels will be in the middle of connections.
27
// @tag zest(bug(154391-ArcEnds(fix))) : use this locator to ensure that labels
27
//@tag zest.bug.160368-ConnectionAlign : replaces MidBenpointLocator in order to have finer control over alignment.
28
// will be in the middle of connections.
29
// @tag zest.bug.160368-ConnectionAlign : replaces MidBenpointLocator in order
30
// to have finer control over alignment.
28
public class AligningBendpointLocator extends AbstractLocator {
31
public class AligningBendpointLocator extends AbstractLocator {
29
	/**
32
	/**
30
	 * "Vertical" alignment contstant. Figures should be placed in the middle
33
	 * "Vertical" alignment contstant. Figures should be placed in the middle of
31
	 * of the line.
34
	 * the line.
32
	 */
35
	 */
33
	public static final int MIDDLE = 0;
36
	public static final int MIDDLE = 0;
34
	/**
37
	/**
Lines 39-76 Link Here
39
	 * "Vertical" alignment constant. Figures should be placed below the line.
42
	 * "Vertical" alignment constant. Figures should be placed below the line.
40
	 */
43
	 */
41
	public static final int BELOW = 2;
44
	public static final int BELOW = 2;
42
	
45
43
	/**
46
	/**
44
	 * "Horizontal" alignment constant. Figures should be placed in the center
47
	 * "Horizontal" alignment constant. Figures should be placed in the center
45
	 * of the points on the line.
48
	 * of the points on the line.
46
	 */
49
	 */
47
	public static final int CENTER = 0;
50
	public static final int CENTER = 0;
48
	
51
49
	/**
52
	/**
50
	 * "Horizontal" alignment constant. Figures should be placed at the beginning
53
	 * "Horizontal" alignment constant. Figures should be placed at the
51
	 * of the line. Figures will be anchored so that they have one end at the
54
	 * beginning of the line. Figures will be anchored so that they have one end
52
	 * beginning of the connection, not so that they are centered at the start
55
	 * at the beginning of the connection, not so that they are centered at the
53
	 * point. Which end of the figure is placed at that point will depend
56
	 * start point. Which end of the figure is placed at that point will depend
54
	 * on the direction of the first two points.
57
	 * on the direction of the first two points.
55
	 */
58
	 */
56
	public static final int BEGINNING = 1;
59
	public static final int BEGINNING = 1;
57
	
60
58
	/**
61
	/**
59
	 * "Horizontal" alignment constant. Figures should be placed at the end of
62
	 * "Horizontal" alignment constant. Figures should be placed at the end of
60
	 * the line. Figures will be anchored so that they have one end at the
63
	 * the line. Figures will be anchored so that they have one end at the
61
	 * beginning of the connection, not so that they are centered at the end
64
	 * beginning of the connection, not so that they are centered at the end
62
	 * point. Which end of the figure is placed at that point will depend
65
	 * point. Which end of the figure is placed at that point will depend on the
63
	 * on the direction of the last two points.
66
	 * direction of the last two points.
64
	 */
67
	 */
65
	public static final int END = 2;
68
	public static final int END = 2;
66
	
69
67
	/**
70
	/**
68
	 * "Horizontal" alignment constant. Figures should be centered between the
71
	 * "Horizontal" alignment constant. Figures should be centered between the
69
	 * first two points on the connection. For connections with only two points, 
72
	 * first two points on the connection. For connections with only two points,
70
	 * this will behave the same as CENTER.
73
	 * this will behave the same as CENTER.
71
	 */
74
	 */
72
	public static final int CENTER_BEGINNING = 3;
75
	public static final int CENTER_BEGINNING = 3;
73
	
76
74
	/**
77
	/**
75
	 * "Horizontal" alignment constant. Figures should be centered between the
78
	 * "Horizontal" alignment constant. Figures should be centered between the
76
	 * last two points on the connection. For connections with only two points,
79
	 * last two points on the connection. For connections with only two points,
Lines 80-99 Link Here
80
	private int horizontal;
83
	private int horizontal;
81
	private int vertical;
84
	private int vertical;
82
	private Connection connection;
85
	private Connection connection;
86
83
	/**
87
	/**
84
	 * @param connection
88
	 * @param connection
85
	 */
89
	 */
86
	public AligningBendpointLocator(Connection connection) {
90
	public AligningBendpointLocator(Connection connection) {
87
		this(connection, CENTER, MIDDLE);
91
		this(connection, CENTER, MIDDLE);
88
	}
92
	}
89
	
93
90
	public AligningBendpointLocator(Connection connection, int horizontal, int vertical) {
94
	public AligningBendpointLocator(Connection connection, int horizontal,
95
			int vertical) {
91
		this.connection = connection;
96
		this.connection = connection;
92
		this.horizontal = horizontal;
97
		this.horizontal = horizontal;
93
		this.vertical = vertical;
98
		this.vertical = vertical;
94
	}
99
	}
95
	
100
96
	/* (non-Javadoc)
101
	/*
102
	 * (non-Javadoc)
103
	 * 
97
	 * @see org.eclipse.draw2d.ConnectionLocator#getReferencePoint()
104
	 * @see org.eclipse.draw2d.ConnectionLocator#getReferencePoint()
98
	 */
105
	 */
99
	protected Point getReferencePoint() {
106
	protected Point getReferencePoint() {
Lines 116-122 Link Here
116
			tempPoints = new PointList();
123
			tempPoints = new PointList();
117
			int s = points.size();
124
			int s = points.size();
118
			tempPoints.addPoint(points.getLastPoint().getCopy());
125
			tempPoints.addPoint(points.getLastPoint().getCopy());
119
			tempPoints.addPoint(points.getPoint(s-2).getCopy());
126
			tempPoints.addPoint(points.getPoint(s - 2).getCopy());
120
			p = tempPoints.getMidpoint().getCopy();
127
			p = tempPoints.getMidpoint().getCopy();
121
		case CENTER:
128
		case CENTER:
122
		default:
129
		default:
Lines 124-170 Link Here
124
		}
131
		}
125
		return p;
132
		return p;
126
	}
133
	}
134
127
	/**
135
	/**
128
	 * Recalculates the position of the figure and returns the updated bounds.
136
	 * Recalculates the position of the figure and returns the updated bounds.
129
	 * @param target The figure to relocate
137
	 * 
138
	 * @param target
139
	 *            The figure to relocate
130
	 */
140
	 */
131
	public void relocate(IFigure target) {
141
	public void relocate(IFigure target) {
132
		Dimension prefSize = target.getPreferredSize();
142
		Dimension prefSize = target.getPreferredSize();
133
		Point center = getReferencePoint();
143
		Point center = getReferencePoint();
134
		calculatePosition();
144
		calculatePosition();
135
		//@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
145
		// @tag zest(bug(GEFProblem)) : there seems to be a bug in GEF that if
136
		//target.translateToRelative(center);
146
		// the following is done, then labels get printed in the wrong location
147
		// target.translateToRelative(center);
137
		target.setBounds(getNewBounds(prefSize, center));
148
		target.setBounds(getNewBounds(prefSize, center));
138
	}
149
	}
139
	
150
140
	/**
151
	/**
141
	 * Translates the center point depending on the horizontal and veritical
152
	 * Translates the center point depending on the horizontal and veritical
142
	 * alignments based on the given bounds.
153
	 * alignments based on the given bounds.
154
	 * 
143
	 * @param center
155
	 * @param center
144
	 */
156
	 */
145
	private void calculatePosition() {
157
	private void calculatePosition() {
146
		PointList points = getConnection().getPoints();
158
		PointList points = getConnection().getPoints();
147
		int position = 0;
159
		int position = 0;
148
		switch(horizontal) {
160
		switch (horizontal) {
149
		case BEGINNING:
161
		case BEGINNING:
150
			Point first = points.getFirstPoint();
162
			Point first = points.getFirstPoint();
151
			Point next = points.getPoint(1);
163
			Point next = points.getPoint(1);
152
			if (first.x <= next.x) 
164
			if (first.x <= next.x) {
153
				position |= PositionConstants.EAST;
165
				position |= PositionConstants.EAST;
154
			else
166
			} else {
155
				position |= PositionConstants.WEST;
167
				position |= PositionConstants.WEST;
168
			}
156
			break;
169
			break;
157
		case END:
170
		case END:
158
			Point last = points.getLastPoint();
171
			Point last = points.getLastPoint();
159
			int s = points.size();
172
			int s = points.size();
160
			Point before = points.getPoint(s-1);
173
			Point before = points.getPoint(s - 1);
161
			if (last.x <= before.x) 
174
			if (last.x <= before.x) {
162
				position |= PositionConstants.EAST;
175
				position |= PositionConstants.EAST;
163
			else
176
			} else {
164
				position |= PositionConstants.WEST;
177
				position |= PositionConstants.WEST;
178
			}
165
			break;
179
			break;
166
		}
180
		}
167
		if (position == 0) position = PositionConstants.CENTER;
181
		if (position == 0) {
182
			position = PositionConstants.CENTER;
183
		}
168
		switch (vertical) {
184
		switch (vertical) {
169
		case ABOVE:
185
		case ABOVE:
170
			position |= PositionConstants.NORTH;
186
			position |= PositionConstants.NORTH;
Lines 176-182 Link Here
176
			position |= PositionConstants.MIDDLE;
192
			position |= PositionConstants.MIDDLE;
177
		}
193
		}
178
		setRelativePosition(position);
194
		setRelativePosition(position);
179
		
195
180
	}
196
	}
181
197
182
	/**
198
	/**
Lines 185-214 Link Here
185
	public int getHorizontalAlignment() {
201
	public int getHorizontalAlignment() {
186
		return horizontal;
202
		return horizontal;
187
	}
203
	}
188
	
204
189
	/**
205
	/**
190
	 * @param horizontal the horizontal alignment to set. One of CENTER,
206
	 * @param horizontal
191
	 * BEGINNING, END, CENTER_BEGINNING, or CENTER_END.
207
	 *            the horizontal alignment to set. One of CENTER, BEGINNING,
208
	 *            END, CENTER_BEGINNING, or CENTER_END.
192
	 */
209
	 */
193
	public void setHorizontalAlignment(int horizontal) {
210
	public void setHorizontalAlignment(int horizontal) {
194
		this.horizontal = horizontal;
211
		this.horizontal = horizontal;
195
	}
212
	}
196
	
213
197
	/**
214
	/**
198
	 * @param vertical the vertical alignment to set. One of ABOVE, MIDDLE, or
215
	 * @param vertical
199
	 * BELOW.
216
	 *            the vertical alignment to set. One of ABOVE, MIDDLE, or BELOW.
200
	 */
217
	 */
201
	public void setVerticalAlginment(int vertical) {
218
	public void setVerticalAlginment(int vertical) {
202
		this.vertical = vertical;
219
		this.vertical = vertical;
203
	}
220
	}
204
	
221
205
	/**
222
	/**
206
	 * @return the vertical alginment.
223
	 * @return the vertical alginment.
207
	 */
224
	 */
208
	public int getVerticalAlignment() {
225
	public int getVerticalAlignment() {
209
		return vertical;
226
		return vertical;
210
	}
227
	}
211
	
228
212
	/**
229
	/**
213
	 * @return the connection
230
	 * @return the connection
214
	 */
231
	 */
(-)src/org/eclipse/zest/core/widgets/internal/GraphLabel.java (-22 / +18 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials are made
3
 * All rights reserved. This program and the accompanying materials are made
4
 * available under the terms of the Eclipse Public License v1.0 which
4
 * available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
Lines 58-64 Link Here
58
	 *            faster, but the
58
	 *            faster, but the
59
	 */
59
	 */
60
	public GraphLabel(String text, boolean cacheLabel) {
60
	public GraphLabel(String text, boolean cacheLabel) {
61
		this("", null, cacheLabel);
61
		this(text, null, cacheLabel);
62
	}
62
	}
63
63
64
	/**
64
	/**
Lines 127-137 Link Here
127
			if (font != null) {
127
			if (font != null) {
128
				Dimension minSize = FigureUtilities.getTextExtents(text, font);
128
				Dimension minSize = FigureUtilities.getTextExtents(text, font);
129
				if (getIcon() != null) {
129
				if (getIcon() != null) {
130
					org.eclipse.swt.graphics.Rectangle imageRect = getIcon().getBounds();
130
					org.eclipse.swt.graphics.Rectangle imageRect = getIcon()
131
					int expandHeight = Math.max(imageRect.height - minSize.height, 0);
131
							.getBounds();
132
					int expandHeight = Math.max(imageRect.height
133
							- minSize.height, 0);
132
					minSize.expand(imageRect.width + 4, expandHeight);
134
					minSize.expand(imageRect.width + 4, expandHeight);
133
				}
135
				}
134
				minSize.expand(10 + (2 * safeBorderWidth), 4 + (2 * safeBorderWidth));
136
				minSize.expand(10 + (2 * safeBorderWidth),
137
						4 + (2 * safeBorderWidth));
135
				setBounds(new Rectangle(getLocation(), minSize));
138
				setBounds(new Rectangle(getLocation(), minSize));
136
			}
139
			}
137
		}
140
		}
Lines 155-161 Link Here
155
		green = (int) (green - (green * 0.20));
158
		green = (int) (green - (green * 0.20));
156
		green = green > 0 ? green : 0;
159
		green = green > 0 ? green : 0;
157
160
158
		Color lightenColor = new Color(Display.getCurrent(), new RGB(red, green, blue));
161
		Color lightenColor = new Color(Display.getCurrent(), new RGB(red,
162
				green, blue));
159
		graphics.setForegroundColor(lightenColor);
163
		graphics.setForegroundColor(lightenColor);
160
		graphics.setBackgroundColor(getBackgroundColor());
164
		graphics.setBackgroundColor(getBackgroundColor());
161
165
Lines 166-184 Link Here
166
		if (graphics instanceof ScaledGraphics) {
170
		if (graphics instanceof ScaledGraphics) {
167
			scale = ((ScaledGraphics) graphics).getAbsoluteScale();
171
			scale = ((ScaledGraphics) graphics).getAbsoluteScale();
168
		}
172
		}
169
		// Top part inside the border (as fillGradient does not allow to fill a rectangle with round corners).
173
		// Top part inside the border (as fillGradient does not allow to fill a
174
		// rectangle with round corners).
170
		Rectangle rect = getBounds().getCopy();
175
		Rectangle rect = getBounds().getCopy();
171
		rect.height /= 2;
176
		rect.height /= 2;
172
		graphics.setForegroundColor(getBackgroundColor());
177
		graphics.setForegroundColor(getBackgroundColor());
173
		graphics.setBackgroundColor(getBackgroundColor());
178
		graphics.setBackgroundColor(getBackgroundColor());
174
		graphics.fillRoundRectangle(rect, arcWidth * safeBorderWidth, arcWidth * 2 * safeBorderWidth);
179
		graphics.fillRoundRectangle(rect, arcWidth * safeBorderWidth, arcWidth
180
				* 2 * safeBorderWidth);
175
181
176
		// Bottom part inside the border.
182
		// Bottom part inside the border.
177
		rect.y = rect.y + rect.height;
183
		rect.y = rect.y + rect.height;
178
		rect.height += 1; // Not sure why it is needed, but it is needed ;-)
184
		rect.height += 1; // Not sure why it is needed, but it is needed ;-)
179
		graphics.setForegroundColor(lightenColor);
185
		graphics.setForegroundColor(lightenColor);
180
		graphics.setBackgroundColor(lightenColor);
186
		graphics.setBackgroundColor(lightenColor);
181
		graphics.fillRoundRectangle(rect, arcWidth * safeBorderWidth, arcWidth * 2 * safeBorderWidth);
187
		graphics.fillRoundRectangle(rect, arcWidth * safeBorderWidth, arcWidth
188
				* 2 * safeBorderWidth);
182
189
183
		// Now fill the middle part of top and bottom part with a gradient.
190
		// Now fill the middle part of top and bottom part with a gradient.
184
		rect = bounds.getCopy();
191
		rect = bounds.getCopy();
Lines 235-246 Link Here
235
	 * @see org.eclipse.draw2d.Label#setText(java.lang.String)
242
	 * @see org.eclipse.draw2d.Label#setText(java.lang.String)
236
	 */
243
	 */
237
	public void setText(String s) {
244
	public void setText(String s) {
238
		if (!s.equals("")) {
245
		super.setText(s);
239
			super.setText(s);
240
241
		} else {
242
			super.setText("");
243
		}
244
		adjustBoundsToFit();
246
		adjustBoundsToFit();
245
	}
247
	}
246
248
Lines 251-257 Link Here
251
	 */
253
	 */
252
	public void setIcon(Image image) {
254
	public void setIcon(Image image) {
253
		super.setIcon(image);
255
		super.setIcon(image);
254
		//adjustBoundsToFit();
256
		adjustBoundsToFit();
255
	}
257
	}
256
258
257
	public Color getBorderColor() {
259
	public Color getBorderColor() {
Lines 277-286 Link Here
277
	public void setArcWidth(int arcWidth) {
279
	public void setArcWidth(int arcWidth) {
278
		this.arcWidth = arcWidth;
280
		this.arcWidth = arcWidth;
279
	}
281
	}
280
281
	public void setBounds(Rectangle rect) {
282
		// TODO Auto-generated method stub
283
		super.setBounds(rect);
284
	}
285
286
}
282
}
(-)src/org/eclipse/zest/core/widgets/internal/XYScaledGraphics.java (-34 / +73 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others. All rights reserved.
2
 * Copyright (c) 2005-2009 IBM Corporation and others. All rights reserved.
3
 * This program and the accompanying materials are made available under the
3
 * This program and the accompanying materials are made available under the
4
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
4
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
5
 * and is available at http://www.eclipse.org/legal/epl-v10.html
5
 * and is available at http://www.eclipse.org/legal/epl-v10.html
Lines 39-45 Link Here
39
 */
39
 */
40
public class XYScaledGraphics extends ScaledGraphics {
40
public class XYScaledGraphics extends ScaledGraphics {
41
41
42
	public static final double MAX_TEXT_SIZE = 0.45; // MAX size, when to stop zooming text
42
	public static final double MAX_TEXT_SIZE = 0.45; // MAX size, when to stop
43
44
	// zooming text
43
45
44
	private static class FontHeightCache {
46
	private static class FontHeightCache {
45
		Font font;
47
		Font font;
Lines 80-86 Link Here
80
		private double appliedY;
82
		private double appliedY;
81
		private Font font;
83
		private Font font;
82
		private int lineWidth;
84
		private int lineWidth;
83
		//private double zoom;  // This has been replaced with xZoom and yZoom
85
		// private double zoom; // This has been replaced with xZoom and yZoom
84
		private double xZoom;
86
		private double xZoom;
85
		private double yZoom;
87
		private double yZoom;
86
88
Lines 105-111 Link Here
105
		 * @param lineWidth
107
		 * @param lineWidth
106
		 *            the line width
108
		 *            the line width
107
		 */
109
		 */
108
		protected State(double xZoom, double yZoom, double x, double y, Font font, int lineWidth) {
110
		protected State(double xZoom, double yZoom, double x, double y,
111
				Font font, int lineWidth) {
109
			this.xZoom = xZoom;
112
			this.xZoom = xZoom;
110
			this.yZoom = yZoom;
113
			this.yZoom = yZoom;
111
			this.appliedX = x;
114
			this.appliedX = x;
Lines 128-134 Link Here
128
		 * @param lineWidth
131
		 * @param lineWidth
129
		 *            the line width
132
		 *            the line width
130
		 */
133
		 */
131
		protected void setValues(double xZoom, double yZoom, double x, double y, Font font, int lineWidth) {
134
		protected void setValues(double xZoom, double yZoom, double x,
135
				double y, Font font, int lineWidth) {
132
			this.xZoom = xZoom;
136
			this.xZoom = xZoom;
133
			this.yZoom = yZoom;
137
			this.yZoom = yZoom;
134
			this.appliedX = x;
138
			this.appliedX = x;
Lines 148-154 Link Here
148
	}
152
	}
149
153
150
	private boolean allowText = true;
154
	private boolean allowText = true;
151
	//	private static final Point PT = new Point();
155
	// private static final Point PT = new Point();
152
	private Map fontCache = new HashMap();
156
	private Map fontCache = new HashMap();
153
	private Map fontDataCache = new HashMap();
157
	private Map fontDataCache = new HashMap();
154
	private FontKey fontKey = new FontKey();
158
	private FontKey fontKey = new FontKey();
Lines 189-200 Link Here
189
193
190
	/** @see Graphics#dispose() */
194
	/** @see Graphics#dispose() */
191
	public void dispose() {
195
	public void dispose() {
192
		//Remove all states from the stack
196
		// Remove all states from the stack
193
		while (stackPointer > 0) {
197
		while (stackPointer > 0) {
194
			popState();
198
			popState();
195
		}
199
		}
196
200
197
		//Dispose fonts
201
		// Dispose fonts
198
		Iterator iter = fontCache.values().iterator();
202
		Iterator iter = fontCache.values().iterator();
199
		while (iter.hasNext()) {
203
		while (iter.hasNext()) {
200
			Font font = ((Font) iter.next());
204
			Font font = ((Font) iter.next());
Lines 221-242 Link Here
221
	public void drawImage(Image srcImage, int x, int y) {
225
	public void drawImage(Image srcImage, int x, int y) {
222
		org.eclipse.swt.graphics.Rectangle size = srcImage.getBounds();
226
		org.eclipse.swt.graphics.Rectangle size = srcImage.getBounds();
223
		double imageZoom = Math.min(xZoom, yZoom);
227
		double imageZoom = Math.min(xZoom, yZoom);
224
		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))));
228
		graphics.drawImage(srcImage, 0, 0, size.width, size.height, (int) (Math
229
				.floor((x * xZoom + fractionalX))), (int) (Math.floor((y
230
				* yZoom + fractionalY))), (int) (Math.floor((size.width
231
				* imageZoom + fractionalX))), (int) (Math.floor((size.height
232
				* imageZoom + fractionalY))));
225
	}
233
	}
226
234
227
	/** @see Graphics#drawImage(Image, int, int, int, int, int, int, int, int) */
235
	/** @see Graphics#drawImage(Image, int, int, int, int, int, int, int, int) */
228
	public void drawImage(Image srcImage, int sx, int sy, int sw, int sh, int tx, int ty, int tw, int th) {
236
	public void drawImage(Image srcImage, int sx, int sy, int sw, int sh,
229
		//"t" == target rectangle, "s" = source
237
			int tx, int ty, int tw, int th) {
238
		// "t" == target rectangle, "s" = source
230
239
231
		Rectangle t = zoomRect(tx, ty, tw, th);
240
		Rectangle t = zoomRect(tx, ty, tw, th);
232
		if (!t.isEmpty()) {
241
		if (!t.isEmpty()) {
233
			graphics.drawImage(srcImage, sx, sy, sw, sh, t.x, t.y, t.width, t.height);
242
			graphics.drawImage(srcImage, sx, sy, sw, sh, t.x, t.y, t.width,
243
					t.height);
234
		}
244
		}
235
	}
245
	}
236
246
237
	/** @see Graphics#drawLine(int, int, int, int) */
247
	/** @see Graphics#drawLine(int, int, int, int) */
238
	public void drawLine(int x1, int y1, int x2, int y2) {
248
	public void drawLine(int x1, int y1, int x2, int y2) {
239
		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))));
249
		graphics.drawLine((int) (Math.floor((x1 * xZoom + fractionalX))),
250
				(int) (Math.floor((y1 * yZoom + fractionalY))), (int) (Math
251
						.floor((x2 * xZoom + fractionalX))), (int) (Math
252
						.floor((y2 * yZoom + fractionalY))));
240
	}
253
	}
241
254
242
	/** @see Graphics#drawOval(int, int, int, int) */
255
	/** @see Graphics#drawOval(int, int, int, int) */
Lines 246-252 Link Here
246
259
247
	/** @see Graphics#drawPoint(int, int) */
260
	/** @see Graphics#drawPoint(int, int) */
248
	public void drawPoint(int x, int y) {
261
	public void drawPoint(int x, int y) {
249
		graphics.drawPoint((int) Math.floor(x * xZoom + fractionalX), (int) Math.floor(y * yZoom + fractionalY));
262
		graphics.drawPoint((int) Math.floor(x * xZoom + fractionalX),
263
				(int) Math.floor(y * yZoom + fractionalY));
250
	}
264
	}
251
265
252
	/**
266
	/**
Lines 280-286 Link Here
280
294
281
	/** @see Graphics#drawRoundRectangle(Rectangle, int, int) */
295
	/** @see Graphics#drawRoundRectangle(Rectangle, int, int) */
282
	public void drawRoundRectangle(Rectangle r, int arcWidth, int arcHeight) {
296
	public void drawRoundRectangle(Rectangle r, int arcWidth, int arcHeight) {
283
		graphics.drawRoundRectangle(zoomRect(r.x, r.y, r.width, r.height), (int) (arcWidth * xZoom), (int) (arcHeight * yZoom));
297
		graphics.drawRoundRectangle(zoomRect(r.x, r.y, r.width, r.height),
298
				(int) (arcWidth * xZoom), (int) (arcHeight * yZoom));
284
	}
299
	}
285
300
286
	/** @see Graphics#drawString(String, int, int) */
301
	/** @see Graphics#drawString(String, int, int) */
Lines 310-318 Link Here
310
	 * @see Graphics#drawTextLayout(TextLayout, int, int, int, int, Color,
325
	 * @see Graphics#drawTextLayout(TextLayout, int, int, int, int, Color,
311
	 *      Color)
326
	 *      Color)
312
	 */
327
	 */
313
	public void drawTextLayout(TextLayout layout, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground) {
328
	public void drawTextLayout(TextLayout layout, int x, int y,
329
			int selectionStart, int selectionEnd, Color selectionForeground,
330
			Color selectionBackground) {
314
		TextLayout scaled = zoomTextLayout(layout);
331
		TextLayout scaled = zoomTextLayout(layout);
315
		graphics.drawTextLayout(scaled, (int) Math.floor(x * xZoom + fractionalX), (int) Math.floor(y * yZoom + fractionalY), selectionStart, selectionEnd, selectionBackground, selectionForeground);
332
		graphics.drawTextLayout(scaled, (int) Math.floor(x * xZoom
333
				+ fractionalX), (int) Math.floor(y * yZoom + fractionalY),
334
				selectionStart, selectionEnd, selectionBackground,
335
				selectionForeground);
316
		scaled.dispose();
336
		scaled.dispose();
317
	}
337
	}
318
338
Lines 354-360 Link Here
354
374
355
	/** @see Graphics#fillRoundRectangle(Rectangle, int, int) */
375
	/** @see Graphics#fillRoundRectangle(Rectangle, int, int) */
356
	public void fillRoundRectangle(Rectangle r, int arcWidth, int arcHeight) {
376
	public void fillRoundRectangle(Rectangle r, int arcWidth, int arcHeight) {
357
		graphics.fillRoundRectangle(zoomFillRect(r.x, r.y, r.width, r.height), (int) (arcWidth * xZoom), (int) (arcHeight * yZoom));
377
		graphics.fillRoundRectangle(zoomFillRect(r.x, r.y, r.width, r.height),
378
				(int) (arcWidth * xZoom), (int) (arcHeight * yZoom));
358
	}
379
	}
359
380
360
	/** @see Graphics#fillString(String, int, int) */
381
	/** @see Graphics#fillString(String, int, int) */
Lines 524-532 Link Here
524
		State s;
545
		State s;
525
		if (stack.size() > stackPointer) {
546
		if (stack.size() > stackPointer) {
526
			s = (State) stack.get(stackPointer);
547
			s = (State) stack.get(stackPointer);
527
			s.setValues(xZoom, yZoom, fractionalX, fractionalY, getLocalFont(), localLineWidth);
548
			s.setValues(xZoom, yZoom, fractionalX, fractionalY, getLocalFont(),
549
					localLineWidth);
528
		} else {
550
		} else {
529
			stack.add(new State(xZoom, yZoom, fractionalX, fractionalY, getLocalFont(), localLineWidth));
551
			stack.add(new State(xZoom, yZoom, fractionalX, fractionalY,
552
					getLocalFont(), localLineWidth));
530
		}
553
		}
531
		stackPointer++;
554
		stackPointer++;
532
555
Lines 554-560 Link Here
554
577
555
	/** @see Graphics#scale(double) */
578
	/** @see Graphics#scale(double) */
556
	public void scale(double amount) {
579
	public void scale(double amount) {
557
		//setScale(zoom * amount);
580
		// setScale(zoom * amount);
558
		throw new RuntimeException("Operation not supported, use scale(x, y)");
581
		throw new RuntimeException("Operation not supported, use scale(x, y)");
559
	}
582
	}
560
583
Lines 681-708 Link Here
681
704
682
	/** @see Graphics#translate(int, int) */
705
	/** @see Graphics#translate(int, int) */
683
	public void translate(int dx, int dy) {
706
	public void translate(int dx, int dy) {
684
		// fractionalX/Y is the fractional part left over from previous 
707
		// fractionalX/Y is the fractional part left over from previous
685
		// translates that gets lost in the integer approximation.
708
		// translates that gets lost in the integer approximation.
686
		double dxFloat = dx * xZoom + fractionalX;
709
		double dxFloat = dx * xZoom + fractionalX;
687
		double dyFloat = dy * yZoom + fractionalY;
710
		double dyFloat = dy * yZoom + fractionalY;
688
		fractionalX = dxFloat - Math.floor(dxFloat);
711
		fractionalX = dxFloat - Math.floor(dxFloat);
689
		fractionalY = dyFloat - Math.floor(dyFloat);
712
		fractionalY = dyFloat - Math.floor(dyFloat);
690
		graphics.translate((int) Math.floor(dxFloat), (int) Math.floor(dyFloat));
713
		graphics
714
				.translate((int) Math.floor(dxFloat), (int) Math.floor(dyFloat));
691
	}
715
	}
692
716
693
	private Rectangle zoomClipRect(Rectangle r) {
717
	private Rectangle zoomClipRect(Rectangle r) {
694
		tempRECT.x = (int) (Math.floor(r.x * xZoom + fractionalX));
718
		tempRECT.x = (int) (Math.floor(r.x * xZoom + fractionalX));
695
		tempRECT.y = (int) (Math.floor(r.y * yZoom + fractionalY));
719
		tempRECT.y = (int) (Math.floor(r.y * yZoom + fractionalY));
696
		tempRECT.width = (int) (Math.ceil(((r.x + r.width) * xZoom + fractionalX))) - tempRECT.x;
720
		tempRECT.width = (int) (Math
697
		tempRECT.height = (int) (Math.ceil(((r.y + r.height) * yZoom + fractionalY))) - tempRECT.y;
721
				.ceil(((r.x + r.width) * xZoom + fractionalX)))
722
				- tempRECT.x;
723
		tempRECT.height = (int) (Math
724
				.ceil(((r.y + r.height) * yZoom + fractionalY)))
725
				- tempRECT.y;
698
		return tempRECT;
726
		return tempRECT;
699
	}
727
	}
700
728
701
	private Rectangle zoomFillRect(int x, int y, int w, int h) {
729
	private Rectangle zoomFillRect(int x, int y, int w, int h) {
702
		tempRECT.x = (int) (Math.floor((x * xZoom + fractionalX)));
730
		tempRECT.x = (int) (Math.floor((x * xZoom + fractionalX)));
703
		tempRECT.y = (int) (Math.floor((y * yZoom + fractionalY)));
731
		tempRECT.y = (int) (Math.floor((y * yZoom + fractionalY)));
704
		tempRECT.width = (int) (Math.floor(((x + w - 1) * xZoom + fractionalX))) - tempRECT.x + 1;
732
		tempRECT.width = (int) (Math.floor(((x + w - 1) * xZoom + fractionalX)))
705
		tempRECT.height = (int) (Math.floor(((y + h - 1) * yZoom + fractionalY))) - tempRECT.y + 1;
733
				- tempRECT.x + 1;
734
		tempRECT.height = (int) (Math
735
				.floor(((y + h - 1) * yZoom + fractionalY)))
736
				- tempRECT.y + 1;
706
		return tempRECT;
737
		return tempRECT;
707
	}
738
	}
708
739
Lines 756-762 Link Here
756
		// Scale the points
787
		// Scale the points
757
		for (int i = 0; (i + 1) < points.length; i += 2) {
788
		for (int i = 0; (i + 1) < points.length; i += 2) {
758
			scaled[i] = (int) (Math.floor((points[i] * xZoom + fractionalX)));
789
			scaled[i] = (int) (Math.floor((points[i] * xZoom + fractionalX)));
759
			scaled[i + 1] = (int) (Math.floor((points[i + 1] * yZoom + fractionalY)));
790
			scaled[i + 1] = (int) (Math
791
					.floor((points[i + 1] * yZoom + fractionalY)));
760
		}
792
		}
761
		return scaled;
793
		return scaled;
762
	}
794
	}
Lines 764-771 Link Here
764
	private Rectangle zoomRect(int x, int y, int w, int h) {
796
	private Rectangle zoomRect(int x, int y, int w, int h) {
765
		tempRECT.x = (int) (Math.floor(x * xZoom + fractionalX));
797
		tempRECT.x = (int) (Math.floor(x * xZoom + fractionalX));
766
		tempRECT.y = (int) (Math.floor(y * yZoom + fractionalY));
798
		tempRECT.y = (int) (Math.floor(y * yZoom + fractionalY));
767
		tempRECT.width = (int) (Math.floor(((x + w) * xZoom + fractionalX))) - tempRECT.x;
799
		tempRECT.width = (int) (Math.floor(((x + w) * xZoom + fractionalX)))
768
		tempRECT.height = (int) (Math.floor(((y + h) * yZoom + fractionalY))) - tempRECT.y;
800
				- tempRECT.x;
801
		tempRECT.height = (int) (Math.floor(((y + h) * yZoom + fractionalY)))
802
				- tempRECT.y;
769
		return tempRECT;
803
		return tempRECT;
770
	}
804
	}
771
805
Lines 798-810 Link Here
798
			int start = 0, offset = 1;
832
			int start = 0, offset = 1;
799
			TextStyle style = null, lastStyle = layout.getStyle(0);
833
			TextStyle style = null, lastStyle = layout.getStyle(0);
800
			for (; offset <= length; offset++) {
834
			for (; offset <= length; offset++) {
801
				if (offset != length && (style = layout.getStyle(offset)) == lastStyle) {
835
				if (offset != length
836
						&& (style = layout.getStyle(offset)) == lastStyle) {
802
					continue;
837
					continue;
803
				}
838
				}
804
				int end = offset - 1;
839
				int end = offset - 1;
805
840
806
				if (lastStyle != null) {
841
				if (lastStyle != null) {
807
					TextStyle zoomedStyle = new TextStyle(zoomFont(lastStyle.font), lastStyle.foreground, lastStyle.background);
842
					TextStyle zoomedStyle = new TextStyle(
843
							zoomFont(lastStyle.font), lastStyle.foreground,
844
							lastStyle.background);
808
					zoomed.setStyle(zoomedStyle, start, end);
845
					zoomed.setStyle(zoomedStyle, start, end);
809
				}
846
				}
810
				lastStyle = style;
847
				lastStyle = style;
Lines 816-822 Link Here
816
853
817
	private Point zoomTextPoint(int x, int y) {
854
	private Point zoomTextPoint(int x, int y) {
818
		if (localCache.font != localFont) {
855
		if (localCache.font != localFont) {
819
			//Font is different, re-calculate its height
856
			// Font is different, re-calculate its height
820
			FontMetrics metric = FigureUtilities.getFontMetrics(localFont);
857
			FontMetrics metric = FigureUtilities.getFontMetrics(localFont);
821
			localCache.height = metric.getHeight() - metric.getDescent();
858
			localCache.height = metric.getHeight() - metric.getDescent();
822
			localCache.font = localFont;
859
			localCache.font = localFont;
Lines 826-832 Link Here
826
			targetCache.font = graphics.getFont();
863
			targetCache.font = graphics.getFont();
827
			targetCache.height = metric.getHeight() - metric.getDescent();
864
			targetCache.height = metric.getHeight() - metric.getDescent();
828
		}
865
		}
829
		return new Point(((int) (Math.floor((x * xZoom) + fractionalX))), (int) (Math.floor((y + localCache.height - 1) * yZoom - targetCache.height + 1 + fractionalY)));
866
		return new Point(((int) (Math.floor((x * xZoom) + fractionalX))),
867
				(int) (Math.floor((y + localCache.height - 1) * yZoom
868
						- targetCache.height + 1 + fractionalY)));
830
	}
869
	}
831
870
832
}
871
}
(-)src/org/eclipse/zest/core/widgets/internal/ZestRootLayer.java (-134 / +150 lines)
Lines 1-189 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others. All rights reserved.
2
 * Copyright (c) 2005-2009 IBM Corporation and others. All rights reserved.
3
 * This program and the accompanying materials are made available under the
3
 * This program and the accompanying materials are made available under the
4
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
4
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
5
 * and is available at http://www.eclipse.org/legal/epl-v10.html
5
 * and is available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
6
 * 
7
 * Contributors: IBM Corporation - initial API and implementation Chisel Group,
7
 * Contributors:
8
 * University of Victoria - Adapted for XY Scaled Graphics
8
 *     IBM Corporation - initial API and implementation Chisel Group,
9
 *     University of Victoria - Adapted for XY Scaled Graphics
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
9
 ******************************************************************************/
11
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets.internal;
12
package org.eclipse.zest.core.widgets.internal;
11
13
14
import java.util.ArrayList;
15
import java.util.HashSet;
16
import java.util.Iterator;
17
12
import org.eclipse.draw2d.FreeformLayer;
18
import org.eclipse.draw2d.FreeformLayer;
13
import org.eclipse.draw2d.IFigure;
19
import org.eclipse.draw2d.IFigure;
14
20
15
/**
21
/**
16
 * The root figure for Zest.  The figure is broken up into four segments, 
22
 * The root figure for Zest. The figure is broken up into following segments:
17
 * 1. The Connections
23
 * <ol>
18
 * 2. The Nodes
24
 * <li>The Connections</li>
19
 * 3. The Highlighted Connections
25
 * <li>The Subgraphs</li>
20
 * 4. The Highlighted Nodes
26
 * <li>The Nodes</li>
21
 * 
27
 * <li>The Highlighted Connections</li>
22
 * @author Ian Bull
28
 * <li>The Highlighted Nodes</li>
29
 * </ol>
23
 * 
30
 * 
24
 */
31
 */
25
public class ZestRootLayer extends FreeformLayer {
32
public class ZestRootLayer extends FreeformLayer {
26
33
27
	public static final boolean EDGES_ON_TOP = false;
34
	public static final int CONNECTIONS_LAYER = 0;
28
	private int numberOfNodes = 0;
35
29
	private int numberOfConnections = 0;
36
	public static final int SUBGRAPHS_LAYER = 1;
30
	private int numberOfHighlightedNodes = 0;
37
31
	private int numberOfHighlightedConnections = 0;
38
	public static final int NODES_LAYER = 2;
39
40
	public static final int CONNECTIONS_HIGHLIGHTED_LAYER = 3;
41
42
	public static final int NODES_HIGHLIGHTED_LAYER = 4;
43
44
	public static final int TOP_LAYER = 5;
45
46
	public static final int NUMBER_OF_LAYERS = 6;
47
48
	private final int[] itemsInLayer = new int[NUMBER_OF_LAYERS];
32
49
33
	/**
50
	/**
34
	 * Adds a node to the ZestRootLayer
51
	 * Set of all figures that are decorations for other figures. A decoration
35
	 * @param nodeFigure The figure representing the node
52
	 * figure is always put one position (or more if there's more than one
53
	 * decoration for the same figure) after the decorated figure in children
54
	 * list.
36
	 */
55
	 */
37
	public void addNode(IFigure nodeFigure) {
56
	private HashSet decoratingFigures = new HashSet();
38
		int nodePosition = getNodePosition();
57
39
		numberOfNodes++;
58
	/**
40
		add(nodeFigure, nodePosition);
59
	 * If true, it indicates that a figure is added using a proper method and
41
	}
60
	 * its layer is known. Otherwise, Figure#add() method was used and layer
61
	 * must be guessed
62
	 */
63
	private boolean isLayerKnown = false;
42
64
43
	/**
65
	/**
44
	 * Removes a node from the layer
66
	 * Adds a node to the ZestRootLayer
67
	 * 
45
	 * @param nodeFigure
68
	 * @param nodeFigure
69
	 *            The figure representing the node
46
	 */
70
	 */
47
	public void removeNode(IFigure nodeFigure) {
71
	public void addNode(IFigure nodeFigure) {
48
		if (!this.getChildren().contains(nodeFigure)) {
72
		addFigure(nodeFigure, NODES_LAYER);
49
			throw new RuntimeException("Node not contained on the ZestRootLayer");
50
		}
51
		int nodePosition = this.getChildren().indexOf(nodeFigure);
52
		if (nodePosition > getHighlightNodeStartPosition()) {
53
			// The node is in the highlight node area
54
			numberOfHighlightedNodes--;
55
		} else {
56
			// The node is in the node area
57
			numberOfNodes--;
58
		}
59
		this.remove(nodeFigure);
60
	}
73
	}
61
74
62
	public void removeConnection(IFigure connectionFigure) {
75
	public void addConnection(IFigure connectionFigure) {
63
		int connectionPosition = this.getChildren().indexOf(connectionFigure);
76
		addFigure(connectionFigure, CONNECTIONS_LAYER);
64
		if (connectionPosition > getHighlightConnectionStartPosition()) {
65
			// The connection is in the highlight connection area
66
			numberOfHighlightedConnections--;
67
		} else {
68
			// The connection is in the connection area
69
			numberOfConnections--;
70
		}
71
		this.remove(connectionFigure);
72
	}
77
	}
73
78
74
	public void addConnection(IFigure connectionFigure) {
79
	public void addSubgraph(IFigure subgraphFigrue) {
75
		int connectionPosition = getConnectionPosition();
80
		addFigure(subgraphFigrue, SUBGRAPHS_LAYER);
76
		numberOfConnections++;
77
		add(connectionFigure, connectionPosition);
78
	}
81
	}
79
82
80
	public void highlightNode(IFigure nodeFigure) {
83
	public void highlightNode(IFigure nodeFigure) {
81
		this.numberOfNodes--;
84
		changeFigureLayer(nodeFigure, NODES_HIGHLIGHTED_LAYER);
82
		int highlightNodePosition = getHighlightNodePosition();
83
		this.numberOfHighlightedNodes++;
84
		this.getChildren().remove(nodeFigure);
85
		this.getChildren().add(highlightNodePosition, nodeFigure);
86
		this.invalidate();
87
		this.repaint();
88
	}
85
	}
89
86
90
	public void highlightConnection(IFigure connectionFigure) {
87
	public void highlightConnection(IFigure connectionFigure) {
91
		this.numberOfConnections--;
88
		changeFigureLayer(connectionFigure, CONNECTIONS_HIGHLIGHTED_LAYER);
92
		int highlightConnectionPosition = getHighlightConnectionPosition();
93
		this.numberOfHighlightedConnections++;
94
		this.getChildren().remove(connectionFigure);
95
		this.getChildren().add(highlightConnectionPosition, connectionFigure);
96
		this.invalidate();
97
		this.repaint();
98
	}
89
	}
99
90
100
	public void unHighlightNode(IFigure nodeFigure) {
91
	public void unHighlightNode(IFigure nodeFigure) {
101
		int nodePosition = this.getChildren().indexOf(nodeFigure);
92
		changeFigureLayer(nodeFigure, NODES_LAYER);
102
		if (nodePosition > getHighlightNodePosition()) {
103
			//throw new RuntimeException("Node: " + nodeFigure + " not currently Highlighted");
104
			return;
105
		}
106
		this.numberOfHighlightedNodes--;
107
		nodePosition = getNodePosition();
108
		this.numberOfNodes++;
109
		this.getChildren().remove(nodeFigure);
110
		this.getChildren().add(nodePosition, nodeFigure);
111
		this.invalidate();
112
		this.repaint();
113
	}
93
	}
114
94
115
	public void unHighlightConnection(IFigure connectionFigure) {
95
	public void unHighlightConnection(IFigure connectionFigure) {
116
		int connectionPosition = this.getChildren().indexOf(connectionFigure);
96
		changeFigureLayer(connectionFigure, CONNECTIONS_LAYER);
117
		if (connectionPosition > getHighlightConnectionPosition()) {
118
			//throw new RuntimeException("Connection: " + connectionFigure + " not currently Highlighted");
119
			return;
120
		}
121
		this.numberOfHighlightedConnections--;
122
		this.numberOfConnections++;
123
		connectionPosition = getConnectionPosition();
124
		this.getChildren().remove(connectionFigure);
125
		if (connectionPosition > this.getChildren().size()) {
126
			this.getChildren().add(connectionFigure);
127
		} else {
128
			this.getChildren().add(connectionPosition, connectionFigure);
129
		}
130
		this.invalidate();
131
		this.repaint();
132
	}
97
	}
133
98
134
	/*
99
	private void changeFigureLayer(IFigure figure, int newLayer) {
135
	 * Node position is at the end of the list of nodes
100
		ArrayList decorations = getDecorations(figure);
136
	 */
101
		remove(figure);
137
	private int getNodePosition() {
138
		if (EDGES_ON_TOP) {
139
			return numberOfNodes;
140
		}
141
		return numberOfConnections + numberOfNodes;
142
	}
143
102
144
	/*
103
		addFigure(figure, newLayer);
145
	 * Connection position is at the end of the list of connections
104
		for (Iterator iterator = decorations.iterator(); iterator.hasNext();) {
146
	 */
105
			addDecoration(figure, (IFigure) iterator.next());
147
	private int getConnectionPosition() {
148
		if (EDGES_ON_TOP) {
149
			return 0 + numberOfConnections + numberOfNodes;
150
		}
106
		}
151
		return 0 + numberOfConnections;
152
	}
153
107
154
	/*
108
		this.invalidate();
155
	 * Highlight node position is at the end of the list of highlighted nodes
109
		this.repaint();
156
	 */
157
	private int getHighlightNodePosition() {
158
		if (EDGES_ON_TOP) {
159
			return numberOfConnections + numberOfNodes + numberOfHighlightedNodes;
160
		}
161
		return numberOfConnections + numberOfHighlightedConnections + numberOfNodes + numberOfHighlightedNodes;
162
	}
110
	}
163
111
164
	/*
112
	private ArrayList getDecorations(IFigure figure) {
165
	 * Highlighted connection position is at the end of the list of highlighted connections
113
		ArrayList result = new ArrayList();
166
	 */
114
		int index = getChildren().indexOf(figure);
167
	private int getHighlightConnectionPosition() {
115
		if (index == -1)
168
		if (EDGES_ON_TOP) {
116
			return result;
169
			return numberOfNodes + +numberOfConnections + numberOfHighlightedNodes + numberOfHighlightedConnections;
117
		for (index++; index < getChildren().size(); index++) {
118
			Object nextFigure = getChildren().get(index);
119
			if (decoratingFigures.contains(nextFigure)) {
120
				result.add(nextFigure);
121
			} else
122
				break;
170
		}
123
		}
171
		return numberOfConnections + numberOfNodes + numberOfHighlightedConnections;
124
		return result;
172
	}
125
	}
173
126
174
	private int getHighlightConnectionStartPosition() {
127
	/**
175
		if (EDGES_ON_TOP) {
128
	 * 
176
			return numberOfConnections + numberOfNodes + numberOfHighlightedNodes;
129
	 * @param layer
177
130
	 * @return position after the last element in given layer
178
		}
131
	 */
179
		return numberOfConnections + numberOfNodes;
132
	private int getPosition(int layer) {
133
		int result = 0;
134
		for (int i = 0; i <= layer; i++)
135
			result += itemsInLayer[i];
136
		return result;
180
	}
137
	}
181
138
182
	private int getHighlightNodeStartPosition() {
139
	/**
183
		if (EDGES_ON_TOP) {
140
	 * 
184
			return numberOfNodes + numberOfConnections;
141
	 * @param position
142
	 * @return number of layer containing element at given position
143
	 */
144
	private int getLayer(int position) {
145
		int layer = 0;
146
		int positionInLayer = itemsInLayer[0];
147
		while (layer < NUMBER_OF_LAYERS - 1 && positionInLayer <= position) {
148
			layer++;
149
			positionInLayer += itemsInLayer[layer];
150
		}
151
		return layer;
152
	}
153
154
	public void addFigure(IFigure figure, int layer) {
155
		int position = getPosition(layer);
156
		itemsInLayer[layer]++;
157
		isLayerKnown = true;
158
		add(figure, position);
159
	}
160
161
	public void add(IFigure child, Object constraint, int index) {
162
		super.add(child, constraint, index);
163
		if (!isLayerKnown) {
164
			int layer = 0, positionInLayer = itemsInLayer[0];
165
			while (positionInLayer < index) {
166
				layer++;
167
				positionInLayer += itemsInLayer[layer];
168
			}
169
			if (index == -1)
170
				layer = NUMBER_OF_LAYERS - 1;
171
			itemsInLayer[layer]++;
172
		}
173
		isLayerKnown = false;
174
	}
175
176
	public void remove(IFigure child) {
177
		int position = this.getChildren().indexOf(child);
178
		if (position == -1)
179
			throw new RuntimeException("Can't remove a figure that is not on this ZestRootLayer");
180
		itemsInLayer[getLayer(position)]--;
181
		if (decoratingFigures.contains(child)) {
182
			decoratingFigures.remove(child);
183
			super.remove(child);
184
		} else {
185
			ArrayList decorations = getDecorations(child);
186
			super.remove(child);
187
			for (Iterator iterator = decorations.iterator(); iterator.hasNext();) {
188
				remove((IFigure) iterator.next());
189
			}
185
		}
190
		}
186
		return numberOfConnections + numberOfHighlightedConnections + numberOfNodes;
187
	}
191
	}
188
192
193
	public void addDecoration(IFigure decorated, IFigure decorating) {
194
		int position = this.getChildren().indexOf(decorated);
195
		if (position == -1)
196
			throw new RuntimeException("Can't add decoration for a figuer that is not on this ZestRootLayer");
197
		itemsInLayer[getLayer(position)]++;
198
		isLayerKnown = true;
199
		do {
200
			position++;
201
		} while (position < getChildren().size() && decoratingFigures.contains(getChildren().get(position)));
202
		decoratingFigures.add(decorating);
203
		add(decorating, position);
204
	}
189
}
205
}
(-)src/org/eclipse/zest/core/widgets/internal/LoopAnchor.java (-8 / +10 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 18-34 Link Here
18
	public LoopAnchor(IFigure owner) {
18
	public LoopAnchor(IFigure owner) {
19
		super(owner);
19
		super(owner);
20
	}
20
	}
21
	
21
22
	/* (non-Javadoc)
22
	/*
23
	 * (non-Javadoc)
24
	 * 
23
	 * @see org.eclipse.draw2d.ChopboxAnchor#getReferencePoint()
25
	 * @see org.eclipse.draw2d.ChopboxAnchor#getReferencePoint()
24
	 */
26
	 */
25
	public Point getReferencePoint() {
27
	public Point getReferencePoint() {
26
		//modification to getReferencePoint. Returns
28
		// modification to getReferencePoint. Returns
27
		//a point on the outside of the owners box, rather than the
29
		// a point on the outside of the owners box, rather than the
28
		//center. Only usefull for self-loops.
30
		// center. Only usefull for self-loops.
29
		if (getOwner() == null)
31
		if (getOwner() == null) {
30
			return null;
32
			return null;
31
		else {
33
		} else {
32
			Point ref = getOwner().getBounds().getCenter();
34
			Point ref = getOwner().getBounds().getCenter();
33
			ref.y = getOwner().getBounds().y;
35
			ref.y = getOwner().getBounds().y;
34
			getOwner().translateToAbsolute(ref);
36
			getOwner().translateToAbsolute(ref);
(-)src/org/eclipse/zest/core/widgets/internal/ExpandGraphLabel.java (-283 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets.internal;
11
12
import org.eclipse.draw2d.ActionEvent;
13
import org.eclipse.draw2d.ActionListener;
14
import org.eclipse.draw2d.Clickable;
15
import org.eclipse.draw2d.ColorConstants;
16
import org.eclipse.draw2d.Figure;
17
import org.eclipse.draw2d.FigureUtilities;
18
import org.eclipse.draw2d.FreeformLayout;
19
import org.eclipse.draw2d.Graphics;
20
import org.eclipse.draw2d.Label;
21
import org.eclipse.draw2d.ToolbarLayout;
22
import org.eclipse.draw2d.Triangle;
23
import org.eclipse.draw2d.geometry.Dimension;
24
import org.eclipse.draw2d.geometry.Point;
25
import org.eclipse.draw2d.geometry.Rectangle;
26
import org.eclipse.zest.core.widgets.GraphContainer;
27
import org.eclipse.swt.graphics.Color;
28
import org.eclipse.swt.graphics.Font;
29
import org.eclipse.swt.graphics.Image;
30
import org.eclipse.swt.graphics.RGB;
31
import org.eclipse.swt.widgets.Display;
32
33
public class ExpandGraphLabel extends Figure implements ActionListener {
34
35
	public static final int OPEN = 1;
36
	public static final int CLOSED = 2;
37
	private int state = CLOSED;
38
	private Expander expander = null;
39
40
	class Expander extends Clickable {
41
		private Triangle triangle;
42
43
		public Expander() {
44
			setStyle(Clickable.STYLE_TOGGLE);
45
			triangle = new Triangle();
46
			triangle.setSize(10, 10);
47
			triangle.setBackgroundColor(ColorConstants.black);
48
			triangle.setForegroundColor(ColorConstants.black);
49
			triangle.setFill(true);
50
			triangle.setDirection(Triangle.EAST);
51
			triangle.setLocation(new Point(5, 3));
52
			this.setLayoutManager(new FreeformLayout());
53
			this.add(triangle);
54
			this.setPreferredSize(15, 15);
55
			this.addActionListener(ExpandGraphLabel.this);
56
		}
57
58
		public void open() {
59
			triangle.setDirection(Triangle.SOUTH);
60
		}
61
62
		public void close() {
63
			triangle.setDirection(Triangle.EAST);
64
		}
65
66
	}
67
68
	/**
69
	 * Sets the expander state (the little triangle) to ExpanderGraphLabel.OPEN or ExpanderGraphLabel.CLOSED
70
	 * @param state
71
	 */
72
	public void setExpandedState(int state) {
73
		if (state == OPEN) {
74
			expander.open();
75
		} else {
76
			expander.close();
77
		}
78
		this.state = state;
79
	}
80
81
	/*
82
	 * (non-Javadoc)
83
	 * @see org.eclipse.draw2d.ActionListener#actionPerformed(org.eclipse.draw2d.ActionEvent)
84
	 */
85
	public void actionPerformed(ActionEvent event) {
86
		if (state == OPEN) {
87
			container.close(true);
88
89
		} else {
90
			container.open(true);
91
		}
92
	}
93
94
	private int arcWidth;
95
	private Label label = null;
96
	private final GraphContainer container;
97
	private ToolbarLayout layout;
98
99
	public ExpandGraphLabel(GraphContainer container, boolean cacheLabel) {
100
		this(container, "", null, cacheLabel);
101
	}
102
103
	public ExpandGraphLabel(GraphContainer container, Image i, boolean cacheLabel) {
104
		this(container, "", i, cacheLabel);
105
	}
106
107
	public ExpandGraphLabel(GraphContainer container, String text, boolean cacheLabel) {
108
		this(container, text, null, cacheLabel);
109
	}
110
111
	public ExpandGraphLabel(GraphContainer container, String text, Image image, boolean cacheLabel) {
112
		this.label = new Label(text) {
113
114
			/*
115
			 * This method is overwritten so that the text is not truncated.
116
			 * (non-Javadoc)
117
			 * @see org.eclipse.draw2d.Label#paintFigure(org.eclipse.draw2d.Graphics)
118
			 */
119
			protected void paintFigure(Graphics graphics) {
120
				if (isOpaque()) {
121
					super.paintFigure(graphics);
122
				}
123
				Rectangle bounds = getBounds();
124
				graphics.translate(bounds.x, bounds.y);
125
				if (getIcon() != null) {
126
					graphics.drawImage(getIcon(), getIconLocation());
127
				}
128
				if (!isEnabled()) {
129
					graphics.translate(1, 1);
130
					graphics.setForegroundColor(ColorConstants.buttonLightest);
131
					graphics.drawText(getSubStringText(), getTextLocation());
132
					graphics.translate(-1, -1);
133
					graphics.setForegroundColor(ColorConstants.buttonDarker);
134
				}
135
				graphics.drawText(getText(), getTextLocation());
136
				graphics.translate(-bounds.x, -bounds.y);
137
			}
138
		};
139
		this.setText(text);
140
		this.setImage(image);
141
		this.container = container;
142
		this.expander = new Expander();
143
		this.arcWidth = 8;
144
		this.setFont(Display.getDefault().getSystemFont());
145
		layout = new ToolbarLayout(true);
146
		layout.setSpacing(5);
147
		layout.setMinorAlignment(ToolbarLayout.ALIGN_CENTER);
148
		this.setLayoutManager(layout);
149
		this.add(this.expander);
150
		this.add(this.label);
151
		//this.remove(this.label);
152
	}
153
154
	/**
155
	 * Adjust the bounds to make the text fit without truncation.
156
	 */
157
	protected void adjustBoundsToFit() {
158
		String text = getText();
159
		if ((text != null) && (text.length() > 0)) {
160
			Font font = getFont();
161
			if (font != null) {
162
				Dimension minSize = FigureUtilities.getTextExtents(text, font);
163
				if (getIcon() != null) {
164
					org.eclipse.swt.graphics.Rectangle imageRect = getIcon().getBounds();
165
					int expandHeight = Math.max(imageRect.height - minSize.height, 0);
166
					minSize.expand(imageRect.width + 4, expandHeight);
167
				}
168
				minSize.expand(10 + (2 * 1) + 100, 4 + (2 * 1));
169
				label.setBounds(new Rectangle(getLocation(), minSize));
170
			}
171
		}
172
	}
173
174
	private Image getIcon() {
175
		return this.label.getIcon();
176
	}
177
178
	private String getText() {
179
		return this.label.getText();
180
	}
181
182
	/*
183
	 * (non-Javadoc)
184
	 * 
185
	 * @see org.eclipse.draw2d.Label#paintFigure(org.eclipse.draw2d.Graphics)
186
	 */
187
	public void paint(Graphics graphics) {
188
189
		int blue = getBackgroundColor().getBlue();
190
		blue = (int) (blue - (blue * 0.20));
191
		blue = blue > 0 ? blue : 0;
192
193
		int red = getBackgroundColor().getRed();
194
		red = (int) (red - (red * 0.20));
195
		red = red > 0 ? red : 0;
196
197
		int green = getBackgroundColor().getGreen();
198
		green = (int) (green - (green * 0.20));
199
		green = green > 0 ? green : 0;
200
201
		Color lightenColor = new Color(Display.getCurrent(), new RGB(red, green, blue));
202
		graphics.setForegroundColor(lightenColor);
203
		graphics.setBackgroundColor(getBackgroundColor());
204
205
		graphics.pushState();
206
207
		// fill in the background
208
		Rectangle bounds = getBounds().getCopy();
209
		Rectangle r = bounds.getCopy();
210
		//r.x += arcWidth / 2;
211
		r.y += arcWidth / 2;
212
		//r.width -= arcWidth;
213
		r.height -= arcWidth;
214
215
		Rectangle top = bounds.getCopy();
216
		top.height /= 2;
217
		//graphics.setForegroundColor(lightenColor);
218
		//graphics.setBackgroundColor(lightenColor);
219
		graphics.setForegroundColor(getBackgroundColor());
220
		graphics.setBackgroundColor(getBackgroundColor());
221
		graphics.fillRoundRectangle(top, arcWidth, arcWidth);
222
223
		top.y = top.y + top.height;
224
		//graphics.setForegroundColor(getBackgroundColor());
225
		//graphics.setBackgroundColor(getBackgroundColor());
226
		graphics.setForegroundColor(lightenColor);
227
		graphics.setBackgroundColor(lightenColor);
228
		graphics.fillRoundRectangle(top, arcWidth, arcWidth);
229
230
		//graphics.setForegroundColor(lightenColor);
231
		//graphics.setBackgroundColor(getBackgroundColor());
232
		graphics.setBackgroundColor(lightenColor);
233
		graphics.setForegroundColor(getBackgroundColor());
234
		graphics.fillGradient(r, true);
235
236
		super.paint(graphics);
237
		graphics.popState();
238
		graphics.setForegroundColor(lightenColor);
239
		graphics.setBackgroundColor(lightenColor);
240
		// paint the border
241
		bounds.setSize(bounds.width - 1, bounds.height - 1);
242
		graphics.drawRoundRectangle(bounds, arcWidth, arcWidth);
243
		lightenColor.dispose();
244
	}
245
246
//	public Dimension getPreferredSize(int hint, int hint2) {
247
	//	return this.label.getPreferredSize();
248
	//}
249
250
	public void setTextT(String string) {
251
		this.setPreferredSize(null);
252
		this.label.setText(string);
253
		this.add(label);
254
		//System.out.println(this.label.getPreferredSize());
255
		this.layout.layout(this);
256
		this.invalidate();
257
		this.revalidate();
258
		this.validate();
259
		//this.remove(label);
260
	}
261
262
	public void setText(String string) {
263
		this.label.setText(string);
264
		//this.label.setPreferredSize(500, 30);
265
		//adjustBoundsToFit();
266
	}
267
268
	public void setImage(Image image) {
269
		this.label.setIcon(image);
270
		//adjustBoundsToFit();
271
	}
272
273
	public void setLocation(Point p) {
274
		// TODO Auto-generated method stub
275
		super.setLocation(p);
276
	}
277
278
	public void setBounds(Rectangle rect) {
279
		// TODO Auto-generated method stub
280
		super.setBounds(rect);
281
	}
282
283
}
(-)src/org/eclipse/zest/core/widgets/internal/PolylineArcConnection.java (-6 / +12 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC,
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
Lines 41-47 Link Here
41
	/*
41
	/*
42
	 * (non-Javadoc)
42
	 * (non-Javadoc)
43
	 * 
43
	 * 
44
	 * @see org.eclipse.draw2d.Polyline#setPoints(org.eclipse.draw2d.geometry.PointList)
44
	 * @see
45
	 * org.eclipse.draw2d.Polyline#setPoints(org.eclipse.draw2d.geometry.PointList
46
	 * )
45
	 */
47
	 */
46
	public void setPoints(PointList points) {
48
	public void setPoints(PointList points) {
47
		updateArc(points);
49
		updateArc(points);
Lines 111-117 Link Here
111
			// the center of the chord
113
			// the center of the chord
112
			float cartChordX = (x2 + x1) / 2;
114
			float cartChordX = (x2 + x1) / 2;
113
			float cartChordY = (y2 + y1) / 2;
115
			float cartChordY = (y2 + y1) / 2;
114
			float chordLength = (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
116
			float chordLength = (float) Math.sqrt((x1 - x2) * (x1 - x2)
117
					+ (y1 - y2) * (y1 - y2));
115
			if (Math.abs(depth) >= chordLength / 2) {
118
			if (Math.abs(depth) >= chordLength / 2) {
116
				depth = (chordLength / 3) * (depth / Math.abs(depth));
119
				depth = (chordLength / 3) * (depth / Math.abs(depth));
117
			}
120
			}
Lines 134-140 Link Here
134
137
135
			float th1;
138
			float th1;
136
			if (Float.isNaN(chordNormal)) {
139
			if (Float.isNaN(chordNormal)) {
137
				cartCenterX = (y1 > y2) ? (cartChordX - r + (depth)) : (cartChordX + r - (depth));
140
				cartCenterX = (y1 > y2) ? (cartChordX - r + (depth))
141
						: (cartChordX + r - (depth));
138
				cartCenterY = cartChordY;
142
				cartCenterY = cartChordY;
139
				th1 = PI / 2;
143
				th1 = PI / 2;
140
			} else if (Float.isInfinite(chordNormal)) {
144
			} else if (Float.isInfinite(chordNormal)) {
Lines 144-152 Link Here
144
			} else {
148
			} else {
145
				// assume that the center of the chord is on the origin.
149
				// assume that the center of the chord is on the origin.
146
				th1 = (float) Math.atan(chordNormal);
150
				th1 = (float) Math.atan(chordNormal);
147
				cartCenterX = (r - (depth)) * (float) Math.sin(th1) + cartChordX;// cartChordX+r
151
				cartCenterX = (r - (depth)) * (float) Math.sin(th1)
152
						+ cartChordX;// cartChordX+r
148
				// -depth;
153
				// -depth;
149
				cartCenterY = (r - (depth)) * (float) Math.cos(th1) + cartChordY;// cartChordY+r-depth;
154
				cartCenterY = (r - (depth)) * (float) Math.cos(th1)
155
						+ cartChordY;// cartChordY+r-depth;
150
156
151
			}
157
			}
152
			// figure out the new angles
158
			// figure out the new angles
(-)src/org/eclipse/zest/core/widgets/internal/RoundedChopboxAnchor.java (-21 / +31 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 16-22 Link Here
16
import org.eclipse.draw2d.geometry.Rectangle;
16
import org.eclipse.draw2d.geometry.Rectangle;
17
17
18
/**
18
/**
19
 * A slight modification to the ChopboxAnchor class to account for the rounded corners.
19
 * A slight modification to the ChopboxAnchor class to account for the rounded
20
 * corners.
20
 * 
21
 * 
21
 * @author Chris Callendar
22
 * @author Chris Callendar
22
 */
23
 */
Lines 24-71 Link Here
24
25
25
	private int arcRadius = 10;
26
	private int arcRadius = 10;
26
	private int shift = 7;
27
	private int shift = 7;
27
	
28
28
	public RoundedChopboxAnchor(int arcRadius) {
29
	public RoundedChopboxAnchor(int arcRadius) {
29
		super();
30
		super();
30
		this.arcRadius = arcRadius;
31
		this.arcRadius = arcRadius;
31
		this.shift = arcRadius - (int)(0.707 * arcRadius);
32
		this.shift = arcRadius - (int) (0.707 * arcRadius);
32
	}
33
	}
33
34
34
	public RoundedChopboxAnchor(IFigure owner, int arcRadius) {
35
	public RoundedChopboxAnchor(IFigure owner, int arcRadius) {
35
		super(owner);
36
		super(owner);
36
		this.arcRadius = arcRadius;
37
		this.arcRadius = arcRadius;
37
		this.shift = arcRadius - (int)(0.707 * arcRadius);
38
		this.shift = arcRadius - (int) (0.707 * arcRadius);
38
	}
39
	}
39
40
40
	/**
41
	/**
41
	 * Modifies the point slightly for the rounded corners.
42
	 * Modifies the point slightly for the rounded corners.
43
	 * 
42
	 * @return Point
44
	 * @return Point
43
	 */
45
	 */
44
	public Point getLocation(Point reference) {
46
	public Point getLocation(Point reference) {
45
		Point p = super.getLocation(reference);
47
		Point p = super.getLocation(reference);
46
		Rectangle bounds = getBox();
48
		Rectangle bounds = getBox();
47
		
49
48
		boolean done = getTranslatedPoint(bounds.getTopLeft(), p, shift, shift);
50
		boolean done = getTranslatedPoint(bounds.getTopLeft(), p, shift, shift);
49
		if (!done)
51
		if (!done) {
50
			done = getTranslatedPoint(bounds.getTopRight(), p, -shift, shift);
52
			done = getTranslatedPoint(bounds.getTopRight(), p, -shift, shift);
51
		if (!done)
53
		}
54
		if (!done) {
52
			done = getTranslatedPoint(bounds.getBottomLeft(), p, shift, -shift);
55
			done = getTranslatedPoint(bounds.getBottomLeft(), p, shift, -shift);
53
		if (!done)
56
		}
54
			done = getTranslatedPoint(bounds.getBottomRight(), p, -shift, -shift);
57
		if (!done) {
58
			done = getTranslatedPoint(bounds.getBottomRight(), p, -shift,
59
					-shift);
60
		}
55
		return p;
61
		return p;
56
	}
62
	}
57
	
63
58
	/**
64
	/**
59
	 * Calculates the distance from the corner to the Point p.  
65
	 * Calculates the distance from the corner to the Point p. If it is less
60
	 * If it is less than the minimum then it translates it and returns the new Point.
66
	 * than the minimum then it translates it and returns the new Point.
61
	 * @param corner	The corner Point.
67
	 * 
62
	 * @param p			The point to translate if close to the corner.
68
	 * @param corner
63
	 * @param dx		The amount to translate in the x direcion.
69
	 *            The corner Point.
64
	 * @param dy		The amount to translate in the y direcion.
70
	 * @param p
65
	 * @return boolean 	If the translation occured.
71
	 *            The point to translate if close to the corner.
72
	 * @param dx
73
	 *            The amount to translate in the x direcion.
74
	 * @param dy
75
	 *            The amount to translate in the y direcion.
76
	 * @return boolean If the translation occured.
66
	 */
77
	 */
67
	private boolean getTranslatedPoint(Point corner, Point p, int dx, int dy) {
78
	private boolean getTranslatedPoint(Point corner, Point p, int dx, int dy) {
68
		int diff = (int)corner.getDistance(p);
79
		int diff = (int) corner.getDistance(p);
69
		if (diff < arcRadius) {
80
		if (diff < arcRadius) {
70
			Point t = corner.getTranslated(dx, dy);
81
			Point t = corner.getTranslated(dx, dy);
71
			p.setLocation(t.x, t.y);
82
			p.setLocation(t.x, t.y);
Lines 73-78 Link Here
73
		}
84
		}
74
		return false;
85
		return false;
75
	}
86
	}
76
	
87
77
	
78
}
88
}
(-)src/org/eclipse/zest/core/widgets/internal/RevealListener.java (-4 / +5 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC, Canada.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 15-25 Link Here
15
/**
15
/**
16
 * 
16
 * 
17
 * A Listener to indicate when a view has become visible.
17
 * A Listener to indicate when a view has become visible.
18
 * 
18
 * @author Ian Bull
19
 * @author Ian Bull
19
 *
20
 * 
20
 */
21
 */
21
public interface RevealListener {
22
public interface RevealListener {
22
	
23
23
	public void revealed( Control c );
24
	public void revealed(Control c);
24
25
25
}
26
}
(-)src/org/eclipse/zest/core/widgets/internal/CachedLabel.java (-8 / +16 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC,
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
Lines 64-70 Link Here
64
	/*
64
	/*
65
	 * (non-Javadoc)
65
	 * (non-Javadoc)
66
	 * 
66
	 * 
67
	 * @see org.eclipse.draw2d.Figure#setForegroundColor(org.eclipse.swt.graphics.Color)
67
	 * @see
68
	 * org.eclipse.draw2d.Figure#setForegroundColor(org.eclipse.swt.graphics
69
	 * .Color)
68
	 */
70
	 */
69
	public void setForegroundColor(Color fg) {
71
	public void setForegroundColor(Color fg) {
70
		updateInvalidation();
72
		updateInvalidation();
Lines 74-80 Link Here
74
	/*
76
	/*
75
	 * (non-Javadoc)
77
	 * (non-Javadoc)
76
	 * 
78
	 * 
77
	 * @see org.eclipse.draw2d.Figure#setBackgroundColor(org.eclipse.swt.graphics.Color)
79
	 * @see
80
	 * org.eclipse.draw2d.Figure#setBackgroundColor(org.eclipse.swt.graphics
81
	 * .Color)
78
	 */
82
	 */
79
	public void setBackgroundColor(Color bg) {
83
	public void setBackgroundColor(Color bg) {
80
		updateInvalidation();
84
		updateInvalidation();
Lines 118-127 Link Here
118
	/*
122
	/*
119
	 * (non-Javadoc)
123
	 * (non-Javadoc)
120
	 * 
124
	 * 
121
	 * @see org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle)
125
	 * @see
126
	 * org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle
127
	 * )
122
	 */
128
	 */
123
	public void setBounds(Rectangle rect) {
129
	public void setBounds(Rectangle rect) {
124
		boolean resize = (rect.width != bounds.width) || (rect.height != bounds.height);
130
		boolean resize = (rect.width != bounds.width)
131
				|| (rect.height != bounds.height);
125
132
126
		if (resize && Animation.isAnimating()) {
133
		if (resize && Animation.isAnimating()) {
127
			updateInvalidation();
134
			updateInvalidation();
Lines 197-203 Link Here
197
			cachedImage = new Image(Display.getCurrent(), width, height);
204
			cachedImage = new Image(Display.getCurrent(), width, height);
198
205
199
			// @tag TODO : Dispose of the image properly
206
			// @tag TODO : Dispose of the image properly
200
			//ZestPlugin.getDefault().addImage(cachedImage.toString(), cachedImage);
207
			// ZestPlugin.getDefault().addImage(cachedImage.toString(),
208
			// cachedImage);
201
209
202
			GC gc = new GC(cachedImage);
210
			GC gc = new GC(cachedImage);
203
211
Lines 205-211 Link Here
205
			graphics2.setBackgroundColor(getBackgroundTextColor());
213
			graphics2.setBackgroundColor(getBackgroundTextColor());
206
			graphics2.fillRectangle(0, 0, width, height);
214
			graphics2.fillRectangle(0, 0, width, height);
207
			graphics2.setForegroundColor(getForegroundColor());
215
			graphics2.setForegroundColor(getForegroundColor());
208
			//graphics2.drawText(getSubStringText(), new Point(0, 0));
216
			// graphics2.drawText(getSubStringText(), new Point(0, 0));
209
			graphics2.drawText(getText(), new Point(0, 0));
217
			graphics2.drawText(getText(), new Point(0, 0));
210
			gc.dispose();
218
			gc.dispose();
211
219
Lines 239-245 Link Here
239
	protected void cleanImage() {
247
	protected void cleanImage() {
240
		if (cachedImage != null) {
248
		if (cachedImage != null) {
241
249
242
			//ZestPlugin.getDefault().removeImage(cachedImage.toString());
250
			// ZestPlugin.getDefault().removeImage(cachedImage.toString());
243
			cachedImage.dispose();
251
			cachedImage.dispose();
244
			cachedImage = null;
252
			cachedImage = null;
245
		}
253
		}
(-)src/org/eclipse/zest/core/widgets/internal/AspectRatioFreeformLayer.java (-31 / +35 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC,
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
5
 * accompanies this distribution, and is available at
Lines 8-15 Link Here
8
 * Contributors: The Chisel Group, University of Victoria
8
 * Contributors: The Chisel Group, University of Victoria
9
 ******************************************************************************/
9
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets.internal;
10
package org.eclipse.zest.core.widgets.internal;
11
11
import org.eclipse.draw2d.FreeformFigure;
12
import org.eclipse.draw2d.FreeformFigure;
13
import org.eclipse.draw2d.FreeformLayer;
12
import org.eclipse.draw2d.FreeformLayer;
14
import org.eclipse.draw2d.FreeformLayout;
13
import org.eclipse.draw2d.FreeformLayout;
15
import org.eclipse.draw2d.Graphics;
14
import org.eclipse.draw2d.Graphics;
Lines 25-32 Link Here
25
import org.eclipse.draw2d.geometry.Translatable;
24
import org.eclipse.draw2d.geometry.Translatable;
26
import org.eclipse.draw2d.text.CaretInfo;
25
import org.eclipse.draw2d.text.CaretInfo;
27
26
27
28
//@tag zest.bug.156286-Scaling.fix : make this implement scalable figure so that a zoom manager can be used on GraphEditParts.
28
//@tag zest.bug.156286-Scaling.fix : make this implement scalable figure so that a zoom manager can be used on GraphEditParts.
29
public class AspectRatioFreeformLayer extends FreeformLayer implements ScalableFigure, FreeformFigure {
29
public class AspectRatioFreeformLayer extends FreeformLayer implements
30
		ScalableFigure, FreeformFigure {
30
31
31
	private double widthScale = 1.0;
32
	private double widthScale = 1.0;
32
	private double heigthScale = 1.0;
33
	private double heigthScale = 1.0;
Lines 37-43 Link Here
37
		setLayoutManager(new FreeformLayout());
38
		setLayoutManager(new FreeformLayout());
38
		setBorder(new MarginBorder(5));
39
		setBorder(new MarginBorder(5));
39
40
40
		//setOpaque(false);
41
		// setOpaque(false);
41
	}
42
	}
42
43
43
	protected boolean isValidationRoot() {
44
	protected boolean isValidationRoot() {
Lines 58-85 Link Here
58
	}
59
	}
59
60
60
	/*
61
	/*
61
	public boolean isCoordinateSystem() {
62
	 * public boolean isCoordinateSystem() { // TODO Auto-generated method stub
62
		// TODO Auto-generated method stub
63
	 * return true; }
63
		return true;
64
	 */
64
	}
65
	*/
66
65
67
	public double getScale() {
66
	public double getScale() {
68
		// TODO Auto-generated method stub
67
		// TODO Auto-generated method stub
69
		throw new RuntimeException("Operation not supported");
68
		throw new RuntimeException("Operation not supported");
70
		// return this.widthScale;
69
		// return this.widthScale;
71
70
72
		//throw new RuntimeException("Operation Not supported");
71
		// throw new RuntimeException("Operation Not supported");
73
	}
72
	}
74
73
75
	public void setScale(double scale) {
74
	public void setScale(double scale) {
76
		//super.setScale( scale );
75
		// super.setScale( scale );
77
		this.widthScale = scale;
76
		this.widthScale = scale;
78
		this.heigthScale = scale;
77
		this.heigthScale = scale;
79
		revalidate();
78
		revalidate();
80
		repaint();
79
		repaint();
81
		//System.out.println("Operation not supported");
80
		// System.out.println("Operation not supported");
82
		//throw new RuntimeException("Operation not supported");
81
		// throw new RuntimeException("Operation not supported");
83
	}
82
	}
84
83
85
	/**
84
	/**
Lines 87-93 Link Here
87
	 */
86
	 */
88
87
89
	public Rectangle getClientArea(Rectangle rect) {
88
	public Rectangle getClientArea(Rectangle rect) {
90
		//return super.getClientArea(rect);
89
		// return super.getClientArea(rect);
91
90
92
		rect.width /= widthScale;
91
		rect.width /= widthScale;
93
		rect.height /= heigthScale;
92
		rect.height /= heigthScale;
Lines 100-111 Link Here
100
		Dimension d = super.getPreferredSize(wHint, hHint);
99
		Dimension d = super.getPreferredSize(wHint, hHint);
101
		int w = getInsets().getWidth();
100
		int w = getInsets().getWidth();
102
		int h = getInsets().getHeight();
101
		int h = getInsets().getHeight();
103
		return d.getExpanded(-w, -h).scale(widthScale, heigthScale).expand(w, h);
102
		return d.getExpanded(-w, -h).scale(widthScale, heigthScale)
103
				.expand(w, h);
104
	}
104
	}
105
105
106
	public void translateFromParent(Translatable t) {
106
	public void translateFromParent(Translatable t) {
107
		super.translateFromParent(t);
107
		super.translateFromParent(t);
108
		//t.performScale(1/widthScale);
108
		// t.performScale(1/widthScale);
109
109
110
		if (t instanceof PrecisionRectangle) {
110
		if (t instanceof PrecisionRectangle) {
111
			PrecisionRectangle r = (PrecisionRectangle) t;
111
			PrecisionRectangle r = (PrecisionRectangle) t;
Lines 137-152 Link Here
137
			Point p = (Point) t;
137
			Point p = (Point) t;
138
			p.scale(1 / widthScale, 1 / heigthScale);
138
			p.scale(1 / widthScale, 1 / heigthScale);
139
		} else if (t instanceof PointList) {
139
		} else if (t instanceof PointList) {
140
			throw new RuntimeException("PointList not supported in AspectRatioScale");
140
			throw new RuntimeException(
141
					"PointList not supported in AspectRatioScale");
141
		} else {
142
		} else {
142
			throw new RuntimeException(t.toString() + " not supported in AspectRatioScale");
143
			throw new RuntimeException(t.toString()
144
					+ " not supported in AspectRatioScale");
143
		}
145
		}
144
146
145
		//t.performScale(1/widthScale);		
147
		// t.performScale(1/widthScale);
146
	}
148
	}
147
149
148
	public void translateToParent(Translatable t) {
150
	public void translateToParent(Translatable t) {
149
		//t.performScale(widthScale);
151
		// t.performScale(widthScale);
150
152
151
		if (t instanceof PrecisionRectangle) {
153
		if (t instanceof PrecisionRectangle) {
152
			PrecisionRectangle r = (PrecisionRectangle) t;
154
			PrecisionRectangle r = (PrecisionRectangle) t;
Lines 157-163 Link Here
157
			r.updateInts();
159
			r.updateInts();
158
		} else if (t instanceof Rectangle) {
160
		} else if (t instanceof Rectangle) {
159
			Rectangle r = (Rectangle) t;
161
			Rectangle r = (Rectangle) t;
160
			//r.performScale(widthScale);
162
			// r.performScale(widthScale);
161
			r.scale(widthScale, heigthScale);
163
			r.scale(widthScale, heigthScale);
162
		} else if (t instanceof CaretInfo) {
164
		} else if (t instanceof CaretInfo) {
163
			CaretInfo c = (CaretInfo) t;
165
			CaretInfo c = (CaretInfo) t;
Lines 179-195 Link Here
179
			Point p = (Point) t;
181
			Point p = (Point) t;
180
			p.scale(widthScale, heigthScale);
182
			p.scale(widthScale, heigthScale);
181
		} else if (t instanceof PointList) {
183
		} else if (t instanceof PointList) {
182
			throw new RuntimeException("PointList not supported in AspectRatioScale");
184
			throw new RuntimeException(
185
					"PointList not supported in AspectRatioScale");
183
		} else {
186
		} else {
184
			throw new RuntimeException(t.toString() + " not supported in AspectRatioScale");
187
			throw new RuntimeException(t.toString()
188
					+ " not supported in AspectRatioScale");
185
		}
189
		}
186
190
187
		super.translateToParent(t);
191
		super.translateToParent(t);
188
	}
192
	}
189
193
190
	//protected boolean useLocalCoordinates() {
194
	// protected boolean useLocalCoordinates() {
191
	//	return true;
195
	// return true;
192
	//}
196
	// }
193
197
194
	protected void paintClientArea(Graphics graphics) {
198
	protected void paintClientArea(Graphics graphics) {
195
199
Lines 211-223 Link Here
211
			g.clipRect(getBounds().getCropped(getInsets()));
215
			g.clipRect(getBounds().getCropped(getInsets()));
212
		}
216
		}
213
217
214
		//g.translate((int)(getBounds().x + getInsets().left) , 
218
		// g.translate((int)(getBounds().x + getInsets().left) ,
215
		//		(int)(getBounds().y  +  getInsets().top) );
219
		// (int)(getBounds().y + getInsets().top) );
216
220
217
		g.scale(widthScale, heigthScale);
221
		g.scale(widthScale, heigthScale);
218
		//g.scale(widthScale);
222
		// g.scale(widthScale);
219
223
220
		//g.scale(widthScale);
224
		// g.scale(widthScale);
221
		g.pushState();
225
		g.pushState();
222
		paintChildren(g);
226
		paintChildren(g);
223
		g.popState();
227
		g.popState();
(-)src/org/eclipse/zest/core/widgets/SubgraphFactory.java (+25 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
12
import org.eclipse.zest.layouts.interfaces.LayoutContext;
13
import org.eclipse.zest.layouts.interfaces.NodeLayout;
14
import org.eclipse.zest.layouts.interfaces.SubgraphLayout;
15
16
/**
17
 * Factory used by {@link Graph} to create subgraphs. One instance of
18
 * SubgraphFactory can be used with multiple graphs unless explicitly stated
19
 * otherwise.
20
 * 
21
 * @since 2.0
22
 */
23
public interface SubgraphFactory {
24
	SubgraphLayout createSubgraph(NodeLayout[] nodes, LayoutContext context);
25
}
(-)src/org/eclipse/zest/core/widgets/FigureSubgraph.java (+199 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
12
import java.util.Iterator;
13
14
import org.eclipse.draw2d.Animation;
15
import org.eclipse.draw2d.FigureListener;
16
import org.eclipse.draw2d.IFigure;
17
import org.eclipse.draw2d.geometry.Dimension;
18
import org.eclipse.draw2d.geometry.Point;
19
import org.eclipse.draw2d.geometry.Rectangle;
20
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension;
21
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint;
22
import org.eclipse.zest.layouts.interfaces.EntityLayout;
23
import org.eclipse.zest.layouts.interfaces.LayoutContext;
24
import org.eclipse.zest.layouts.interfaces.NodeLayout;
25
26
/**
27
 * A subgraph layout that represents a subgraph as a single figure. An entity
28
 * representing subgraph is not resizable by layout algorithm unless proper
29
 * methods are redefined in a subclass.
30
 * 
31
 * @since 2.0
32
 */
33
public abstract class FigureSubgraph extends DefaultSubgraph {
34
35
	protected IFigure figure;
36
	private DisplayIndependentPoint location;
37
	private boolean isLayoutBeingApplied = false;
38
39
	/**
40
	 * Listens to changes in this subgraph's figure and fires proper event in
41
	 * its layout context.
42
	 */
43
	protected class SubgraphFigrueListener implements FigureListener {
44
		private Rectangle previousBounds = figure.getBounds().getCopy();
45
46
		public void figureMoved(IFigure source) {
47
			if (Animation.isAnimating() || isLayoutBeingApplied) {
48
				return;
49
			}
50
			refreshSize();
51
			refreshLocation();
52
			Rectangle newBounds = figure.getBounds();
53
			if (!newBounds.getSize().equals(previousBounds.getSize())) {
54
				context.fireEntityResizedEvent(FigureSubgraph.this);
55
			} else if (!newBounds.getLocation().equals(
56
					previousBounds.getLocation())) {
57
				context.fireEntityMovedEvent(FigureSubgraph.this);
58
			}
59
			previousBounds = newBounds.getCopy();
60
		}
61
	};
62
63
	/**
64
	 * Creates a figure for this subgraph and stores it in {@link #figure}.
65
	 * 
66
	 * This method may not be called right after creation of the subgraph but
67
	 * later when the figure is actually needed (lazy initialization).
68
	 */
69
	protected abstract void createFigure();
70
71
	/**
72
	 * Updates the figure stored in {@link #figure} depending on current nodes
73
	 * contained in this subgraph. If this method creates a new instance of
74
	 * IFigure, it should also add a {@link SubgraphFigrueListener} to it.
75
	 */
76
	protected abstract void updateFigure();
77
78
	public IFigure getFigure() {
79
		if (figure == null) {
80
			createFigure();
81
			updateFigure();
82
			figure.addFigureListener(new SubgraphFigrueListener());
83
			context.container.addSubgraphFigure(figure);
84
		}
85
		return figure;
86
	}
87
88
	protected FigureSubgraph(NodeLayout[] nodes, LayoutContext context) {
89
		super(context);
90
		addNodes(nodes);
91
	}
92
93
	/**
94
	 * {@inheritDoc}
95
	 * 
96
	 * All nodes added to this subgraph are moved to the center of the figure
97
	 * (so that collapsing and expanding animation looks cool).
98
	 */
99
	public void addNodes(NodeLayout[] nodes) {
100
		int initialCount = this.nodes.size();
101
		super.addNodes(nodes);
102
		if (this.nodes.size() > initialCount && figure != null) {
103
			updateFigure();
104
			if (location != null) {
105
				for (int i = 0; i < nodes.length; i++) {
106
					nodes[i].setLocation(location.x, location.y);
107
				}
108
			}
109
		}
110
	}
111
112
	public void removeNodes(NodeLayout[] nodes) {
113
		int initialCount = this.nodes.size();
114
		super.removeNodes(nodes);
115
		if (this.nodes.size() < initialCount && figure != null && !disposed) {
116
			updateFigure();
117
		}
118
	}
119
120
	public EntityLayout[] getSuccessingEntities() {
121
		// TODO Auto-generated method stub
122
		return super.getSuccessingEntities();
123
	}
124
125
	public EntityLayout[] getPredecessingEntities() {
126
		// TODO Auto-generated method stub
127
		return super.getPredecessingEntities();
128
	}
129
130
	public DisplayIndependentDimension getSize() {
131
		Dimension size = getFigure().getSize();
132
		return new DisplayIndependentDimension(size.width, size.height);
133
	}
134
135
	public DisplayIndependentPoint getLocation() {
136
		if (location == null) {
137
			Point location2 = getFigure().getBounds().getLocation();
138
			Dimension size = getFigure().getSize();
139
			return new DisplayIndependentPoint(location2.x + size.width / 2,
140
					location2.y + size.height / 2);
141
		}
142
		return new DisplayIndependentPoint(location);
143
	}
144
145
	public void setLocation(double x, double y) {
146
		super.setLocation(x, y);
147
		for (Iterator iterator = nodes.iterator(); iterator.hasNext();) {
148
			NodeLayout node = (NodeLayout) iterator.next();
149
			node.setLocation(x, y);
150
		}
151
152
		if (location != null) {
153
			location.x = x;
154
			location.y = y;
155
		} else {
156
			location = new DisplayIndependentPoint(x, y);
157
			// the first location change will be applied immediately
158
			applyLayoutChanges();
159
		}
160
	}
161
162
	protected void refreshLocation() {
163
		Rectangle bounds = figure.getBounds();
164
		if (location == null) {
165
			location = new DisplayIndependentPoint(0, 0);
166
		}
167
		location.x = bounds.x + bounds.width / 2;
168
		location.y = bounds.y + bounds.height / 2;
169
	}
170
171
	public boolean isGraphEntity() {
172
		return true;
173
	}
174
175
	public boolean isMovable() {
176
		return true;
177
	}
178
179
	protected void dispose() {
180
		if (!disposed) {
181
			super.dispose();
182
			if (figure != null) {
183
				context.container.getGraph().removeSubgraphFigure(figure);
184
			}
185
		}
186
	}
187
188
	protected void applyLayoutChanges() {
189
		getFigure();
190
		if (location != null) {
191
			isLayoutBeingApplied = true;
192
			Dimension size = figure.getSize();
193
			figure.setLocation(new Point(location.x - size.width / 2,
194
					location.y - size.height / 2));
195
			isLayoutBeingApplied = false;
196
		}
197
	}
198
199
}
(-)src/org/eclipse/zest/core/widgets/FisheyeListener.java (+61 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
12
import org.eclipse.draw2d.IFigure;
13
14
/**
15
 * Interface for listener that can be added to {@link Graph} and receive
16
 * notifications when fisheye figures are added, removed or replaced in it.
17
 * 
18
 * @since 2.0
19
 */
20
public interface FisheyeListener {
21
22
	/**
23
	 * Called when a fisheye figure is added to an observed graph.
24
	 * 
25
	 * @param graph
26
	 *            observed graph
27
	 * @param originalFigure
28
	 *            figure to be fisheyed
29
	 * @param fisheyeFigure
30
	 *            the added fisheye figure
31
	 */
32
	public void fisheyeAdded(Graph graph, IFigure originalFigure,
33
			IFigure fisheyeFigure);
34
35
	/**
36
	 * Called when a fisheye figure is removed form an observed graph.
37
	 * 
38
	 * @param graph
39
	 *            observed graph
40
	 * @param originalFigure
41
	 *            figure that was fisheyed
42
	 * @param fisheyeFigure
43
	 *            the removed fisheye figure
44
	 */
45
	public void fisheyeRemoved(Graph graph, IFigure originalFigure,
46
			IFigure fisheyeFigure);
47
48
	/**
49
	 * Called when one fisheye figure is replaced by another in an observed
50
	 * graph.
51
	 * 
52
	 * @param graph
53
	 *            observed graph
54
	 * @param oldFisheyeFigure
55
	 *            fisheye figure that is replaced
56
	 * @param newFisheyeFigure
57
	 *            fisheye figure that replaces the old figure
58
	 */
59
	public void fisheyeReplaced(Graph graph, IFigure oldFisheyeFigure,
60
			IFigure newFisheyeFigure);
61
}
(-)src/org/eclipse/zest/core/viewers/ZoomManager.java (+612 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others. All rights reserved.
3
 * This program and the accompanying materials are made available under the
4
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
5
 * and is available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors:
8
 *     IBM Corporation - initial API and implementation
9
 ******************************************************************************/
10
package org.eclipse.zest.core.viewers;
11
12
import java.util.ArrayList;
13
import java.util.Collections;
14
import java.util.Iterator;
15
import java.util.List;
16
17
import org.eclipse.draw2d.FreeformFigure;
18
import org.eclipse.draw2d.IFigure;
19
import org.eclipse.draw2d.ScalableFigure;
20
import org.eclipse.draw2d.ScalableFreeformLayeredPane;
21
import org.eclipse.draw2d.Viewport;
22
import org.eclipse.draw2d.geometry.Dimension;
23
import org.eclipse.draw2d.geometry.Point;
24
import org.eclipse.draw2d.geometry.Rectangle;
25
import org.eclipse.swt.widgets.Display;
26
import org.eclipse.zest.core.viewers.internal.SharedMessages;
27
28
/**
29
 * Manage the primary zoom function in a graphical viewer. This class is used by
30
 * the zoom contribution items, including:
31
 * <UL>
32
 * <LI>{@link org.eclipse.gef.ui.actions.ZoomInAction}
33
 * <LI>{@link org.eclipse.gef.ui.actions.ZoomOutAction}
34
 * <LI>and {@link org.eclipse.gef.ui.actions.ZoomComboContributionItem}
35
 * </UL>
36
 * <P>
37
 * A ZoomManager controls how zoom in and zoom out are performed. It also
38
 * determines the list of choices the user sees in the drop-down Combo on the
39
 * toolbar. The zoom manager controls a <code>ScalableFigure</code>, which
40
 * performs the actual zoom, and also a <code>Viewport</code>. The viewport is
41
 * needed so that the scrolled location is preserved as the zoom level changes.
42
 * <p>
43
 * <b>NOTE:</b> For the settings of {@link #FIT_ALL Page}, {@link #FIT_WIDTH
44
 * Width} and {@link #FIT_HEIGHT Height} to work properly, the given
45
 * <code>Viewport</code> should have its scrollbars always visible or never
46
 * visible. Otherwise, these settings may cause undesired effects.
47
 * 
48
 * @author Dan Lee
49
 * @author Eric Bordeau
50
 * @since 2.0
51
 */
52
public class ZoomManager {
53
54
	/** Style bit meaning don't animate any zooms */
55
	public static final int ANIMATE_NEVER = 0;
56
	/** Style bit meaning animate during {@link #zoomIn()} and {@link #zoomOut()} */
57
	public static final int ANIMATE_ZOOM_IN_OUT = 1;
58
59
	private List listeners = new ArrayList();
60
61
	private double multiplier = 1.0;
62
	private ScalableFigure pane;
63
	private Viewport viewport;
64
	private double zoom = 1.0;
65
	// private int zoomAnimationStyle = ANIMATE_NEVER;
66
	private String currentZoomContant = null;
67
	private double[] zoomLevels = { .5, .75, 1.0, 1.5, 2.0, 2.5, 3, 4 };
68
69
	/**
70
	 * String constant for the "Height" zoom level. At this zoom level, the zoom
71
	 * manager will adopt a zoom setting such that the entire height of the
72
	 * diagram will be visible on the screen.
73
	 */
74
	public static final String FIT_HEIGHT = SharedMessages.FitHeightAction_Label;
75
	/**
76
	 * String constant for the "Width" zoom level. At this zoom level, the zoom
77
	 * manager will adopt a zoom setting such that the entire width of the
78
	 * diagram will be visible on the screen.
79
	 */
80
	public static final String FIT_WIDTH = SharedMessages.FitWidthAction_Label;
81
	/**
82
	 * String constant for the "Page" zoom level. At this zoom level, the zoom
83
	 * manager will adopt a zoom setting such that the entire diagram will be
84
	 * visible on the screen.
85
	 */
86
	public static final String FIT_ALL = SharedMessages.FitAllAction_Label;
87
	private List zoomLevelContributions = Collections.EMPTY_LIST;
88
89
	//DecimalFormat format = new DecimalFormat("####%"); //$NON-NLS-1$
90
91
	/**
92
	 * Creates a new ZoomManager.
93
	 * 
94
	 * @param pane
95
	 *            The ScalableFigure associated with this ZoomManager
96
	 * @param viewport
97
	 *            The Viewport assoicated with this ZoomManager
98
	 */
99
	public ZoomManager(ScalableFigure pane, Viewport viewport) {
100
		this.pane = pane;
101
		this.viewport = viewport;
102
		zoomLevelContributions = new ArrayList();
103
		zoomLevelContributions.add(FIT_ALL);
104
	}
105
106
	/**
107
	 * @deprecated Use {@link #ZoomManager(ScalableFigure, Viewport)} instead.
108
	 *             Creates a new ZoomManager
109
	 * @param pane
110
	 *            The ScalableFreeformLayeredPane associated with this
111
	 *            ZoomManager
112
	 * @param viewport
113
	 *            The Viewport assoicated with this viewport
114
	 */
115
	public ZoomManager(ScalableFreeformLayeredPane pane, Viewport viewport) {
116
		this.pane = pane;
117
		this.viewport = viewport;
118
	}
119
120
	/**
121
	 * Adds the given ZoomListener to this ZoomManager's list of listeners.
122
	 * 
123
	 * @param listener
124
	 *            the ZoomListener to be added
125
	 */
126
	public void addZoomListener(ZoomListener listener) {
127
		listeners.add(listener);
128
	}
129
130
	/**
131
	 * returns <code>true</code> if the zoommanager can perform
132
	 * <code>zoomIn()</code>.
133
	 * 
134
	 * @return boolean true if zoomIn can be called
135
	 */
136
	public boolean canZoomIn() {
137
		return getZoom() < getMaxZoom();
138
	}
139
140
	/**
141
	 * returns <code>true</code> if the zoommanager can perform
142
	 * <code>zoomOut()</code>.
143
	 * 
144
	 * @return boolean true if zoomOut can be called
145
	 */
146
	public boolean canZoomOut() {
147
		return getZoom() > getMinZoom();
148
	}
149
150
	/**
151
	 * Notifies listeners that the zoom level has changed.
152
	 */
153
	protected void fireZoomChanged() {
154
		Iterator iter = listeners.iterator();
155
		while (iter.hasNext()) {
156
			((ZoomListener) iter.next()).zoomChanged(zoom);
157
		}
158
	}
159
160
	private double getFitXZoomLevel(int which) {
161
		IFigure fig = getScalableFigure();
162
163
		Dimension available = getViewport().getClientArea().getSize();
164
		Dimension desired;
165
		if (fig instanceof FreeformFigure) {
166
			desired = ((FreeformFigure) fig).getFreeformExtent().getCopy()
167
					.union(0, 0).getSize();
168
		} else {
169
			desired = fig.getPreferredSize().getCopy();
170
		}
171
172
		desired.width -= fig.getInsets().getWidth();
173
		desired.height -= fig.getInsets().getHeight();
174
175
		while (fig != getViewport()) {
176
			available.width -= fig.getInsets().getWidth();
177
			available.height -= fig.getInsets().getHeight();
178
			fig = fig.getParent();
179
		}
180
181
		double scaleX = Math.min(available.width * zoom / desired.width,
182
				getMaxZoom());
183
		double scaleY = Math.min(available.height * zoom / desired.height,
184
				getMaxZoom());
185
		if (which == 0) {
186
			return scaleX;
187
		}
188
		if (which == 1) {
189
			return scaleY;
190
		}
191
		return Math.min(scaleX, scaleY);
192
	}
193
194
	/**
195
	 * Calculates and returns the zoom percent required so that the entire
196
	 * height of the {@link #getScalableFigure() scalable figure} is visible on
197
	 * the screen. This is the zoom level associated with {@link #FIT_HEIGHT}.
198
	 * 
199
	 * @return zoom setting required to fit the scalable figure vertically on
200
	 *         the screen
201
	 */
202
	protected double getFitHeightZoomLevel() {
203
		return getFitXZoomLevel(1);
204
	}
205
206
	/**
207
	 * Calculates and returns the zoom percentage required to fit the entire
208
	 * {@link #getScalableFigure() scalable figure} on the screen. This is the
209
	 * zoom setting associated with {@link #FIT_ALL}. It is the minimum of
210
	 * {@link #getFitHeightZoomLevel()} and {@link #getFitWidthZoomLevel()}.
211
	 * 
212
	 * @return zoom setting required to fit the entire scalable figure on the
213
	 *         screen
214
	 */
215
	protected double getFitPageZoomLevel() {
216
		return getFitXZoomLevel(2);
217
	}
218
219
	/**
220
	 * Calculates and returns the zoom percentage required so that the entire
221
	 * width of the {@link #getScalableFigure() scalable figure} is visible on
222
	 * the screen. This is the zoom setting associated with {@link #FIT_WIDTH}.
223
	 * 
224
	 * @return zoom setting required to fit the scalable figure horizontally on
225
	 *         the screen
226
	 */
227
	protected double getFitWidthZoomLevel() {
228
		return getFitXZoomLevel(0);
229
	}
230
231
	/**
232
	 * Returns the maxZoom.
233
	 * 
234
	 * @return double
235
	 */
236
	public double getMaxZoom() {
237
		return getZoomLevels()[getZoomLevels().length - 1];
238
	}
239
240
	/**
241
	 * Returns the minZoom.
242
	 * 
243
	 * @return double
244
	 */
245
	public double getMinZoom() {
246
		return getZoomLevels()[0];
247
	}
248
249
	/**
250
	 * Returns the mutltiplier. This value is used to use zoom levels internally
251
	 * that are proportionally different than those displayed to the user. e.g.
252
	 * with a multiplier value of 2.0, the zoom level 1.0 will be displayed as
253
	 * "200%".
254
	 * 
255
	 * @return double The multiplier
256
	 */
257
	public double getUIMultiplier() {
258
		return multiplier;
259
	}
260
261
	/**
262
	 * Returns the zoom level that is one level higher than the current level.
263
	 * If zoom level is at maximum, returns the maximum.
264
	 * 
265
	 * @return double The next zoom level
266
	 */
267
	public double getNextZoomLevel() {
268
		for (int i = 0; i < zoomLevels.length; i++) {
269
			if (zoomLevels[i] > zoom) {
270
				return zoomLevels[i];
271
			}
272
		}
273
		return getMaxZoom();
274
	}
275
276
	/**
277
	 * Returns the zoom level that is one level higher than the current level.
278
	 * If zoom level is at maximum, returns the maximum.
279
	 * 
280
	 * @return double The previous zoom level
281
	 */
282
	public double getPreviousZoomLevel() {
283
		for (int i = 1; i < zoomLevels.length; i++) {
284
			if (zoomLevels[i] >= zoom) {
285
				return zoomLevels[i - 1];
286
			}
287
		}
288
		return getMinZoom();
289
	}
290
291
	/**
292
	 * Returns the figure which performs the actual zooming.
293
	 * 
294
	 * @return the scalable figure
295
	 */
296
	public ScalableFigure getScalableFigure() {
297
		return pane;
298
	}
299
300
	/**
301
	 * Returns the viewport.
302
	 * 
303
	 * @return Viewport
304
	 */
305
	public Viewport getViewport() {
306
		return viewport;
307
	}
308
309
	/**
310
	 * Returns the current zoom level.
311
	 * 
312
	 * @return double the zoom level
313
	 */
314
	public double getZoom() {
315
		return zoom;
316
	}
317
318
	private String format(double d) {
319
		return "" + ((int) (d * 100)) + "%";
320
	}
321
322
	/**
323
	 * Returns the current zoom level as a percentage formatted String
324
	 * 
325
	 * @return String The current zoom level as a String
326
	 */
327
	public String getZoomAsText() {
328
		if (currentZoomContant != null) {
329
			return currentZoomContant;
330
		}
331
332
		// String newItem = format.format(zoom * multiplier);
333
		String newItem = format(zoom * multiplier);
334
		return newItem;
335
	}
336
337
	/**
338
	 * Returns the list of strings that should be appended to the list of
339
	 * numerical zoom levels. These could be things such as Fit Width, Fit Page,
340
	 * etc. May return <code>null</code>.
341
	 * 
342
	 * @return the list of contributed zoom levels
343
	 */
344
	public List getZoomLevelContributions() {
345
		return zoomLevelContributions;
346
	}
347
348
	/**
349
	 * Returns the zoomLevels.
350
	 * 
351
	 * @return double[]
352
	 */
353
	public double[] getZoomLevels() {
354
		return zoomLevels;
355
	}
356
357
	/**
358
	 * Returns the list of zoom levels as Strings in percent notation, plus any
359
	 * additional zoom levels that were contributed using
360
	 * {@link #setZoomLevelContributions(List)}.
361
	 * 
362
	 * @return List The list of zoom levels
363
	 */
364
	public String[] getZoomLevelsAsText() {
365
		String[] zoomLevelStrings = new String[zoomLevels.length
366
				+ zoomLevelContributions.size()];
367
368
		if (zoomLevelContributions != null) {
369
			for (int i = 0; i < zoomLevelContributions.size(); i++) {
370
				zoomLevelStrings[i] = (String) zoomLevelContributions.get(i);
371
			}
372
		}
373
		for (int i = 0; i < zoomLevels.length; i++) {
374
			// zoomLevelStrings[i + zoomLevelContributions.size()] =
375
			// format.format(zoomLevels[i] * multiplier);
376
			zoomLevelStrings[i + zoomLevelContributions.size()] = format(zoomLevels[i]
377
					* multiplier);
378
		}
379
380
		return zoomLevelStrings;
381
	}
382
383
	/**
384
	 * Sets the zoom level to the given value. Min-max range check is not done.
385
	 * 
386
	 * @param zoom
387
	 *            the new zoom level
388
	 */
389
	protected void primSetZoom(double zoom) {
390
		Point p1 = getViewport().getClientArea().getCenter();
391
		Point p2 = p1.getCopy();
392
		Point p = getViewport().getViewLocation();
393
		double prevZoom = this.zoom;
394
		this.zoom = zoom;
395
		pane.setScale(zoom);
396
		fireZoomChanged();
397
		getViewport().validate();
398
399
		p2.scale(zoom / prevZoom);
400
		Dimension dif = p2.getDifference(p1);
401
		p.x += dif.width;
402
		p.y += dif.height;
403
		setViewLocation(p);
404
	}
405
406
	/**
407
	 * Removes the given ZoomListener from this ZoomManager's list of listeners.
408
	 * 
409
	 * @param listener
410
	 *            the ZoomListener to be removed
411
	 */
412
	public void removeZoomListener(ZoomListener listener) {
413
		listeners.remove(listener);
414
	}
415
416
	/**
417
	 * Sets the UI multiplier. The UI multiplier is applied to all zoom settings
418
	 * when they are presented to the user ({@link #getZoomAsText()}).
419
	 * Similarly, the multiplier is inversely applied when the user specifies a
420
	 * zoom level ({@link #setZoomAsText(String)}).
421
	 * <P>
422
	 * When the UI multiplier is <code>1.0</code>, the User will see the exact
423
	 * zoom level that is being applied. If the value is <code>2.0</code>, then
424
	 * a scale of <code>0.5</code> will be labeled "100%" to the User.
425
	 * 
426
	 * @param multiplier
427
	 *            The mutltiplier to set
428
	 */
429
	public void setUIMultiplier(double multiplier) {
430
		this.multiplier = multiplier;
431
	}
432
433
	/**
434
	 * Sets the Viewport's view associated with this ZoomManager to the passed
435
	 * Point
436
	 * 
437
	 * @param p
438
	 *            The new location for the Viewport's view.
439
	 */
440
	public void setViewLocation(Point p) {
441
		viewport.setViewLocation(p.x, p.y);
442
443
	}
444
445
	/**
446
	 * Sets the zoom level to the given value. If the zoom is out of the min-max
447
	 * range, it will be ignored.
448
	 * 
449
	 * @param zoom
450
	 *            the new zoom level
451
	 */
452
	public void setZoom(double zoom) {
453
		currentZoomContant = null;
454
		zoom = Math.min(getMaxZoom(), zoom);
455
		zoom = Math.max(getMinZoom(), zoom);
456
		if (this.zoom != zoom) {
457
			primSetZoom(zoom);
458
		}
459
	}
460
461
	/**
462
	 * Sets which zoom methods get animated.
463
	 * 
464
	 * @param style
465
	 *            the style bits determining the zoom methods to be animated.
466
	 */
467
	public void setZoomAnimationStyle(int style) {
468
		// zoomAnimationStyle = style;
469
	}
470
471
	/**
472
	 * Sets zoom to the passed string. The string must be composed of numeric
473
	 * characters only with the exception of a decimal point and a '%' as the
474
	 * last character. If the zoom level contribution list has been set, this
475
	 * method should be overridden to provide the appropriate zoom
476
	 * implementation for the new zoom levels.
477
	 * 
478
	 * @param zoomString
479
	 *            The new zoom level
480
	 */
481
	public void setZoomAsText(String zoomString) {
482
		currentZoomContant = null;
483
		if (zoomString.equalsIgnoreCase(FIT_HEIGHT)) {
484
			currentZoomContant = FIT_HEIGHT;
485
			primSetZoom(getFitHeightZoomLevel());
486
			viewport.getUpdateManager().performUpdate();
487
			viewport.setViewLocation(viewport.getHorizontalRangeModel()
488
					.getValue(), viewport.getVerticalRangeModel().getMinimum());
489
		} else if (zoomString.equalsIgnoreCase(FIT_ALL)) {
490
			currentZoomContant = FIT_ALL;
491
			primSetZoom(getFitPageZoomLevel());
492
			viewport.getUpdateManager().performUpdate();
493
			viewport.setViewLocation(viewport.getHorizontalRangeModel()
494
					.getMinimum(), viewport.getVerticalRangeModel()
495
					.getMinimum());
496
		} else if (zoomString.equalsIgnoreCase(FIT_WIDTH)) {
497
			currentZoomContant = FIT_WIDTH;
498
			primSetZoom(getFitWidthZoomLevel());
499
			viewport.getUpdateManager().performUpdate();
500
			viewport.setViewLocation(viewport.getHorizontalRangeModel()
501
					.getMinimum(), viewport.getVerticalRangeModel().getValue());
502
		} else {
503
			try {
504
				// Trim off the '%'
505
				if (zoomString.charAt(zoomString.length() - 1) == '%') {
506
					zoomString = zoomString.substring(0,
507
							zoomString.length() - 1);
508
				}
509
				double newZoom = Double.parseDouble(zoomString) / 100;
510
				setZoom(newZoom / multiplier);
511
			} catch (Exception e) {
512
				Display.getCurrent().beep();
513
			}
514
		}
515
	}
516
517
	/**
518
	 * Sets the list of zoom level contributions (as strings). If you contribute
519
	 * something <b>other than</b> {@link #FIT_HEIGHT}, {@link #FIT_WIDTH} and
520
	 * {@link #FIT_ALL} you must subclass this class and override this method to
521
	 * implement your contributed zoom function.
522
	 * 
523
	 * @param contributions
524
	 *            the list of contributed zoom levels
525
	 */
526
	public void setZoomLevelContributions(List contributions) {
527
		zoomLevelContributions = contributions;
528
	}
529
530
	/**
531
	 * Sets the zoomLevels.
532
	 * 
533
	 * @param zoomLevels
534
	 *            The zoomLevels to set
535
	 */
536
	public void setZoomLevels(double[] zoomLevels) {
537
		this.zoomLevels = zoomLevels;
538
	}
539
540
	/**
541
	 * Sets the zoom level to be one level higher
542
	 */
543
	public void zoomIn() {
544
		setZoom(getNextZoomLevel());
545
	}
546
547
	/**
548
	 * Currently does nothing.
549
	 * 
550
	 * @param rect
551
	 *            a rectangle
552
	 */
553
	public void zoomTo(Rectangle rect) {
554
	}
555
556
	// private void performAnimatedZoom(Rectangle rect, boolean zoomIn, int
557
	// iterationCount) {
558
	// double finalRatio;
559
	// double zoomIncrement;
560
	//	
561
	// if (zoomIn) {
562
	// finalRatio = zoom / getNextZoomLevel();
563
	// zoomIncrement = (getNextZoomLevel() - zoom) / iterationCount;
564
	// } else {
565
	// finalRatio = zoom / getPreviousZoomLevel();
566
	// zoomIncrement = (getPreviousZoomLevel() - zoom) / iterationCount;
567
	// }
568
	//	
569
	// getScalableFigure().translateToRelative(rect);
570
	// Point originalViewLocation = getViewport().getViewLocation();
571
	// Point finalViewLocation = calculateViewLocation(rect, finalRatio);
572
	//	
573
	// double xIncrement =
574
	// (double) (finalViewLocation.x - originalViewLocation.x) / iterationCount;
575
	// double yIncrement =
576
	// (double) (finalViewLocation.y - originalViewLocation.y) / iterationCount;
577
	//	
578
	// double originalZoom = zoom;
579
	// Point currentViewLocation = new Point();
580
	// for (int i = 1; i < iterationCount; i++) {
581
	// currentViewLocation.x = (int)(originalViewLocation.x + (xIncrement * i));
582
	// currentViewLocation.y = (int)(originalViewLocation.y + (yIncrement * i));
583
	// setZoom(originalZoom + zoomIncrement * i);
584
	// getViewport().validate();
585
	// setViewLocation(currentViewLocation);
586
	// getViewport().getUpdateManager().performUpdate();
587
	// }
588
	//	
589
	// if (zoomIn)
590
	// setZoom(getNextZoomLevel());
591
	// else
592
	// setZoom(getPreviousZoomLevel());
593
	//	
594
	// getViewport().validate();
595
	// setViewLocation(finalViewLocation);
596
	// }
597
	//
598
	// private Point calculateViewLocation(Rectangle zoomRect, double ratio) {
599
	// Point viewLocation = new Point();
600
	// viewLocation.x = (int)(zoomRect.x / ratio);
601
	// viewLocation.y = (int)(zoomRect.y / ratio);
602
	// return viewLocation;
603
	// }
604
605
	/**
606
	 * Sets the zoom level to be one level lower
607
	 */
608
	public void zoomOut() {
609
		setZoom(getPreviousZoomLevel());
610
	}
611
612
}
(-).refactorings/2009/8/35/refactorings.index (+5 lines)
Added Link Here
1
1251470760220	Delete element
2
1251470800714	Delete elements
3
1251470850904	Delete element
4
1251470853786	Delete element
5
1251470950914	Delete element
(-)src/org/eclipse/zest/core/widgets/custom/CGraphNode.java (+76 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria 
9
 *               Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
10
 ******************************************************************************/
11
package org.eclipse.zest.core.widgets.custom;
12
13
import org.eclipse.draw2d.IFigure;
14
import org.eclipse.swt.graphics.Color;
15
import org.eclipse.swt.graphics.Font;
16
import org.eclipse.zest.core.widgets.Graph;
17
import org.eclipse.zest.core.widgets.GraphContainer;
18
import org.eclipse.zest.core.widgets.GraphNode;
19
20
/**
21
 * A Custom Graph Node
22
 * 
23
 * @since 2.0
24
 */
25
public class CGraphNode extends GraphNode {
26
27
	IFigure figure = null;
28
29
	/**
30
	 * @since 2.0
31
	 */
32
	public CGraphNode(Graph graphModel, int style, IFigure figure) {
33
		super(graphModel, style, figure);
34
	}
35
36
	/**
37
	 * @since 2.0
38
	 */
39
	public CGraphNode(GraphContainer graphModel, int style, IFigure figure) {
40
		super(graphModel, style, figure);
41
	}
42
43
	public IFigure getFigure() {
44
		return super.getFigure();
45
	}
46
47
	protected IFigure createFigureForModel() {
48
		this.figure = (IFigure) this.getData();
49
		return this.figure;
50
	}
51
52
	public void setBackgroundColor(Color c) {
53
		getFigure().setBackgroundColor(c);
54
	}
55
56
	public void setFont(Font font) {
57
		getFigure().setFont(font);
58
	}
59
60
	public Color getBackgroundColor() {
61
		return getFigure().getBackgroundColor();
62
	}
63
64
	public Font getFont() {
65
		return getFigure().getFont();
66
	}
67
68
	public Color getForegroundColor() {
69
		return getFigure().getForegroundColor();
70
	}
71
72
	protected void updateFigureForModel(IFigure currentFigure) {
73
		// Undefined
74
	}
75
76
}
(-)src/org/eclipse/zest/core/widgets/LayoutFilter.java (+20 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors: The Chisel Group, University of Victoria 
9
 *               Mateusz Matela
10
 ******************************************************************************/
11
package org.eclipse.zest.core.widgets;
12
13
/**
14
 * @since 2.0
15
 */
16
public interface LayoutFilter {
17
18
	public boolean isObjectFiltered(GraphItem item);
19
20
}
(-)src/org/eclipse/zest/core/widgets/custom/LabelSubgraph.java (+68 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets.custom;
11
12
import org.eclipse.draw2d.Label;
13
import org.eclipse.swt.graphics.Color;
14
import org.eclipse.zest.core.widgets.FigureSubgraph;
15
import org.eclipse.zest.core.widgets.internal.GraphLabel;
16
import org.eclipse.zest.layouts.interfaces.LayoutContext;
17
import org.eclipse.zest.layouts.interfaces.NodeLayout;
18
19
/**
20
 * A subgraph layout that displays a label showing number of items pruned within
21
 * it.
22
 * 
23
 * @since 2.0
24
 */
25
public class LabelSubgraph extends FigureSubgraph {
26
27
	private Color backgroundColor;
28
	private Color foregroundColor;
29
30
	/**
31
	 * Sets the foreground color of this subgraph (that is color of the text on
32
	 * the label).
33
	 * 
34
	 * @param color
35
	 *            color to set
36
	 */
37
	public void setForegroundColor(Color color) {
38
		figure.setForegroundColor(color);
39
	}
40
41
	/**
42
	 * Sets the background color of this subgraph's label.
43
	 * 
44
	 * @param color
45
	 *            color to set
46
	 */
47
	public void setBackgroundColor(Color color) {
48
		figure.setBackgroundColor(color);
49
	}
50
51
	protected void createFigure() {
52
		figure = new GraphLabel(false);
53
		figure.setForegroundColor(foregroundColor);
54
		figure.setBackgroundColor(backgroundColor);
55
		updateFigure();
56
	}
57
58
	protected void updateFigure() {
59
		((Label) figure).setText("" + nodes.size());
60
	}
61
62
	public LabelSubgraph(NodeLayout[] nodes, LayoutContext context,
63
			Color foregroundColor, Color backgroundColor) {
64
		super(nodes, context);
65
		this.foregroundColor = foregroundColor;
66
		this.backgroundColor = backgroundColor;
67
	}
68
}
(-).refactorings/2009/8/35/refactorings.history (+3 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<session version="1.0">&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.core&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.core&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.core.viewers.internal.AbstractStructuredGraphViewer.java&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 2 element(s) from project &apos;org.eclipse.zest.core&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.core&apos;&#x0D;&#x0A;- Original elements:&#x0D;&#x0A;     org.eclipse.zest.core.viewers.internal.ZoomListener.java&#x0D;&#x0A;     org.eclipse.zest.core.viewers.internal.ZoomManager.java" description="Delete elements" element1="/src&lt;org.eclipse.zest.core.viewers.internal{ZoomListener.java" element2="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.core&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.core&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.core.widgets.CGraphNode.java&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.core&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.core&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.core.widgets.ConstraintAdapter.java&apos;" description="Delete element" element1="/src&lt;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"/>&#x0A;<refactoring accessors="true" comment="Delete 1 element(s) from project &apos;org.eclipse.zest.core&apos;&#x0D;&#x0A;- Original project: &apos;org.eclipse.zest.core&apos;&#x0D;&#x0A;- Original element: &apos;org.eclipse.zest.core.widgets.internal.ExpandGraphLabel.java&apos;" description="Delete element" element1="/src&lt;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"/>
3
</session>
(-)src/org/eclipse/zest/core/viewers/AbstractStructuredGraphViewer.java (+774 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright 2005-2009, CHISEL Group, University of Victoria, Victoria, BC,
3
 * Canada. All rights reserved. This program and the accompanying materials are
4
 * made available under the terms of the Eclipse Public License v1.0 which
5
 * accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     The Chisel Group, University of Victoria
10
 *     Mateusz Matela <mateusz.matela@gmail.com> - [tree] Add Space Tree support to Graph widget - https://bugs.eclipse.org/bugs/show_bug.cgi?id=277534
11
 ******************************************************************************/
12
package org.eclipse.zest.core.viewers;
13
14
import java.util.ArrayList;
15
import java.util.Comparator;
16
import java.util.HashMap;
17
import java.util.Iterator;
18
import java.util.LinkedList;
19
import java.util.List;
20
import java.util.Map;
21
import java.util.TreeSet;
22
23
import org.eclipse.draw2d.IFigure;
24
import org.eclipse.swt.SWT;
25
import org.eclipse.swt.SWTError;
26
import org.eclipse.swt.events.DisposeEvent;
27
import org.eclipse.swt.widgets.Widget;
28
import org.eclipse.zest.core.viewers.internal.IStylingGraphModelFactory;
29
import org.eclipse.zest.core.widgets.Graph;
30
import org.eclipse.zest.core.widgets.GraphConnection;
31
import org.eclipse.zest.core.widgets.GraphContainer;
32
import org.eclipse.zest.core.widgets.GraphItem;
33
import org.eclipse.zest.core.widgets.GraphNode;
34
import org.eclipse.zest.core.widgets.ZestStyles;
35
import org.eclipse.zest.core.widgets.custom.CGraphNode;
36
import org.eclipse.zest.layouts.LayoutAlgorithm;
37
38
/**
39
 * Abstraction of graph viewers to implement functionality used by all of them.
40
 * Not intended to be implemented by clients. Use one of the provided children
41
 * instead.
42
 * 
43
 * @author Del Myers
44
 * @since 2.0
45
 */
46
public abstract class AbstractStructuredGraphViewer extends AbstractZoomableViewer {
47
	/**
48
	 * Contains top-level styles for the entire graph. Set in the constructor. *
49
	 */
50
	private int graphStyle;
51
52
	/**
53
	 * Contains node-level styles for the graph. Set in setNodeStyle(). Defaults
54
	 * are used in the constructor.
55
	 */
56
	private int nodeStyle;
57
58
	/**
59
	 * Contains arc-level styles for the graph. Set in setConnectionStyle().
60
	 * Defaults are used in the constructor.
61
	 */
62
	private int connectionStyle;
63
64
	private HashMap nodesMap = new HashMap();
65
	private HashMap connectionsMap = new HashMap();
66
67
	/**
68
	 * A simple graph comparator that orders graph elements based on thier type
69
	 * (connection or node), and their unique object identification.
70
	 */
71
	private class SimpleGraphComparator implements Comparator {
72
		TreeSet storedStrings;
73
74
		/**
75
		 * 
76
		 */
77
		public SimpleGraphComparator() {
78
			this.storedStrings = new TreeSet();
79
		}
80
81
		/*
82
		 * (non-Javadoc)
83
		 * 
84
		 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
85
		 */
86
		public int compare(Object arg0, Object arg1) {
87
			if (arg0 instanceof GraphNode && arg1 instanceof GraphConnection) {
88
				return 1;
89
			} else if (arg0 instanceof GraphConnection && arg1 instanceof GraphNode) {
90
				return -1;
91
			}
92
			if (arg0.equals(arg1)) {
93
				return 0;
94
			}
95
			return getObjectString(arg0).compareTo(getObjectString(arg1));
96
		}
97
98
		private String getObjectString(Object o) {
99
			String s = o.getClass().getName() + "@" + Integer.toHexString(o.hashCode());
100
			while (storedStrings.contains(s)) {
101
				s = s + 'X';
102
			}
103
			return s;
104
		}
105
	}
106
107
	protected AbstractStructuredGraphViewer(int graphStyle) {
108
		this.graphStyle = graphStyle;
109
		this.connectionStyle = SWT.NONE;
110
		this.nodeStyle = SWT.NONE;
111
112
	}
113
114
	/**
115
	 * Sets the default style for nodes in this graph. Note: if an input is set
116
	 * on the viewer, a ZestException will be thrown.
117
	 * 
118
	 * @param nodeStyle
119
	 *            the style for the nodes.
120
	 * @see #ZestStyles
121
	 */
122
	public void setNodeStyle(int nodeStyle) {
123
		if (getInput() != null) {
124
			throw new SWTError(SWT.ERROR_UNSPECIFIED);
125
		}
126
		this.nodeStyle = nodeStyle;
127
	}
128
129
	/**
130
	 * Sets the default style for connections in this graph. Note: if an input
131
	 * is set on the viewer, a ZestException will be thrown.
132
	 * 
133
	 * @param connectionStyle
134
	 *            the style for the connections.
135
	 * @see #ZestStyles
136
	 */
137
	public void setConnectionStyle(int connectionStyle) {
138
		if (getInput() != null) {
139
			throw new SWTError(SWT.ERROR_UNSPECIFIED);
140
		}
141
		if (!ZestStyles.validateConnectionStyle(connectionStyle)) {
142
			throw new SWTError(SWT.ERROR_INVALID_ARGUMENT);
143
		}
144
		this.connectionStyle = connectionStyle;
145
	}
146
147
	/**
148
	 * Returns the style set for the graph
149
	 * 
150
	 * @return The style set of the graph
151
	 */
152
	public int getGraphStyle() {
153
		return graphStyle;
154
	}
155
156
	/**
157
	 * Returns the style set for the nodes.
158
	 * 
159
	 * @return the style set for the nodes.
160
	 */
161
	public int getNodeStyle() {
162
		return nodeStyle;
163
	}
164
165
	public Graph getGraphControl() {
166
		return (Graph) getControl();
167
	}
168
169
	/**
170
	 * @return the connection style.
171
	 */
172
	public int getConnectionStyle() {
173
		return connectionStyle;
174
	}
175
176
	/**
177
	 * Sets the layout algorithm for this viewer. Subclasses may place
178
	 * restrictions on the algorithms that it accepts.
179
	 * 
180
	 * @param algorithm
181
	 *            the layout algorithm
182
	 * @param run
183
	 *            true if the layout algorithm should be run immediately. This
184
	 *            is a hint.
185
	 */
186
	public abstract void setLayoutAlgorithm(LayoutAlgorithm algorithm, boolean run);
187
188
	/**
189
	 * Gets the current layout algorithm.
190
	 * 
191
	 * @return the current layout algorithm.
192
	 */
193
	protected abstract LayoutAlgorithm getLayoutAlgorithm();
194
195
	/**
196
	 * Equivalent to setLayoutAlgorithm(algorithm, false).
197
	 * 
198
	 * @param algorithm
199
	 */
200
	public void setLayoutAlgorithm(LayoutAlgorithm algorithm) {
201
		setLayoutAlgorithm(algorithm, false);
202
	}
203
204
	public Object[] getNodeElements() {
205
		return this.nodesMap.keySet().toArray();
206
	}
207
208
	public Object[] getConnectionElements() {
209
		return this.connectionsMap.keySet().toArray();
210
	}
211
212
	/**
213
	 * @noreference This method is not intended to be referenced by clients.
214
	 * @return
215
	 */
216
	public HashMap getNodesMap() {
217
		return this.nodesMap;
218
	}
219
220
	/**
221
	 * 
222
	 * @param element
223
	 * @return
224
	 * @noreference This method is not intended to be referenced by clients.
225
	 */
226
	public GraphNode addGraphModelContainer(Object element) {
227
		GraphNode node = this.getGraphModelNode(element);
228
		if (node == null) {
229
			node = new GraphContainer((Graph) getControl(), SWT.NONE);
230
			this.nodesMap.put(element, node);
231
			node.setData(element);
232
		}
233
		return node;
234
	}
235
236
	/**
237
	 * 
238
	 * @param container
239
	 * @param element
240
	 * @return
241
	 * @noreference This method is not intended to be referenced by clients.
242
	 */
243
	public GraphNode addGraphModelNode(GraphContainer container, Object element) {
244
		GraphNode node = this.getGraphModelNode(element);
245
		if (node == null) {
246
			node = new GraphNode(container, SWT.NONE);
247
			this.nodesMap.put(element, node);
248
			node.setData(element);
249
		}
250
		return node;
251
	}
252
253
	/**
254
	 * 
255
	 * @param element
256
	 * @param figure
257
	 * @return
258
	 * @noreference This method is not intended to be referenced by clients.
259
	 */
260
	public GraphNode addGraphModelNode(Object element, IFigure figure) {
261
		GraphNode node = this.getGraphModelNode(element);
262
		if (node == null) {
263
			if (figure != null) {
264
				node = new CGraphNode((Graph) getControl(), SWT.NONE, figure);
265
				this.nodesMap.put(element, node);
266
				node.setData(element);
267
			} else {
268
				node = new GraphNode((Graph) getControl(), SWT.NONE);
269
				this.nodesMap.put(element, node);
270
				node.setData(element);
271
			}
272
		}
273
		return node;
274
	}
275
276
	/**
277
	 * 
278
	 * @param element
279
	 * @param source
280
	 * @param target
281
	 * @return
282
	 * @noreference This method is not intended to be referenced by clients.
283
	 */
284
	public GraphConnection addGraphModelConnection(Object element, GraphNode source, GraphNode target) {
285
		GraphConnection connection = this.getGraphModelConnection(element);
286
		if (connection == null) {
287
			connection = new GraphConnection((Graph) getControl(), SWT.NONE, source, target);
288
			this.connectionsMap.put(element, connection);
289
			connection.setData(element);
290
		}
291
		return connection;
292
293
	}
294
295
	/**
296
	 * 
297
	 * @param obj
298
	 * @return
299
	 * @noreference This method is not intended to be referenced by clients.
300
	 */
301
	public GraphConnection getGraphModelConnection(Object obj) {
302
		return (GraphConnection) this.connectionsMap.get(obj);
303
	}
304
305
	/**
306
	 * 
307
	 * @param obj
308
	 * @return
309
	 * @noreference This method is not intended to be referenced by clients.
310
	 */
311
	public GraphNode getGraphModelNode(Object obj) {
312
		return (GraphNode) this.nodesMap.get(obj);
313
	}
314
315
	/**
316
	 * @param obj
317
	 * @noreference This method is not intended to be referenced by clients.
318
	 */
319
	public void removeGraphModelConnection(Object obj) {
320
		GraphConnection connection = (GraphConnection) connectionsMap.get(obj);
321
		if (connection != null) {
322
			connectionsMap.remove(obj);
323
			if (!connection.isDisposed()) {
324
				connection.dispose();
325
			}
326
		}
327
	}
328
329
	/**
330
	 * @noreference This method is not intended to be referenced by clients.
331
	 */
332
	public void removeGraphModelNode(Object obj) {
333
		GraphNode node = (GraphNode) nodesMap.get(obj);
334
		if (node != null) {
335
			nodesMap.remove(obj);
336
			if (!node.isDisposed()) {
337
				node.dispose();
338
			}
339
		}
340
	}
341
342
	protected void handleDispose(DisposeEvent event) {
343
344
		if (getControl() != null && !getControl().isDisposed()) {
345
			getControl().dispose();
346
		}
347
		super.handleDispose(event);
348
	}
349
350
	/*
351
	 * (non-Javadoc)
352
	 * 
353
	 * @see org.eclipse.jface.viewers.StructuredViewer#internalRefresh(java.lang.Object)
354
	 */
355
	protected void internalRefresh(Object element) {
356
		if (getInput() == null) {
357
			return;
358
		}
359
		if (element == getInput()) {
360
			getFactory().refreshGraph(getGraphControl());
361
		} else {
362
			getFactory().refresh(getGraphControl(), element);
363
		}
364
		// After all the items are loaded, we call update to ensure drawing.
365
		// This way the damaged area does not get too big if we start
366
		// adding and removing more nodes
367
		getGraphControl().getLightweightSystem().getUpdateManager().performUpdate();
368
	}
369
370
	protected void doUpdateItem(Widget item, Object element, boolean fullMap) {
371
		if (item == getGraphControl()) {
372
			getFactory().update(getNodesArray(getGraphControl()));
373
			getFactory().update(getConnectionsArray(getGraphControl()));
374
		} else if (item instanceof GraphItem) {
375
			getFactory().update((GraphItem) item);
376
		}
377
	}
378
379
	/*
380
	 * (non-Javadoc)
381
	 * 
382
	 * @see org.eclipse.jface.viewers.StructuredViewer#doFindInputItem(java.lang.Object)
383
	 */
384
	protected Widget doFindInputItem(Object element) {
385
386
		if (element == getInput() && element instanceof Widget) {
387
			return (Widget) element;
388
		}
389
		return null;
390
	}
391
392
	/*
393
	 * (non-Javadoc)
394
	 * 
395
	 * @see org.eclipse.jface.viewers.StructuredViewer#doFindItem(java.lang.Object)
396
	 */
397
	protected Widget doFindItem(Object element) {
398
		Widget node = (Widget) nodesMap.get(element);
399
		Widget connection = (Widget) connectionsMap.get(element);
400
		return (node != null) ? node : connection;
401
	}
402
403
	/*
404
	 * (non-Javadoc)
405
	 * 
406
	 * @see org.eclipse.jface.viewers.StructuredViewer#getSelectionFromWidget()
407
	 */
408
	protected List getSelectionFromWidget() {
409
		List internalSelection = getWidgetSelection();
410
		LinkedList externalSelection = new LinkedList();
411
		for (Iterator i = internalSelection.iterator(); i.hasNext();) {
412
			// @tag zest.todo : should there be a method on IGraphItem to get
413
			// the external data?
414
			GraphItem item = (GraphItem) i.next();
415
			if (item instanceof GraphNode) {
416
				externalSelection.add(((GraphNode) item).getData());
417
			} else if (item instanceof GraphConnection) {
418
				externalSelection.add(((GraphConnection) item).getExternalConnection());
419
			} else if (item instanceof Widget) {
420
				externalSelection.add(((Widget) item).getData());
421
			}
422
		}
423
		return externalSelection;
424
	}
425
426
	protected GraphItem[] /* GraphItem */findItems(List l) {
427
		if (l == null) {
428
			return new GraphItem[0];
429
		}
430
431
		ArrayList list = new ArrayList();
432
		Iterator iterator = l.iterator();
433
434
		while (iterator.hasNext()) {
435
			GraphItem w = (GraphItem) findItem(iterator.next());
436
			list.add(w);
437
		}
438
		return (GraphItem[]) list.toArray(new GraphItem[list.size()]);
439
	}
440
441
	/*
442
	 * (non-Javadoc)
443
	 * 
444
	 * @see org.eclipse.jface.viewers.StructuredViewer#setSelectionToWidget(java.util.List,
445
	 *      boolean)
446
	 */
447
	protected void setSelectionToWidget(List l, boolean reveal) {
448
		Graph control = (Graph) getControl();
449
		List selection = new LinkedList();
450
		for (Iterator i = l.iterator(); i.hasNext();) {
451
			Object obj = i.next();
452
			GraphNode node = (GraphNode) nodesMap.get(obj);
453
			GraphConnection conn = (GraphConnection) connectionsMap.get(obj);
454
			if (node != null) {
455
				selection.add(node);
456
			}
457
			if (conn != null) {
458
				selection.add(conn);
459
			}
460
		}
461
		control.setSelection((GraphNode[]) selection.toArray(new GraphNode[selection.size()]));
462
	}
463
464
	/**
465
	 * Gets the internal model elements that are selected.
466
	 * 
467
	 * @return
468
	 */
469
	protected List getWidgetSelection() {
470
		Graph control = (Graph) getControl();
471
		return control.getSelection();
472
	}
473
474
	/*
475
	 * (non-Javadoc)
476
	 * 
477
	 * @see org.eclipse.jface.viewers.Viewer#inputChanged(java.lang.Object,
478
	 *      java.lang.Object)
479
	 */
480
	protected void inputChanged(Object input, Object oldInput) {
481
		IStylingGraphModelFactory factory = getFactory();
482
		factory.setConnectionStyle(getConnectionStyle());
483
		factory.setNodeStyle(getNodeStyle());
484
485
		// Save the old map so we can set the size and position of any nodes
486
		// that are the same
487
		Map oldNodesMap = nodesMap;
488
		Graph graph = (Graph) getControl();
489
		graph.setSelection(new GraphNode[0]);
490
491
		Iterator iterator = nodesMap.values().iterator();
492
		while (iterator.hasNext()) {
493
			GraphNode node = (GraphNode) iterator.next();
494
			if (!node.isDisposed()) {
495
				node.dispose();
496
			}
497
		}
498
499
		iterator = connectionsMap.values().iterator();
500
		while (iterator.hasNext()) {
501
			GraphConnection connection = (GraphConnection) iterator.next();
502
			if (!connection.isDisposed()) {
503
				connection.dispose();
504
			}
505
		}
506
507
		nodesMap = new HashMap();
508
		connectionsMap = new HashMap();
509
510
		graph = factory.createGraphModel(graph);
511
512
		((Graph) getControl()).setNodeStyle(getNodeStyle());
513
		((Graph) getControl()).setConnectionStyle(getConnectionStyle());
514
515
		// check if any of the pre-existing nodes are still present
516
		// in this case we want them to keep the same location & size
517
		for (Iterator iter = oldNodesMap.keySet().iterator(); iter.hasNext();) {
518
			Object data = iter.next();
519
			GraphNode newNode = (GraphNode) nodesMap.get(data);
520
			if (newNode != null) {
521
				GraphNode oldNode = (GraphNode) oldNodesMap.get(data);
522
				newNode.setLocation(oldNode.getLocation().x, oldNode.getLocation().y);
523
				if (oldNode.isSizeFixed()) {
524
					newNode.setSize(oldNode.getSize().width, oldNode.getSize().height);
525
				}
526
			}
527
		}
528
	}
529
530
	/**
531
	 * Returns the factory used to create the model. This must not be called
532
	 * before the content provider is set.
533
	 * 
534
	 * @return
535
	 * @noreference This method is not intended to be referenced by clients.
536
	 * @nooverride This method is not intended to be re-implemented or extended by clients.
537
	 */
538
	protected abstract IStylingGraphModelFactory getFactory();
539
540
	protected void filterVisuals() {
541
		if (getGraphControl() == null) {
542
			return;
543
		}
544
		Object[] filtered = getFilteredChildren(getInput());
545
		SimpleGraphComparator comparator = new SimpleGraphComparator();
546
		TreeSet filteredElements = new TreeSet(comparator);
547
		TreeSet unfilteredElements = new TreeSet(comparator);
548
		List connections = getGraphControl().getConnections();
549
		List nodes = getGraphControl().getNodes();
550
		if (filtered.length == 0) {
551
			// set everything to invisible.
552
			// @tag zest.bug.156528-Filters.check : should we only filter out
553
			// the nodes?
554
			for (Iterator i = connections.iterator(); i.hasNext();) {
555
				GraphConnection c = (GraphConnection) i.next();
556
				c.setVisible(false);
557
			}
558
			for (Iterator i = nodes.iterator(); i.hasNext();) {
559
				GraphNode n = (GraphNode) i.next();
560
				n.setVisible(false);
561
			}
562
			return;
563
		}
564
		for (Iterator i = connections.iterator(); i.hasNext();) {
565
			GraphConnection c = (GraphConnection) i.next();
566
			if (c.getExternalConnection() != null) {
567
				unfilteredElements.add(c);
568
			}
569
		}
570
		for (Iterator i = nodes.iterator(); i.hasNext();) {
571
			GraphNode n = (GraphNode) i.next();
572
			if (n.getData() != null) {
573
				unfilteredElements.add(n);
574
			}
575
		}
576
		for (int i = 0; i < filtered.length; i++) {
577
			Object modelElement = connectionsMap.get(filtered[i]);
578
			if (modelElement == null) {
579
				modelElement = nodesMap.get(filtered[i]);
580
			}
581
			if (modelElement != null) {
582
				filteredElements.add(modelElement);
583
			}
584
		}
585
		unfilteredElements.removeAll(filteredElements);
586
		// set all the elements that did not pass the filters to invisible, and
587
		// all the elements that passed to visible.
588
		while (unfilteredElements.size() > 0) {
589
			GraphItem i = (GraphItem) unfilteredElements.first();
590
			i.setVisible(false);
591
			unfilteredElements.remove(i);
592
		}
593
		while (filteredElements.size() > 0) {
594
			GraphItem i = (GraphItem) filteredElements.first();
595
			i.setVisible(true);
596
			filteredElements.remove(i);
597
		}
598
	}
599
600
	/*
601
	 * (non-Javadoc)
602
	 * 
603
	 * @see org.eclipse.jface.viewers.StructuredViewer#getRawChildren(java.lang.Object)
604
	 */
605
	protected Object[] getRawChildren(Object parent) {
606
		if (parent == getInput()) {
607
			// get the children from the model.
608
			LinkedList children = new LinkedList();
609
			if (getGraphControl() != null) {
610
				List connections = getGraphControl().getConnections();
611
				List nodes = getGraphControl().getNodes();
612
				for (Iterator i = connections.iterator(); i.hasNext();) {
613
					GraphConnection c = (GraphConnection) i.next();
614
					if (c.getExternalConnection() != null) {
615
						children.add(c.getExternalConnection());
616
					}
617
				}
618
				for (Iterator i = nodes.iterator(); i.hasNext();) {
619
					GraphNode n = (GraphNode) i.next();
620
					if (n.getData() != null) {
621
						children.add(n.getData());
622
					}
623
				}
624
				return children.toArray();
625
			}
626
		}
627
		return super.getRawChildren(parent);
628
	}
629
630
	/**
631
	 * 
632
	 */
633
	public void reveal(Object element) {
634
		Widget[] items = this.findItems(element);
635
		for (int i = 0; i < items.length; i++) {
636
			Widget item = items[i];
637
			if (item instanceof GraphNode) {
638
				GraphNode graphModelNode = (GraphNode) item;
639
				graphModelNode.highlight();
640
			} else if (item instanceof GraphConnection) {
641
				GraphConnection graphModelConnection = (GraphConnection) item;
642
				graphModelConnection.highlight();
643
			}
644
		}
645
	}
646
647
	public void unReveal(Object element) {
648
		Widget[] items = this.findItems(element);
649
		for (int i = 0; i < items.length; i++) {
650
			Widget item = items[i];
651
			if (item instanceof GraphNode) {
652
				GraphNode graphModelNode = (GraphNode) item;
653
				graphModelNode.unhighlight();
654
			} else if (item instanceof GraphConnection) {
655
				GraphConnection graphModelConnection = (GraphConnection) item;
656
				graphModelConnection.unhighlight();
657
			}
658
		}
659
	}
660
661
	/**
662
	 * Applies the viewers layouts.
663
	 * 
664
	 */
665
	public abstract void applyLayout();
666
667
	/**
668
	 * Removes the given connection object from the layout algorithm and the
669
	 * model.
670
	 * 
671
	 * @param connection
672
	 */
673
	public void removeRelationship(Object connection) {
674
		GraphConnection relationship = (GraphConnection) connectionsMap.get(connection);
675
676
		if (relationship != null) {
677
			// remove the relationship from the model
678
			relationship.dispose();
679
		}
680
	}
681
682
	/**
683
	 * Creates a new node and adds it to the graph. If it already exists nothing
684
	 * happens.
685
	 * 
686
	 * @param newNode
687
	 */
688
	public void addNode(Object element) {
689
		if (nodesMap.get(element) == null) {
690
			// create the new node
691
			getFactory().createNode(getGraphControl(), element);
692
693
		}
694
	}
695
696
	/**
697
	 * Removes the given element from the layout algorithm and the model.
698
	 * 
699
	 * @param element
700
	 *            The node element to remove.
701
	 */
702
	public void removeNode(Object element) {
703
		GraphNode node = (GraphNode) nodesMap.get(element);
704
705
		if (node != null) {
706
			// remove the node and it's connections from the model
707
			node.dispose();
708
		}
709
	}
710
711
	/**
712
	 * Creates a new relationship between the source node and the destination
713
	 * node. If either node doesn't exist then it will be created.
714
	 * 
715
	 * @param connection
716
	 *            The connection data object.
717
	 * @param srcNode
718
	 *            The source node data object.
719
	 * @param destNode
720
	 *            The destination node data object.
721
	 */
722
	public void addRelationship(Object connection, Object srcNode, Object destNode) {
723
		// create the new relationship
724
		IStylingGraphModelFactory modelFactory = getFactory();
725
		modelFactory.createConnection(getGraphControl(), connection, srcNode, destNode);
726
727
	}
728
729
	/**
730
	 * Adds a new relationship given the connection. It will use the content
731
	 * provider to determine the source and destination nodes.
732
	 * 
733
	 * @param connection
734
	 *            The connection data object.
735
	 */
736
	public void addRelationship(Object connection) {
737
		IStylingGraphModelFactory modelFactory = getFactory();
738
		if (connectionsMap.get(connection) == null) {
739
			if (modelFactory.getContentProvider() instanceof IGraphContentProvider) {
740
				IGraphContentProvider content = ((IGraphContentProvider) modelFactory.getContentProvider());
741
				Object source = content.getSource(connection);
742
				Object dest = content.getDestination(connection);
743
				// create the new relationship
744
				modelFactory.createConnection(getGraphControl(), connection, source, dest);
745
			} else {
746
				throw new UnsupportedOperationException();
747
			}
748
		}
749
	}
750
751
	/**
752
	 * Converts the list of GraphModelConnection objects into an array and
753
	 * returns it.
754
	 * 
755
	 * @return GraphModelConnection[]
756
	 */
757
	protected GraphConnection[] getConnectionsArray(Graph graph) {
758
		GraphConnection[] connsArray = new GraphConnection[graph.getConnections().size()];
759
		connsArray = (GraphConnection[]) graph.getConnections().toArray(connsArray);
760
		return connsArray;
761
	}
762
763
	/**
764
	 * Converts the list of GraphModelNode objects into an array an returns it.
765
	 * 
766
	 * @return GraphModelNode[]
767
	 */
768
	protected GraphNode[] getNodesArray(Graph graph) {
769
		GraphNode[] nodesArray = new GraphNode[graph.getNodes().size()];
770
		nodesArray = (GraphNode[]) graph.getNodes().toArray(nodesArray);
771
		return nodesArray;
772
	}
773
774
}
(-)src/org/eclipse/zest/core/widgets/DefaultSubgraph.java (+393 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
12
import java.util.ArrayList;
13
import java.util.HashMap;
14
import java.util.HashSet;
15
import java.util.Iterator;
16
import java.util.Set;
17
18
import org.eclipse.draw2d.ColorConstants;
19
import org.eclipse.swt.graphics.Color;
20
import org.eclipse.zest.core.widgets.custom.LabelSubgraph;
21
import org.eclipse.zest.core.widgets.custom.TriangleSubgraph;
22
import org.eclipse.zest.core.widgets.custom.TriangleSubgraph.TriangleParameters;
23
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension;
24
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint;
25
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
26
import org.eclipse.zest.layouts.interfaces.ConnectionLayout;
27
import org.eclipse.zest.layouts.interfaces.EntityLayout;
28
import org.eclipse.zest.layouts.interfaces.LayoutContext;
29
import org.eclipse.zest.layouts.interfaces.NodeLayout;
30
import org.eclipse.zest.layouts.interfaces.SubgraphLayout;
31
32
/**
33
 * Default implementation of {@link SubgraphLayout}. Every subgraph added to
34
 * Zest {@link Graph} should inherit from this class. The default implementation
35
 * is very simple. A node pruned to this subgraph is minimized and all
36
 * connections adjacent to it are made invisible. No additional graphic elements
37
 * are added to the graph, but subclasses may add them.
38
 * 
39
 * @since 2.0
40
 */
41
public class DefaultSubgraph implements SubgraphLayout {
42
43
	/**
44
	 * Default factory for {@link DefaultSubgraph}. It creates one subgraph for
45
	 * a whole graph and throws every node into it.
46
	 */
47
	public static class DefaultSubgraphFactory implements SubgraphFactory {
48
		private HashMap contextToSubgraph = new HashMap();
49
50
		public SubgraphLayout createSubgraph(NodeLayout[] nodes,
51
				LayoutContext context) {
52
			DefaultSubgraph subgraph = (DefaultSubgraph) contextToSubgraph
53
					.get(context);
54
			if (subgraph == null) {
55
				subgraph = new DefaultSubgraph(context);
56
				contextToSubgraph.put(context, subgraph);
57
			}
58
			subgraph.addNodes(nodes);
59
			return subgraph;
60
		}
61
	};
62
63
	public static class LabelSubgraphFactory implements SubgraphFactory {
64
		private Color defaultForegroundColor = ColorConstants.black;
65
		private Color defaultBackgroundColor = ColorConstants.yellow;
66
67
		/**
68
		 * Changes the default foreground color for newly created subgraphs.
69
		 * 
70
		 * @param c
71
		 *            color to use
72
		 */
73
		public void setDefualtForegroundColor(Color c) {
74
			defaultForegroundColor = c;
75
		}
76
77
		/**
78
		 * Changes the default background color for newly created subgraphs.
79
		 * 
80
		 * @param c
81
		 *            color to use
82
		 */
83
		public void setDefaultBackgroundColor(Color c) {
84
			defaultBackgroundColor = c;
85
		}
86
87
		public SubgraphLayout createSubgraph(NodeLayout[] nodes,
88
				LayoutContext context) {
89
			return new LabelSubgraph(nodes, context, defaultForegroundColor,
90
					defaultBackgroundColor);
91
		}
92
	};
93
94
	public static class TriangleSubgraphFactory implements SubgraphFactory {
95
		private TriangleParameters parameters = new TriangleParameters();
96
97
		public SubgraphLayout createSubgraph(NodeLayout[] nodes,
98
				LayoutContext context) {
99
			return new TriangleSubgraph(nodes, context,
100
					(TriangleParameters) parameters.clone());
101
		}
102
103
		/**
104
		 * 
105
		 * @return initial color of triangles created with this factory
106
		 */
107
		public Color getColor() {
108
			return parameters.color;
109
		}
110
111
		/**
112
		 * Changes the default color for newly created subgraphs.
113
		 * 
114
		 * @param color
115
		 *            color to use
116
		 */
117
		public void setColor(Color color) {
118
			parameters.color = color;
119
		}
120
121
		/**
122
		 * 
123
		 * @return initial direction of triangles created with this factory
124
		 */
125
		public int getDirection() {
126
			return parameters.direction;
127
		}
128
129
		/**
130
		 * Changes the default direction for newly cretaed subgraphs.
131
		 * 
132
		 * @param direction
133
		 *            direction to use, can be {@link SubgraphLayout#TOP_DOWN},
134
		 *            {@link SubgraphLayout#BOTTOM_UP},
135
		 *            {@link SubgraphLayout#LEFT_RIGHT}, or
136
		 *            {@link SubgraphLayout#RIGHT_LEFT}
137
		 */
138
		public void setDirection(int direction) {
139
			parameters.direction = direction;
140
		}
141
142
		/**
143
		 * 
144
		 * @return maximum height of triangles created with this factory
145
		 */
146
		public double getReferenceHeight() {
147
			return parameters.referenceHeight;
148
		}
149
150
		/**
151
		 * Sets the maximum height for the triangle visualizing this subgraph.
152
		 * 
153
		 * @param referenceHeight
154
		 *            height to use
155
		 */
156
		public void setReferenceHeight(double referenceHeight) {
157
			parameters.referenceHeight = referenceHeight;
158
		}
159
160
		/**
161
		 * 
162
		 * @return maximum base length of triangles created with this factory
163
		 */
164
		public double getReferenceBase() {
165
			return parameters.referenceBase;
166
		}
167
168
		/**
169
		 * Sets the maximum base length for the triangle visualizing this
170
		 * subgraph.
171
		 * 
172
		 * @param referenceBase
173
		 *            base length to use
174
		 */
175
176
		public void setReferenceBase(double referenceBase) {
177
			parameters.referenceBase = referenceBase;
178
		}
179
	};
180
181
	/**
182
	 * Factory for {@link PrunedSuccessorsSubgraph}. It creates one subgraph for
183
	 * a whole graph and throws every node into it.
184
	 */
185
	public static class PrunedSuccessorsSubgraphFactory implements
186
			SubgraphFactory {
187
		private HashMap contextToSubgraph = new HashMap();
188
189
		public SubgraphLayout createSubgraph(NodeLayout[] nodes,
190
				LayoutContext context) {
191
			PrunedSuccessorsSubgraph subgraph = (PrunedSuccessorsSubgraph) contextToSubgraph
192
					.get(context);
193
			if (subgraph == null) {
194
				subgraph = new PrunedSuccessorsSubgraph(context);
195
				contextToSubgraph.put(context, subgraph);
196
			}
197
			subgraph.addNodes(nodes);
198
			return subgraph;
199
		}
200
201
		/**
202
		 * Updates a label for given node (creates the label if necessary).
203
		 * 
204
		 * @param node
205
		 *            node to update
206
		 */
207
		public void updateLabelForNode(InternalNodeLayout node) {
208
			InternalLayoutContext context = node.getOwnerLayoutContext();
209
			PrunedSuccessorsSubgraph subgraph = (PrunedSuccessorsSubgraph) contextToSubgraph
210
					.get(context);
211
			if (subgraph == null) {
212
				subgraph = new PrunedSuccessorsSubgraph(context);
213
				contextToSubgraph.put(context, subgraph);
214
			}
215
			subgraph.updateNodeLabel(node);
216
		}
217
218
	};
219
220
	protected final InternalLayoutContext context;
221
222
	protected final Set nodes = new HashSet();
223
224
	protected boolean disposed = false;
225
226
	protected DefaultSubgraph(LayoutContext context2) {
227
		if (context2 instanceof InternalLayoutContext) {
228
			this.context = (InternalLayoutContext) context2;
229
		} else {
230
			throw new RuntimeException(
231
					"This subgraph can be only created with LayoutContext provided by Zest Graph");
232
		}
233
	}
234
235
	public boolean isGraphEntity() {
236
		return false;
237
	}
238
239
	public void setSize(double width, double height) {
240
		// do nothing
241
		context.checkChangesAllowed();
242
	}
243
244
	public void setLocation(double x, double y) {
245
		// do nothing
246
		context.checkChangesAllowed();
247
	}
248
249
	public boolean isResizable() {
250
		return false;
251
	}
252
253
	public boolean isMovable() {
254
		return false;
255
	}
256
257
	public EntityLayout[] getSuccessingEntities() {
258
		return new EntityLayout[0];
259
	}
260
261
	public DisplayIndependentDimension getSize() {
262
		DisplayIndependentRectangle bounds = context.getBounds();
263
		return new DisplayIndependentDimension(bounds.width, bounds.height);
264
	}
265
266
	public double getPreferredAspectRatio() {
267
		return 0;
268
	}
269
270
	public EntityLayout[] getPredecessingEntities() {
271
		return new EntityLayout[0];
272
	}
273
274
	public DisplayIndependentPoint getLocation() {
275
		DisplayIndependentRectangle bounds = context.getBounds();
276
		return new DisplayIndependentPoint(bounds.x + bounds.width / 2,
277
				bounds.y + bounds.height / 2);
278
	}
279
280
	public boolean isDirectionDependant() {
281
		return false;
282
	}
283
284
	public void setDirection(int direction) {
285
		context.checkChangesAllowed();
286
		// do nothing
287
	}
288
289
	public void removeNodes(NodeLayout[] nodes) {
290
		context.checkChangesAllowed();
291
		ArrayList removedNodes = new ArrayList();
292
		for (int i = 0; i < nodes.length; i++) {
293
			if (this.nodes.remove(nodes[i])) {
294
				nodes[i].prune(null);
295
				nodes[i].setMinimized(false);
296
				refreshConnectionsVisibility(nodes[i].getIncomingConnections());
297
				refreshConnectionsVisibility(nodes[i].getOutgoingConnections());
298
				removedNodes.add(nodes[i]);
299
			}
300
		}
301
		if (!removedNodes.isEmpty()) {
302
			context.fireNodesPrunedEvent((NodeLayout[]) removedNodes
303
					.toArray(new NodeLayout[removedNodes.size()]));
304
		}
305
		if (this.nodes.isEmpty()) {
306
			dispose();
307
		}
308
	}
309
310
	public void removeDisposedNodes() {
311
		for (Iterator iterator = nodes.iterator(); iterator.hasNext();) {
312
			InternalNodeLayout node = (InternalNodeLayout) iterator.next();
313
			if (node.isDisposed()) {
314
				iterator.remove();
315
			}
316
		}
317
	}
318
319
	public NodeLayout[] getNodes() {
320
		InternalNodeLayout[] result = new InternalNodeLayout[nodes.size()];
321
		int i = 0;
322
		for (Iterator iterator = nodes.iterator(); iterator.hasNext();) {
323
			result[i] = (InternalNodeLayout) iterator.next();
324
			if (!context.isLayoutItemFiltered(result[i].getNode())) {
325
				i++;
326
			}
327
		}
328
		if (i == nodes.size()) {
329
			return result;
330
		}
331
332
		NodeLayout[] result2 = new NodeLayout[i];
333
		System.arraycopy(result, 0, result2, 0, i);
334
		return result2;
335
	}
336
337
	public int countNodes() {
338
		return nodes.size();
339
	}
340
341
	public void addNodes(NodeLayout[] nodes) {
342
		context.checkChangesAllowed();
343
		ArrayList addedNodes = new ArrayList();
344
		for (int i = 0; i < nodes.length; i++) {
345
			if (this.nodes.add(nodes[i])) {
346
				nodes[i].prune(this);
347
				nodes[i].setMinimized(true);
348
				refreshConnectionsVisibility(nodes[i].getIncomingConnections());
349
				refreshConnectionsVisibility(nodes[i].getOutgoingConnections());
350
				addedNodes.add(nodes[i]);
351
			}
352
		}
353
		if (!addedNodes.isEmpty()) {
354
			context.fireNodesPrunedEvent((NodeLayout[]) addedNodes
355
					.toArray(new NodeLayout[addedNodes.size()]));
356
		}
357
	}
358
359
	protected void refreshConnectionsVisibility(ConnectionLayout[] connections) {
360
		for (int i = 0; i < connections.length; i++) {
361
			connections[i].setVisible(!connections[i].getSource().isPruned()
362
					&& !connections[i].getTarget().isPruned());
363
		}
364
	}
365
366
	/**
367
	 * Makes sure that value returned by {@link #getLocation()} will be equal to
368
	 * current location of this subgraph.
369
	 */
370
	protected void refreshLocation() {
371
		// do nothing, to be reimplemented in subclasses
372
	}
373
374
	/**
375
	 * Makes sure that value returned by {@link #getSize()} will be equal to
376
	 * current size of this subgraph.
377
	 */
378
	protected void refreshSize() {
379
		// do nothing, to be reimplemented in subclasses
380
	}
381
382
	protected void applyLayoutChanges() {
383
		// do nothing
384
	}
385
386
	protected void dispose() {
387
		if (!disposed) {
388
			context.removeSubgrah(this);
389
			disposed = true;
390
		}
391
	}
392
393
};
(-)src/org/eclipse/zest/core/widgets/InternalNodeLayout.java (+327 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
12
import java.util.ArrayList;
13
import java.util.HashMap;
14
import java.util.HashSet;
15
import java.util.Iterator;
16
17
import org.eclipse.draw2d.FigureListener;
18
import org.eclipse.draw2d.IFigure;
19
import org.eclipse.draw2d.geometry.Dimension;
20
import org.eclipse.draw2d.geometry.Point;
21
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentDimension;
22
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentPoint;
23
import org.eclipse.zest.layouts.interfaces.ConnectionLayout;
24
import org.eclipse.zest.layouts.interfaces.EntityLayout;
25
import org.eclipse.zest.layouts.interfaces.NodeLayout;
26
import org.eclipse.zest.layouts.interfaces.SubgraphLayout;
27
28
class InternalNodeLayout implements NodeLayout {
29
30
	/**
31
	 * This listener is added to nodes' figures as a workaround for the problem
32
	 * of minimized nodes leaving single on the graph pixels when zoomed out
33
	 */
34
	private final static FigureListener figureListener = new FigureListener() {
35
		public void figureMoved(IFigure source) {
36
			// hide figures of minimized nodes
37
			GraphNode node = (GraphNode) figureToNode.get(source);
38
			if (node.getLayout().isMinimized() && source.getSize().equals(0, 0)) {
39
				source.setVisible(false);
40
			} else {
41
				source.setVisible(node.isVisible());
42
			}
43
		}
44
	};
45
	private final static HashMap figureToNode = new HashMap();
46
47
	private DisplayIndependentPoint location;
48
	private DisplayIndependentDimension size;
49
	private boolean minimized = false;
50
	private final GraphNode node;
51
	private final InternalLayoutContext ownerLayoutContext;
52
	private DefaultSubgraph subgraph;
53
	private boolean isDisposed = false;
54
55
	public InternalNodeLayout(GraphNode graphNode) {
56
		this.node = graphNode;
57
		this.ownerLayoutContext = node.parent.getLayoutContext();
58
		graphNode.nodeFigure.addFigureListener(figureListener);
59
		figureToNode.put(graphNode.nodeFigure, graphNode);
60
	}
61
62
	public DisplayIndependentPoint getLocation() {
63
		if (location == null) {
64
			refreshLocation();
65
		}
66
		return new DisplayIndependentPoint(location);
67
	}
68
69
	public DisplayIndependentDimension getSize() {
70
		if (size == null) {
71
			refreshSize();
72
		}
73
		return new DisplayIndependentDimension(size);
74
	}
75
76
	public SubgraphLayout getSubgraph() {
77
		return subgraph;
78
	}
79
80
	public boolean isMovable() {
81
		return true;
82
	}
83
84
	public boolean isPrunable() {
85
		return ownerLayoutContext.isPruningEnabled();
86
	}
87
88
	public boolean isPruned() {
89
		return subgraph != null;
90
	}
91
92
	public boolean isResizable() {
93
		return (node.parent.getItem().getStyle() & ZestStyles.NODES_NO_LAYOUT_RESIZE) == 0;
94
	}
95
96
	public void prune(SubgraphLayout subgraph) {
97
		if (subgraph != null && !(subgraph instanceof DefaultSubgraph)) {
98
			throw new RuntimeException(
99
					"InternalNodeLayout can be pruned only to instance of DefaultSubgraph.");
100
		}
101
		ownerLayoutContext.checkChangesAllowed();
102
		if (subgraph == this.subgraph) {
103
			return;
104
		}
105
		if (this.subgraph != null) {
106
			SubgraphLayout subgraph2 = this.subgraph;
107
			this.subgraph = null;
108
			subgraph2.removeNodes(new NodeLayout[] { this });
109
		}
110
		if (subgraph != null) {
111
			this.subgraph = (DefaultSubgraph) subgraph;
112
			subgraph.addNodes(new NodeLayout[] { this });
113
		}
114
	}
115
116
	public void setLocation(double x, double y) {
117
		ownerLayoutContext.checkChangesAllowed();
118
		internalSetLocation(x, y);
119
	}
120
121
	private void internalSetLocation(double x, double y) {
122
		if (location != null) {
123
			location.x = x;
124
			location.y = y;
125
		} else {
126
			location = new DisplayIndependentPoint(x, y);
127
		}
128
	}
129
130
	public void setSize(double width, double height) {
131
		ownerLayoutContext.checkChangesAllowed();
132
		internalSetSize(width, height);
133
	}
134
135
	private void internalSetSize(double width, double height) {
136
		if (size != null) {
137
			size.width = width;
138
			size.height = height;
139
		} else {
140
			size = new DisplayIndependentDimension(width, height);
141
		}
142
	}
143
144
	public void setMinimized(boolean minimized) {
145
		ownerLayoutContext.checkChangesAllowed();
146
		getSize();
147
		this.minimized = minimized;
148
	}
149
150
	public boolean isMinimized() {
151
		return minimized;
152
	}
153
154
	public NodeLayout[] getPredecessingNodes() {
155
		ConnectionLayout[] connections = getIncomingConnections();
156
		NodeLayout[] result = new NodeLayout[connections.length];
157
		for (int i = 0; i < connections.length; i++) {
158
			result[i] = connections[i].getSource();
159
			if (result[i] == this) {
160
				result[i] = connections[i].getTarget();
161
			}
162
		}
163
		return result;
164
	}
165
166
	public NodeLayout[] getSuccessingNodes() {
167
		ConnectionLayout[] connections = getOutgoingConnections();
168
		NodeLayout[] result = new NodeLayout[connections.length];
169
		for (int i = 0; i < connections.length; i++) {
170
			result[i] = connections[i].getTarget();
171
			if (result[i] == this) {
172
				result[i] = connections[i].getSource();
173
			}
174
		}
175
		return result;
176
	}
177
178
	public EntityLayout[] getSuccessingEntities() {
179
		if (isPruned()) {
180
			return new NodeLayout[0];
181
		}
182
		ArrayList result = new ArrayList();
183
		HashSet addedSubgraphs = new HashSet();
184
		NodeLayout[] successingNodes = getSuccessingNodes();
185
		for (int i = 0; i < successingNodes.length; i++) {
186
			if (!successingNodes[i].isPruned()) {
187
				result.add(successingNodes[i]);
188
			} else {
189
				SubgraphLayout successingSubgraph = successingNodes[i]
190
						.getSubgraph();
191
				if (successingSubgraph.isGraphEntity()
192
						&& !addedSubgraphs.contains(successingSubgraph)) {
193
					result.add(successingSubgraph);
194
					addedSubgraphs.add(successingSubgraph);
195
				}
196
			}
197
		}
198
		return (EntityLayout[]) result.toArray(new EntityLayout[result.size()]);
199
	}
200
201
	public EntityLayout[] getPredecessingEntities() {
202
		if (isPruned()) {
203
			return new NodeLayout[0];
204
		}
205
		ArrayList result = new ArrayList();
206
		HashSet addedSubgraphs = new HashSet();
207
		NodeLayout[] predecessingNodes = getPredecessingNodes();
208
		for (int i = 0; i < predecessingNodes.length; i++) {
209
			if (!predecessingNodes[i].isPruned()) {
210
				result.add(predecessingNodes[i]);
211
			} else {
212
				SubgraphLayout predecessingSubgraph = predecessingNodes[i]
213
						.getSubgraph();
214
				if (predecessingSubgraph.isGraphEntity()
215
						&& !addedSubgraphs.contains(predecessingSubgraph)) {
216
					result.add(predecessingSubgraph);
217
					addedSubgraphs.add(predecessingSubgraph);
218
				}
219
			}
220
		}
221
		return (EntityLayout[]) result.toArray(new EntityLayout[result.size()]);
222
	}
223
224
	public ConnectionLayout[] getIncomingConnections() {
225
		ArrayList result = new ArrayList();
226
		for (Iterator iterator = node.getTargetConnections().iterator(); iterator
227
				.hasNext();) {
228
			GraphConnection connection = (GraphConnection) iterator.next();
229
			if (!ownerLayoutContext.isLayoutItemFiltered(connection)) {
230
				result.add(connection.getLayout());
231
			}
232
		}
233
		for (Iterator iterator = node.getSourceConnections().iterator(); iterator
234
				.hasNext();) {
235
			GraphConnection connection = (GraphConnection) iterator.next();
236
			if (!connection.isDirected()
237
					&& !ownerLayoutContext.isLayoutItemFiltered(connection)) {
238
				result.add(connection.getLayout());
239
			}
240
		}
241
		return (ConnectionLayout[]) result.toArray(new ConnectionLayout[result
242
				.size()]);
243
	}
244
245
	public ConnectionLayout[] getOutgoingConnections() {
246
		ArrayList result = new ArrayList();
247
		for (Iterator iterator = node.getSourceConnections().iterator(); iterator
248
				.hasNext();) {
249
			GraphConnection connection = (GraphConnection) iterator.next();
250
			if (!ownerLayoutContext.isLayoutItemFiltered(connection)) {
251
				result.add(connection.getLayout());
252
			}
253
		}
254
		for (Iterator iterator = node.getTargetConnections().iterator(); iterator
255
				.hasNext();) {
256
			GraphConnection connection = (GraphConnection) iterator.next();
257
			if (!connection.isDirected()
258
					&& !ownerLayoutContext.isLayoutItemFiltered(connection)) {
259
				result.add(connection.getLayout());
260
			}
261
		}
262
		return (ConnectionLayout[]) result.toArray(new ConnectionLayout[result
263
				.size()]);
264
	}
265
266
	public double getPreferredAspectRatio() {
267
		return 0;
268
	}
269
270
	GraphNode getNode() {
271
		return node;
272
	}
273
274
	void applyLayout() {
275
		if (minimized) {
276
			node.setSize(0, 0);
277
			if (location != null) {
278
				node.setLocation(location.x, location.y);
279
			}
280
		} else {
281
			node.setSize(-1, -1);
282
			if (location != null) {
283
				node.setLocation(location.x - getSize().width / 2, location.y
284
						- size.height / 2);
285
			}
286
			if (size != null) {
287
				Dimension currentSize = node.getSize();
288
				if (size.width != currentSize.width
289
						|| size.height != currentSize.height) {
290
					node.setSize(size.width, size.height);
291
				}
292
			}
293
		}
294
	}
295
296
	InternalLayoutContext getOwnerLayoutContext() {
297
		return ownerLayoutContext;
298
	}
299
300
	void refreshSize() {
301
		Dimension size2 = node.getSize();
302
		internalSetSize(size2.width, size2.height);
303
	}
304
305
	void refreshLocation() {
306
		Point location2 = node.getLocation();
307
		internalSetLocation(location2.x + getSize().width / 2, location2.y
308
				+ size.height / 2);
309
	}
310
311
	public String toString() {
312
		return node.toString() + "(layout)";
313
	}
314
315
	void dispose() {
316
		isDisposed = true;
317
		if (subgraph != null) {
318
			subgraph.removeDisposedNodes();
319
		}
320
		ownerLayoutContext.fireNodeRemovedEvent(node.getLayout());
321
		figureToNode.remove(node.nodeFigure);
322
	}
323
324
	boolean isDisposed() {
325
		return isDisposed;
326
	}
327
}
(-)src/org/eclipse/zest/core/widgets/PrunedSuccessorsSubgraph.java (+275 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
12
import java.util.Arrays;
13
import java.util.HashMap;
14
import java.util.HashSet;
15
import java.util.Iterator;
16
17
import org.eclipse.draw2d.AncestorListener;
18
import org.eclipse.draw2d.ColorConstants;
19
import org.eclipse.draw2d.FigureListener;
20
import org.eclipse.draw2d.IFigure;
21
import org.eclipse.draw2d.geometry.Dimension;
22
import org.eclipse.draw2d.geometry.Point;
23
import org.eclipse.draw2d.geometry.Rectangle;
24
import org.eclipse.swt.graphics.Font;
25
import org.eclipse.swt.graphics.FontData;
26
import org.eclipse.swt.widgets.Display;
27
import org.eclipse.zest.core.widgets.internal.GraphLabel;
28
import org.eclipse.zest.core.widgets.internal.ZestRootLayer;
29
import org.eclipse.zest.layouts.interfaces.LayoutContext;
30
import org.eclipse.zest.layouts.interfaces.NodeLayout;
31
32
/**
33
 * A subgraph that for each unexpanded node in a graph adds a label showing
34
 * number of pruned successors (as unexpanded node is considered a node for
35
 * which {@link Graph#canExpand(GraphNode)} returns true AND
36
 * {@link Graph#canCollapse(GraphNode)} returns false). It doesn't matter which
37
 * subgraph a node is pruned to, so the factory for this subgraph uses one
38
 * instance for whole layout context.
39
 */
40
class PrunedSuccessorsSubgraph extends DefaultSubgraph {
41
42
	private class LabelAncestorListener extends AncestorListener.Stub {
43
		private final IFigure originalFigure;
44
		private IFigure fisheyeFigure;
45
46
		public LabelAncestorListener(IFigure originalFigure,
47
				IFigure fisheyeFigure) {
48
			this.originalFigure = originalFigure;
49
			this.fisheyeFigure = fisheyeFigure;
50
		}
51
52
		public void ancestorRemoved(IFigure ancestor) {
53
			if (fisheyeFigure != null) {
54
				final GraphLabel label = (GraphLabel) nodeFigureToLabel
55
						.get(fisheyeFigure);
56
				if (label == null) {
57
					return;
58
				}
59
				nodeFigureToLabel.remove(fisheyeFigure);
60
				Display.getDefault().asyncExec(new Runnable() {
61
					public void run() {
62
						label
63
								.removeAncestorListener(LabelAncestorListener.this);
64
					}
65
				});
66
				fisheyeFigure.removeFigureListener(nodeFigureListener);
67
				originalFigure.addFigureListener(nodeFigureListener);
68
				labelToAncestorListener.remove(label);
69
				fisheyeFigure = null;
70
				addLabelForFigure(originalFigure, label);
71
				refreshLabelBounds(originalFigure, label);
72
			}
73
		}
74
	}
75
76
	private final FigureListener nodeFigureListener = new FigureListener() {
77
		public void figureMoved(IFigure source) {
78
			GraphLabel label = (GraphLabel) nodeFigureToLabel.get(source);
79
			if (label != null) {
80
				refreshLabelBounds(source, label);
81
			}
82
		}
83
	};
84
85
	private final FisheyeListener fisheyeListener = new FisheyeListener() {
86
87
		public void fisheyeReplaced(Graph graph, IFigure oldFisheyeFigure,
88
				IFigure newFisheyeFigure) {
89
			oldFisheyeFigure.removeFigureListener(nodeFigureListener);
90
			newFisheyeFigure.addFigureListener(nodeFigureListener);
91
			GraphLabel label = (GraphLabel) nodeFigureToLabel
92
					.remove(oldFisheyeFigure);
93
			nodeFigureToLabel.put(newFisheyeFigure, label);
94
95
			LabelAncestorListener ancestorListener = (LabelAncestorListener) labelToAncestorListener
96
					.get(label);
97
			ancestorListener.fisheyeFigure = null;
98
			addLabelForFigure(newFisheyeFigure, label);
99
			ancestorListener.fisheyeFigure = newFisheyeFigure;
100
			refreshLabelBounds(newFisheyeFigure, label);
101
		}
102
103
		public void fisheyeRemoved(Graph graph, IFigure originalFigure,
104
				IFigure fisheyeFigure) {
105
			// do nothing - labelAncestorListener will take care of cleaning
106
			// up
107
		}
108
109
		public void fisheyeAdded(Graph graph, IFigure originalFigure,
110
				IFigure fisheyeFigure) {
111
			originalFigure.removeFigureListener(nodeFigureListener);
112
			fisheyeFigure.addFigureListener(nodeFigureListener);
113
			GraphLabel label = (GraphLabel) nodeFigureToLabel
114
					.get(originalFigure);
115
			if (label == null) {
116
				return;
117
			}
118
			nodeFigureToLabel.put(fisheyeFigure, label);
119
			refreshLabelBounds(fisheyeFigure, label);
120
			addLabelForFigure(fisheyeFigure, label);
121
			LabelAncestorListener labelAncestorListener = new LabelAncestorListener(
122
					originalFigure, fisheyeFigure);
123
			label.addAncestorListener(labelAncestorListener);
124
			labelToAncestorListener.put(label, labelAncestorListener);
125
		}
126
	};
127
128
	/**
129
	 * Maps from figures of nodes to labels showing number of nodes hidden
130
	 * successors
131
	 */
132
	private HashMap nodeFigureToLabel = new HashMap();
133
134
	private HashMap labelToAncestorListener = new HashMap();
135
136
	protected PrunedSuccessorsSubgraph(LayoutContext context2) {
137
		super(context2);
138
		context.container.getGraph().addFisheyeListener(fisheyeListener);
139
	}
140
141
	public void addNodes(NodeLayout[] nodes) {
142
		super.addNodes(nodes);
143
		HashSet nodesToUpdate = new HashSet();
144
		for (int i = 0; i < nodes.length; i++) {
145
			nodesToUpdate
146
					.addAll(Arrays.asList(nodes[i].getPredecessingNodes()));
147
		}
148
		for (Iterator iterator = nodesToUpdate.iterator(); iterator.hasNext();) {
149
			InternalNodeLayout nodeToUpdate = (InternalNodeLayout) iterator
150
					.next();
151
			updateNodeLabel(nodeToUpdate);
152
		}
153
154
	}
155
156
	public void removeNodes(NodeLayout[] nodes) {
157
		super.removeNodes(nodes);
158
		HashSet nodesToUpdate = new HashSet();
159
		for (int i = 0; i < nodes.length; i++) {
160
			nodesToUpdate
161
					.addAll(Arrays.asList(nodes[i].getPredecessingNodes()));
162
			if (((InternalNodeLayout) nodes[i]).isDisposed()) {
163
				removeFigureForNode((InternalNodeLayout) nodes[i]);
164
			} else {
165
				nodesToUpdate.add(nodes[i]);
166
			}
167
		}
168
		for (Iterator iterator = nodesToUpdate.iterator(); iterator.hasNext();) {
169
			InternalNodeLayout predecessor = (InternalNodeLayout) iterator
170
					.next();
171
			updateNodeLabel(predecessor);
172
		}
173
	}
174
175
	private void addLabelForFigure(IFigure figure, GraphLabel label) {
176
		IFigure parent = figure.getParent();
177
		if (parent instanceof ZestRootLayer) {
178
			((ZestRootLayer) parent).addDecoration(figure, label);
179
		} else {
180
			if (parent.getChildren().contains(label)) {
181
				parent.remove(label);
182
			}
183
			int index = parent.getChildren().indexOf(figure);
184
			parent.add(label, index + 1);
185
		}
186
	}
187
188
	private void refreshLabelBounds(IFigure figure, GraphLabel label) {
189
		Rectangle figureBounds = figure.getBounds();
190
		if (figureBounds.width * figureBounds.height > 0) {
191
			label.setText(label.getText()); // hack: resets label's size
192
			Dimension labelSize = label.getSize();
193
			labelSize.expand(-6, -4);
194
			Point anchorPoint = figure.getBounds().getBottomRight();
195
			anchorPoint.x -= labelSize.width / 2;
196
			anchorPoint.y -= labelSize.height / 2;
197
			Rectangle bounds = new Rectangle(anchorPoint, labelSize);
198
			label.setBounds(bounds);
199
			label.getParent().setConstraint(label, bounds);
200
		} else {
201
			label.getParent().setConstraint(label,
202
					new Rectangle(figureBounds.x, figureBounds.y, 0, 0));
203
			label
204
					.setBounds(new Rectangle(figureBounds.x, figureBounds.y, 0,
205
							0));
206
		}
207
	}
208
209
	void updateNodeLabel(InternalNodeLayout internalNode) {
210
		if (internalNode.isDisposed()) {
211
			return;
212
		}
213
		IFigure figure = internalNode.getNode().getFigure();
214
		GraphLabel label = (GraphLabel) nodeFigureToLabel.get(figure);
215
		IFigure fisheye = getFisheyeFigure(figure);
216
		if (fisheye != null) {
217
			figure = fisheye;
218
		}
219
		if (label == null) {
220
			label = new GraphLabel(false);
221
			label.setForegroundColor(ColorConstants.white);
222
			label.setBackgroundColor(ColorConstants.red);
223
			FontData fontData = Display.getDefault().getSystemFont()
224
					.getFontData()[0];
225
			fontData.setHeight(6);
226
			label.setFont(new Font(Display.getCurrent(), fontData));
227
			figure.addFigureListener(nodeFigureListener);
228
			addLabelForFigure(figure, label);
229
			nodeFigureToLabel.put(figure, label);
230
		}
231
232
		GraphNode graphNode = internalNode.getNode();
233
		if (!graphNode.getGraphModel().canExpand(graphNode)
234
				|| graphNode.getGraphModel().canCollapse(graphNode)
235
				|| internalNode.isPruned()) {
236
			label.setVisible(false);
237
		} else {
238
			NodeLayout[] successors = internalNode.getSuccessingNodes();
239
			int numberOfHiddenSuccessors = 0;
240
			for (int i = 0; i < successors.length; i++) {
241
				if (successors[i].isPruned()) {
242
					numberOfHiddenSuccessors++;
243
				}
244
			}
245
			String labelText = numberOfHiddenSuccessors > 0 ? ""
246
					+ numberOfHiddenSuccessors : "";
247
			if (!labelText.equals(label.getText())) {
248
				label.setText(labelText);
249
			}
250
			label.setVisible(true);
251
		}
252
253
		refreshLabelBounds(figure, label);
254
	}
255
256
	private IFigure getFisheyeFigure(IFigure originalFigure) {
257
		// a node has a fisheye if and only if its label has an AncestorListener
258
		GraphLabel label = (GraphLabel) nodeFigureToLabel.get(originalFigure);
259
		LabelAncestorListener ancestorListener = (LabelAncestorListener) labelToAncestorListener
260
				.get(label);
261
		if (ancestorListener != null) {
262
			return ancestorListener.fisheyeFigure;
263
		}
264
		return null;
265
	}
266
267
	private void removeFigureForNode(InternalNodeLayout internalNode) {
268
		IFigure figure = internalNode.getNode().getFigure();
269
		GraphLabel label = (GraphLabel) nodeFigureToLabel.get(figure);
270
		if (label != null && label.getParent() != null) {
271
			label.getParent().remove(label);
272
		}
273
		nodeFigureToLabel.remove(figure);
274
	}
275
}
(-)src/org/eclipse/zest/core/widgets/InternalLayoutContext.java (+561 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
12
import java.util.ArrayList;
13
import java.util.Arrays;
14
import java.util.HashSet;
15
import java.util.Iterator;
16
import java.util.List;
17
18
import org.eclipse.draw2d.Animation;
19
import org.eclipse.zest.layouts.LayoutAlgorithm;
20
import org.eclipse.zest.layouts.dataStructures.DisplayIndependentRectangle;
21
import org.eclipse.zest.layouts.interfaces.ConnectionLayout;
22
import org.eclipse.zest.layouts.interfaces.ContextListener;
23
import org.eclipse.zest.layouts.interfaces.EntityLayout;
24
import org.eclipse.zest.layouts.interfaces.ExpandCollapseManager;
25
import org.eclipse.zest.layouts.interfaces.GraphStructureListener;
26
import org.eclipse.zest.layouts.interfaces.LayoutContext;
27
import org.eclipse.zest.layouts.interfaces.LayoutListener;
28
import org.eclipse.zest.layouts.interfaces.NodeLayout;
29
import org.eclipse.zest.layouts.interfaces.PruningListener;
30
import org.eclipse.zest.layouts.interfaces.SubgraphLayout;
31
32
class InternalLayoutContext implements LayoutContext {
33
34
	private final static int INSETS = 15;
35
36
	final IContainer container;
37
	private final List filters = new ArrayList();
38
	private final List contextListeners = new ArrayList();
39
	private final List graphStructureListeners = new ArrayList();
40
	private final List layoutListeners = new ArrayList();
41
	private final List pruningListeners = new ArrayList();
42
	private LayoutAlgorithm mainAlgorithm;
43
	private LayoutAlgorithm layoutAlgorithm;
44
	private ExpandCollapseManager expandCollapseManager;
45
	private SubgraphFactory subgraphFactory = new DefaultSubgraph.DefaultSubgraphFactory();
46
	private final HashSet subgraphs = new HashSet();
47
	private boolean eventsOn = true;
48
	private boolean backgorundLayoutEnabled = true;
49
	private boolean externalLayoutInvocation = false;
50
51
	/**
52
	 * @param graph
53
	 *            the graph owning this context
54
	 */
55
	InternalLayoutContext(Graph graph) {
56
		this.container = graph;
57
	}
58
59
	InternalLayoutContext(GraphContainer container) {
60
		this.container = container;
61
	}
62
63
	public void addContextListener(ContextListener listener) {
64
		contextListeners.add(listener);
65
	}
66
67
	public void addGraphStructureListener(GraphStructureListener listener) {
68
		graphStructureListeners.add(listener);
69
	}
70
71
	public void addLayoutListener(LayoutListener listener) {
72
		layoutListeners.add(listener);
73
	}
74
75
	public void addPruningListener(PruningListener listener) {
76
		pruningListeners.add(listener);
77
	}
78
79
	public SubgraphLayout createSubgraph(NodeLayout[] nodes) {
80
		checkChangesAllowed();
81
		InternalNodeLayout[] internalNodes = new InternalNodeLayout[nodes.length];
82
		for (int i = 0; i < nodes.length; i++) {
83
			internalNodes[i] = (InternalNodeLayout) nodes[i];
84
		}
85
		SubgraphLayout subgraph = subgraphFactory.createSubgraph(internalNodes,
86
				this);
87
		subgraphs.add(subgraph);
88
		return subgraph;
89
	}
90
91
	void removeSubgrah(DefaultSubgraph subgraph) {
92
		subgraphs.remove(subgraph);
93
	}
94
95
	public void flushChanges(boolean animationHint) {
96
		// TODO support for asynchronous call
97
		if (!container.getGraph().isVisible()) {
98
			return;
99
		}
100
		eventsOn = false;
101
		if (animationHint) {
102
			Animation.markBegin();
103
		}
104
		for (Iterator iterator = container.getNodes().iterator(); iterator
105
				.hasNext();) {
106
			GraphNode node = (GraphNode) iterator.next();
107
			node.applyLayoutChanges();
108
		}
109
		for (Iterator iterator = container.getConnections().iterator(); iterator
110
				.hasNext();) {
111
			GraphConnection connection = (GraphConnection) iterator.next();
112
			connection.applyLayoutChanges();
113
		}
114
		for (Iterator iterator = subgraphs.iterator(); iterator.hasNext();) {
115
			DefaultSubgraph subgraph = (DefaultSubgraph) iterator.next();
116
			subgraph.applyLayoutChanges();
117
		}
118
		if (animationHint) {
119
			Animation.run(Graph.ANIMATION_TIME);
120
		}
121
		eventsOn = true;
122
	}
123
124
	public DisplayIndependentRectangle getBounds() {
125
		DisplayIndependentRectangle result = new DisplayIndependentRectangle(
126
				container.getLayoutBounds());
127
128
		result.x += INSETS;
129
		result.y += INSETS;
130
		result.width = Math.max(result.width - 2 * INSETS, 0);
131
		result.height = Math.max(result.height - 2 * INSETS, 0);
132
		return result;
133
	}
134
135
	public LayoutAlgorithm getMainLayoutAlgorithm() {
136
		return mainAlgorithm;
137
	}
138
139
	public ExpandCollapseManager getExpandCollapseManager() {
140
		return expandCollapseManager;
141
	}
142
143
	public NodeLayout[] getNodes() {
144
		ArrayList result = new ArrayList();
145
		for (Iterator iterator = this.container.getNodes().iterator(); iterator
146
				.hasNext();) {
147
			GraphNode node = (GraphNode) iterator.next();
148
			if (!isLayoutItemFiltered(node)) {
149
				result.add(node.getLayout());
150
			}
151
		}
152
		return (NodeLayout[]) result.toArray(new NodeLayout[result.size()]);
153
	}
154
155
	public EntityLayout[] getEntities() {
156
		HashSet addedSubgraphs = new HashSet();
157
		ArrayList result = new ArrayList();
158
		for (Iterator iterator = this.container.getNodes().iterator(); iterator
159
				.hasNext();) {
160
			GraphNode node = (GraphNode) iterator.next();
161
			if (!isLayoutItemFiltered(node)) {
162
				InternalNodeLayout nodeLayout = node.getLayout();
163
				if (!nodeLayout.isPruned()) {
164
					result.add(nodeLayout);
165
				} else {
166
					SubgraphLayout subgraph = nodeLayout.getSubgraph();
167
					if (subgraph.isGraphEntity()
168
							&& !addedSubgraphs.contains(subgraph)) {
169
						result.add(subgraph);
170
						addedSubgraphs.add(subgraph);
171
					}
172
				}
173
			}
174
		}
175
		return (EntityLayout[]) result.toArray(new EntityLayout[result.size()]);
176
	}
177
178
	public SubgraphLayout[] getSubgraphs() {
179
		SubgraphLayout[] result = new SubgraphLayout[subgraphs.size()];
180
		int subgraphCount = 0;
181
		for (Iterator iterator = subgraphs.iterator(); iterator.hasNext();) {
182
			SubgraphLayout subgraph = (SubgraphLayout) iterator.next();
183
			NodeLayout[] nodes = subgraph.getNodes();
184
			for (int i = 0; i < nodes.length; i++) {
185
				if (!isLayoutItemFiltered(((InternalNodeLayout) nodes[i])
186
						.getNode())) {
187
					result[subgraphCount++] = subgraph;
188
					break;
189
				}
190
			}
191
		}
192
		if (subgraphCount == subgraphs.size()) {
193
			return result;
194
		} else {
195
			SubgraphLayout[] result2 = new SubgraphLayout[subgraphCount];
196
			System.arraycopy(result, 0, result2, 0, subgraphCount);
197
			return result2;
198
		}
199
	}
200
201
	public boolean isBoundsExpandable() {
202
		return false;
203
	}
204
205
	public boolean isBackgroundLayoutEnabled() {
206
		return backgorundLayoutEnabled;
207
	}
208
209
	void setBackgroundLayoutEnabled(boolean enabled) {
210
		if (this.backgorundLayoutEnabled != enabled) {
211
			this.backgorundLayoutEnabled = enabled;
212
			fireBackgroundEnableChangedEvent();
213
		}
214
	}
215
216
	public boolean isPruningEnabled() {
217
		return expandCollapseManager != null;
218
	}
219
220
	public void removeContextListener(ContextListener listener) {
221
		contextListeners.remove(listener);
222
	}
223
224
	public void removeGraphStructureListener(GraphStructureListener listener) {
225
		graphStructureListeners.remove(listener);
226
	}
227
228
	public void removeLayoutListener(LayoutListener listener) {
229
		layoutListeners.remove(listener);
230
	}
231
232
	public void removePruningListener(PruningListener listener) {
233
		pruningListeners.remove(listener);
234
	}
235
236
	public void setMainLayoutAlgorithm(LayoutAlgorithm algorithm) {
237
		mainAlgorithm = algorithm;
238
	}
239
240
	public void setExpandCollapseManager(
241
			ExpandCollapseManager expandCollapseManager) {
242
		this.expandCollapseManager = expandCollapseManager;
243
		expandCollapseManager.initExpansion(this);
244
	}
245
246
	public ConnectionLayout[] getConnections() {
247
		List connections = container.getConnections();
248
		ConnectionLayout[] result = new ConnectionLayout[connections.size()];
249
		int i = 0;
250
		for (Iterator iterator = connections.iterator(); iterator.hasNext();) {
251
			GraphConnection connection = (GraphConnection) iterator.next();
252
			if (!isLayoutItemFiltered(connection)) {
253
				result[i++] = connection.getLayout();
254
			}
255
		}
256
		if (i == result.length) {
257
			return result;
258
		}
259
		ConnectionLayout[] result2 = new ConnectionLayout[i];
260
		System.arraycopy(result, 0, result2, 0, i);
261
		return result2;
262
	}
263
264
	public ConnectionLayout[] getConnections(EntityLayout source,
265
			EntityLayout target) {
266
		ArrayList result = new ArrayList();
267
268
		ArrayList sourcesList = new ArrayList();
269
		if (source instanceof NodeLayout) {
270
			sourcesList.add(source);
271
		}
272
		if (source instanceof SubgraphLayout) {
273
			sourcesList.addAll(Arrays.asList(((SubgraphLayout) source)
274
					.getNodes()));
275
		}
276
277
		HashSet targets = new HashSet();
278
		if (target instanceof NodeLayout) {
279
			targets.add(target);
280
		}
281
		if (target instanceof SubgraphLayout) {
282
			targets.addAll(Arrays.asList(((SubgraphLayout) target).getNodes()));
283
		}
284
285
		for (Iterator iterator = sourcesList.iterator(); iterator.hasNext();) {
286
			NodeLayout source2 = (NodeLayout) iterator.next();
287
			ConnectionLayout[] outgoingConnections = source2
288
					.getOutgoingConnections();
289
			for (int i = 0; i < outgoingConnections.length; i++) {
290
				ConnectionLayout connection = outgoingConnections[i];
291
				if ((connection.getSource() == source2 && targets
292
						.contains(connection.getTarget()))
293
						|| (connection.getTarget() == source2 && targets
294
								.contains(connection.getSource()))) {
295
					result.add(connection);
296
				}
297
			}
298
299
		}
300
		return (ConnectionLayout[]) result.toArray(new ConnectionLayout[result
301
				.size()]);
302
	}
303
304
	void addFilter(LayoutFilter filter) {
305
		filters.add(filter);
306
	}
307
308
	void removeFilter(LayoutFilter filter) {
309
		filters.remove(filter);
310
	}
311
312
	boolean isLayoutItemFiltered(GraphItem item) {
313
		for (Iterator it = filters.iterator(); it.hasNext();) {
314
			LayoutFilter filter = (LayoutFilter) it.next();
315
			if (filter.isObjectFiltered(item)) {
316
				return true;
317
			}
318
		}
319
		return false;
320
	}
321
322
	void setExpanded(NodeLayout node, boolean expanded) {
323
		externalLayoutInvocation = true;
324
		if (expandCollapseManager != null) {
325
			expandCollapseManager.setExpanded(this, node, expanded);
326
		}
327
		externalLayoutInvocation = false;
328
	}
329
330
	boolean canExpand(NodeLayout node) {
331
		return expandCollapseManager != null
332
				&& expandCollapseManager.canExpand(this, node);
333
	}
334
335
	boolean canCollapse(NodeLayout node) {
336
		return expandCollapseManager != null
337
				&& expandCollapseManager.canCollapse(this, node);
338
	}
339
340
	void setSubgraphFactory(SubgraphFactory factory) {
341
		subgraphFactory = factory;
342
	}
343
344
	SubgraphFactory getSubgraphFactory() {
345
		return subgraphFactory;
346
	}
347
348
	void applyMainAlgorithm() {
349
		if (backgorundLayoutEnabled && mainAlgorithm != null) {
350
			mainAlgorithm.applyLayout(true);
351
			flushChanges(false);
352
		}
353
	}
354
355
	/**
356
	 * Sets layout algorithm for this context. It differs from
357
	 * {@link #setMainLayoutAlgorithm(LayoutAlgorithm) main algorithm} in that
358
	 * it's always used when {@link #applyLayoutAlgorithm(boolean)} and not
359
	 * after firing of events.
360
	 */
361
	void setLayoutAlgorithm(LayoutAlgorithm algorithm) {
362
		if (this.layoutAlgorithm != null) {
363
			this.layoutAlgorithm.setLayoutContext(null);
364
		}
365
		this.layoutAlgorithm = algorithm;
366
		this.layoutAlgorithm.setLayoutContext(this);
367
	}
368
369
	LayoutAlgorithm getLayoutAlgorithm() {
370
		return layoutAlgorithm;
371
	}
372
373
	void applyLayout(boolean clean) {
374
		if (layoutAlgorithm != null) {
375
			externalLayoutInvocation = true;
376
			layoutAlgorithm.applyLayout(clean);
377
			externalLayoutInvocation = false;
378
		}
379
	}
380
381
	void checkChangesAllowed() {
382
		if (!backgorundLayoutEnabled && !externalLayoutInvocation) {
383
			throw new RuntimeException(
384
					"Layout not allowed to perform changes in layout context!");
385
		}
386
	}
387
388
	void fireNodeAddedEvent(NodeLayout node) {
389
		boolean intercepted = !eventsOn;
390
		GraphStructureListener[] listeners = (GraphStructureListener[]) graphStructureListeners
391
				.toArray(new GraphStructureListener[graphStructureListeners
392
						.size()]);
393
		for (int i = 0; i < listeners.length && !intercepted; i++) {
394
			intercepted = listeners[i].nodeAdded(this, node);
395
		}
396
		if (!intercepted) {
397
			applyMainAlgorithm();
398
		}
399
	}
400
401
	void fireNodeRemovedEvent(NodeLayout node) {
402
		boolean intercepted = !eventsOn;
403
		GraphStructureListener[] listeners = (GraphStructureListener[]) graphStructureListeners
404
				.toArray(new GraphStructureListener[graphStructureListeners
405
						.size()]);
406
		for (int i = 0; i < listeners.length && !intercepted; i++) {
407
			intercepted = listeners[i].nodeRemoved(this, node);
408
		}
409
		if (!intercepted) {
410
			applyMainAlgorithm();
411
		}
412
	}
413
414
	void fireConnectionAddedEvent(ConnectionLayout connection) {
415
		InternalLayoutContext sourceContext = ((InternalNodeLayout) connection
416
				.getSource()).getOwnerLayoutContext();
417
		InternalLayoutContext targetContext = ((InternalNodeLayout) connection
418
				.getTarget()).getOwnerLayoutContext();
419
		if (sourceContext != targetContext) {
420
			// connection between nodes in different containers is not
421
			// interesting for layout algorithms
422
			return;
423
		}
424
		if (sourceContext == this) {
425
			boolean intercepted = !eventsOn;
426
			GraphStructureListener[] listeners = (GraphStructureListener[]) graphStructureListeners
427
					.toArray(new GraphStructureListener[graphStructureListeners
428
							.size()]);
429
			for (int i = 0; i < listeners.length && !intercepted; i++) {
430
				intercepted = listeners[i].connectionAdded(this, connection);
431
			}
432
			if (!intercepted) {
433
				applyMainAlgorithm();
434
			}
435
		} else {
436
			sourceContext.fireConnectionAddedEvent(connection);
437
		}
438
	}
439
440
	void fireConnectionRemovedEvent(ConnectionLayout connection) {
441
		InternalLayoutContext sourceContext = ((InternalNodeLayout) connection
442
				.getSource()).getOwnerLayoutContext();
443
		InternalLayoutContext targetContext = ((InternalNodeLayout) connection
444
				.getTarget()).getOwnerLayoutContext();
445
		if (sourceContext != targetContext) {
446
			// connection between nodes in different containers is not
447
			// interesting for layout algorithms
448
			return;
449
		}
450
		if (sourceContext == this) {
451
			boolean intercepted = !eventsOn;
452
			GraphStructureListener[] listeners = (GraphStructureListener[]) graphStructureListeners
453
					.toArray(new GraphStructureListener[graphStructureListeners
454
							.size()]);
455
			for (int i = 0; i < listeners.length && !intercepted; i++) {
456
				intercepted = listeners[i].connectionRemoved(this, connection);
457
			}
458
			if (!intercepted) {
459
				applyMainAlgorithm();
460
			}
461
		} else {
462
			sourceContext.fireConnectionAddedEvent(connection);
463
		}
464
	}
465
466
	void fireConnectionWeightChanged(ConnectionLayout connection) {
467
		boolean intercepted = !eventsOn;
468
		GraphStructureListener[] listeners = (GraphStructureListener[]) graphStructureListeners
469
				.toArray(new GraphStructureListener[graphStructureListeners
470
						.size()]);
471
		for (int i = 0; i < listeners.length && !intercepted; i++) {
472
			intercepted = listeners[i]
473
					.connectionWeightChanged(this, connection);
474
		}
475
		if (!intercepted) {
476
			applyMainAlgorithm();
477
		}
478
	}
479
480
	void fireConnectionDirectedChanged(ConnectionLayout connection) {
481
		boolean intercepted = !eventsOn;
482
		GraphStructureListener[] listeners = (GraphStructureListener[]) graphStructureListeners
483
				.toArray(new GraphStructureListener[graphStructureListeners
484
						.size()]);
485
		for (int i = 0; i < listeners.length && !intercepted; i++) {
486
			intercepted = listeners[i].connectionDirectedChanged(this,
487
					connection);
488
		}
489
		if (!intercepted) {
490
			applyMainAlgorithm();
491
		}
492
	}
493
494
	void fireBoundsChangedEvent() {
495
		boolean intercepted = !eventsOn;
496
		ContextListener[] listeners = (ContextListener[]) contextListeners
497
				.toArray(new ContextListener[contextListeners.size()]);
498
		for (int i = 0; i < listeners.length && !intercepted; i++) {
499
			intercepted = listeners[i].boundsChanged(this);
500
		}
501
		if (!intercepted) {
502
			applyMainAlgorithm();
503
		}
504
	}
505
506
	void fireBackgroundEnableChangedEvent() {
507
		ContextListener[] listeners = (ContextListener[]) contextListeners
508
				.toArray(new ContextListener[contextListeners.size()]);
509
		for (int i = 0; i < listeners.length; i++) {
510
			listeners[i].backgroundEnableChanged(this);
511
		}
512
	}
513
514
	void fireEntityMovedEvent(EntityLayout entity) {
515
		boolean intercepted = !eventsOn;
516
		LayoutListener[] listeners = (LayoutListener[]) layoutListeners
517
				.toArray(new LayoutListener[layoutListeners.size()]);
518
		for (int i = 0; i < listeners.length && !intercepted; i++) {
519
			intercepted = listeners[i].entityMoved(this, entity);
520
		}
521
		if (!intercepted) {
522
			applyMainAlgorithm();
523
		}
524
	}
525
526
	void fireEntityResizedEvent(EntityLayout entity) {
527
		boolean intercepted = !eventsOn;
528
		LayoutListener[] listeners = (LayoutListener[]) layoutListeners
529
				.toArray(new LayoutListener[layoutListeners.size()]);
530
		for (int i = 0; i < listeners.length && !intercepted; i++) {
531
			intercepted = listeners[i].entityResized(this, entity);
532
		}
533
		if (!intercepted) {
534
			applyMainAlgorithm();
535
		}
536
	}
537
538
	void fireNodesPrunedEvent(NodeLayout[] nodes) {
539
		boolean intercepted = !eventsOn;
540
		PruningListener[] listeners = (PruningListener[]) pruningListeners
541
				.toArray(new PruningListener[pruningListeners.size()]);
542
		for (int i = 0; i < listeners.length && !intercepted; i++) {
543
			intercepted = listeners[i].nodesPruned(this, nodes);
544
		}
545
		if (!intercepted) {
546
			applyMainAlgorithm();
547
		}
548
	}
549
550
	void fireNodesUnprunedEvent(NodeLayout[] nodes, SubgraphLayout subgraph) {
551
		boolean intercepted = !eventsOn;
552
		PruningListener[] listeners = (PruningListener[]) pruningListeners
553
				.toArray(new PruningListener[pruningListeners.size()]);
554
		for (int i = 0; i < listeners.length && !intercepted; i++) {
555
			intercepted = listeners[i].nodesUnpruned(this, nodes, subgraph);
556
		}
557
		if (!intercepted) {
558
			applyMainAlgorithm();
559
		}
560
	}
561
}
(-)src/org/eclipse/zest/core/widgets/custom/TriangleSubgraph.java (+255 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets.custom;
11
12
import java.util.HashMap;
13
14
import org.eclipse.draw2d.ColorConstants;
15
import org.eclipse.draw2d.Graphics;
16
import org.eclipse.draw2d.Shape;
17
import org.eclipse.draw2d.geometry.PointList;
18
import org.eclipse.draw2d.geometry.Rectangle;
19
import org.eclipse.swt.graphics.Color;
20
import org.eclipse.zest.core.widgets.FigureSubgraph;
21
import org.eclipse.zest.layouts.algorithms.TreeLayoutObserver;
22
import org.eclipse.zest.layouts.algorithms.TreeLayoutObserver.TreeListener;
23
import org.eclipse.zest.layouts.algorithms.TreeLayoutObserver.TreeNode;
24
import org.eclipse.zest.layouts.interfaces.LayoutContext;
25
import org.eclipse.zest.layouts.interfaces.NodeLayout;
26
import org.eclipse.zest.layouts.interfaces.SubgraphLayout;
27
28
/**
29
 * A subgraph that is visualized in a graph as a triangle. It assumes that nodes
30
 * in context that uses them are arranged in a tree structure and the nodes
31
 * added to the subgraph are a subtree (except for the subtree's root, which
32
 * should not be added).
33
 * 
34
 * The triangle has three features that show the properties of a subtree
35
 * contained within it:
36
 * <ul>
37
 * <li><b>Height of the triangle</b> is proportional to the height of the
38
 * subtree. If the subtree contains the whole tree, the triangle's height will
39
 * be equal to value provided with
40
 * {@link TriangleSubgraph#setReferenceHeight(double)} (default is 50).</li>
41
 * <li><b>Length of the triangle's base</b> depends on the number of leaves in
42
 * the subtree. More precisely, it is proportional to the logarithm of the
43
 * percent that the subtree's leaves make of the whole context's leaves. The
44
 * proportion factor is adjusted so that for a subtree containing all the leaves
45
 * the base has length provided with {@link TriangleSubgraph}
46
 * {@link #setReferenceBase(double)} (default is 50) and for a subtree
47
 * containing only one leaf the base has length 1.</li>
48
 * <li><b>Background color of the triangle</b> depends on average number of
49
 * children for nodes in the subtree. The less is this value, the more bright is
50
 * the color (up to white for a subtree with average number of children equal to
51
 * 1). The average value is calculated only for nodes that have at least one
52
 * child. The root of the subtree (which is not directly added to this subgraph)
53
 * is also accounted.</li>
54
 * </ul>
55
 * 
56
 * When the first subgraph of this class is created for a layout context, a
57
 * {@link TreeLayoutObserver} is created for the context. It must keep track of
58
 * changes in the graph structure, so events related to it should not be
59
 * intercepted by other listeners before they reach the subgraph's observer.
60
 * 
61
 * @since 2.0
62
 */
63
public class TriangleSubgraph extends FigureSubgraph {
64
65
	public static class TriangleParameters implements Cloneable {
66
		public Color color = ColorConstants.black;
67
68
		public int direction = TOP_DOWN;
69
70
		public double referenceHeight = 50;
71
72
		public double referenceBase = 50;
73
74
		public Object clone() {
75
			TriangleParameters result = new TriangleParameters();
76
			result.color = color;
77
			result.direction = direction;
78
			result.referenceHeight = referenceHeight;
79
			result.referenceBase = referenceBase;
80
			return result;
81
		}
82
	}
83
84
	private class IsoscelesTriangle extends Shape {
85
86
		private PointList points = new PointList(3);
87
88
		protected void fillShape(Graphics graphics) {
89
			graphics.fillPolygon(points);
90
		}
91
92
		protected void outlineShape(Graphics graphics) {
93
			graphics.drawPolygon(points);
94
		}
95
96
		protected void primTranslate(int dx, int dy) {
97
			super.primTranslate(dx, dy);
98
			points.translate(dx, dy);
99
		}
100
101
		public void validate() {
102
			super.validate();
103
			Rectangle r = new Rectangle();
104
			r.setBounds(getBounds());
105
			r.crop(getInsets());
106
			points.removeAllPoints();
107
			switch (parameters.direction) {
108
			case TOP_DOWN:
109
				points.addPoint(r.x + r.width / 2, r.y);
110
				points.addPoint(r.x, r.y + r.height);
111
				points.addPoint(r.x + r.width, r.y + r.height);
112
				break;
113
			case BOTTOM_UP:
114
				points.addPoint(r.x + r.width / 2, r.y + r.height);
115
				points.addPoint(r.x, r.y);
116
				points.addPoint(r.x + r.width, r.y);
117
				break;
118
			case LEFT_RIGHT:
119
				points.addPoint(r.x, r.y + r.height / 2);
120
				points.addPoint(r.x + r.width, r.y);
121
				points.addPoint(r.x + r.width, r.y + r.height);
122
				break;
123
			case RIGHT_LEFT:
124
				points.addPoint(r.x + r.width, r.y + r.height / 2);
125
				points.addPoint(r.x, r.y);
126
				points.addPoint(r.x, r.y + r.height);
127
				break;
128
			}
129
		}
130
	}
131
132
	private static HashMap contextToTree = new HashMap();
133
134
	private TriangleParameters parameters;
135
136
	public TriangleSubgraph(NodeLayout[] nodes, LayoutContext context,
137
			TriangleParameters triangleParameters) {
138
		super(nodes, context);
139
		this.parameters = triangleParameters;
140
		if (contextToTree.get(context) == null) {
141
			TreeLayoutObserver treeLayoutObserver = new TreeLayoutObserver(
142
					context, null);
143
			treeLayoutObserver.addTreeListener(new TreeListener() {
144
				protected void defaultHandle(TreeNode changedNode) {
145
					SubgraphLayout subgraph = changedNode.getNode()
146
							.getSubgraph();
147
					if (subgraph instanceof TriangleSubgraph) {
148
						((TriangleSubgraph) subgraph).updateFigure();
149
					}
150
				}
151
			});
152
			contextToTree.put(context, treeLayoutObserver);
153
		}
154
	}
155
156
	protected void createFigure() {
157
		figure = new IsoscelesTriangle();
158
		figure.setBackgroundColor(parameters.color);
159
		figure.setForegroundColor(parameters.color);
160
	}
161
162
	private double log(double value, double base) {
163
		return Math.log(value) / Math.log(base);
164
	}
165
166
	protected void updateFigure() {
167
		TreeLayoutObserver tree = (TreeLayoutObserver) contextToTree
168
				.get(context);
169
		TreeNode subgraphRoot = tree.getTreeNode((NodeLayout) nodes.iterator()
170
				.next());
171
		if (subgraphRoot == null) {
172
			return;
173
		}
174
		while (nodes.contains(subgraphRoot.getNode())) {
175
			subgraphRoot = subgraphRoot.getParent();
176
		}
177
178
		TreeNode superRoot = tree.getSuperRoot();
179
		double triangleHeight = parameters.referenceHeight
180
				* subgraphRoot.getHeight() / superRoot.getHeight();
181
182
		int numOfNodes = superRoot.getNumOfDescendants();
183
		int numOfNodesWithChildren = numOfNodes - superRoot.getNumOfLeaves()
184
				+ 1;
185
		double logBase = (numOfNodesWithChildren > 0) ? (double) numOfNodes
186
				/ numOfNodesWithChildren : 1;
187
		// logarithm base is the average number of children for whole context
188
		double triangleBaseModifier = (parameters.referenceBase - 1)
189
				/ log(superRoot.getNumOfLeaves(), logBase);
190
		double triangleBase = parameters.referenceBase
191
				+ triangleBaseModifier
192
				* log((double) subgraphRoot.getNumOfLeaves()
193
						/ superRoot.getNumOfLeaves(), logBase);
194
195
		if (parameters.direction == 0) {
196
			parameters.direction = parameters.direction;
197
		}
198
		if (parameters.direction == TOP_DOWN
199
				|| parameters.direction == BOTTOM_UP) {
200
			figure.setSize((int) (triangleBase + 0.5),
201
					(int) (triangleHeight + 0.5));
202
		} else {
203
			figure.setSize((int) (triangleHeight + 0.5),
204
					(int) (triangleBase + 0.5));
205
		}
206
207
		int numOfNodesWithChildrenInSubgraph = nodes.size()
208
				- subgraphRoot.getNumOfLeaves() + 1;
209
		double avgNumOfChildrenInSugbraph = (numOfNodesWithChildrenInSubgraph > 0) ? (double) nodes
210
				.size()
211
				/ numOfNodesWithChildrenInSubgraph
212
				: 1;
213
		int r = (int) (parameters.color.getRed() + ((double) 255 - parameters.color
214
				.getRed())
215
				/ avgNumOfChildrenInSugbraph);
216
		int g = (int) (parameters.color.getGreen() + ((double) 255 - parameters.color
217
				.getGreen())
218
				/ avgNumOfChildrenInSugbraph);
219
		int b = (int) (parameters.color.getBlue() + ((double) 255 - parameters.color
220
				.getBlue())
221
				/ avgNumOfChildrenInSugbraph);
222
		figure.setBackgroundColor(new Color(parameters.color.getDevice(), r, g,
223
				b));
224
		figure.setForegroundColor(parameters.color);
225
	}
226
227
	public boolean isDirectionDependant() {
228
		return true;
229
	}
230
231
	public void setDirection(int direction) {
232
		super.setDirection(direction);
233
		if (parameters.direction == direction) {
234
			return;
235
		}
236
		if (direction == TOP_DOWN || direction == BOTTOM_UP
237
				|| direction == LEFT_RIGHT || direction == RIGHT_LEFT) {
238
			parameters.direction = direction;
239
			updateFigure();
240
		} else {
241
			throw new IllegalArgumentException("invalid direction");
242
		}
243
	}
244
245
	/**
246
	 * Changes the color of the triangle visualizing this subgraph.
247
	 * 
248
	 * @param color
249
	 *            color to use
250
	 */
251
	public void setColor(Color color) {
252
		parameters.color = color;
253
		updateFigure();
254
	}
255
}
(-)src/org/eclipse/zest/core/viewers/ZoomListener.java (+28 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others. All rights reserved.
3
 * This program and the accompanying materials are made available under the
4
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
5
 * and is available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors:
8
 *     IBM Corporation - initial API and implementation
9
 *******************************************************************************/
10
package org.eclipse.zest.core.viewers;
11
12
/**
13
 * Listens to zoom level changes.
14
 * 
15
 * @author Eric Bordeau
16
 * @since 2.0
17
 */
18
public interface ZoomListener {
19
20
	/**
21
	 * Called whenever the ZoomManager's zoom level changes.
22
	 * 
23
	 * @param zoom
24
	 *            the new zoom level.
25
	 */
26
	void zoomChanged(double zoom);
27
28
}
(-)src/org/eclipse/zest/core/widgets/DAGExpandCollapseManager.java (+356 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Mateusz Matela and others. All rights reserved. This
3
 * program and the accompanying materials are made available under the terms of
4
 * the Eclipse Public License v1.0 which accompanies this distribution, and is
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * Contributors: Mateusz Matela - initial API and implementation
8
 *               Ian Bull
9
 ******************************************************************************/
10
package org.eclipse.zest.core.widgets;
11
12
import java.util.HashMap;
13
import java.util.HashSet;
14
import java.util.Iterator;
15
import java.util.Map;
16
17
import org.eclipse.zest.layouts.interfaces.ConnectionLayout;
18
import org.eclipse.zest.layouts.interfaces.ContextListener;
19
import org.eclipse.zest.layouts.interfaces.ExpandCollapseManager;
20
import org.eclipse.zest.layouts.interfaces.GraphStructureListener;
21
import org.eclipse.zest.layouts.interfaces.LayoutContext;
22
import org.eclipse.zest.layouts.interfaces.NodeLayout;
23
24
/**
25
 * <p>
26
 * An {@link ExpandCollapseManager} specialized for Directed Acyclic Graphs. It
27
 * works correctly only when all connections are directed (and of course nodes
28
 * form an acyclic graph). It's supposed to be used with
29
 * {@link InternalLayoutContext}.
30
 * </p>
31
 * <p>
32
 * When a node is collapsed, all its outgoing connections are hidden and these
33
 * successors that have no visible incoming nodes are pruned. When a node is
34
 * expanded, all its successors are unpruned and connections pointing to them
35
 * are shown.
36
 * </p>
37
 * </p>
38
 * <p>
39
 * <b>NOTE:</b> A <code>Graph</code> using this manger should use
40
 * {@link DefaultSubgraph}, which doesn't show any information about subgraphs
41
 * in the graph. That's because for this manager it doesn't matter which
42
 * subgraph a node belongs to (each pruning creates a new subgraph). Also, this
43
 * manager adds a label to each collapsed node showing number of its successors.
44
 * </p>
45
 * One instance of this class can serve only one instance of <code>Graph</code>.
46
 * 
47
 * @since 2.0
48
 */
49
public class DAGExpandCollapseManager implements ExpandCollapseManager {
50
51
	private InternalLayoutContext context;
52
53
	private HashSet expandedNodes = new HashSet();
54
55
	private HashSet nodesToPrune = new HashSet();
56
57
	private HashSet nodesToUnprune = new HashSet();
58
59
	private HashSet nodesToUpdate = new HashSet();
60
61
	private HashMap connectionsToChangeVisibility = new HashMap();
62
63
	private boolean cleanLayoutScheduled = false;
64
65
	private boolean hidingConnections = false;
66
67
	public void initExpansion(final LayoutContext context2) {
68
		if (!(context2 instanceof InternalLayoutContext)) {
69
			throw new RuntimeException(
70
					"This manager works only with org.eclipse.zest.core.widgets.InternalLayoutContext");
71
		}
72
		context = (InternalLayoutContext) context2;
73
74
		context.addGraphStructureListener(new GraphStructureListener.Stub() {
75
			public boolean nodeRemoved(LayoutContext context, NodeLayout node) {
76
				if (isExpanded(node)) {
77
					collapse(node);
78
				}
79
				flushChanges(false, true);
80
				return false;
81
			}
82
83
			public boolean nodeAdded(LayoutContext context, NodeLayout node) {
84
				resetState(node);
85
				flushChanges(false, true);
86
				return false;
87
			}
88
89
			public boolean connectionRemoved(LayoutContext context,
90
					ConnectionLayout connection) {
91
				NodeLayout target = connection.getTarget();
92
				if (!isExpanded(target)
93
						&& target.getIncomingConnections().length == 0) {
94
					expand(target);
95
				}
96
				flushChanges(false, true);
97
				return false;
98
			}
99
100
			public boolean connectionAdded(LayoutContext context,
101
					ConnectionLayout connection) {
102
				if (!connection.isDirected()) {
103
					throw new RuntimeException(
104
							"Only directed connections can be used with DAGExpandCollapseManager");
105
				}
106
				resetState(connection.getTarget());
107
				updateNodeLabel(connection.getSource());
108
				refreshConnectionsVisibility(connection.getSource());
109
				flushChanges(false, true);
110
				return false;
111
			}
112
113
		});
114
115
		context.addContextListener(new ContextListener.Stub() {
116
			public void backgroundEnableChanged(LayoutContext context) {
117
				flushChanges(false, false);
118
			}
119
		});
120
	}
121
122
	public boolean canCollapse(LayoutContext context, NodeLayout node) {
123
		return isExpanded(node) && !node.isPruned()
124
				&& node.getOutgoingConnections().length > 0;
125
	}
126
127
	public boolean canExpand(LayoutContext context, NodeLayout node) {
128
		return !isExpanded(node) && !node.isPruned()
129
				&& node.getOutgoingConnections().length > 0;
130
	}
131
132
	public void setExpanded(LayoutContext context, NodeLayout node,
133
			boolean expanded) {
134
135
		if (isExpanded(node) == expanded) {
136
			return;
137
		}
138
		if (expanded) {
139
			if (canExpand(context, node)) {
140
				expand(node);
141
			}
142
		} else {
143
			if (canCollapse(context, node)) {
144
				collapse(node);
145
			}
146
		}
147
		refreshConnectionsVisibility(node);
148
		flushChanges(true, true);
149
	}
150
151
	/**
152
	 * Returns true if this collapse manager hides all outgoing connections of
153
	 * collapsed nodes. Returns false if connections pointing to a node that is
154
	 * not pruned (because it as predecessing node which is expanded) stay
155
	 * visible.
156
	 * 
157
	 * @return whether or not all connections going out of collapsed nodes are
158
	 *         hidden.
159
	 */
160
	public boolean isHidingConnections() {
161
		return hidingConnections;
162
	}
163
164
	/**
165
	 * Changes the way connections outgoing from collapsed nodes are hidden. If
166
	 * set to true, all such connections are always hidden. If set to false, a
167
	 * connection is visible if a node it points to is not pruned (which means
168
	 * that node has another predecessing node which is expanded).
169
	 * 
170
	 * Default is false.
171
	 * 
172
	 * @param hidingConnections
173
	 *            true if all outgoing connections of collapsed nodes should be
174
	 *            hidden.
175
	 */
176
	public void setHidingConnections(boolean hidingConnections) {
177
		this.hidingConnections = hidingConnections;
178
		NodeLayout[] nodes = context.getNodes();
179
		for (int i = 0; i < nodes.length; i++) {
180
			refreshConnectionsVisibility(nodes[i]);
181
		}
182
		flushChanges(false, false);
183
	}
184
185
	private void refreshConnectionsVisibility(NodeLayout node) {
186
		ConnectionLayout[] outgoingConnections = node.getOutgoingConnections();
187
		for (int i = 0; i < outgoingConnections.length; i++) {
188
			setConnectionVisible(
189
					outgoingConnections[i],
190
					isExpanded(node)
191
							|| (!hidingConnections && !isPruned(node) && !isPruned(outgoingConnections[i]
192
									.getTarget())));
193
		}
194
	}
195
196
	private void expand(NodeLayout node) {
197
		setExpanded(node, true);
198
		NodeLayout[] successingNodes = node.getSuccessingNodes();
199
		for (int i = 0; i < successingNodes.length; i++) {
200
			unpruneNode(successingNodes[i]);
201
		}
202
		updateNodeLabel(node);
203
	}
204
205
	private void collapse(NodeLayout node) {
206
		if (isExpanded(node)) {
207
			setExpanded(node, false);
208
		} else {
209
			return;
210
		}
211
		NodeLayout[] successors = node.getSuccessingNodes();
212
		for (int i = 0; i < successors.length; i++) {
213
			checkPruning(successors[i]);
214
			if (isPruned(successors[i])) {
215
				collapse(successors[i]);
216
			}
217
		}
218
		updateNodeLabel(node);
219
	}
220
221
	private void checkPruning(NodeLayout node) {
222
		boolean prune = true;
223
		NodeLayout[] predecessors = node.getPredecessingNodes();
224
		for (int j = 0; j < predecessors.length; j++) {
225
			if (isExpanded(predecessors[j])) {
226
				prune = false;
227
				break;
228
			}
229
		}
230
		if (prune) {
231
			pruneNode(node);
232
		} else {
233
			unpruneNode(node);
234
		}
235
	}
236
237
	/**
238
	 * By default nodes at the top (having no predecessors) are expanded. The
239
	 * rest are collapsed and pruned if they don't have any expanded
240
	 * predecessors
241
	 * 
242
	 * @param target
243
	 */
244
	private void resetState(NodeLayout node) {
245
		NodeLayout[] predecessors = node.getPredecessingNodes();
246
		if (predecessors.length == 0) {
247
			expand(node);
248
		} else {
249
			collapse(node);
250
			checkPruning(node);
251
		}
252
	}
253
254
	/**
255
	 * If given node belongs to a layout context using
256
	 * {@link PrunedSuccessorsSubgraph}, update of the nodes's label is forced.
257
	 * 
258
	 * @param node
259
	 *            node to update
260
	 */
261
	private void updateNodeLabel(NodeLayout node) {
262
		nodesToUpdate.add(node);
263
	}
264
265
	private void updateNodeLabel2(InternalNodeLayout node) {
266
		SubgraphFactory subgraphFactory = node.getOwnerLayoutContext()
267
				.getSubgraphFactory();
268
		if (subgraphFactory instanceof DefaultSubgraph.PrunedSuccessorsSubgraphFactory) {
269
			((DefaultSubgraph.PrunedSuccessorsSubgraphFactory) subgraphFactory)
270
					.updateLabelForNode(node);
271
		}
272
	}
273
274
	private void pruneNode(NodeLayout node) {
275
		if (isPruned(node)) {
276
			return;
277
		}
278
		nodesToUnprune.remove(node);
279
		nodesToPrune.add(node);
280
	}
281
282
	private void unpruneNode(NodeLayout node) {
283
		if (!isPruned(node)) {
284
			return;
285
		}
286
		nodesToPrune.remove(node);
287
		nodesToUnprune.add(node);
288
	}
289
290
	private void setConnectionVisible(ConnectionLayout connection,
291
			boolean visible) {
292
		if (connection.isVisible() == visible) {
293
			return;
294
		}
295
		connectionsToChangeVisibility.put(connection, new Boolean(visible));
296
	}
297
298
	private boolean isPruned(NodeLayout node) {
299
		if (nodesToUnprune.contains(node)) {
300
			return false;
301
		}
302
		if (nodesToPrune.contains(node)) {
303
			return true;
304
		}
305
		return node.isPruned();
306
	}
307
308
	private void flushChanges(boolean force, boolean clean) {
309
		cleanLayoutScheduled = cleanLayoutScheduled || clean;
310
		if (!force && !context.isBackgroundLayoutEnabled()) {
311
			return;
312
		}
313
314
		for (Iterator iterator = nodesToUnprune.iterator(); iterator.hasNext();) {
315
			NodeLayout node = (NodeLayout) iterator.next();
316
			node.prune(null);
317
		}
318
		nodesToUnprune.clear();
319
320
		if (!nodesToPrune.isEmpty()) {
321
			context.createSubgraph((NodeLayout[]) nodesToPrune
322
					.toArray(new NodeLayout[nodesToPrune.size()]));
323
			nodesToPrune.clear();
324
		}
325
326
		for (Iterator iterator = nodesToUpdate.iterator(); iterator.hasNext();) {
327
			InternalNodeLayout node = (InternalNodeLayout) iterator.next();
328
			updateNodeLabel2(node);
329
		}
330
		nodesToUpdate.clear();
331
332
		for (Iterator iterator = connectionsToChangeVisibility.entrySet()
333
				.iterator(); iterator.hasNext();) {
334
			Map.Entry entry = (Map.Entry) iterator.next();
335
			ConnectionLayout connection = (ConnectionLayout) entry.getKey();
336
			Boolean visible = (Boolean) entry.getValue();
337
			connection.setVisible(visible.booleanValue());
338
		}
339
340
		context.applyLayout(cleanLayoutScheduled);
341
		cleanLayoutScheduled = false;
342
		context.flushChanges(true);
343
	}
344
345
	private boolean isExpanded(NodeLayout node) {
346
		return expandedNodes.contains(node);
347
	}
348
349
	private void setExpanded(NodeLayout node, boolean expanded) {
350
		if (expanded) {
351
			expandedNodes.add(node);
352
		} else {
353
			expandedNodes.remove(node);
354
		}
355
	}
356
}

Return to bug 277534