View | Details | Raw Unified | Return to bug 281246 | Differences between
and this patch

Collapse All | Expand All

(-)a/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/GraphConnection.java (-32 / +18 lines)
Lines 17-28 Link Here
17
import org.eclipse.draw2d.Graphics;
17
import org.eclipse.draw2d.Graphics;
18
import org.eclipse.draw2d.IFigure;
18
import org.eclipse.draw2d.IFigure;
19
import org.eclipse.draw2d.Label;
19
import org.eclipse.draw2d.Label;
20
import org.eclipse.draw2d.Locator;
21
import org.eclipse.draw2d.MidpointLocator;
22
import org.eclipse.draw2d.PolygonDecoration;
20
import org.eclipse.draw2d.PolygonDecoration;
23
import org.eclipse.draw2d.PolylineConnection;
21
import org.eclipse.draw2d.PolylineConnection;
24
import org.eclipse.draw2d.Shape;
22
import org.eclipse.draw2d.Shape;
25
import org.eclipse.draw2d.geometry.Point;
26
import org.eclipse.swt.graphics.Color;
23
import org.eclipse.swt.graphics.Color;
27
import org.eclipse.swt.graphics.Font;
24
import org.eclipse.swt.graphics.Font;
28
import org.eclipse.swt.widgets.Display;
25
import org.eclipse.swt.widgets.Display;
Lines 59-65 Link Here
59
	private int curveDepth;
56
	private int curveDepth;
60
	private boolean isDisposed = false;
57
	private boolean isDisposed = false;
61
58
62
	private Label connectionLabel = null;
59
	private PolylineLabelDecoration connectionLabel = null;
63
	private PolylineArcConnection connectionFigure = null;
60
	private PolylineArcConnection connectionFigure = null;
64
	private PolylineArcConnection cachedConnectionFigure = null;
61
	private PolylineArcConnection cachedConnectionFigure = null;
65
	private Connection sourceContainerConnectionFigure = null;
62
	private Connection sourceContainerConnectionFigure = null;
Lines 474-493 Link Here
474
	 *            The depth of the curve
471
	 *            The depth of the curve
475
	 */
472
	 */
476
	public void setCurveDepth(int depth) {
473
	public void setCurveDepth(int depth) {
477
		if (this.curveDepth == 0 && depth != 0 || this.curveDepth != 0
474
		/*
478
				&& depth == 0) {
475
		 * if (this.curveDepth == 0 && depth != 0 || this.curveDepth != 0 &&
479
			// There is currently no curve, so we have to create
476
		 * depth == 0) { // There is currently no curve, so we have to create //
480
			// a curved connection
477
		 * a curved connection this.cachedConnectionFigure = connectionFigure;
481
			this.cachedConnectionFigure = connectionFigure;
478
		 * graph.removeConnection(this); this.curveDepth = depth;
482
			graph.removeConnection(this);
479
		 * this.connectionFigure = doCreateFigure();
483
			this.curveDepth = depth;
480
		 * registerConnection(sourceNode, destinationNode);
484
			this.connectionFigure = doCreateFigure();
481
		 * updateFigure(this.connectionFigure); } else {
485
			registerConnection(sourceNode, destinationNode);
482
		 */
486
			updateFigure(this.connectionFigure);
483
		this.curveDepth = depth;
487
		} else {
484
		updateFigure(this.connectionFigure);
488
			this.curveDepth = depth;
485
		// }
489
			updateFigure(this.connectionFigure);
490
		}
491
	}
486
	}
492
487
493
	/*
488
	/*
Lines 651-674 Link Here
651
		PolylineArcConnection connectionFigure = cachedOrNewConnectionFigure();
646
		PolylineArcConnection connectionFigure = cachedOrNewConnectionFigure();
652
		ChopboxAnchor sourceAnchor = null;
647
		ChopboxAnchor sourceAnchor = null;
653
		ChopboxAnchor targetAnchor = null;
648
		ChopboxAnchor targetAnchor = null;
654
		this.connectionLabel = new Label();
649
		this.connectionLabel = new PolylineLabelDecoration();
655
		Locator labelLocator = null;
650
		connectionLabel.setTextPosition(PolylineLabelDecoration.POSITION_DEST);
656
651
657
		if (getSource() == getDestination()) {
652
		if (getSource() == getDestination()) {
658
			// If this is a self loop, create a looped arc and put the locator
653
			// If this is a self loop, create a looped arc and put the locator
659
			// at the top of the connection
654
			// at the top of the connection
660
			sourceAnchor = new LoopAnchor(getSource().getNodeFigure());
655
			sourceAnchor = new LoopAnchor(getSource().getNodeFigure());
661
			targetAnchor = new LoopAnchor(getDestination().getNodeFigure());
656
			targetAnchor = new LoopAnchor(getDestination().getNodeFigure());
662
			labelLocator = new MidpointLocator(connectionFigure, 0) {
657
			connectionLabel.setTrimText(false);
663
				protected Point getReferencePoint() {
664
					Point p = Point.SINGLETON;
665
					p.x = getConnection().getPoints().getPoint(getIndex()).x;
666
					p.y = (int) (getConnection().getPoints().getPoint(
667
							getIndex()).y - (curveDepth * 1.5));
668
					getConnection().translateToAbsolute(p);
669
					return p;
670
				}
671
			};
672
		} else {
658
		} else {
673
			if (curveDepth != 0) {
659
			if (curveDepth != 0) {
674
				connectionFigure.setDepth(this.curveDepth);
660
				connectionFigure.setDepth(this.curveDepth);
Lines 678-691 Link Here
678
					getSource().getNodeFigure(), 8);
664
					getSource().getNodeFigure(), 8);
679
			targetAnchor = new RoundedChopboxAnchor(getDestination()
665
			targetAnchor = new RoundedChopboxAnchor(getDestination()
680
					.getNodeFigure(), 8);
666
					.getNodeFigure(), 8);
681
			labelLocator = new MidpointLocator(connectionFigure, 0);
682
		}
667
		}
683
668
684
		connectionFigure.setSourceAnchor(sourceAnchor);
669
		connectionFigure.setSourceAnchor(sourceAnchor);
685
		connectionFigure.setTargetAnchor(targetAnchor);
670
		connectionFigure.setTargetAnchor(targetAnchor);
686
		connectionFigure.add(this.connectionLabel, labelLocator);
687
671
688
		doUpdateFigure(connectionFigure);
672
		doUpdateFigure(connectionFigure);
673
		connectionFigure.add(this.connectionLabel, new PolylineLabelLocator(
674
				connectionFigure));
689
		return connectionFigure;
675
		return connectionFigure;
690
	}
676
	}
691
677
(-)a/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/PolylineLabelDecoration.java (+445 lines)
Added Link Here
1
package org.eclipse.zest.core.widgets;
2
3
import org.eclipse.draw2d.AbstractBackground;
4
import org.eclipse.draw2d.ColorConstants;
5
import org.eclipse.draw2d.Graphics;
6
import org.eclipse.draw2d.Label;
7
import org.eclipse.draw2d.PolylineConnection;
8
import org.eclipse.draw2d.RotatableDecoration;
9
import org.eclipse.draw2d.geometry.Dimension;
10
import org.eclipse.draw2d.geometry.Point;
11
import org.eclipse.draw2d.geometry.PointList;
12
import org.eclipse.draw2d.geometry.Rectangle;
13
import org.eclipse.swt.graphics.Font;
14
import org.eclipse.swt.graphics.Image;
15
16
/**
17
 * A decorative label Figure intended to be placed on a
18
 * {@link PolylineConnection}.
19
 * 
20
 * @since 3.5
21
 */
22
public class PolylineLabelDecoration extends Label implements
23
		RotatableDecoration {
24
25
	private static final int ICON_SPACER = 5;
26
	private static final int TEXT_MARGINS = 5; // 2 pixels from both ends
27
28
	public static final int POSITION_CENTER = 0;
29
	public static final int POSITION_SOURCE = 1;
30
	public static final int POSITION_DEST = 2;
31
32
	private Point location = new Point();
33
	private Point refPoint = new Point();
34
	private double angle;
35
	private int curveDepth;
36
	private int textPosition = POSITION_CENTER;
37
38
	private boolean trimText = true;
39
40
	private Rectangle segmentBase;
41
	private Point[] unalignedBounds;
42
	private String subStringText;
43
44
	public PolylineLabelDecoration() {
45
		super();
46
	}
47
48
	public PolylineLabelDecoration(Image i) {
49
		super(i);
50
	}
51
52
	public PolylineLabelDecoration(String s) {
53
		super(s);
54
	}
55
56
	public PolylineLabelDecoration(String s, Image i) {
57
		super(s, i);
58
	}
59
60
	/**
61
	 * Find the bounding box that encloses the two reference points (
62
	 * {@link #refPoint} and {@link #location}).
63
	 */
64
	private Rectangle getSegmentBase() {
65
		if (segmentBase == null) {
66
67
			int xDiff = refPoint.x - location.x;
68
			int yDiff = refPoint.y - location.y;
69
			int length = length(xDiff, yDiff);
70
			int textLength = getSubStringTextSize().width;
71
			if (getIconSize().width > 0)
72
				textLength += getIconSize().width + ICON_SPACER;
73
74
			// extend boundingBox to contain whole textSubstring
75
			int xInc = 0;
76
			int yInc = 0;
77
			if (textLength > 0) {
78
				if (length == 0) {
79
					xInc = textLength;
80
					yInc = 0;
81
				} else {
82
					xInc = xDiff * (textLength - length) / length;
83
					yInc = yDiff * (textLength - length) / length;
84
				}
85
			}
86
87
			// text positioning
88
			int offsetLength = 0;
89
			if (textPosition == POSITION_SOURCE) {
90
				offsetLength = -(length - textLength - (TEXT_MARGINS * 2)) / 2;
91
			} else if (textPosition == POSITION_DEST) {
92
				offsetLength = (length - textLength - (TEXT_MARGINS * 2)) / 2;
93
			}
94
95
			int xOffset = length == 0 ? 0 : (xDiff * offsetLength / length);
96
			int yOffset = length == 0 ? 0 : (yDiff * offsetLength / length);
97
98
			int width = Math.abs(xDiff + xInc);
99
			int height = Math.abs(yDiff + yInc);
100
101
			int x, y;
102
			if (xDiff >= 0) {
103
				// width = (int) (xDiff + xInc);
104
				x = location.x - (xInc / 2) + xOffset;
105
			} else {
106
				// width = (int) (-xDiff - xInc);
107
				x = refPoint.x + (xInc / 2) + xOffset;
108
			}
109
			if (yDiff >= 0) {
110
				// height = (int) (yDiff + yInc);
111
				y = location.y - (yInc / 2) + yOffset;
112
			} else {
113
				// height = (int) (-yDiff - yInc);
114
				y = refPoint.y + (yInc / 2) + yOffset;
115
			}
116
117
			segmentBase = new Rectangle(x, y, width, height);
118
		}
119
		return segmentBase;
120
	}
121
122
	public void setFont(Font f) {
123
		super.setFont(f);
124
	}
125
126
	/**
127
	 * Oriented rectangular polygon which contains whole label
128
	 */
129
	protected Point[] getUnalignedBounds() {
130
		if (unalignedBounds == null) {
131
132
			int textWidth = getSubStringTextSize().width;
133
			if (getIconSize().width > 0)
134
				textWidth += getIconSize().width + ICON_SPACER;
135
136
			int textHeight = getSubStringTextSize().height;
137
			if (getIconSize().height > textHeight)
138
				textHeight = getIconSize().height;
139
140
			Point topLeft = getSegmentBase().getTopLeft();
141
142
			if (angle < 0) {
143
				topLeft.translate(0, getSegmentBase().height);
144
			}
145
			if (angle < -90.0 || angle > 90.0) {
146
				topLeft.translate(0, angle < 0 ? -getSegmentBase().height
147
						: getSegmentBase().height);
148
				translate(topLeft, textHeight - curveDepth,
149
						Math.toRadians(angle) + Math.PI / 2);
150
			} else {
151
				translate(topLeft, -textHeight - curveDepth,
152
						Math.toRadians(angle) + Math.PI / 2);
153
			}
154
155
			double radians = Math.toRadians(angle);
156
			if (angle > 90.0 || angle < -90.0)
157
				radians = radians - Math.PI;
158
159
			Point bottomLeft = topLeft.getCopy();
160
			translate(bottomLeft, textHeight, radians + Math.PI / 2);
161
162
			Point topRight = topLeft.getCopy();
163
			translate(topRight, textWidth, radians);
164
165
			Point bottomRight = bottomLeft.getCopy();
166
			translate(bottomRight, textWidth, radians);
167
168
			unalignedBounds = new Point[] { topLeft, topRight, bottomRight,
169
					bottomLeft };
170
		}
171
		return unalignedBounds;
172
	}
173
174
	/**
175
	 * Axis-aligned rectangle which fully contains unalignedBounds
176
	 */
177
	public Rectangle getBounds() {
178
		if (bounds == null) {
179
			// heightDiff = 0;
180
181
			Point[] ubox = getUnalignedBounds();
182
183
			// The four points represent a rectangle that contains only the
184
			// text. However, its coordinate is at an angle
185
			// with the absolute coordinate, so it cannot be set as the bounds.
186
			// Need to compute the bounds by searching
187
			// for the leftmost x, rightmost x, highest y and lowest y
188
189
			int xLeft = ubox[0].x;
190
			int xRight = ubox[0].x;
191
			int yTop = ubox[0].y;
192
			int yBottom = ubox[0].y;
193
			for (int i = 1; i < ubox.length; i++) {
194
				Point point = ubox[i];
195
				if (point.x < xLeft) {
196
					xLeft = point.x;
197
				} else if (point.x > xRight) {
198
					xRight = point.x;
199
				}
200
201
				// Don't forget that (0,0) is the top left point of the screen!
202
				if (point.y < yTop) {
203
					yTop = point.y;
204
				} else if (point.y > yBottom) {
205
					yBottom = point.y;
206
				}
207
			}
208
			Rectangle rectangle = new Rectangle(xLeft, yTop, xRight - xLeft,
209
					yBottom - yTop);
210
			// if (rectangle.height < textSize.height) {
211
			// heightDiff = textSize.height - rectangle.height;
212
			// rectangle.height = textSize.height;
213
			// }
214
			// If the rectangle's width is small, then it means that it is
215
			// nearly vertical. For proper behavior, it must
216
			// be at least the textSize's height.
217
			Dimension textSize = getSubStringTextSize();
218
			if (rectangle.width < textSize.height) {
219
				rectangle.width = textSize.height;
220
			}
221
			bounds = rectangle;
222
		}
223
		return super.getBounds();
224
	}
225
226
	// location of icon within bounds
227
	protected Point getIconLocation() {
228
		int linkLength = length(getSegmentBase().width, getSegmentBase().height);
229
230
		int iconWidth = getIconSize().width;
231
		if (iconWidth > 0)
232
			iconWidth += ICON_SPACER;
233
234
		int x;
235
		switch (getTextAlignment()) {
236
		case LEFT:
237
			x = 0;
238
			break;
239
		case RIGHT:
240
			x = (int) (linkLength - (getSubStringTextSize().width + iconWidth));
241
			break;
242
		default:
243
			x = (int) (linkLength - (getSubStringTextSize().width + iconWidth)) / 2;
244
		}
245
		if (x < 0) {
246
			x = 0;
247
		}
248
249
		int y = 0;
250
		if (getIconSize().height < getSubStringTextSize().height)
251
			y = getIconSize().height - getSubStringTextSize().height;
252
253
		return new Point(x, y);
254
	}
255
256
	// shift of text within bounds
257
	protected Point getTextLocation() {
258
		int linkLength = length(getSegmentBase().width, getSegmentBase().height);
259
260
		int iconWidth = getIconSize().width;
261
		if (iconWidth > 0)
262
			iconWidth += ICON_SPACER;
263
264
		int x;
265
		switch (getTextAlignment()) {
266
		case LEFT:
267
			x = iconWidth;
268
			break;
269
		case RIGHT:
270
			x = (int) (linkLength - getSubStringTextSize().width);
271
			break;
272
		default:
273
			x = ((int) (linkLength - (getSubStringTextSize().width + iconWidth)) / 2)
274
					+ iconWidth;
275
		}
276
277
		if (x < 0)
278
			x = 0;
279
280
		int y = 0;
281
		if (getIconSize().height > getSubStringTextSize().height)
282
			y = getIconSize().height - getSubStringTextSize().height;
283
284
		return new Point(x, y);
285
	}
286
287
	public String getSubStringText() {
288
		if (subStringText != null) {
289
			return subStringText;
290
		}
291
292
		String text = getText();
293
		subStringText = text;
294
295
		if (!trimText) {
296
			return subStringText;
297
		}
298
299
		int xDiff = refPoint.x - location.x;
300
		int yDiff = refPoint.y - location.y;
301
		int maxtextLength = length(xDiff, yDiff) - (TEXT_MARGINS * 2);
302
303
		if (getIconSize().width > 0) {
304
			maxtextLength -= getIconSize().width + ICON_SPACER;
305
		}
306
307
		int widthShrink = (int) (getTextSize().width - maxtextLength);
308
		if (widthShrink <= 0) {
309
			return subStringText;
310
		}
311
312
		Dimension effectiveSize = getTextSize().getExpanded(-widthShrink, 0);
313
		Font currentFont = getFont();
314
		int dotsWidth = getTextUtilities().getTextExtents(
315
				getTruncationString(), currentFont).width;
316
317
		if (effectiveSize.width < dotsWidth) {
318
			effectiveSize.width = dotsWidth;
319
		}
320
321
		int subStringLength = getTextUtilities().getLargestSubstringConfinedTo(
322
				text, currentFont, effectiveSize.width - dotsWidth);
323
		subStringText = new String(text.substring(0, subStringLength)
324
				+ getTruncationString());
325
		return subStringText;
326
	}
327
328
	protected void paintFigure(Graphics graphics) {
329
		// Draws the text
330
		graphics.pushState();
331
		/*
332
		 * Point[] uboxs = getUnalignedBounds(); PointList pls = new
333
		 * PointList(); for (int i = 0; i < uboxs.length; i++)
334
		 * pls.addPoint(uboxs[i]); graphics.drawPolygon(pls);
335
		 */
336
		graphics.translate(getUnalignedBounds()[0]);
337
		if (angle < -90.0 || angle > 90.0) {
338
			graphics.rotate((float) angle + 180);
339
		} else {
340
			graphics.rotate((float) angle);
341
		}
342
343
		if (isOpaque()) {
344
			Point[] ubox = getUnalignedBounds();
345
			PointList pl = new PointList();
346
			for (int i = 0; i < ubox.length; i++)
347
				pl.addPoint(ubox[i]);
348
			graphics.fillPolygon(pl);
349
		}
350
		if (getBorder() instanceof AbstractBackground) {
351
			((AbstractBackground) getBorder()).paintBackground(this, graphics,
352
					NO_INSETS);
353
		}
354
		if (getIcon() != null) {
355
			graphics.drawImage(getIcon(), getIconLocation());
356
		}
357
		if (!isEnabled()) {
358
			graphics.translate(1, 1);
359
			graphics.setForegroundColor(ColorConstants.buttonLightest);
360
			graphics.drawText(getSubStringText(), new Point());
361
			graphics.translate(-1, -1);
362
			graphics.setForegroundColor(ColorConstants.buttonDarker);
363
		}
364
		graphics.drawText(getSubStringText(), getTextLocation());
365
		graphics.popState();
366
	}
367
368
	public boolean containsPoint(int x, int y) {
369
		boolean contains = super.containsPoint(x, y);
370
371
		if (contains) {
372
			// check if point is within unaligned box
373
			Point[] ubox = getUnalignedBounds();
374
			PointList pl = new PointList();
375
			for (int i = 0; i < ubox.length; i++)
376
				pl.addPoint(ubox[i]);
377
			pl.addPoint(ubox[0]);
378
			contains = pl.polygonContainsPoint(x, y);
379
		}
380
		return contains;
381
	}
382
383
	public void invalidate() {
384
		subStringText = null;
385
		super.invalidate();
386
	}
387
388
	public void setLocation(Point p) {
389
		location.setLocation(p);
390
		segmentBase = null;
391
		unalignedBounds = null;
392
		bounds = null;
393
		invalidate();
394
	}
395
396
	public void setReferencePoint(Point ref) {
397
		Point pt = Point.SINGLETON;
398
		refPoint.setLocation(ref);
399
		pt.setLocation(ref);
400
		pt.negate().translate(location);
401
		this.angle = Math.toDegrees(Math.atan2(pt.y, pt.x));
402
		segmentBase = null;
403
		unalignedBounds = null;
404
		bounds = null;
405
		invalidate();
406
	}
407
408
	public void setCurveDepth(int depth) {
409
		this.curveDepth = depth;
410
		segmentBase = null;
411
		unalignedBounds = null;
412
		bounds = null;
413
		invalidate();
414
	}
415
416
	public void setTrimText(boolean trimText) {
417
		this.trimText = trimText;
418
		segmentBase = null;
419
		unalignedBounds = null;
420
		bounds = null;
421
		invalidate();
422
	}
423
424
	public void setTextPosition(int textPosition) {
425
		this.textPosition = textPosition;
426
		segmentBase = null;
427
		unalignedBounds = null;
428
		bounds = null;
429
		invalidate();
430
	}
431
432
	/**
433
	 * Translate a point using polar coordinate.
434
	 */
435
	private static final void translate(Point pointToTranslate, int radius,
436
			double radians) {
437
		pointToTranslate.translate((int) (radius * Math.cos(radians)),
438
				(int) (radius * Math.sin(radians)));
439
	}
440
441
	private static final int length(long w, long h) {
442
		return (int) Math.sqrt(w * w + h * h);
443
	}
444
445
}
(-)a/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/PolylineLabelLocator.java (+55 lines)
Added Link Here
1
package org.eclipse.zest.core.widgets;
2
3
import org.eclipse.draw2d.Connection;
4
import org.eclipse.draw2d.IFigure;
5
import org.eclipse.draw2d.Locator;
6
import org.eclipse.draw2d.geometry.PointList;
7
import org.eclipse.zest.core.widgets.internal.PolylineArcConnection;
8
9
/**
10
 * Locator used to place a {@link PolylineLabelDecoration} on a
11
 * {@link Connection}.
12
 * 
13
 * @since 3.5
14
 */
15
public class PolylineLabelLocator implements Locator {
16
17
	private Connection connection;
18
19
	/**
20
	 * Constructs a LabelLocator associated with passed connection.
21
	 * 
22
	 * @param connection
23
	 *            The connection associated with the locator
24
	 */
25
	public PolylineLabelLocator(Connection connection) {
26
		this.connection = connection;
27
	}
28
29
	/**
30
	 * Relocates the passed in figure (which must be a
31
	 * {@link PolylineLabelDecoration}) at the start of the connection.
32
	 * 
33
	 * @param target
34
	 *            The PolylineLabelDecoration to relocate
35
	 */
36
	public void relocate(IFigure target) {
37
38
		PointList points = connection.getPoints();
39
		PolylineLabelDecoration dec = (PolylineLabelDecoration) target;
40
41
		dec.setLocation(points.getFirstPoint());
42
		dec.setReferencePoint(points.getLastPoint());
43
		if (connection instanceof PolylineArcConnection)
44
			dec.setCurveDepth(((PolylineArcConnection) connection).getDepth());
45
46
		/*
47
		 * int l = points.size(); if (l % 2 == 0) {
48
		 * dec.setLocation(points.getPoint(l / 2 - 1));
49
		 * dec.setReferencePoint(points.getPoint(l / 2)); } else {
50
		 * dec.setLocation(points.getPoint(l / 2 - 1));
51
		 * dec.setReferencePoint(points.getPoint(l / 2 + 1)); }
52
		 */
53
54
	}
55
}
(-)a/org.eclipse.zest.core/src/org/eclipse/zest/core/widgets/internal/PolylineArcConnection.java (+4 lines)
Lines 49-54 Link Here
49
		updateArc(points);
49
		updateArc(points);
50
	}
50
	}
51
51
52
	public int getDepth() {
53
		return depth;
54
	}
55
52
	/**
56
	/**
53
	 * This method is not supported by this kind of connection. Points are
57
	 * This method is not supported by this kind of connection. Points are
54
	 * calculated based on the arc definition.
58
	 * calculated based on the arc definition.

Return to bug 281246