1
2
3
4
5
6
7 package pl.edu.agh.cast.schema.figure;
8
9 import org.eclipse.draw2d.AnchorListener;
10 import org.eclipse.draw2d.ConnectionAnchor;
11 import org.eclipse.draw2d.ConnectionAnchorBase;
12 import org.eclipse.draw2d.Graphics;
13 import org.eclipse.draw2d.IFigure;
14 import org.eclipse.draw2d.Label;
15 import org.eclipse.draw2d.PolygonDecoration;
16 import org.eclipse.draw2d.PolylineConnection;
17 import org.eclipse.draw2d.geometry.Dimension;
18 import org.eclipse.draw2d.geometry.Point;
19 import org.eclipse.draw2d.geometry.PointList;
20 import org.eclipse.draw2d.geometry.Rectangle;
21 import org.eclipse.swt.SWT;
22 import org.eclipse.swt.graphics.Color;
23 import org.eclipse.swt.widgets.Display;
24
25 import pl.edu.agh.cast.common.HexColor;
26 import pl.edu.agh.cast.model.visual.backward.ConnectionGroup;
27
28
29
30
31
32
33 public class DoublePolylineConnection extends ModifiablePolylineConnection {
34
35 private final int LinesDistance = 10;
36
37 private int BORDER_CONSTANT = 10;
38
39 private PolylineConnection _secondPolyline;
40
41 private Label _firstLabel;
42
43 private Label _secondLabel;
44
45 private InternalConnectionAnchor _sourceAnchor;
46
47 private ConnectionGroup _connectionGroup;
48
49 public DoublePolylineConnection(ConnectionGroup connectionGroup) {
50
51 _connectionGroup = connectionGroup;
52
53 _secondPolyline = new PolylineConnection();
54 _firstLabel = new Label("");
55 _firstLabel.setBackgroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
56 _firstLabel.setOpaque(true);
57 _secondLabel = new Label("");
58 _secondLabel.setBackgroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
59 _secondLabel.setOpaque(true);
60
61 setTargetDecoration(new PolygonDecoration());
62 setLineStyle(Graphics.LINE_SOLID);
63 _secondPolyline.setSourceDecoration(new PolygonDecoration());
64 _secondPolyline.setLineStyle(Graphics.LINE_SOLID);
65
66 _sourceAnchor = new InternalConnectionAnchor(_secondPolyline);
67
68 add(_firstLabel);
69
70 add(_secondLabel);
71
72 add(_secondPolyline);
73
74 refresh();
75 }
76
77 @Override
78 public void setPoints(PointList points) {
79 float angle = getAngle(points);
80
81 PointList firstLinePoints = new PointList();
82 PointList secondLinePoints = new PointList();
83
84 Point firstPoint = points.getFirstPoint();
85 Point lastPoint = points.getLastPoint();
86 int xVector = firstPoint.x - lastPoint.x;
87 int yVector = firstPoint.y - lastPoint.y;
88 double vectorLength = (Math.sqrt(xVector * xVector + yVector * yVector));
89 if (vectorLength > 3 * BORDER_CONSTANT) {
90 double xUnitVector = xVector / vectorLength;
91 double yUnitVector = yVector / vectorLength;
92
93 firstPoint = new Point(firstPoint.x - xUnitVector * BORDER_CONSTANT, firstPoint.y - yUnitVector
94 * BORDER_CONSTANT);
95 lastPoint = new Point(lastPoint.x + xUnitVector * BORDER_CONSTANT, lastPoint.y + yUnitVector
96 * BORDER_CONSTANT);
97 points = new PointList();
98 points.addPoint(firstPoint);
99 points.addPoint(lastPoint);
100 }
101
102 for (int i = 0; i < points.size(); i++) {
103 Point original = points.getPoint(i);
104 firstLinePoints.addPoint(translateFirstLinePoint(original, angle));
105 secondLinePoints.addPoint(translateSecondLinePoint(original, angle));
106 }
107
108 super.setPoints(firstLinePoints);
109 _secondPolyline.setPoints(secondLinePoints);
110 setLabelsBounds(firstLinePoints, secondLinePoints, angle);
111 }
112
113 private float getAngle(PointList points) {
114 float dx = points.getLastPoint().x - points.getFirstPoint().x;
115 float dy = points.getLastPoint().y - points.getFirstPoint().y;
116 return (float)Math.atan2(dx, dy);
117 }
118
119 private Point translateFirstLinePoint(Point original, float angle) {
120 int newX = (int)(original.x + LinesDistance * Math.cos(angle) / 2);
121 int newY = (int)(original.y - LinesDistance * Math.sin(angle) / 2);
122 return new Point(newX, newY);
123 }
124
125 private Point translateSecondLinePoint(Point original, float angle) {
126 int newX = (int)(original.x - LinesDistance * Math.cos(angle) / 2);
127 int newY = (int)(original.y + LinesDistance * Math.sin(angle) / 2);
128 return new Point(newX, newY);
129 }
130
131 private Point getMiddlePoint(PointList points) {
132 int x = (points.getLastPoint().x + points.getFirstPoint().x) / 2;
133 int y = (points.getLastPoint().y + points.getFirstPoint().y) / 2;
134 return new Point(x, y);
135 }
136
137 @Override
138 public void setSourceAnchor(ConnectionAnchor anchor) {
139 if (getSourceAnchor() != null) {
140 getSourceAnchor().removeAnchorListener(_sourceAnchor);
141 }
142
143 super.setSourceAnchor(anchor);
144
145 if (anchor != null) {
146 anchor.addAnchorListener(_sourceAnchor);
147 }
148 }
149
150 @Override
151 public void setTargetAnchor(ConnectionAnchor anchor) {
152 if (getTargetAnchor() != null) {
153 getTargetAnchor().removeAnchorListener(_sourceAnchor);
154 }
155
156 super.setTargetAnchor(anchor);
157
158 if (anchor != null) {
159 anchor.addAnchorListener(_sourceAnchor);
160 }
161 }
162
163 private void setLabelsBounds(PointList firstLinePoints, PointList secondLinePoints, float angle) {
164 Point firstLabelPoint = getMiddlePoint(firstLinePoints);
165 Dimension firstLabelSize = _firstLabel.getPreferredSize();
166
167 Point secondLabelPoint = getMiddlePoint(secondLinePoints);
168 Dimension secondLabelSize = _secondLabel.getPreferredSize();
169
170 if (firstLabelPoint.x < secondLabelPoint.x) {
171 firstLabelPoint.x = (int)(firstLabelPoint.x - firstLabelSize.width * Math.abs(Math.cos(angle)));
172 } else if (secondLabelPoint.x < firstLabelPoint.x) {
173 secondLabelPoint.x = (int)(secondLabelPoint.x - secondLabelSize.width * Math.abs(Math.cos(angle)));
174 }
175
176 if (firstLabelPoint.y < secondLabelPoint.y) {
177 firstLabelPoint.y = (int)(firstLabelPoint.y - firstLabelSize.height * Math.abs(Math.sin(angle)));
178 } else if (secondLabelPoint.y < firstLabelPoint.y) {
179 secondLabelPoint.y = (int)(secondLabelPoint.y - secondLabelSize.height * Math.abs(Math.sin(angle)));
180 }
181
182 _firstLabel.setBounds(new Rectangle(firstLabelPoint, firstLabelSize));
183 _secondLabel.setBounds(new Rectangle(secondLabelPoint, secondLabelSize));
184 }
185
186 private class InternalConnectionAnchor extends ConnectionAnchorBase implements AnchorListener {
187
188 private Point _desiredLocation;
189
190 private PolylineConnection _connection;
191
192 public InternalConnectionAnchor(PolylineConnection connection) {
193 _connection = connection;
194 _connection.setSourceAnchor(this);
195 }
196
197 public Point getLocation(Point location) {
198 return _desiredLocation;
199 }
200
201 public IFigure getOwner() {
202 return null;
203 }
204
205 public Point getReferencePoint() {
206 return _desiredLocation;
207 }
208
209 public void anchorMoved(ConnectionAnchor anchor) {
210 _desiredLocation = _connection.getPoints().getFirstPoint();
211 _connection.getPoints().getLastPoint();
212 fireAnchorMoved();
213 }
214 }
215
216 @Override
217 public void refresh() {
218 _firstLabel.setText((String)_connectionGroup.getAttributeValue(ConnectionGroup.DOUBLE_CONNECTION_SOURCE_LABEL)
219 .getValue());
220 _secondLabel.setText((String)_connectionGroup.getAttributeValue(ConnectionGroup.DOUBLE_CONNECTION_TARGET_LABEL)
221 .getValue());
222
223 HexColor hexColor = (HexColor)_connectionGroup.getAttributeValue(ConnectionGroup.LINE_COLOR).getValue();
224 this.setForegroundColor(new Color(null, hexColor.getRed(), hexColor.getGreen(), hexColor.getBlue()));
225 _secondPolyline.setForegroundColor(new Color(null, hexColor.getRed(), hexColor.getGreen(), hexColor.getBlue()));
226
227 revalidate();
228 repaint();
229 }
230 }