001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019:
020: package org.netbeans.modules.bpel.design.model.connections;
021:
022: import java.awt.Color;
023: import java.awt.Graphics2D;
024: import java.awt.RenderingHints;
025: import java.awt.Shape;
026: import java.awt.geom.Ellipse2D;
027: import java.awt.geom.Line2D;
028: import java.util.ArrayList;
029: import java.util.List;
030: import org.netbeans.modules.bpel.design.geometry.FCoords;
031: import org.netbeans.modules.bpel.design.geometry.FPath;
032: import org.netbeans.modules.bpel.design.geometry.FPoint;
033: import org.netbeans.modules.bpel.design.geometry.FShape;
034: import org.netbeans.modules.bpel.design.geometry.FStroke;
035: import org.netbeans.modules.bpel.design.geometry.Triangle;
036: import org.netbeans.modules.bpel.design.model.elements.VisualElement;
037: import org.netbeans.modules.bpel.design.model.patterns.CompositePattern;
038: import org.netbeans.modules.bpel.design.model.patterns.Pattern;
039:
040: public class Connection {
041:
042: private VisualElement source;
043: private VisualElement target;
044:
045: /**
046: * directions can be changed in derived classes
047: */
048: private Direction sourceDirection;
049: private Direction targetDirection;
050:
051: private Pattern pattern;
052:
053: private boolean paintArrow = true;
054: private boolean paintSlash = false;
055: private boolean paintDashed = false;
056: private boolean paintCircle = false;
057: protected FPoint endPoint;
058: protected FPoint startPoint;
059:
060: private float x1 = 0, y1 = 0;
061: private float dx, dy;
062:
063: private final int uid;
064:
065: private boolean needsRedraw = true;
066:
067: private FPath path;
068:
069: public Connection(Pattern pattern) {
070: this .pattern = pattern;
071: uid = uidCounter++;
072: pattern.addConnection(this );
073: }
074:
075: public void setPaintArrow(boolean b) {
076: paintArrow = b;
077: }
078:
079: public void setPaintCircle(boolean b) {
080: paintCircle = b;
081: }
082:
083: public void setPaintSlash(boolean b) {
084: paintSlash = b;
085: }
086:
087: public void setPaintDashed(boolean b) {
088: paintDashed = b;
089: }
090:
091: public boolean isPaintArrow() {
092: return paintArrow;
093: }
094:
095: public boolean isPaintCircle() {
096: return paintCircle;
097: }
098:
099: public boolean isPaintSlash() {
100: return paintSlash;
101: }
102:
103: public boolean isPaintDashed() {
104: return paintDashed;
105: }
106:
107: public FPoint getStartPoint() {
108: return startPoint;
109: }
110:
111: public FPoint getEndPoint() {
112: return endPoint;
113: }
114:
115: public void setStartAndEndPoints(FPoint startPoint, FPoint endPoint) {
116:
117: this .startPoint = startPoint;
118: this .endPoint = endPoint;
119:
120: float newX1 = startPoint.x;
121: float newY1 = startPoint.y;
122: float newX2 = endPoint.x;
123: float newY2 = endPoint.y;
124:
125: float newDX = newX2 - newX1;
126: float newDY = newY2 - newY1;
127:
128: float oldX1 = this .x1;
129: float oldY1 = this .y1;
130:
131: float oldDX = this .dx;
132: float oldDY = this .dy;
133:
134: final float epsilon = 0.33f;
135:
136: if (needsRedraw || newX1 != oldX1 || newY1 != oldY1
137: || newDX != oldDX || newDY != oldDY) {
138: this .x1 = newX1;
139: this .y1 = newY1;
140: this .dx = newDX;
141: this .dy = newDY;
142: update();
143: }
144: }
145:
146: protected double findXStep(double x1, double dx) {
147: return x1 + dx / 2;
148: }
149:
150: protected double findYStep(double y1, double dy) {
151: return y1 + dy / 2.0;
152: }
153:
154: protected void update() {
155: double dx = this .dx;
156: double dy = this .dy;
157:
158: double cx = findXStep(x1, dx) - x1;
159: double cy = findYStep(y1, dy) - y1;
160:
161: FPoint[] points = null;
162:
163: if (sourceDirection == targetDirection) {
164: double t;
165: switch (sourceDirection) {
166: case TOP:
167: t = Math.min(0, dy) - BRACKET_SIZE;
168: points = new FPoint[] { new FPoint(0, 0),
169: new FPoint(0, t), new FPoint(dx, t),
170: new FPoint(dx, dy) };
171: break;
172: case BOTTOM:
173: t = Math.max(0, dy) + BRACKET_SIZE;
174: points = new FPoint[] { new FPoint(0, 0),
175: new FPoint(0, t), new FPoint(dx, t),
176: new FPoint(dx, dy) };
177: break;
178: case LEFT:
179: t = Math.min(0, dx) - BRACKET_SIZE;
180: points = new FPoint[] { new FPoint(0, 0),
181: new FPoint(t, 0), new FPoint(t, dy),
182: new FPoint(dx, dy) };
183: break;
184: case RIGHT:
185: t = Math.max(0, dx) + BRACKET_SIZE;
186: points = new FPoint[] { new FPoint(0, 0),
187: new FPoint(t, 0), new FPoint(t, dy),
188: new FPoint(dx, dy) };
189: break;
190: }
191: } else if (sourceDirection.isVertical()) {
192: if (targetDirection.isVertical()) {
193: // source direction - vertical
194: // target direction - vertical
195: if (dy != 0) {
196: points = new FPoint[] { new FPoint(0, 0),
197: new FPoint(0, cy), new FPoint(dx, cy),
198: new FPoint(dx, dy) };
199: }
200: } else {
201: // source direction - vertical
202: // target direction - horizontal
203: points = new FPoint[] { new FPoint(0, 0),
204: new FPoint(0, dy), new FPoint(dx, dy) };
205: }
206: } else {
207: if (targetDirection.isVertical()) {
208: // source direction - horizontal
209: // target direction - vertical
210: points = new FPoint[] { new FPoint(0, 0),
211: new FPoint(dx, 0), new FPoint(dx, dy) };
212: } else {
213: // source direction - horizontal
214: // target direction - horizontal
215: if (dx != 0) {
216: points = new FPoint[] { new FPoint(0, 0),
217: new FPoint(cx, 0), new FPoint(cx, dy),
218: new FPoint(dx, dy) };
219: }
220: }
221: }
222:
223: if (points != null) {
224: path = new FPath(points).round(2).translate(x1, y1);
225: } else {
226: path = null;
227: }
228:
229: needsRedraw = false;
230: }
231:
232: public void connect(VisualElement source,
233: Direction sourceDirection, VisualElement target,
234: Direction targetDirection) {
235: setSource(source, sourceDirection);
236: setTarget(target, targetDirection);
237: }
238:
239: public void setSource(VisualElement newSource,
240: Direction newSourceDirection) {
241: assert newSource != null;
242:
243: VisualElement oldSource = this .source;
244: Direction oldSourceDirection = this .sourceDirection;
245:
246: if (newSource != oldSource) {
247: if (oldSource != null) {
248: oldSource.removeOutputConnection(this );
249: }
250: newSource.addOutputConnection(this );
251: this .source = newSource;
252: needsRedraw = true;
253: }
254:
255: if (newSourceDirection != oldSourceDirection) {
256: this .sourceDirection = newSourceDirection;
257: needsRedraw = true;
258: }
259: }
260:
261: public void setTarget(VisualElement newTarget,
262: Direction newTargetDirection) {
263: assert newTarget != null;
264:
265: VisualElement oldTarget = this .target;
266: Direction oldTargetDirection = this .targetDirection;
267:
268: if (newTarget != oldTarget) {
269: if (oldTarget != null) {
270: oldTarget.removeInputConnection(this );
271: }
272: newTarget.addInputConnection(this );
273: this .target = newTarget;
274: needsRedraw = true;
275: }
276:
277: if (oldTargetDirection != newTargetDirection) {
278: this .targetDirection = newTargetDirection;
279: needsRedraw = true;
280: }
281: }
282:
283: public Direction getSourceDirection() {
284: return sourceDirection;
285: }
286:
287: public Direction getTargetDirection() {
288: return targetDirection;
289: }
290:
291: public VisualElement getTarget() {
292: return target;
293: }
294:
295: public VisualElement getSource() {
296: return source;
297: }
298:
299: public Pattern getPattern() {
300: return pattern;
301: }
302:
303: public void remove() {
304: if (source != null) {
305: source.removeOutputConnection(this );
306: source = null;
307: }
308:
309: if (target != null) {
310: target.removeInputConnection(this );
311: target = null;
312: }
313:
314: pattern.removeConnection(this );
315: }
316:
317: public String toString() {
318: return "Connection: " + getClass().getName() + ", belongs to "
319: + pattern + ", from " + getSource() + ", to "
320: + getTarget();
321: }
322:
323: public FPath getPath() {
324: return path;
325: }
326:
327: public FPath getSegmentsForPattern(CompositePattern pattern) {
328:
329: Pattern sp = source.getPattern();
330: Pattern tp = target.getPattern();
331:
332: boolean substructFromTarget = false;
333: boolean substructAll = false;
334:
335: List<Pattern> sParents = new ArrayList<Pattern>();
336: for (Pattern p = sp; p != null; p = p.getParent()) {
337: sParents.add(p);
338: }
339:
340: Pattern cp = null; // common pattern
341: for (Pattern p = tp; p != null; p = p.getParent()) {
342: if (p == pattern)
343: substructFromTarget = true;
344:
345: if (sParents.contains(p)) {
346: cp = p;
347: break;
348: }
349: }
350:
351: if (cp == pattern) {
352: substructAll = true;
353: }
354:
355: FPath result = path.intersect(pattern.getBorder().getShape());
356:
357: FShape targetBorder = null;
358: for (Pattern p = tp; (p != cp) && (p != pattern); p = p
359: .getParent()) {
360: if (!(p instanceof CompositePattern))
361: continue;
362: if (((CompositePattern) p).getBorder() == null)
363: continue;
364: targetBorder = ((CompositePattern) p).getBorder()
365: .getShape();
366: }
367:
368: FShape sourceBorder = null;
369: for (Pattern p = sp; (p != cp) && (p != pattern); p = p
370: .getParent()) {
371: if (!(p instanceof CompositePattern))
372: continue;
373: if (((CompositePattern) p).getBorder() == null)
374: continue;
375: sourceBorder = ((CompositePattern) p).getBorder()
376: .getShape();
377: }
378:
379: if (substructAll) {
380: if (sourceBorder != null) {
381: result = result.subtract(sourceBorder);
382: }
383: if (targetBorder != null) {
384: result = result.subtract(targetBorder);
385: }
386: } else if (substructFromTarget) {
387: if (targetBorder != null) {
388: result = result.subtract(targetBorder);
389: }
390: } else {
391: if (sourceBorder != null) {
392: result = result.subtract(sourceBorder);
393: }
394: }
395:
396: return result;
397: }
398:
399: public int getUID() {
400: return uid;
401: }
402:
403: private static int uidCounter = 0;
404:
405: public void paint(Graphics2D g2) {
406: assert (path != null) : "Invalid connection(path is null) found on diagram: "
407: + this ;
408: paintConnection(g2, path, isPaintDashed(), isPaintArrow(),
409: isPaintSlash(), isPaintCircle(), null);
410: }
411:
412: public void paintThumbnail(Graphics2D g2) {
413: assert (path != null) : "Invalid connection(path is null) found on diagram: "
414: + this ;
415: paintConnection(g2, path, false, false, false, false, null);
416: }
417:
418: // Rendering constants
419: public static final Color COLOR = new Color(0xE68B2C);
420: public static final Color CIRCLE_FILL = new Color(0xFFFFFF);
421:
422: public static void paintConnection(Graphics2D g2, FPath path,
423: boolean paintDashed, boolean paintArrow,
424: boolean paintSlash, boolean paintCircle, Color color) {
425: paintConnection(g2, path, paintDashed, paintArrow, paintSlash,
426: paintCircle, 1, color);
427: }
428:
429: public static void paintConnection(Graphics2D g2, FPath path,
430: boolean paintDashed, boolean paintArrow,
431: boolean paintSlash, boolean paintCircle, double width,
432: Color color) {
433: if (path == null)
434: return;
435: if (path.length() <= 0.0f)
436: return;
437:
438: if (color == null) {
439: color = COLOR;
440: }
441:
442: g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
443: RenderingHints.VALUE_STROKE_NORMALIZE);
444:
445: g2.setPaint(color);
446: if (paintDashed) {
447: g2.setStroke(new FStroke(width, 3).createStroke(g2));
448: } else {
449: g2.setStroke(new FStroke(width).createStroke(g2));
450: }
451:
452: g2.draw(path);
453:
454: if (paintDashed) {
455: g2.setStroke(new FStroke(width).createStroke(g2));
456: }
457:
458: if (paintArrow) {
459: FCoords coords = path.coords(1.0);
460: FPoint p1 = coords.getPoint(-4.0, 2.0);
461: FPoint p2 = coords.getPoint(-4.0, -2.0);
462:
463: Shape arrowShape = new Triangle(coords.x, coords.y, p1.x,
464: p1.y, p2.x, p2.y);
465:
466: g2.fill(arrowShape);
467: g2.draw(arrowShape);
468: }
469:
470: if (paintSlash) {
471: FCoords coords = path.coords(0.0);
472: FPoint p1 = coords.getPoint(5.0, -4.0);
473: FPoint p2 = coords.getPoint(11.0, 4.0);
474: g2.draw(new Line2D.Float(p1.x, p1.y, p2.x, p2.y));
475: }
476:
477: if (paintCircle) {
478: FPoint center = path.coords(0.0).getPoint(2.0, 0);
479: Shape s = new Ellipse2D.Double(center.x - 2, center.y - 2,
480: 4, 4);
481: g2.setPaint(CIRCLE_FILL);
482: g2.fill(s);
483: g2.setPaint(color);
484: g2.draw(s);
485: }
486: }
487:
488: public static final float BRACKET_SIZE = 16;
489:
490: private static FStroke SOLID_STROKE = new FStroke(1);
491: private static FStroke DASHED_STROKE = new FStroke(1, 3);
492: }
|