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