1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package de.jaret.util.ui.timebars.swt.renderer;
21
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import org.eclipse.swt.SWT;
26 import org.eclipse.swt.graphics.Color;
27 import org.eclipse.swt.graphics.GC;
28 import org.eclipse.swt.graphics.Point;
29 import org.eclipse.swt.graphics.RGB;
30 import org.eclipse.swt.graphics.Rectangle;
31 import org.eclipse.swt.printing.Printer;
32
33 import de.jaret.util.date.Interval;
34 import de.jaret.util.ui.timebars.TimeBarViewerDelegate;
35 import de.jaret.util.ui.timebars.model.IIntervalRelation;
36 import de.jaret.util.ui.timebars.model.IIntervalRelation.Type;
37 import de.jaret.util.ui.timebars.model.IRelationalInterval;
38 import de.jaret.util.ui.timebars.model.TimeBarRow;
39
40
41
42
43
44
45
46
47 public class RelationRenderer extends RendererBase implements IRelationRenderer {
48
49 private static final int DEFAULT_CACHE_SIZE = 200;
50
51
52 private static final RGB DEFAULT_LINE_COLOR = new RGB(0, 0, 0);
53
54 private static final RGB DEFAULT_SELECTED_COLOR = new RGB(0, 0, 255);
55
56 private static final int DEFAULT_LINE_WIDTH = 1;
57
58 private static final int DEFAULT_ARROW_SIZE = 5;
59
60
61 private List<Line> _cache;
62
63 protected Color _lineColor;
64
65 protected Color _selectedColor;
66
67
68 protected int _lineWidth = DEFAULT_LINE_WIDTH;
69
70 protected int _arrowSize = DEFAULT_ARROW_SIZE;
71
72
73
74
75
76
77
78 public RelationRenderer(Printer printer) {
79 super(printer);
80 }
81
82
83
84
85 public RelationRenderer() {
86 super(null);
87 }
88
89
90
91
92
93
94
95 private void initColors(GC gc) {
96 if (_lineColor == null) {
97 _lineColor = new Color(gc.getDevice(), DEFAULT_LINE_COLOR);
98 _selectedColor = new Color(gc.getDevice(), DEFAULT_SELECTED_COLOR);
99 }
100 }
101
102
103
104
105 public void renderRelations(TimeBarViewerDelegate delegate, GC gc,
106 boolean printing) {
107
108 if (_lineColor == null) {
109 initColors(gc);
110 }
111 _cache = new ArrayList<Line>(DEFAULT_CACHE_SIZE);
112
113 int firstRow = delegate.getFirstRow();
114
115
116 Rectangle clipSave = gc.getClipping();
117 Rectangle nc = new Rectangle(delegate.getDiagramRect().x, delegate
118 .getDiagramRect().y, delegate.getDiagramRect().width, delegate
119 .getDiagramRect().height);
120 gc.setClipping(gc.getClipping().intersection(nc));
121
122 int upperYBound = delegate.getDiagramRect().y;
123 int lowerYBound = upperYBound + delegate.getDiagramRect().height;
124
125
126
127
128
129
130 int rowsDisplayed = delegate.getRowsDisplayed();
131 for (int r = firstRow; r <= firstRow + rowsDisplayed + 1
132 && r < delegate.getRowCount(); r++) {
133 TimeBarRow row = delegate.getRow(r);
134 int y = delegate.yForRow(row);
135 int rowHeight = delegate.getTimeBarViewState().getRowHeight(row);
136 if (y == -1) {
137
138 break;
139 }
140
141
142
143
144
145 if ((y >= upperYBound && y <= lowerYBound)
146 || (y + rowHeight >= upperYBound && y + rowHeight <= lowerYBound)
147 || (upperYBound > y && upperYBound < y + rowHeight)) {
148 drawRow(delegate, gc, delegate.getRow(r), y, printing);
149 }
150 }
151 gc.setClipping(clipSave);
152
153 }
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169 private void drawRow(TimeBarViewerDelegate delegate, GC gc, TimeBarRow row,
170 int y, boolean printing) {
171 for (Interval interval : row.getIntervals()) {
172
173 if (delegate.getIntervalFilter() == null
174 || delegate.getIntervalFilter().isInResult(interval)) {
175 if (interval instanceof IRelationalInterval) {
176 IRelationalInterval rInterval = (IRelationalInterval) interval;
177 for (IIntervalRelation relation : rInterval.getRelations()) {
178
179
180 if (delegate.getIntervalFilter() == null
181 || (delegate.getIntervalFilter().isInResult(
182 relation.getStartInterval()) && delegate
183 .getIntervalFilter().isInResult(
184 relation.getEndInterval()))) {
185 if (!hasBeenDrawn(relation)) {
186 drawDependency(delegate, gc, rInterval, y, row,
187 relation);
188 }
189 }
190 }
191 }
192 }
193 }
194
195 }
196 int limitCoord(int coord) {
197 if (coord<-100) {
198 coord = -100;
199 } else if (coord>15000) {
200 coord = 15000;
201 }
202 return coord;
203 }
204 void limitCoord(int[] coords) {
205 for (int i=0;i<coords.length;i++) {
206 coords[i] = limitCoord(coords[i]);
207 }
208 }
209
210 Rectangle limitCoord(Rectangle rect) {
211 if (rect.x<-100) {
212 rect.width = rect.width+rect.x+100;
213 rect.x= -100;
214 }
215 if (rect.width>15000) {
216 rect.width = 15000;
217 }
218 return rect;
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237 private void drawDependency(TimeBarViewerDelegate delegate, GC gc,
238 IRelationalInterval rInterval, int y, TimeBarRow row,
239 IIntervalRelation relation) {
240 int off = scaleX(_arrowSize + _arrowSize / 2);
241
242 boolean selected = delegate.getSelectionModel().isSelected(relation);
243
244 Color fg = gc.getForeground();
245 int lineWidth = gc.getLineWidth();
246 int linejoin = gc.getLineJoin();
247 gc.setLineJoin(SWT.JOIN_ROUND);
248
249 Color color = null;
250 if (selected) {
251 color = _selectedColor;
252 } else {
253 color = _lineColor;
254 }
255 gc.setForeground(color);
256 gc.setLineWidth(scaleX(_lineWidth));
257
258 IRelationalInterval beginTask;
259 TimeBarRow beginRow;
260 Point begin;
261
262 IRelationalInterval endTask;
263 TimeBarRow endRow;
264 Point end;
265
266 if (relation.getStartInterval().equals(rInterval)) {
267 beginTask = rInterval;
268 beginRow = row;
269
270 endTask = relation.getEndInterval();
271 endRow = getRowForInterval(delegate, endTask);
272 } else {
273 endTask = rInterval;
274 endRow = row;
275
276 beginTask = relation.getStartInterval();
277 beginRow = getRowForInterval(delegate, beginTask);
278 }
279
280 int rheight = delegate.getTimeBarViewState().getRowHeight(beginRow);
281
282 if (relation.getType() == IIntervalRelation.Type.END_BEGIN) {
283 begin = getRightPoint(delegate, beginRow, beginTask);
284 end = getLeftPoint(delegate, endRow, endTask);
285 int ydir = end.y > begin.y ? 1 : -1;
286
287 int[] points = new int[] { begin.x, begin.y, begin.x + off,
288 begin.y, begin.x + off, begin.y + (rheight / 2 * ydir),
289 end.x - off, begin.y + (rheight / 2 * ydir), end.x - off,
290 end.y, end.x, end.y };
291 limitCoord(points);
292 gc.drawPolyline(points);
293
294 gc.setForeground(color);
295 registerLines(relation, points);
296
297 drawArrow(gc, begin, end, color, relation.getDirection(), relation
298 .getType());
299
300 } else if (relation.getType() == IIntervalRelation.Type.BEGIN_BEGIN) {
301 begin = getLeftPoint(delegate, beginRow, beginTask);
302 end = getLeftPoint(delegate, endRow, endTask);
303 int ydir = end.y > begin.y ? 1 : -1;
304
305 int[] points = new int[] { begin.x, begin.y, begin.x - off,
306 begin.y, begin.x - off, begin.y + (rheight / 2 * ydir),
307 end.x - off, begin.y + (rheight / 2 * ydir), end.x - off,
308 end.y, end.x, end.y };
309
310 limitCoord(points);
311 gc.drawPolyline(points);
312 registerLines(relation, points);
313 drawArrow(gc, begin, end, color, relation.getDirection(), relation
314 .getType());
315 } else if (relation.getType() == IIntervalRelation.Type.END_END) {
316 begin = getRightPoint(delegate, beginRow, beginTask);
317 end = getRightPoint(delegate, endRow, endTask);
318 int ydir = end.y > begin.y ? 1 : -1;
319
320 int[] points = new int[] { begin.x, begin.y, begin.x + off,
321 begin.y, begin.x + off, begin.y + (rheight / 2 * ydir),
322 end.x + off, begin.y + (rheight / 2 * ydir), end.x + off,
323 end.y, end.x, end.y };
324 limitCoord(points);
325 gc.drawPolyline(points);
326 registerLines(relation, points);
327 drawArrow(gc, begin, end, color, relation.getDirection(), relation
328 .getType());
329 } else if (relation.getType() == IIntervalRelation.Type.BEGIN_END) {
330 begin = getLeftPoint(delegate, beginRow, beginTask);
331 end = getRightPoint(delegate, endRow, endTask);
332 int ydir = end.y > begin.y ? 1 : -1;
333
334
335 int[] points = new int[] { begin.x, begin.y, begin.x - off,
336 begin.y, begin.x - off, begin.y + (rheight / 2 * ydir),
337 end.x + off, begin.y + (rheight / 2 * ydir), end.x + off,
338 end.y, end.x, end.y };
339 limitCoord(points);
340 gc.drawPolyline(points);
341 registerLines(relation, points);
342 drawArrow(gc, begin, end, color, relation.getDirection(), relation
343 .getType());
344 }
345 gc.setForeground(fg);
346 gc.setLineWidth(lineWidth);
347 gc.setLineJoin(linejoin);
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361
362 private Point getRightPoint(TimeBarViewerDelegate delegate, TimeBarRow row,
363 Interval interval) {
364 java.awt.Rectangle rect = delegate.getIntervalBounds(row, interval);
365 return new Point(rect.x + rect.width, rect.y + rect.height / 2);
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379
380 private Point getLeftPoint(TimeBarViewerDelegate delegate, TimeBarRow row,
381 Interval interval) {
382 java.awt.Rectangle rect = delegate.getIntervalBounds(row, interval);
383 return new Point(rect.x, rect.y + rect.height / 2);
384 }
385
386
387
388
389
390
391
392
393
394
395 private TimeBarRow getRowForInterval(TimeBarViewerDelegate delegate,
396 Interval interval) {
397 return delegate.getModel().getRowForInterval(interval);
398 }
399
400
401
402
403
404
405
406
407 private boolean hasBeenDrawn(IIntervalRelation relation) {
408 if (_cache != null) {
409 for (Line l : _cache) {
410 if (l.relation.equals(relation)) {
411 return true;
412 }
413 }
414 }
415 return false;
416 }
417
418
419
420
421
422
423
424
425
426 private void registerLines(IIntervalRelation relation, int[] coords) {
427 for (int i = 0; i <= coords.length - 4; i += 2) {
428 _cache.add(new Line(relation, coords[i], coords[i + 1],
429 coords[i + 2], coords[i + 3]));
430 }
431 }
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449 private void drawArrow(GC gc, Point begin, Point end, Color color,
450 IIntervalRelation.Direction direction, Type type) {
451
452 if (direction.equals(IIntervalRelation.Direction.BACK)
453 || direction.equals(IIntervalRelation.Direction.BI)) {
454 if (type.equals(Type.END_BEGIN) || type.equals(Type.END_END)) {
455 drawArrow(gc, begin, false, color);
456 } else {
457 drawArrow(gc, begin, true, color);
458 }
459 }
460 if (direction.equals(IIntervalRelation.Direction.FORWARD)
461 || direction.equals(IIntervalRelation.Direction.BI)) {
462 if (type.equals(Type.BEGIN_END) || type.equals(Type.END_END)) {
463 drawArrow(gc, end, false, color);
464 } else {
465 drawArrow(gc, end, true, color);
466 }
467 }
468 }
469
470
471
472
473
474
475
476
477
478
479
480
481
482 private void drawArrow(GC gc, Point p, boolean leftToRight, Color color) {
483 Color bg = gc.getBackground();
484 gc.setBackground(color);
485 int off = scaleX(_arrowSize);
486 int[] points;
487 if (leftToRight) {
488 int[] pts = { p.x, p.y, p.x - off, p.y - off, p.x - off, p.y + off };
489 points = pts;
490 } else {
491 int[] pts = { p.x, p.y, p.x + off, p.y - off, p.x + off, p.y + off };
492 points = pts;
493 }
494 limitCoord(points);
495 gc.fillPolygon(points);
496 gc.setBackground(bg);
497 }
498
499
500
501
502 public List<IIntervalRelation> getRelationsForCoord(int x, int y) {
503 List<IIntervalRelation> result = new ArrayList<IIntervalRelation>(2);
504 if (_cache != null) {
505 for (Line line : _cache) {
506 if (line.hit(x, y, 2)) {
507 result.add(line.relation);
508 }
509 }
510 }
511
512 return result;
513 }
514
515
516
517
518 public String getTooltip(int x, int y) {
519 List<IIntervalRelation> result = getRelationsForCoord(x, y);
520 if (result.size() == 0) {
521 return null;
522 } else {
523 return result.get(0).toString();
524 }
525 }
526
527
528
529
530 public void dispose() {
531 _cache = null;
532 if (_lineColor != null) {
533 _lineColor.dispose();
534 _selectedColor.dispose();
535 }
536 }
537
538
539
540
541 public IRelationRenderer createPrintRenderer(Printer printer) {
542 return new RelationRenderer(printer);
543 }
544
545
546
547
548
549
550
551 public class Line {
552
553 public IIntervalRelation relation;
554
555 public int x1;
556
557 public int y1;
558
559 public int x2;
560
561 public int y2;
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577 public Line(IIntervalRelation relation, int x1, int y1, int x2, int y2) {
578 this.relation = relation;
579 this.x1 = x1;
580 this.y1 = y1;
581 this.x2 = x2;
582 this.y2 = y2;
583 }
584
585
586
587
588
589
590
591
592
593
594
595
596 public boolean hit(int x, int y, int tolerance) {
597 if (x1 == x2) {
598 if (x1 - tolerance <= x && x <= x1 + tolerance) {
599 if ((y1 < y2 && y1 - tolerance <= y && y <= y2 + tolerance)
600 || (y2 < y1 && y2 - tolerance <= y && y <= y1
601 + tolerance)) {
602 return true;
603 }
604 }
605 } else {
606 if (y1 == y2) {
607 if (y1 - tolerance <= y && y <= y1 + tolerance) {
608 if ((x1 < x2 && x1 - tolerance <= x && x <= x2
609 + tolerance)
610 || (x2 < x1 && x2 - tolerance <= x && x <= x1
611 + tolerance)) {
612 return true;
613 }
614 }
615 }
616 }
617 return false;
618 }
619 }
620
621
622
623
624
625
626 public int getLineWidth() {
627 return _lineWidth;
628 }
629
630
631
632
633
634
635
636 public void setLineWidth(int lineWidth) {
637 _lineWidth = lineWidth;
638 }
639
640
641
642
643
644
645 public int getArrowSize() {
646 return _arrowSize;
647 }
648
649
650
651
652
653
654
655 public void setArrowSize(int arrowSize) {
656 _arrowSize = arrowSize;
657 }
658
659 }