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