Merge corrected branch 'master'
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / widgets / timegraph / widgets / TimeGraphControl.java
1 /*****************************************************************************
2 * Copyright (c) 2007, 2008 Intel Corporation, 2009, 2010, 2011, 2012 Ericsson.
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 * Intel Corporation - Initial API and implementation
10 * Ruslan A. Scherbakov, Intel - Initial API and implementation
11 * Alvaro Sanchez-Leon - Updated for TMF
12 * Patrick Tasse - Refactoring
13 *
14 *****************************************************************************/
15
16 package org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets;
17
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Vector;
22
23 import org.eclipse.jface.viewers.ISelection;
24 import org.eclipse.jface.viewers.ISelectionChangedListener;
25 import org.eclipse.jface.viewers.ISelectionProvider;
26 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphProvider;
27 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTreeListener;
28 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphTreeExpansionEvent;
29 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;
30 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
31 import org.eclipse.swt.SWT;
32 import org.eclipse.swt.events.ControlEvent;
33 import org.eclipse.swt.events.ControlListener;
34 import org.eclipse.swt.events.FocusEvent;
35 import org.eclipse.swt.events.FocusListener;
36 import org.eclipse.swt.events.KeyEvent;
37 import org.eclipse.swt.events.KeyListener;
38 import org.eclipse.swt.events.MouseEvent;
39 import org.eclipse.swt.events.MouseListener;
40 import org.eclipse.swt.events.MouseMoveListener;
41 import org.eclipse.swt.events.MouseTrackListener;
42 import org.eclipse.swt.events.MouseWheelListener;
43 import org.eclipse.swt.events.PaintEvent;
44 import org.eclipse.swt.events.SelectionEvent;
45 import org.eclipse.swt.events.SelectionListener;
46 import org.eclipse.swt.events.TraverseEvent;
47 import org.eclipse.swt.events.TraverseListener;
48 import org.eclipse.swt.graphics.Cursor;
49 import org.eclipse.swt.graphics.GC;
50 import org.eclipse.swt.graphics.Image;
51 import org.eclipse.swt.graphics.Point;
52 import org.eclipse.swt.graphics.Rectangle;
53 import org.eclipse.swt.widgets.Composite;
54 import org.eclipse.swt.widgets.Event;
55 import org.eclipse.swt.widgets.Listener;
56 import org.eclipse.swt.widgets.ScrollBar;
57
58 public class TimeGraphControl extends TimeGraphBaseControl implements FocusListener, KeyListener, MouseMoveListener, MouseListener, MouseWheelListener, ControlListener, SelectionListener, MouseTrackListener, TraverseListener, ISelectionProvider {
59
60 private static final int DRAG_NONE = 0;
61 private static final int DRAG_TRACE_ITEM = 1;
62 private static final int DRAG_SPLIT_LINE = 2;
63 public static final boolean DEFAULT_DRAW_THREAD_JOIN = true;
64 public static final boolean DEFAULT_DRAW_THREAD_WAIT = true;
65 public static final boolean DEFAULT_DRAW_THREAD_RELEASE = true;
66 public static final int H_SCROLLBAR_MAX = Integer.MAX_VALUE - 1;
67
68 private static final double zoomCoeff = 1.5;
69
70 private ITimeDataProvider _timeProvider;
71 private boolean _isInFocus = false;
72 private boolean _isDragCursor3 = false;
73 private boolean _isWaitCursor = true;
74 private boolean _mouseOverSplitLine = false;
75 private int _itemHeightDefault = 19;
76 private int _itemHeight = _itemHeightDefault;
77 private int _minimumItemWidth = 0;
78 private int _topIndex = 0;
79 private int _dragState = DRAG_NONE;
80 private int _dragX0 = 0;
81 private int _dragX = 0;
82 private int _idealNameSpace = 0;
83 // private double _timeStep = 10000000;
84 private long _time0bak;
85 private long _time1bak;
86 private ITimeGraphProvider fTimeGraphProvider = null;
87 private ItemData _data = null;
88 private List<SelectionListener> _selectionListeners;
89 private List<ISelectionChangedListener> _selectionChangedListeners = new ArrayList<ISelectionChangedListener>();
90 private List<ITimeGraphTreeListener> _treeListeners = new ArrayList<ITimeGraphTreeListener>();
91 private Cursor _dragCursor3;
92 private Cursor _WaitCursor;
93
94 // Vertical formatting formatting for the state control view
95 private boolean _visibleVerticalScroll = true;
96 private int _borderWidth = 0;
97 private int _headerHeight = 0;
98
99 private Listener mouseScrollFilterListener;
100
101 public TimeGraphControl(Composite parent, TimeGraphColorScheme colors) {
102
103 super(parent, colors, SWT.NO_BACKGROUND | SWT.H_SCROLL | SWT.DOUBLE_BUFFERED);
104
105 _data = new ItemData();
106
107 addFocusListener(this);
108 addMouseListener(this);
109 addMouseMoveListener(this);
110 addMouseTrackListener(this);
111 addMouseWheelListener(this);
112 addTraverseListener(this);
113 addKeyListener(this);
114 addControlListener(this);
115 ScrollBar scrollHor = getHorizontalBar();
116
117 if (scrollHor != null) {
118 scrollHor.addSelectionListener(this);
119 }
120
121 _dragCursor3 = new Cursor(super.getDisplay(), SWT.CURSOR_SIZEWE);
122 _WaitCursor = new Cursor(super.getDisplay(), SWT.CURSOR_WAIT);
123 }
124
125 @Override
126 public void dispose() {
127 super.dispose();
128 _dragCursor3.dispose();
129 _WaitCursor.dispose();
130 }
131
132 /**
133 * Sets the timegraph provider used by this timegraph viewer.
134 *
135 * @param timeGraphProvider the timegraph provider
136 */
137 public void setTimeGraphProvider(ITimeGraphProvider timeGraphProvider) {
138 fTimeGraphProvider = timeGraphProvider;
139 fTimeGraphProvider.setTimeGraphControl(this);
140 }
141
142 public void setTimeProvider(ITimeDataProvider timeProvider) {
143 _timeProvider = timeProvider;
144 adjustScrolls();
145 redraw();
146 }
147
148 public void addSelectionListener(SelectionListener listener) {
149 if (listener == null)
150 SWT.error(SWT.ERROR_NULL_ARGUMENT);
151 if (null == _selectionListeners)
152 _selectionListeners = new ArrayList<SelectionListener>();
153 _selectionListeners.add(listener);
154 }
155
156 public void removeSelectionListener(SelectionListener listener) {
157 if (null != _selectionListeners)
158 _selectionListeners.remove(listener);
159 }
160
161 public void fireSelectionChanged() {
162 if (null != _selectionListeners) {
163 Iterator<SelectionListener> it = _selectionListeners.iterator();
164 while (it.hasNext()) {
165 SelectionListener listener = it.next();
166 listener.widgetSelected(null);
167 }
168 }
169 }
170
171 public void fireDefaultSelection() {
172 if (null != _selectionListeners) {
173 Iterator<SelectionListener> it = _selectionListeners.iterator();
174 while (it.hasNext()) {
175 SelectionListener listener = it.next();
176 listener.widgetDefaultSelected(null);
177 }
178 }
179 }
180
181 public Object[] getTraces() {
182 return _data.getTraces();
183 }
184
185 public boolean[] getTraceFilter() {
186 return _data.getTraceFilter();
187 }
188
189 public void refreshData() {
190 _data.refreshData();
191 adjustScrolls();
192 redraw();
193 }
194
195 public void refreshData(ITimeGraphEntry traces[]) {
196 _data.refreshData(traces);
197 adjustScrolls();
198 redraw();
199 }
200
201 public void adjustScrolls() {
202 if (null == _timeProvider) {
203 getHorizontalBar().setValues(0, 1, 1, 1, 1, 1);
204 return;
205 }
206
207 // HORIZONTAL BAR
208 // Visible window
209 long time0 = _timeProvider.getTime0();
210 long time1 = _timeProvider.getTime1();
211 // Time boundaries
212 long timeMin = _timeProvider.getMinTime();
213 long timeMax = _timeProvider.getMaxTime();
214
215 long delta = timeMax - timeMin;
216
217 int timePos = 0;
218 int thumb = H_SCROLLBAR_MAX;
219
220 if (delta != 0) {
221 // Thumb size (page size)
222 thumb = Math.max(1, (int) (H_SCROLLBAR_MAX * ((double) (time1 - time0) / delta)));
223 // At the beginning of visible window
224 timePos = (int) (H_SCROLLBAR_MAX * ((double) (time0 - timeMin) / delta));
225 }
226
227 // position, minimum, maximum, thumb size, increment (half page)t, page
228 // increment size (full page)
229 getHorizontalBar().setValues(timePos, 0, H_SCROLLBAR_MAX, thumb, Math.max(1, thumb / 2), Math.max(2, thumb));
230 }
231
232 boolean ensureVisibleItem(int idx, boolean redraw) {
233 boolean changed = false;
234 if (idx < 0) {
235 for (idx = 0; idx < _data._expandedItems.length; idx++) {
236 if (((TimeGraphItem) _data._expandedItems[idx])._selected)
237 break;
238 }
239 }
240 if (idx >= _data._expandedItems.length)
241 return changed;
242 if (idx < _topIndex) {
243 _topIndex = idx;
244 //FIXME:getVerticalBar().setSelection(_topItem);
245 if (redraw)
246 redraw();
247 changed = true;
248 } else {
249 int page = countPerPage();
250 if (idx >= _topIndex + page) {
251 _topIndex = idx - page + 1;
252 //FIXME:getVerticalBar().setSelection(_topItem);
253 if (redraw)
254 redraw();
255 changed = true;
256 }
257 }
258 return changed;
259 }
260
261 public void setTopIndex(int idx) {
262 idx = Math.min(idx, _data._expandedItems.length - countPerPage());
263 idx = Math.max(0, idx);
264 _topIndex = idx;
265 redraw();
266 }
267
268 public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
269 TimeGraphItem item = _data.findItem(entry);
270 if (item != null && item._expanded != expanded) {
271 item._expanded = expanded;
272 _data.updateExpandedItems();
273 redraw();
274 }
275 }
276
277 public void addTreeListener (ITimeGraphTreeListener listener) {
278 if (!_treeListeners.contains(listener)) {
279 _treeListeners.add(listener);
280 }
281 }
282
283 public void removeTreeListener (ITimeGraphTreeListener listener) {
284 if (_treeListeners.contains(listener)) {
285 _treeListeners.remove(listener);
286 }
287 }
288
289 public void fireTreeEvent(ITimeGraphEntry entry, boolean expanded) {
290 TimeGraphTreeExpansionEvent event = new TimeGraphTreeExpansionEvent(this, entry);
291 for (ITimeGraphTreeListener listener : _treeListeners) {
292 if (expanded) {
293 listener.treeExpanded(event);
294 } else {
295 listener.treeCollapsed(event);
296 }
297 }
298 }
299
300 @Override
301 public ISelection getSelection() {
302 TimeGraphSelection sel = new TimeGraphSelection();
303 ITimeGraphEntry trace = getSelectedTrace();
304 if (null != trace && null != _timeProvider) {
305 long selectedTime = _timeProvider.getSelectedTime();
306 ITimeEvent event = Utils.findEvent(trace, selectedTime, 0);
307 if (event != null)
308 sel.add(event);
309 else
310 sel.add(trace);
311 }
312 return sel;
313 }
314
315 public ISelection getSelectionTrace() {
316 TimeGraphSelection sel = new TimeGraphSelection();
317 ITimeGraphEntry trace = getSelectedTrace();
318 if (null != trace) {
319 sel.add(trace);
320 }
321 return sel;
322 }
323
324 public void selectTrace(int n) {
325 if (n != 1 && n != -1)
326 return;
327 boolean changed = false;
328 int lastSelection = -1;
329 for (int i = 0; i < _data._expandedItems.length; i++) {
330 TimeGraphItem item = (TimeGraphItem) _data._expandedItems[i];
331 if (item._selected) {
332 lastSelection = i;
333 if (1 == n && i < _data._expandedItems.length - 1) {
334 item._selected = false;
335 if (item._hasChildren) {
336 _data.expandItem(i);
337 fireTreeEvent(item._trace, item._expanded);
338 }
339 item = (TimeGraphItem) _data._expandedItems[i + 1];
340 if (item._hasChildren) {
341 _data.expandItem(i + 1);
342 fireTreeEvent(item._trace, item._expanded);
343 item = (TimeGraphItem) _data._expandedItems[i + 2];
344 }
345 item._selected = true;
346 changed = true;
347 } else if (-1 == n && i > 0) {
348 i--;
349 TimeGraphItem prevItem = (TimeGraphItem) _data._expandedItems[i];
350 if (prevItem._hasChildren) {
351 if (prevItem._expanded) {
352 if (i > 0) {
353 i--;
354 prevItem = (TimeGraphItem) _data._expandedItems[i];
355 }
356 }
357 if (!prevItem._expanded) {
358 _data.expandItem(i);
359 fireTreeEvent(prevItem._trace, prevItem._expanded);
360 prevItem = (TimeGraphItem) _data._expandedItems[i + prevItem.children.size()];
361 item._selected = false;
362 prevItem._selected = true;
363 changed = true;
364 }
365 } else {
366 item._selected = false;
367 prevItem._selected = true;
368 changed = true;
369 }
370 }
371 break;
372 }
373 }
374 if (lastSelection < 0 && _data._expandedItems.length > 0) {
375 TimeGraphItem item = (TimeGraphItem) _data._expandedItems[0];
376 if (item._hasChildren) {
377 _data.expandItem(0);
378 fireTreeEvent(item._trace, item._expanded);
379 item = (TimeGraphItem) _data._expandedItems[1];
380 item._selected = true;
381 changed = true;
382 } else {
383 item._selected = true;
384 changed = true;
385 }
386 }
387 if (changed) {
388 ensureVisibleItem(-1, false);
389 redraw();
390 fireSelectionChanged();
391 }
392 }
393
394 public void selectEvent(int n) {
395 if (null == _timeProvider)
396 return;
397 ITimeGraphEntry trace = getSelectedTrace();
398 if (trace == null)
399 return;
400 long selectedTime = _timeProvider.getSelectedTime();
401 long endTime = _timeProvider.getEndTime();
402 ITimeEvent nextEvent;
403 if (-1 == n && selectedTime > endTime)
404 nextEvent = Utils.findEvent(trace, selectedTime, 0);
405 else
406 nextEvent = Utils.findEvent(trace, selectedTime, n);
407 if (null == nextEvent && -1 == n)
408 nextEvent = Utils.getFirstEvent(trace);
409 if (null != nextEvent) {
410 long nextTime = nextEvent.getTime();
411 // If last event detected e.g. going back or not moving to a next
412 // event
413 if (nextTime <= selectedTime && n == 1) {
414 // Select to the end of this last event
415 nextTime = nextEvent.getTime() + nextEvent.getDuration();
416 // but not beyond the end of the trace
417 if (nextTime > endTime) {
418 nextTime = endTime;
419 }
420 }
421 _timeProvider.setSelectedTimeInt(nextTime, true);
422 fireSelectionChanged();
423 } else if (1 == n) {
424 _timeProvider.setSelectedTimeInt(endTime, true);
425 fireSelectionChanged();
426 }
427 }
428
429 public void selectNextEvent() {
430 selectEvent(1);
431 // Notify if visible time window has been adjusted
432 _timeProvider.setStartFinishTimeNotify(_timeProvider.getTime0(), _timeProvider.getTime1());
433 }
434
435 public void selectPrevEvent() {
436 selectEvent(-1);
437 // Notify if visible time window has been adjusted
438 _timeProvider.setStartFinishTimeNotify(_timeProvider.getTime0(), _timeProvider.getTime1());
439 }
440
441 public void selectNextTrace() {
442 selectTrace(1);
443 }
444
445 public void selectPrevTrace() {
446 selectTrace(-1);
447 }
448
449 /**
450 * Zooming based on mouse cursor location with mouse scrolling
451 *
452 * @param zoomIn
453 */
454 public void zoom(boolean zoomIn) {
455 int globalX = getDisplay().getCursorLocation().x;
456 Point p = toControl(globalX, 0);
457 int nameSpace = _timeProvider.getNameSpace();
458 int timeSpace = _timeProvider.getTimeSpace();
459 int xPos = Math.max(nameSpace, Math.min(nameSpace + timeSpace, p.x));
460 long time0 = _timeProvider.getTime0();
461 long time1 = _timeProvider.getTime1();
462 long interval = time1 - time0;
463 if (interval == 0) {
464 interval = 1;
465 } // to allow getting out of single point interval
466 long newInterval;
467 if (zoomIn) {
468 newInterval = Math.max(Math.round((double) interval * 0.8), _timeProvider.getMinTimeInterval());
469 } else {
470 newInterval = (long) Math.ceil((double) interval * 1.25);
471 }
472 long center = time0 + Math.round(((double) (xPos - nameSpace) / timeSpace * interval));
473 long newTime0 = center - Math.round((double) newInterval * (center - time0) / interval);
474 long newTime1 = newTime0 + newInterval;
475 _timeProvider.setStartFinishTime(newTime0, newTime1);
476 }
477
478 /**
479 * zoom in using single click
480 */
481 public void zoomIn() {
482 long _time0 = _timeProvider.getTime0();
483 long _time1 = _timeProvider.getTime1();
484 long _range = _time1 - _time0;
485 long selTime = _timeProvider.getSelectedTime();
486 if (selTime <= _time0 || selTime >= _time1) {
487 selTime = (_time0 + _time1) / 2;
488 }
489 long time0 = selTime - (long) ((selTime - _time0) / zoomCoeff);
490 long time1 = selTime + (long) ((_time1 - selTime) / zoomCoeff);
491
492 long inaccuracy = (_timeProvider.getMaxTime() - _timeProvider.getMinTime()) - (time1 - time0);
493
494 // Trace.debug("selTime:" + selTime + " time0:" + time0 + " time1:"
495 // + time1 + " inaccuracy:" + inaccuracy);
496
497 if (inaccuracy > 0 && inaccuracy < 100) {
498 _timeProvider.setStartFinishTimeNotify(_timeProvider.getMinTime(), _timeProvider.getMaxTime());
499 return;
500 }
501
502 long m = _timeProvider.getMinTimeInterval();
503 if ((time1 - time0) < m) {
504 time0 = selTime - (long) ((selTime - _time0) * m / _range);
505 time1 = time0 + m;
506 }
507
508 _timeProvider.setStartFinishTimeNotify(time0, time1);
509 }
510
511 /**
512 * zoom out using single click
513 */
514 public void zoomOut() {
515 long _time0 = _timeProvider.getTime0();
516 long _time1 = _timeProvider.getTime1();
517 long selTime = _timeProvider.getSelectedTime();
518 if (selTime <= _time0 || selTime >= _time1) {
519 selTime = (_time0 + _time1) / 2;
520 }
521 long time0 = (long) (selTime - (selTime - _time0) * zoomCoeff);
522 long time1 = (long) (selTime + (_time1 - selTime) * zoomCoeff);
523
524 long inaccuracy = (_timeProvider.getMaxTime() - _timeProvider.getMinTime()) - (time1 - time0);
525 if (inaccuracy > 0 && inaccuracy < 100) {
526 _timeProvider.setStartFinishTimeNotify(_timeProvider.getMinTime(), _timeProvider.getMaxTime());
527 return;
528 }
529
530 _timeProvider.setStartFinishTimeNotify(time0, time1);
531 }
532
533 public ITimeGraphEntry getSelectedTrace() {
534 ITimeGraphEntry trace = null;
535 int idx = getSelectedIndex();
536 if (idx >= 0)
537 trace = _data._expandedItems[idx]._trace;
538 return trace;
539 }
540
541 public int getSelectedIndex() {
542 int idx = -1;
543 for (int i = 0; i < _data._expandedItems.length; i++) {
544 TimeGraphItem item = (TimeGraphItem) _data._expandedItems[i];
545 if (item._selected) {
546 idx = i;
547 break;
548 }
549 }
550 return idx;
551 }
552
553 boolean toggle(int idx) {
554 boolean toggled = false;
555 if (idx >= 0 && idx < _data._expandedItems.length) {
556 TimeGraphItem item = (TimeGraphItem) _data._expandedItems[idx];
557 if (item._hasChildren) {
558 item._expanded = !item._expanded;
559 _data.updateExpandedItems();
560 adjustScrolls();
561 redraw();
562 toggled = true;
563 fireTreeEvent(item._trace, item._expanded);
564 }
565 }
566 return toggled;
567 }
568
569 int getItemIndexAtY(int y) {
570 if (y < 0) {
571 return -1;
572 }
573 int idx = y / _itemHeight;
574 idx += _topIndex;
575 if (idx < _data._expandedItems.length) {
576 return idx;
577 }
578 return -1;
579 }
580
581 boolean isOverSplitLine(int x) {
582 if (x < 0 || null == _timeProvider)
583 return false;
584 int w = 4;
585 int nameWidth = _timeProvider.getNameSpace();
586 if (x > nameWidth - w && x < nameWidth + w) {
587 return true;
588 } else {
589 return false;
590 }
591 }
592
593 TimeGraphItem getItem(Point pt) {
594 int idx = getItemIndexAtY(pt.y);
595 return idx >= 0 ? (TimeGraphItem) _data._expandedItems[idx] : null;
596 }
597
598 long getTimeAtX(int x) {
599 if (null == _timeProvider)
600 return -1;
601 long hitTime = -1;
602 Point size = getCtrlSize();
603 long time0 = _timeProvider.getTime0();
604 long time1 = _timeProvider.getTime1();
605 int nameWidth = _timeProvider.getNameSpace();
606 x -= nameWidth;
607 if (x >= 0 && size.x >= nameWidth) {
608 if (time1 - time0 > size.x - nameWidth - RIGHT_MARGIN) {
609 // get the last possible time represented by the pixel position
610 // by taking the time of the next pixel position minus 1
611 // nanosecond
612 hitTime = time0 + (long) ((time1 - time0) * ((double) (x + 1) / (size.x - nameWidth - RIGHT_MARGIN))) - 1;
613 } else {
614 hitTime = time0 + (long) ((time1 - time0) * ((double) (x) / (size.x - nameWidth - RIGHT_MARGIN)));
615 }
616 }
617 return hitTime;
618 }
619
620 void selectItem(int idx, boolean addSelection) {
621 boolean changed = false;
622 if (addSelection) {
623 if (idx >= 0 && idx < _data._expandedItems.length) {
624 TimeGraphItem item = (TimeGraphItem) _data._expandedItems[idx];
625 changed = (item._selected == false);
626 item._selected = true;
627 }
628 } else {
629 for (int i = 0; i < _data._expandedItems.length; i++) {
630 TimeGraphItem item = (TimeGraphItem) _data._expandedItems[i];
631 if ((i == idx && !item._selected) || (idx == -1 && item._selected)) {
632 changed = true;
633 }
634 item._selected = i == idx;
635 }
636 }
637 changed |= ensureVisibleItem(idx, true);
638 if (changed)
639 redraw();
640 }
641
642 public void selectItem(ITimeGraphEntry trace, boolean addSelection) {
643 int idx = _data.findItemIndex(trace);
644 selectItem(idx, addSelection);
645 }
646
647 public int countPerPage() {
648 int height = getCtrlSize().y;
649 int count = 0;
650 if (height > 0)
651 count = height / _itemHeight;
652 return count;
653 }
654
655 public int getTopIndex() {
656 return _topIndex;
657 }
658
659 public int getExpandedElementCount() {
660 return _data._expandedItems.length;
661 }
662
663 Point getCtrlSize() {
664 Point size = getSize();
665 if (getHorizontalBar().isVisible()) {
666 size.y -= getHorizontalBar().getSize().y;
667 }
668 return size;
669 }
670
671 Rectangle getNameRect(Rectangle bound, int idx, int nameWidth) {
672 idx -= _topIndex;
673 int x = bound.x;
674 int y = bound.y + idx * _itemHeight;
675 int width = nameWidth;
676 int height = _itemHeight;
677 return new Rectangle(x, y, width, height);
678 }
679
680 Rectangle getStatesRect(Rectangle bound, int idx, int nameWidth) {
681 idx -= _topIndex;
682 int x = bound.x + nameWidth;
683 int y = bound.y + idx * _itemHeight;
684 int width = bound.width - x;
685 int height = _itemHeight;
686 return new Rectangle(x, y, width, height);
687 }
688
689 public void drawTraceEvent(Rectangle bound, ITimeEvent e, int nItem, int color, GC gc) {
690 int nameWidth = _timeProvider.getNameSpace();
691
692 long time0 = _timeProvider.getTime0();
693 long time1 = _timeProvider.getTime1();
694 if (time0 == time1)
695 return;
696
697 int xr = bound.x + nameWidth;
698 double pixelsPerNanoSec = (bound.width - xr <= RIGHT_MARGIN) ? 0 : (double) (bound.width - xr - RIGHT_MARGIN) / (time1 - time0);
699
700 int x0 = xr + (int) ((e.getTime() - time0) * pixelsPerNanoSec);
701 if (x0 < xr)
702 return;
703
704 int y0 = bound.y + (nItem - _topIndex) * _itemHeight + 3;
705
706 gc.setBackground(_colors.getColor(color));
707 int c[] = { x0 - 3, y0 - 3, x0, y0, x0 + 3, y0 - 3 };
708 gc.fillPolygon(c);
709 }
710
711 @Override
712 void paint(Rectangle bounds, PaintEvent e) {
713 GC gc = e.gc;
714 gc.setBackground(_colors.getColor(TimeGraphColorScheme.BACKGROUND));
715 drawBackground(gc, bounds.x, bounds.y, bounds.width, bounds.height);
716
717 if (bounds.width < 2 || bounds.height < 2 || null == _timeProvider)
718 return;
719
720 _idealNameSpace = 0;
721 int nameSpace = _timeProvider.getNameSpace();
722
723 // draw empty name space background
724 int nbDrawn = _data._expandedItems.length - _topIndex;
725 if (_itemHeight * nbDrawn < bounds.height) {
726 gc.setBackground(_colors.getBkColor(false, false, true));
727 drawBackground(gc, bounds.x, _itemHeight * nbDrawn, nameSpace, bounds.height - _itemHeight * nbDrawn);
728 }
729
730 fTimeGraphProvider.drawItems(bounds, _timeProvider, _data._expandedItems, _topIndex, nameSpace, gc);
731
732 // draw selected time
733 long time0 = _timeProvider.getTime0();
734 long time1 = _timeProvider.getTime1();
735 long selectedTime = _timeProvider.getSelectedTime();
736 double pixelsPerNanoSec = (bounds.width - nameSpace <= RIGHT_MARGIN) ? 0 : (double) (bounds.width - nameSpace - RIGHT_MARGIN) / (time1 - time0);
737 int x = bounds.x + nameSpace + (int) ((double) (selectedTime - time0) * pixelsPerNanoSec);
738 if (x >= nameSpace && x < bounds.x + bounds.width) {
739 gc.setForeground(_colors.getColor(TimeGraphColorScheme.SELECTED_TIME));
740 gc.drawLine(x, bounds.y, x, bounds.y + bounds.height);
741 }
742
743 // draw drag line, no line if name space is 0.
744 if (DRAG_SPLIT_LINE == _dragState) {
745 gc.setForeground(_colors.getColor(TimeGraphColorScheme.BLACK));
746 gc.drawLine(bounds.x + nameSpace, bounds.y, bounds.x + nameSpace, bounds.y + bounds.height - 1);
747 } else if (DRAG_NONE == _dragState && _mouseOverSplitLine && _timeProvider.getNameSpace() > 0) {
748 gc.setForeground(_colors.getColor(TimeGraphColorScheme.RED));
749 gc.drawLine(bounds.x + nameSpace, bounds.y, bounds.x + nameSpace, bounds.y + bounds.height - 1);
750 }
751 }
752
753 public void drawItems(Rectangle bounds, ITimeDataProvider timeProvider, TimeGraphItem[] items, int topIndex, int nameSpace, GC gc) {
754 // draw trace states
755 for (int i = topIndex; i < items.length; i++) {
756 TimeGraphItem item = (TimeGraphItem) items[i];
757 fTimeGraphProvider.drawItem(item, bounds, timeProvider, i, nameSpace, gc);
758 }
759 }
760
761 /**
762 * Draws the item
763 *
764 * @param item the item to draw
765 * @param bounds the container rectangle
766 * @param i the item index
767 * @param nameSpace the name space
768 * @param gc
769 */
770 public void drawItem(TimeGraphItem item, Rectangle bounds, ITimeDataProvider timeProvider, int i, int nameSpace, GC gc) {
771 long time0 = timeProvider.getTime0();
772 long time1 = timeProvider.getTime1();
773 long endTime = timeProvider.getEndTime();
774 long selectedTime = timeProvider.getSelectedTime();
775
776 Rectangle nameRect = getNameRect(bounds, i, nameSpace);
777 if (nameRect.y >= bounds.y + bounds.height) {
778 return;
779 }
780
781 if (item._trace.getTimeEventsIterator() == null) {
782 Rectangle statesRect = getStatesRect(bounds, i, nameSpace);
783 nameRect.width += statesRect.width;
784 drawName(item, nameRect, gc);
785 } else {
786 drawName(item, nameRect, gc);
787 }
788 Rectangle rect = getStatesRect(bounds, i, nameSpace);
789 if (rect.isEmpty())
790 return;
791 if (time1 <= time0) {
792 gc.setBackground(_colors.getBkColor(false, false, false));
793 gc.fillRectangle(rect);
794 return;
795 }
796
797 // Initialize _rect1 to same values as enclosing rectangle rect
798 Rectangle stateRect = Utils.clone(rect);
799 boolean selected = item._selected;
800 // K pixels per second
801 double pixelsPerNanoSec = (rect.width <= RIGHT_MARGIN) ? 0 : (double) (rect.width - RIGHT_MARGIN) / (time1 - time0);
802
803 boolean group = item._trace.getTimeEventsIterator() == null;
804
805 if (group) {
806 // gc.setBackground(_colors.getBkColorGroup(selected, _isInFocus));
807 // gc.fillRectangle(rect);
808 } else {
809 ITimeGraphEntry trace = item._trace;
810
811 double x0 = rect.x;
812 long maxDuration = (timeProvider.getTimeSpace() == 0) ? Long.MAX_VALUE : 1 * (time1 - time0) / timeProvider.getTimeSpace();
813 Iterator<ITimeEvent> iterator = trace.getTimeEventsIterator(time0, time1, maxDuration);
814 // Drawing rectangle is smaller than reserved space
815 stateRect.y += 3;
816 stateRect.height -= 6;
817
818 // Clean up to empty line to draw on top
819 int xEnd = rect.x + rect.width;
820 fillSpace(rect, gc, selected);
821 if (iterator.hasNext()) {
822 ITimeEvent currEvent = iterator.next();
823 ITimeEvent nextEvent = null;
824 long currEventTime = currEvent.getTime();
825 long currEventDuration = currEvent.getDuration();
826 // initial value
827 long nextEventTime = currEventTime;
828 // x0 - Points to the beginning of the event being drawn
829 double step = (double) ((currEventTime - time0) * pixelsPerNanoSec);
830 x0 = rect.x + step;
831 // xEnd - Points to the end of the events rectangle
832 double x1 = -1;
833 double xNext = 0;
834
835 // draw event states
836 while (/* x0 <= xEnd && */null != currEvent) {
837 boolean stopped = false;// currEvent instanceof
838 // refresh current event duration as the loop moves
839 currEventDuration = currEvent.getDuration();
840 // TsfTmTraceDeadEvent;
841 if (iterator.hasNext()) {
842 nextEvent = iterator.next();
843 nextEventTime = nextEvent.getTime();
844 } else if (stopped) {
845 nextEvent = null;
846 nextEventTime = time1;
847 } else {
848 nextEvent = null;
849 nextEventTime = endTime;
850 }
851
852 // Calculate position to next event
853 xNext = rect.x + (double) ((nextEventTime - time0) * pixelsPerNanoSec);
854
855 // Calculate end position of current event
856 if (currEventDuration < 0) {
857 x1 = rect.x + (double) ((nextEventTime - time0) * pixelsPerNanoSec);
858 } else if (currEventDuration == 0) {
859 x1 = x0;
860 } else {
861 x1 = x0 + (double) ((currEventDuration) * pixelsPerNanoSec);
862 }
863
864 // If event end position x1 further away than start position
865 // of next event, cut width till next event
866 if (currEventDuration != 0) {
867 x1 = x1 > xNext ? xNext : x1;
868 }
869 // if event end boundary is within time range
870 if (x1 >= rect.x && x0 <= xEnd) {
871 if (currEventDuration != 0) {
872 x0 = (double) (x0 >= rect.x ? x0 : rect.x);
873 stateRect.width = (int) ((x1 <= xEnd ? x1 : xEnd) - x0);
874 } else {
875 stateRect.width = 1;
876 }
877 stateRect.width = Math.max(getMinimumItemWidth(), stateRect.width);
878 stateRect.x = (int) x0;
879 boolean timeSelected = currEventTime <= selectedTime && selectedTime < nextEventTime;
880 fTimeGraphProvider.drawState(_colors, currEvent, stateRect, gc, selected, false, timeSelected);
881 // Advance rectangle to next start position and Fill
882 // with space until next event
883 stateRect.x += stateRect.width;
884 x0 = stateRect.x;
885 }
886
887 // lastEvent = currEvent;
888 currEvent = nextEvent;
889 currEventTime = nextEventTime;
890 // Move x0 to the beginning of next event
891 x0 = rect.x + (double) ((nextEventTime - time0) * pixelsPerNanoSec);
892 }
893 }
894 }
895 }
896
897 void drawName(TimeGraphItem item, Rectangle bounds, GC gc) {
898 boolean group = item._trace.getTimeEventsIterator() == null;
899 if (group) {
900 gc.setBackground(_colors.getBkColorGroup(item._selected, _isInFocus));
901 gc.fillRectangle(bounds);
902 if (item._selected && _isInFocus) {
903 gc.setForeground(_colors.getBkColor(item._selected, _isInFocus, false));
904 gc.drawRectangle(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1);
905 }
906 } else {
907 gc.setBackground(_colors.getBkColor(item._selected, _isInFocus, true));
908 gc.setForeground(_colors.getFgColor(item._selected, _isInFocus));
909 gc.fillRectangle(bounds);
910 }
911
912 // No name to be drawn
913 if (_timeProvider.getNameSpace() == 0) {
914 return;
915 }
916
917 int leftMargin = MARGIN + item.level * EXPAND_SIZE;
918 if (item._hasChildren) {
919 gc.setForeground(_colors.getFgColorGroup(false, false));
920 gc.setBackground(_colors.getBkColor(false, false, false));
921 Rectangle rect = Utils.clone(bounds);
922 rect.x += leftMargin;
923 rect.y += (bounds.height - EXPAND_SIZE) / 2;
924 rect.width = EXPAND_SIZE;
925 rect.height = EXPAND_SIZE;
926 gc.fillRectangle(rect);
927 gc.drawRectangle(rect.x, rect.y, rect.width - 1, rect.height - 1);
928 int midy = rect.y + rect.height / 2;
929 gc.drawLine(rect.x + 2, midy, rect.x + rect.width - 3, midy);
930 if (!item._expanded) {
931 int midx = rect.x + rect.width / 2;
932 gc.drawLine(midx, rect.y + 2, midx, rect.y + rect.height - 3);
933 }
934 }
935 leftMargin += EXPAND_SIZE + MARGIN;
936
937 Image img = fTimeGraphProvider.getItemImage(item._trace);
938 if (img != null) {
939 // draw icon
940 int imgHeight = img.getImageData().height;
941 int imgWidth = img.getImageData().width;
942 int x = leftMargin;
943 int y = bounds.y + (bounds.height - imgHeight) / 2;
944 gc.drawImage(img, x, y);
945 leftMargin += imgWidth + MARGIN;
946 }
947 String name = item._name;
948 Point size = gc.stringExtent(name);
949 if (_idealNameSpace < leftMargin + size.x + MARGIN) {
950 _idealNameSpace = leftMargin + size.x + MARGIN;
951 }
952 if (!group) {
953 // cut long string with "..."
954 int width = bounds.width - leftMargin;
955 int cuts = 0;
956 while (size.x > width && name.length() > 1) {
957 cuts++;
958 name = name.substring(0, name.length() - 1);
959 size = gc.stringExtent(name + "..."); //$NON-NLS-1$
960 }
961 if (cuts > 0) {
962 name += "..."; //$NON-NLS-1$
963 }
964 }
965 Rectangle rect = Utils.clone(bounds);
966 rect.x += leftMargin;
967 rect.width -= leftMargin;
968 // draw text
969 if (rect.width > 0) {
970 rect.y += 2;
971 int textWidth = Utils.drawText(gc, name, rect, true);
972 leftMargin += textWidth + MARGIN;
973 rect.y -= 2;
974
975 if (!group) {
976 // draw middle line
977 int x = bounds.x + leftMargin;
978 int width = bounds.width - x;
979 int midy = bounds.y + bounds.height / 2;
980 gc.setForeground(_colors.getColor(TimeGraphColorScheme.MID_LINE));
981 gc.drawLine(x, midy, x + width, midy);
982 }
983 }
984 }
985
986 public void drawState(TimeGraphColorScheme colors, int colorIdx,
987 Rectangle rect, GC gc, boolean selected, boolean rectBound,
988 boolean timeSelected) {
989
990 boolean visible = rect.width == 0 ? false : true;
991 int colorIdx1 = colorIdx;
992
993 timeSelected = timeSelected && selected;
994 if (timeSelected) {
995 colorIdx1 = colorIdx + TimeGraphColorScheme.STATES_SEL0 - TimeGraphColorScheme.STATES0;
996 }
997
998 if (visible) {
999 // fill all rect area
1000 if (rect.isEmpty())
1001 return;
1002
1003 gc.setBackground(colors.getColor(colorIdx1));
1004 gc.fillRectangle(rect);
1005 colorIdx1 = colorIdx + TimeGraphColorScheme.STATES_BORDER0 - TimeGraphColorScheme.STATES0;
1006 gc.setForeground(colors.getColor(colorIdx1));
1007
1008 // draw bounds
1009 if (!timeSelected) {
1010 if (rectBound && rect.width >= 3) {
1011 gc.drawRectangle(rect.x, rect.y, rect.width - 1, rect.height - 1);
1012 } else {
1013 // Draw the top and bottom borders i.e. no side borders
1014 // top
1015 gc.drawLine(rect.x, rect.y, rect.x + rect.width - 1, rect.y);
1016 // bottom
1017 gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1);
1018 }
1019 }
1020 } else {
1021 // selected rectangle area is not visible but can be represented
1022 // with a broken vertical line of specified width.
1023 int width = 2;
1024 rect.width = width;
1025 // check if height is greater than zero.
1026 if (rect.isEmpty())
1027 return;
1028 // colorIdx1 = TraceColorScheme.BLACK;
1029 gc.setForeground(colors.getColor(colorIdx));
1030 int s = gc.getLineStyle();
1031 int w = gc.getLineWidth();
1032 gc.setLineStyle(SWT.LINE_DOT);
1033 gc.setLineWidth(width);
1034 // Trace.debug("Reactangle not visible, drawing vertical line with: "
1035 // + rect.x + "," + rect.y + "," + rect.x + "," + rect.y
1036 // + rect.height);
1037 gc.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height);
1038 gc.setLineStyle(s);
1039 gc.setLineWidth(w);
1040 }
1041 }
1042
1043 private void fillSpace(Rectangle rect, GC gc, boolean selected) {
1044 gc.setBackground(_colors.getBkColor(selected, _isInFocus, false));
1045 gc.fillRectangle(rect);
1046 // draw middle line
1047 gc.setForeground(_colors.getColor(TimeGraphColorScheme.MID_LINE));
1048 int midy = rect.y + rect.height / 2;
1049 gc.drawLine(rect.x, midy, rect.x + rect.width, midy);
1050 }
1051
1052 @Override
1053 public void keyTraversed(TraverseEvent e) {
1054 if ((e.detail == SWT.TRAVERSE_TAB_NEXT) || (e.detail == SWT.TRAVERSE_TAB_PREVIOUS))
1055 e.doit = true;
1056 }
1057
1058 @Override
1059 public void keyPressed(KeyEvent e) {
1060 int idx = -1;
1061 if (_data._expandedItems.length == 0) {
1062 return;
1063 }
1064 if (SWT.HOME == e.keyCode) {
1065 idx = 0;
1066 } else if (SWT.END == e.keyCode) {
1067 idx = _data._expandedItems.length - 1;
1068 } else if (SWT.ARROW_DOWN == e.keyCode) {
1069 idx = getSelectedIndex();
1070 if (idx < 0)
1071 idx = 0;
1072 else if (idx < _data._expandedItems.length - 1)
1073 idx++;
1074 } else if (SWT.ARROW_UP == e.keyCode) {
1075 idx = getSelectedIndex();
1076 if (idx < 0)
1077 idx = 0;
1078 else if (idx > 0)
1079 idx--;
1080 } else if (SWT.ARROW_LEFT == e.keyCode) {
1081 selectPrevEvent();
1082 } else if (SWT.ARROW_RIGHT == e.keyCode) {
1083 selectNextEvent();
1084 } else if (SWT.PAGE_DOWN == e.keyCode) {
1085 int page = countPerPage();
1086 idx = getSelectedIndex();
1087 if (idx < 0)
1088 idx = 0;
1089 idx += page;
1090 if (idx >= _data._expandedItems.length)
1091 idx = _data._expandedItems.length - 1;
1092 } else if (SWT.PAGE_UP == e.keyCode) {
1093 int page = countPerPage();
1094 idx = getSelectedIndex();
1095 if (idx < 0)
1096 idx = 0;
1097 idx -= page;
1098 if (idx < 0)
1099 idx = 0;
1100 } else if (SWT.CR == e.keyCode) {
1101 idx = getSelectedIndex();
1102 if (idx >= 0) {
1103 if (_data._expandedItems[idx]._hasChildren) {
1104 toggle(idx);
1105 } else {
1106 fireDefaultSelection();
1107 }
1108 }
1109 idx = -1;
1110 }
1111 if (idx >= 0) {
1112 selectItem(idx, false);
1113 fireSelectionChanged();
1114 }
1115 }
1116
1117 @Override
1118 public void keyReleased(KeyEvent e) {
1119 }
1120
1121 @Override
1122 public void focusGained(FocusEvent e) {
1123 _isInFocus = true;
1124 redraw();
1125 }
1126
1127 @Override
1128 public void focusLost(FocusEvent e) {
1129 _isInFocus = false;
1130 if (DRAG_NONE != _dragState) {
1131 setCapture(false);
1132 _dragState = DRAG_NONE;
1133 }
1134 redraw();
1135 }
1136
1137 public boolean isInFocus() {
1138 return _isInFocus;
1139 }
1140
1141 @Override
1142 public void mouseMove(MouseEvent e) {
1143 if (null == _timeProvider)
1144 return;
1145 Point size = getCtrlSize();
1146 if (DRAG_TRACE_ITEM == _dragState) {
1147 int nameWidth = _timeProvider.getNameSpace();
1148 int x = e.x - nameWidth;
1149 if (x > 0 && size.x > nameWidth && _dragX != x) {
1150 _dragX = x;
1151 double pixelsPerNanoSec = (size.x - nameWidth <= RIGHT_MARGIN) ? 0 : (double) (size.x - nameWidth - RIGHT_MARGIN) / (_time1bak - _time0bak);
1152 long timeDelta = (long) ((pixelsPerNanoSec == 0) ? 0 : ((_dragX - _dragX0) / pixelsPerNanoSec));
1153 long time1 = _time1bak - timeDelta;
1154 long maxTime = _timeProvider.getMaxTime();
1155 if (time1 > maxTime)
1156 time1 = maxTime;
1157 long time0 = time1 - (_time1bak - _time0bak);
1158 if (time0 < _timeProvider.getMinTime()) {
1159 time0 = _timeProvider.getMinTime();
1160 time1 = time0 + (_time1bak - _time0bak);
1161 }
1162 _timeProvider.setStartFinishTime(time0, time1);
1163 }
1164 } else if (DRAG_SPLIT_LINE == _dragState) {
1165 _dragX = e.x;
1166 _timeProvider.setNameSpace(e.x);
1167 } else if (DRAG_NONE == _dragState) {
1168 boolean mouseOverSplitLine = isOverSplitLine(e.x);
1169 if (_mouseOverSplitLine != mouseOverSplitLine) {
1170 redraw();
1171 }
1172 _mouseOverSplitLine = mouseOverSplitLine;
1173 // Make sure any time changes are notified to the application e.g.
1174 // getting back from the horizontal scroll bar or zoomed using the
1175 // mouse wheel
1176 _timeProvider.notifyStartFinishTime();
1177 }
1178 updateCursor(e.x, e.y);
1179 }
1180
1181 @Override
1182 public void mouseDoubleClick(MouseEvent e) {
1183 if (null == _timeProvider)
1184 return;
1185 if (1 == e.button) {
1186 if (isOverSplitLine(e.x) && _timeProvider.getNameSpace() != 0) {
1187 _timeProvider.setNameSpace(_idealNameSpace);
1188 boolean mouseOverSplitLine = isOverSplitLine(e.x);
1189 if (_mouseOverSplitLine != mouseOverSplitLine) {
1190 redraw();
1191 }
1192 _mouseOverSplitLine = mouseOverSplitLine;
1193 return;
1194 }
1195 int idx = getItemIndexAtY(e.y);
1196 if (idx >= 0) {
1197 selectItem(idx, false);
1198 fireDefaultSelection();
1199 }
1200 }
1201 }
1202
1203 /**
1204 * <p>
1205 * If the x, y position is over the vertical split line (name to time
1206 * ranges), then change the cursor to a drag cursor to indicate the user the
1207 * possibility of resizing
1208 * </p>
1209 *
1210 * @param x
1211 * @param y
1212 */
1213 void updateCursor(int x, int y) {
1214 // if Wait cursor not active, check for the need to change to a drag
1215 // cursor
1216 if (_isWaitCursor == false) {
1217 boolean isSplitLine = isOverSplitLine(x);
1218 // No dragcursor is name space is fixed to zero
1219 if (isSplitLine && !_isDragCursor3 && _timeProvider.getNameSpace() > 0) {
1220 setCursor(_dragCursor3);
1221 _isDragCursor3 = true;
1222 } else if (!isSplitLine && _isDragCursor3) {
1223 setCursor(null);
1224 _isDragCursor3 = false;
1225 }
1226 }
1227 }
1228
1229 /**
1230 * Provide the possibilty to control the wait cursor externally e.g. data
1231 * requests in progress
1232 *
1233 * @param waitInd
1234 */
1235 public void waitCursor(boolean waitInd) {
1236 // Update cursor as indicated
1237 if (waitInd) {
1238 setCursor(_WaitCursor);
1239 _isWaitCursor = true;
1240 } else {
1241 setCursor(null);
1242 _isWaitCursor = false;
1243 }
1244
1245 // Get ready for next mouse move
1246 _isDragCursor3 = false;
1247 }
1248
1249 @Override
1250 public void mouseDown(MouseEvent e) {
1251 if (null == _timeProvider)
1252 return;
1253 int idx;
1254 if (1 == e.button) {
1255 int nameSpace = _timeProvider.getNameSpace();
1256 if (nameSpace != 0) {
1257 if (isOverSplitLine(e.x)) {
1258 _dragState = DRAG_SPLIT_LINE;
1259 _dragX = _dragX0 = e.x;
1260 _time0bak = _timeProvider.getTime0();
1261 _time1bak = _timeProvider.getTime1();
1262 redraw();
1263 return;
1264 }
1265 }
1266
1267 idx = getItemIndexAtY(e.y);
1268 if (idx >= 0) {
1269 TimeGraphItem item = _data._expandedItems[idx];
1270 if (item._hasChildren && e.x < nameSpace && e.x < MARGIN + (item.level + 1) * EXPAND_SIZE) {
1271 toggle(idx);
1272 } else {
1273 long hitTime = getTimeAtX(e.x);
1274 if (hitTime >= 0) {
1275 // _timeProvider.setSelectedTimeInt(hitTime, false);
1276 setCapture(true);
1277 _dragState = DRAG_TRACE_ITEM;
1278 _dragX = _dragX0 = e.x - nameSpace;
1279 _time0bak = _timeProvider.getTime0();
1280 _time1bak = _timeProvider.getTime1();
1281 }
1282 }
1283 selectItem(idx, false);
1284 fireSelectionChanged();
1285 } else {
1286 selectItem(idx, false); // clear selection
1287 redraw();
1288 fireSelectionChanged();
1289 }
1290 }
1291 }
1292
1293 @Override
1294 public void mouseUp(MouseEvent e) {
1295 if (DRAG_NONE != _dragState) {
1296 setCapture(false);
1297 if (DRAG_TRACE_ITEM == _dragState) {
1298 // Notify time provider to check the need for listener
1299 // notification
1300 _timeProvider.notifyStartFinishTime();
1301 if (_dragX == _dragX0) { // click without drag
1302 long time = getTimeAtX(e.x);
1303 _timeProvider.setSelectedTimeInt(time, false);
1304 }
1305 } else if (DRAG_SPLIT_LINE == _dragState) {
1306 redraw();
1307 }
1308 _dragState = DRAG_NONE;
1309 }
1310 }
1311
1312 @Override
1313 public void controlMoved(ControlEvent e) {
1314 }
1315
1316 @Override
1317 public void controlResized(ControlEvent e) {
1318 adjustScrolls();
1319 }
1320
1321 @Override
1322 public void widgetDefaultSelected(SelectionEvent e) {
1323 }
1324
1325 @Override
1326 public void widgetSelected(SelectionEvent e) {
1327 if (e.widget == getVerticalBar()) {
1328 _topIndex = getVerticalBar().getSelection();
1329 if (_topIndex < 0)
1330 _topIndex = 0;
1331 redraw();
1332 } else if (e.widget == getHorizontalBar() && null != _timeProvider) {
1333 int start = getHorizontalBar().getSelection();
1334 long time0 = _timeProvider.getTime0();
1335 long time1 = _timeProvider.getTime1();
1336 long timeMin = _timeProvider.getMinTime();
1337 long timeMax = _timeProvider.getMaxTime();
1338 long delta = timeMax - timeMin;
1339
1340 long range = time1 - time0;
1341 // _timeRangeFixed = true;
1342 time0 = timeMin + Math.round(delta * ((double) start / H_SCROLLBAR_MAX));
1343 time1 = time0 + range;
1344
1345 // TODO: Follow-up with Bug 310310
1346 // In Linux SWT.DRAG is the only value received
1347 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=310310
1348 if (e.detail == SWT.DRAG) {
1349 _timeProvider.setStartFinishTime(time0, time1);
1350 } else {
1351 _timeProvider.setStartFinishTimeNotify(time0, time1);
1352 }
1353 }
1354 }
1355
1356 @Override
1357 public void mouseEnter(MouseEvent e) {
1358 if (mouseScrollFilterListener == null) {
1359 mouseScrollFilterListener = new Listener() {
1360 // This filter is used to prevent scrolling of the view when the
1361 // mouse wheel is used to zoom
1362 @Override
1363 public void handleEvent(Event event) {
1364 event.doit = false;
1365 }
1366 };
1367 getDisplay().addFilter(SWT.MouseWheel, mouseScrollFilterListener);
1368 }
1369 }
1370
1371 @Override
1372 public void mouseExit(MouseEvent e) {
1373 if (mouseScrollFilterListener != null) {
1374 getDisplay().removeFilter(SWT.MouseWheel, mouseScrollFilterListener);
1375 mouseScrollFilterListener = null;
1376 }
1377 if (_mouseOverSplitLine) {
1378 _mouseOverSplitLine = false;
1379 redraw();
1380 }
1381 }
1382
1383 @Override
1384 public void mouseHover(MouseEvent e) {
1385 }
1386
1387 @Override
1388 public void mouseScrolled(MouseEvent e) {
1389 if ((mouseScrollFilterListener == null) || _dragState != DRAG_NONE) {
1390 return;
1391 }
1392 if (e.x < _timeProvider.getNameSpace()) {
1393 setTopIndex(getTopIndex() - e.count);
1394 } else {
1395 if (e.count > 0) {
1396 zoom(true);
1397 } else if (e.count < 0) {
1398 zoom(false);
1399 }
1400 }
1401 }
1402
1403 public boolean isVisibleVerticalScroll() {
1404 return _visibleVerticalScroll;
1405 }
1406
1407 @Override
1408 public int getBorderWidth() {
1409 return _borderWidth;
1410 }
1411
1412 public void setBorderWidth(int borderWidth) {
1413 this._borderWidth = borderWidth;
1414 }
1415
1416 public int getHeaderHeight() {
1417 return _headerHeight;
1418 }
1419
1420 public void setHeaderHeight(int headerHeight) {
1421 this._headerHeight = headerHeight;
1422 }
1423
1424 public int getItemHeight() {
1425 return _itemHeight;
1426 }
1427
1428 public void setItemHeight(int rowHeight) {
1429 this._itemHeight = rowHeight;
1430 }
1431
1432 public void setMinimumItemWidth(int width) {
1433 this._minimumItemWidth = width;
1434 }
1435
1436 public int getMinimumItemWidth() {
1437 return _minimumItemWidth;
1438 }
1439
1440 public Vector<ITimeGraphEntry> getFilteredOut() {
1441 return _data.getFilteredOut();
1442 }
1443
1444 // @Override
1445 @Override
1446 public void addSelectionChangedListener(ISelectionChangedListener listener) {
1447 if (listener != null) {
1448 if (!_selectionChangedListeners.contains(listener)) {
1449 _selectionChangedListeners.add(listener);
1450 }
1451 }
1452 }
1453
1454 // @Override
1455 @Override
1456 public void removeSelectionChangedListener(ISelectionChangedListener listener) {
1457 if (listener != null) {
1458 _selectionChangedListeners.remove(listener);
1459 }
1460 }
1461
1462 // @Override
1463 @Override
1464 public void setSelection(ISelection selection) {
1465 if (selection instanceof TimeGraphSelection) {
1466 TimeGraphSelection sel = (TimeGraphSelection) selection;
1467 Object ob = sel.getFirstElement();
1468 if (ob instanceof ITimeGraphEntry) {
1469 ITimeGraphEntry trace = (ITimeGraphEntry) ob;
1470 selectItem(trace, false);
1471 }
1472 }
1473
1474 }
1475
1476 }
1477
1478 class ItemData {
1479 public TimeGraphItem[] _expandedItems = new TimeGraphItem[0];
1480 public TimeGraphItem[] _items = new TimeGraphItem[0];
1481 private ITimeGraphEntry _traces[] = new ITimeGraphEntry[0];
1482 private boolean traceFilter[] = new boolean[0];
1483 private Vector<ITimeGraphEntry> filteredOut = new Vector<ITimeGraphEntry>();
1484
1485 public ItemData() {
1486 }
1487
1488 TimeGraphItem findItem(ITimeGraphEntry entry) {
1489 if (entry == null)
1490 return null;
1491
1492 for (int i = 0; i < _items.length; i++) {
1493 TimeGraphItem item = _items[i];
1494 if (item._trace == entry) {
1495 return item;
1496 }
1497 }
1498
1499 return null;
1500 }
1501
1502 int findItemIndex(ITimeGraphEntry trace) {
1503 if (trace == null)
1504 return -1;
1505
1506 for (int i = 0; i < _expandedItems.length; i++) {
1507 TimeGraphItem item = _expandedItems[i];
1508 if (item._trace == trace) {
1509 return i;
1510 }
1511 }
1512
1513 return -1;
1514 }
1515
1516 public void refreshData() {
1517 List<TimeGraphItem> itemList = new ArrayList<TimeGraphItem>();
1518 filteredOut.clear();
1519 for (int i = 0; i < _traces.length; i++) {
1520 ITimeGraphEntry entry = _traces[i];
1521 refreshData(itemList, null, 0, entry);
1522 }
1523 _items = itemList.toArray(new TimeGraphItem[0]);
1524 updateExpandedItems();
1525 }
1526
1527 private void refreshData(List<TimeGraphItem> itemList, TimeGraphItem parent, int level, ITimeGraphEntry entry) {
1528 TimeGraphItem item = new TimeGraphItem(entry, entry.getName(), level);
1529 if (parent != null) {
1530 parent.children.add(item);
1531 }
1532 itemList.add(item);
1533 if (entry.hasChildren()) {
1534 item._expanded = true;
1535 item._hasChildren = true;
1536 for (ITimeGraphEntry child : entry.getChildren()) {
1537 refreshData(itemList, item, level + 1, child);
1538 }
1539 }
1540 }
1541
1542 public void updateExpandedItems() {
1543 List<TimeGraphItem> expandedItemList = new ArrayList<TimeGraphItem>();
1544 for (int i = 0; i < _traces.length; i++) {
1545 ITimeGraphEntry entry = _traces[i];
1546 TimeGraphItem item = findItem(entry);
1547 refreshExpanded(expandedItemList, item);
1548 }
1549 _expandedItems = expandedItemList.toArray(new TimeGraphItem[0]);
1550 }
1551
1552 private void refreshExpanded(List<TimeGraphItem> expandedItemList, TimeGraphItem item) {
1553 expandedItemList.add(item);
1554 if (item._hasChildren && item._expanded) {
1555 for (TimeGraphItem child : item.children) {
1556 refreshExpanded(expandedItemList, child);
1557 }
1558 }
1559 }
1560
1561 public void expandItem(int idx) {
1562 if (idx < 0 || idx >= _expandedItems.length)
1563 return;
1564 TimeGraphItem item = (TimeGraphItem) _expandedItems[idx];
1565 if (item._hasChildren && !item._expanded) {
1566 item._expanded = true;
1567 updateExpandedItems();
1568 }
1569 }
1570
1571 public void refreshData(ITimeGraphEntry traces[]) {
1572 if (traces == null || traces.length == 0) {
1573 traceFilter = null;
1574 } else if (traceFilter == null || traces.length != traceFilter.length) {
1575 traceFilter = new boolean[traces.length];
1576 java.util.Arrays.fill(traceFilter, true);
1577 }
1578
1579 _traces = traces;
1580 refreshData();
1581 }
1582
1583 public Object[] getTraces() {
1584 return _traces;
1585 }
1586
1587 public boolean[] getTraceFilter() {
1588 return traceFilter;
1589 }
1590
1591 public Vector<ITimeGraphEntry> getFilteredOut() {
1592 return filteredOut;
1593 }
1594 }
This page took 0.067101 seconds and 6 git commands to generate.