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
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
14 *****************************************************************************/
16 package org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
;
18 import java
.util
.ArrayList
;
19 import java
.util
.Iterator
;
20 import java
.util
.List
;
21 import java
.util
.Vector
;
23 import org
.eclipse
.jface
.viewers
.ISelection
;
24 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
25 import org
.eclipse
.jface
.viewers
.ISelectionProvider
;
26 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphProvider
;
27 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphTreeListener
;
28 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphTreeExpansionEvent
;
29 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
30 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
31 import org
.eclipse
.swt
.SWT
;
32 import org
.eclipse
.swt
.events
.ControlEvent
;
33 import org
.eclipse
.swt
.events
.ControlListener
;
34 import org
.eclipse
.swt
.events
.FocusEvent
;
35 import org
.eclipse
.swt
.events
.FocusListener
;
36 import org
.eclipse
.swt
.events
.KeyEvent
;
37 import org
.eclipse
.swt
.events
.KeyListener
;
38 import org
.eclipse
.swt
.events
.MouseEvent
;
39 import org
.eclipse
.swt
.events
.MouseListener
;
40 import org
.eclipse
.swt
.events
.MouseMoveListener
;
41 import org
.eclipse
.swt
.events
.MouseTrackListener
;
42 import org
.eclipse
.swt
.events
.MouseWheelListener
;
43 import org
.eclipse
.swt
.events
.PaintEvent
;
44 import org
.eclipse
.swt
.events
.SelectionEvent
;
45 import org
.eclipse
.swt
.events
.SelectionListener
;
46 import org
.eclipse
.swt
.events
.TraverseEvent
;
47 import org
.eclipse
.swt
.events
.TraverseListener
;
48 import org
.eclipse
.swt
.graphics
.Cursor
;
49 import org
.eclipse
.swt
.graphics
.GC
;
50 import org
.eclipse
.swt
.graphics
.Image
;
51 import org
.eclipse
.swt
.graphics
.Point
;
52 import org
.eclipse
.swt
.graphics
.Rectangle
;
53 import org
.eclipse
.swt
.widgets
.Composite
;
54 import org
.eclipse
.swt
.widgets
.Event
;
55 import org
.eclipse
.swt
.widgets
.Listener
;
56 import org
.eclipse
.swt
.widgets
.ScrollBar
;
58 public class TimeGraphControl
extends TimeGraphBaseControl
implements FocusListener
, KeyListener
, MouseMoveListener
, MouseListener
, MouseWheelListener
, ControlListener
, SelectionListener
, MouseTrackListener
, TraverseListener
, ISelectionProvider
{
60 private static final int DRAG_NONE
= 0;
61 private static final int DRAG_TRACE_ITEM
= 1;
62 private static final int DRAG_SPLIT_LINE
= 2;
63 public static final boolean DEFAULT_DRAW_THREAD_JOIN
= true;
64 public static final boolean DEFAULT_DRAW_THREAD_WAIT
= true;
65 public static final boolean DEFAULT_DRAW_THREAD_RELEASE
= true;
66 public static final int H_SCROLLBAR_MAX
= Integer
.MAX_VALUE
- 1;
68 private static final double zoomCoeff
= 1.5;
70 private ITimeDataProvider _timeProvider
;
71 private boolean _isInFocus
= false;
72 private boolean _isDragCursor3
= false;
73 private boolean _isWaitCursor
= true;
74 private boolean _mouseOverSplitLine
= false;
75 private int _itemHeightDefault
= 19;
76 private int _itemHeight
= _itemHeightDefault
;
77 private int _minimumItemWidth
= 0;
78 private int _topIndex
= 0;
79 private int _dragState
= DRAG_NONE
;
80 private int _dragX0
= 0;
81 private int _dragX
= 0;
82 private int _idealNameSpace
= 0;
83 // private double _timeStep = 10000000;
84 private long _time0bak
;
85 private long _time1bak
;
86 private ITimeGraphProvider fTimeGraphProvider
= null;
87 private ItemData _data
= null;
88 private List
<SelectionListener
> _selectionListeners
;
89 private List
<ISelectionChangedListener
> _selectionChangedListeners
= new ArrayList
<ISelectionChangedListener
>();
90 private List
<ITimeGraphTreeListener
> _treeListeners
= new ArrayList
<ITimeGraphTreeListener
>();
91 private Cursor _dragCursor3
;
92 private Cursor _WaitCursor
;
94 // Vertical formatting formatting for the state control view
95 private boolean _visibleVerticalScroll
= true;
96 private int _borderWidth
= 0;
97 private int _headerHeight
= 0;
99 private Listener mouseScrollFilterListener
;
101 public TimeGraphControl(Composite parent
, TimeGraphColorScheme colors
) {
103 super(parent
, colors
, SWT
.NO_BACKGROUND
| SWT
.H_SCROLL
| SWT
.DOUBLE_BUFFERED
);
105 _data
= new ItemData();
107 addFocusListener(this);
108 addMouseListener(this);
109 addMouseMoveListener(this);
110 addMouseTrackListener(this);
111 addMouseWheelListener(this);
112 addTraverseListener(this);
113 addKeyListener(this);
114 addControlListener(this);
115 ScrollBar scrollHor
= getHorizontalBar();
117 if (scrollHor
!= null) {
118 scrollHor
.addSelectionListener(this);
121 _dragCursor3
= new Cursor(super.getDisplay(), SWT
.CURSOR_SIZEWE
);
122 _WaitCursor
= new Cursor(super.getDisplay(), SWT
.CURSOR_WAIT
);
126 public void dispose() {
128 _dragCursor3
.dispose();
129 _WaitCursor
.dispose();
133 * Sets the timegraph provider used by this timegraph viewer.
135 * @param timeGraphProvider the timegraph provider
137 public void setTimeGraphProvider(ITimeGraphProvider timeGraphProvider
) {
138 fTimeGraphProvider
= timeGraphProvider
;
139 fTimeGraphProvider
.setTimeGraphControl(this);
142 public void setTimeProvider(ITimeDataProvider timeProvider
) {
143 _timeProvider
= timeProvider
;
148 public void addSelectionListener(SelectionListener listener
) {
149 if (listener
== null)
150 SWT
.error(SWT
.ERROR_NULL_ARGUMENT
);
151 if (null == _selectionListeners
)
152 _selectionListeners
= new ArrayList
<SelectionListener
>();
153 _selectionListeners
.add(listener
);
156 public void removeSelectionListener(SelectionListener listener
) {
157 if (null != _selectionListeners
)
158 _selectionListeners
.remove(listener
);
161 public void fireSelectionChanged() {
162 if (null != _selectionListeners
) {
163 Iterator
<SelectionListener
> it
= _selectionListeners
.iterator();
164 while (it
.hasNext()) {
165 SelectionListener listener
= it
.next();
166 listener
.widgetSelected(null);
171 public void fireDefaultSelection() {
172 if (null != _selectionListeners
) {
173 Iterator
<SelectionListener
> it
= _selectionListeners
.iterator();
174 while (it
.hasNext()) {
175 SelectionListener listener
= it
.next();
176 listener
.widgetDefaultSelected(null);
181 public Object
[] getTraces() {
182 return _data
.getTraces();
185 public boolean[] getTraceFilter() {
186 return _data
.getTraceFilter();
189 public void refreshData() {
195 public void refreshData(ITimeGraphEntry traces
[]) {
196 _data
.refreshData(traces
);
201 public void adjustScrolls() {
202 if (null == _timeProvider
) {
203 getHorizontalBar().setValues(0, 1, 1, 1, 1, 1);
209 long time0
= _timeProvider
.getTime0();
210 long time1
= _timeProvider
.getTime1();
212 long timeMin
= _timeProvider
.getMinTime();
213 long timeMax
= _timeProvider
.getMaxTime();
215 long delta
= timeMax
- timeMin
;
218 int thumb
= H_SCROLLBAR_MAX
;
221 // Thumb size (page size)
222 thumb
= Math
.max(1, (int) (H_SCROLLBAR_MAX
* ((double) (time1
- time0
) / delta
)));
223 // At the beginning of visible window
224 timePos
= (int) (H_SCROLLBAR_MAX
* ((double) (time0
- timeMin
) / delta
));
227 // position, minimum, maximum, thumb size, increment (half page)t, page
228 // increment size (full page)
229 getHorizontalBar().setValues(timePos
, 0, H_SCROLLBAR_MAX
, thumb
, Math
.max(1, thumb
/ 2), Math
.max(2, thumb
));
232 boolean ensureVisibleItem(int idx
, boolean redraw
) {
233 boolean changed
= false;
235 for (idx
= 0; idx
< _data
._expandedItems
.length
; idx
++) {
236 if (((TimeGraphItem
) _data
._expandedItems
[idx
])._selected
)
240 if (idx
>= _data
._expandedItems
.length
)
242 if (idx
< _topIndex
) {
244 //FIXME:getVerticalBar().setSelection(_topItem);
249 int page
= countPerPage();
250 if (idx
>= _topIndex
+ page
) {
251 _topIndex
= idx
- page
+ 1;
252 //FIXME:getVerticalBar().setSelection(_topItem);
261 public void setTopIndex(int idx
) {
262 idx
= Math
.min(idx
, _data
._expandedItems
.length
- countPerPage());
263 idx
= Math
.max(0, idx
);
268 public void setExpandedState(ITimeGraphEntry entry
, boolean expanded
) {
269 TimeGraphItem item
= _data
.findItem(entry
);
270 if (item
!= null && item
._expanded
!= expanded
) {
271 item
._expanded
= expanded
;
272 _data
.updateExpandedItems();
277 public void addTreeListener (ITimeGraphTreeListener listener
) {
278 if (!_treeListeners
.contains(listener
)) {
279 _treeListeners
.add(listener
);
283 public void removeTreeListener (ITimeGraphTreeListener listener
) {
284 if (_treeListeners
.contains(listener
)) {
285 _treeListeners
.remove(listener
);
289 public void fireTreeEvent(ITimeGraphEntry entry
, boolean expanded
) {
290 TimeGraphTreeExpansionEvent event
= new TimeGraphTreeExpansionEvent(this, entry
);
291 for (ITimeGraphTreeListener listener
: _treeListeners
) {
293 listener
.treeExpanded(event
);
295 listener
.treeCollapsed(event
);
301 public ISelection
getSelection() {
302 TimeGraphSelection sel
= new TimeGraphSelection();
303 ITimeGraphEntry trace
= getSelectedTrace();
304 if (null != trace
&& null != _timeProvider
) {
305 long selectedTime
= _timeProvider
.getSelectedTime();
306 ITimeEvent event
= Utils
.findEvent(trace
, selectedTime
, 0);
315 public ISelection
getSelectionTrace() {
316 TimeGraphSelection sel
= new TimeGraphSelection();
317 ITimeGraphEntry trace
= getSelectedTrace();
324 public void selectTrace(int n
) {
325 if (n
!= 1 && n
!= -1)
327 boolean changed
= false;
328 int lastSelection
= -1;
329 for (int i
= 0; i
< _data
._expandedItems
.length
; i
++) {
330 TimeGraphItem item
= (TimeGraphItem
) _data
._expandedItems
[i
];
331 if (item
._selected
) {
333 if (1 == n
&& i
< _data
._expandedItems
.length
- 1) {
334 item
._selected
= false;
335 if (item
._hasChildren
) {
337 fireTreeEvent(item
._trace
, item
._expanded
);
339 item
= (TimeGraphItem
) _data
._expandedItems
[i
+ 1];
340 if (item
._hasChildren
) {
341 _data
.expandItem(i
+ 1);
342 fireTreeEvent(item
._trace
, item
._expanded
);
343 item
= (TimeGraphItem
) _data
._expandedItems
[i
+ 2];
345 item
._selected
= true;
347 } else if (-1 == n
&& i
> 0) {
349 TimeGraphItem prevItem
= (TimeGraphItem
) _data
._expandedItems
[i
];
350 if (prevItem
._hasChildren
) {
351 if (prevItem
._expanded
) {
354 prevItem
= (TimeGraphItem
) _data
._expandedItems
[i
];
357 if (!prevItem
._expanded
) {
359 fireTreeEvent(prevItem
._trace
, prevItem
._expanded
);
360 prevItem
= (TimeGraphItem
) _data
._expandedItems
[i
+ prevItem
.children
.size()];
361 item
._selected
= false;
362 prevItem
._selected
= true;
366 item
._selected
= false;
367 prevItem
._selected
= true;
374 if (lastSelection
< 0 && _data
._expandedItems
.length
> 0) {
375 TimeGraphItem item
= (TimeGraphItem
) _data
._expandedItems
[0];
376 if (item
._hasChildren
) {
378 fireTreeEvent(item
._trace
, item
._expanded
);
379 item
= (TimeGraphItem
) _data
._expandedItems
[1];
380 item
._selected
= true;
383 item
._selected
= true;
388 ensureVisibleItem(-1, false);
390 fireSelectionChanged();
394 public void selectEvent(int n
) {
395 if (null == _timeProvider
)
397 ITimeGraphEntry trace
= getSelectedTrace();
400 long selectedTime
= _timeProvider
.getSelectedTime();
401 long endTime
= _timeProvider
.getEndTime();
402 ITimeEvent nextEvent
;
403 if (-1 == n
&& selectedTime
> endTime
)
404 nextEvent
= Utils
.findEvent(trace
, selectedTime
, 0);
406 nextEvent
= Utils
.findEvent(trace
, selectedTime
, n
);
407 if (null == nextEvent
&& -1 == n
)
408 nextEvent
= Utils
.getFirstEvent(trace
);
409 if (null != nextEvent
) {
410 long nextTime
= nextEvent
.getTime();
411 // If last event detected e.g. going back or not moving to a next
413 if (nextTime
<= selectedTime
&& n
== 1) {
414 // Select to the end of this last event
415 nextTime
= nextEvent
.getTime() + nextEvent
.getDuration();
416 // but not beyond the end of the trace
417 if (nextTime
> endTime
) {
421 _timeProvider
.setSelectedTimeInt(nextTime
, true);
422 fireSelectionChanged();
424 _timeProvider
.setSelectedTimeInt(endTime
, true);
425 fireSelectionChanged();
429 public void selectNextEvent() {
431 // Notify if visible time window has been adjusted
432 _timeProvider
.setStartFinishTimeNotify(_timeProvider
.getTime0(), _timeProvider
.getTime1());
435 public void selectPrevEvent() {
437 // Notify if visible time window has been adjusted
438 _timeProvider
.setStartFinishTimeNotify(_timeProvider
.getTime0(), _timeProvider
.getTime1());
441 public void selectNextTrace() {
445 public void selectPrevTrace() {
450 * Zooming based on mouse cursor location with mouse scrolling
454 public void zoom(boolean zoomIn
) {
455 int globalX
= getDisplay().getCursorLocation().x
;
456 Point p
= toControl(globalX
, 0);
457 int nameSpace
= _timeProvider
.getNameSpace();
458 int timeSpace
= _timeProvider
.getTimeSpace();
459 int xPos
= Math
.max(nameSpace
, Math
.min(nameSpace
+ timeSpace
, p
.x
));
460 long time0
= _timeProvider
.getTime0();
461 long time1
= _timeProvider
.getTime1();
462 long interval
= time1
- time0
;
465 } // to allow getting out of single point interval
468 newInterval
= Math
.max(Math
.round((double) interval
* 0.8), _timeProvider
.getMinTimeInterval());
470 newInterval
= (long) Math
.ceil((double) interval
* 1.25);
472 long center
= time0
+ Math
.round(((double) (xPos
- nameSpace
) / timeSpace
* interval
));
473 long newTime0
= center
- Math
.round((double) newInterval
* (center
- time0
) / interval
);
474 long newTime1
= newTime0
+ newInterval
;
475 _timeProvider
.setStartFinishTime(newTime0
, newTime1
);
479 * zoom in using single click
481 public void zoomIn() {
482 long _time0
= _timeProvider
.getTime0();
483 long _time1
= _timeProvider
.getTime1();
484 long _range
= _time1
- _time0
;
485 long selTime
= _timeProvider
.getSelectedTime();
486 if (selTime
<= _time0
|| selTime
>= _time1
) {
487 selTime
= (_time0
+ _time1
) / 2;
489 long time0
= selTime
- (long) ((selTime
- _time0
) / zoomCoeff
);
490 long time1
= selTime
+ (long) ((_time1
- selTime
) / zoomCoeff
);
492 long inaccuracy
= (_timeProvider
.getMaxTime() - _timeProvider
.getMinTime()) - (time1
- time0
);
494 // Trace.debug("selTime:" + selTime + " time0:" + time0 + " time1:"
495 // + time1 + " inaccuracy:" + inaccuracy);
497 if (inaccuracy
> 0 && inaccuracy
< 100) {
498 _timeProvider
.setStartFinishTimeNotify(_timeProvider
.getMinTime(), _timeProvider
.getMaxTime());
502 long m
= _timeProvider
.getMinTimeInterval();
503 if ((time1
- time0
) < m
) {
504 time0
= selTime
- (long) ((selTime
- _time0
) * m
/ _range
);
508 _timeProvider
.setStartFinishTimeNotify(time0
, time1
);
512 * zoom out using single click
514 public void zoomOut() {
515 long _time0
= _timeProvider
.getTime0();
516 long _time1
= _timeProvider
.getTime1();
517 long selTime
= _timeProvider
.getSelectedTime();
518 if (selTime
<= _time0
|| selTime
>= _time1
) {
519 selTime
= (_time0
+ _time1
) / 2;
521 long time0
= (long) (selTime
- (selTime
- _time0
) * zoomCoeff
);
522 long time1
= (long) (selTime
+ (_time1
- selTime
) * zoomCoeff
);
524 long inaccuracy
= (_timeProvider
.getMaxTime() - _timeProvider
.getMinTime()) - (time1
- time0
);
525 if (inaccuracy
> 0 && inaccuracy
< 100) {
526 _timeProvider
.setStartFinishTimeNotify(_timeProvider
.getMinTime(), _timeProvider
.getMaxTime());
530 _timeProvider
.setStartFinishTimeNotify(time0
, time1
);
533 public ITimeGraphEntry
getSelectedTrace() {
534 ITimeGraphEntry trace
= null;
535 int idx
= getSelectedIndex();
537 trace
= _data
._expandedItems
[idx
]._trace
;
541 public int getSelectedIndex() {
543 for (int i
= 0; i
< _data
._expandedItems
.length
; i
++) {
544 TimeGraphItem item
= (TimeGraphItem
) _data
._expandedItems
[i
];
545 if (item
._selected
) {
553 boolean toggle(int idx
) {
554 boolean toggled
= false;
555 if (idx
>= 0 && idx
< _data
._expandedItems
.length
) {
556 TimeGraphItem item
= (TimeGraphItem
) _data
._expandedItems
[idx
];
557 if (item
._hasChildren
) {
558 item
._expanded
= !item
._expanded
;
559 _data
.updateExpandedItems();
563 fireTreeEvent(item
._trace
, item
._expanded
);
569 int getItemIndexAtY(int y
) {
573 int idx
= y
/ _itemHeight
;
575 if (idx
< _data
._expandedItems
.length
) {
581 boolean isOverSplitLine(int x
) {
582 if (x
< 0 || null == _timeProvider
)
585 int nameWidth
= _timeProvider
.getNameSpace();
586 if (x
> nameWidth
- w
&& x
< nameWidth
+ w
) {
593 TimeGraphItem
getItem(Point pt
) {
594 int idx
= getItemIndexAtY(pt
.y
);
595 return idx
>= 0 ?
(TimeGraphItem
) _data
._expandedItems
[idx
] : null;
598 long getTimeAtX(int x
) {
599 if (null == _timeProvider
)
602 Point size
= getCtrlSize();
603 long time0
= _timeProvider
.getTime0();
604 long time1
= _timeProvider
.getTime1();
605 int nameWidth
= _timeProvider
.getNameSpace();
607 if (x
>= 0 && size
.x
>= nameWidth
) {
608 if (time1
- time0
> size
.x
- nameWidth
- RIGHT_MARGIN
) {
609 // get the last possible time represented by the pixel position
610 // by taking the time of the next pixel position minus 1
612 hitTime
= time0
+ (long) ((time1
- time0
) * ((double) (x
+ 1) / (size
.x
- nameWidth
- RIGHT_MARGIN
))) - 1;
614 hitTime
= time0
+ (long) ((time1
- time0
) * ((double) (x
) / (size
.x
- nameWidth
- RIGHT_MARGIN
)));
620 void selectItem(int idx
, boolean addSelection
) {
621 boolean changed
= false;
623 if (idx
>= 0 && idx
< _data
._expandedItems
.length
) {
624 TimeGraphItem item
= (TimeGraphItem
) _data
._expandedItems
[idx
];
625 changed
= (item
._selected
== false);
626 item
._selected
= true;
629 for (int i
= 0; i
< _data
._expandedItems
.length
; i
++) {
630 TimeGraphItem item
= (TimeGraphItem
) _data
._expandedItems
[i
];
631 if ((i
== idx
&& !item
._selected
) || (idx
== -1 && item
._selected
)) {
634 item
._selected
= i
== idx
;
637 changed
|= ensureVisibleItem(idx
, true);
642 public void selectItem(ITimeGraphEntry trace
, boolean addSelection
) {
643 int idx
= _data
.findItemIndex(trace
);
644 selectItem(idx
, addSelection
);
647 public int countPerPage() {
648 int height
= getCtrlSize().y
;
651 count
= height
/ _itemHeight
;
655 public int getTopIndex() {
659 public int getExpandedElementCount() {
660 return _data
._expandedItems
.length
;
663 Point
getCtrlSize() {
664 Point size
= getSize();
665 if (getHorizontalBar().isVisible()) {
666 size
.y
-= getHorizontalBar().getSize().y
;
671 Rectangle
getNameRect(Rectangle bound
, int idx
, int nameWidth
) {
674 int y
= bound
.y
+ idx
* _itemHeight
;
675 int width
= nameWidth
;
676 int height
= _itemHeight
;
677 return new Rectangle(x
, y
, width
, height
);
680 Rectangle
getStatesRect(Rectangle bound
, int idx
, int nameWidth
) {
682 int x
= bound
.x
+ nameWidth
;
683 int y
= bound
.y
+ idx
* _itemHeight
;
684 int width
= bound
.width
- x
;
685 int height
= _itemHeight
;
686 return new Rectangle(x
, y
, width
, height
);
689 public void drawTraceEvent(Rectangle bound
, ITimeEvent e
, int nItem
, int color
, GC gc
) {
690 int nameWidth
= _timeProvider
.getNameSpace();
692 long time0
= _timeProvider
.getTime0();
693 long time1
= _timeProvider
.getTime1();
697 int xr
= bound
.x
+ nameWidth
;
698 double pixelsPerNanoSec
= (bound
.width
- xr
<= RIGHT_MARGIN
) ?
0 : (double) (bound
.width
- xr
- RIGHT_MARGIN
) / (time1
- time0
);
700 int x0
= xr
+ (int) ((e
.getTime() - time0
) * pixelsPerNanoSec
);
704 int y0
= bound
.y
+ (nItem
- _topIndex
) * _itemHeight
+ 3;
706 gc
.setBackground(_colors
.getColor(color
));
707 int c
[] = { x0
- 3, y0
- 3, x0
, y0
, x0
+ 3, y0
- 3 };
712 void paint(Rectangle bounds
, PaintEvent e
) {
714 gc
.setBackground(_colors
.getColor(TimeGraphColorScheme
.BACKGROUND
));
715 drawBackground(gc
, bounds
.x
, bounds
.y
, bounds
.width
, bounds
.height
);
717 if (bounds
.width
< 2 || bounds
.height
< 2 || null == _timeProvider
)
721 int nameSpace
= _timeProvider
.getNameSpace();
723 // draw empty name space background
724 int nbDrawn
= _data
._expandedItems
.length
- _topIndex
;
725 if (_itemHeight
* nbDrawn
< bounds
.height
) {
726 gc
.setBackground(_colors
.getBkColor(false, false, true));
727 drawBackground(gc
, bounds
.x
, _itemHeight
* nbDrawn
, nameSpace
, bounds
.height
- _itemHeight
* nbDrawn
);
730 fTimeGraphProvider
.drawItems(bounds
, _timeProvider
, _data
._expandedItems
, _topIndex
, nameSpace
, gc
);
732 // draw selected time
733 long time0
= _timeProvider
.getTime0();
734 long time1
= _timeProvider
.getTime1();
735 long selectedTime
= _timeProvider
.getSelectedTime();
736 double pixelsPerNanoSec
= (bounds
.width
- nameSpace
<= RIGHT_MARGIN
) ?
0 : (double) (bounds
.width
- nameSpace
- RIGHT_MARGIN
) / (time1
- time0
);
737 int x
= bounds
.x
+ nameSpace
+ (int) ((double) (selectedTime
- time0
) * pixelsPerNanoSec
);
738 if (x
>= nameSpace
&& x
< bounds
.x
+ bounds
.width
) {
739 gc
.setForeground(_colors
.getColor(TimeGraphColorScheme
.SELECTED_TIME
));
740 gc
.drawLine(x
, bounds
.y
, x
, bounds
.y
+ bounds
.height
);
743 // draw drag line, no line if name space is 0.
744 if (DRAG_SPLIT_LINE
== _dragState
) {
745 gc
.setForeground(_colors
.getColor(TimeGraphColorScheme
.BLACK
));
746 gc
.drawLine(bounds
.x
+ nameSpace
, bounds
.y
, bounds
.x
+ nameSpace
, bounds
.y
+ bounds
.height
- 1);
747 } else if (DRAG_NONE
== _dragState
&& _mouseOverSplitLine
&& _timeProvider
.getNameSpace() > 0) {
748 gc
.setForeground(_colors
.getColor(TimeGraphColorScheme
.RED
));
749 gc
.drawLine(bounds
.x
+ nameSpace
, bounds
.y
, bounds
.x
+ nameSpace
, bounds
.y
+ bounds
.height
- 1);
753 public void drawItems(Rectangle bounds
, ITimeDataProvider timeProvider
, TimeGraphItem
[] items
, int topIndex
, int nameSpace
, GC gc
) {
755 for (int i
= topIndex
; i
< items
.length
; i
++) {
756 TimeGraphItem item
= (TimeGraphItem
) items
[i
];
757 fTimeGraphProvider
.drawItem(item
, bounds
, timeProvider
, i
, nameSpace
, gc
);
764 * @param item the item to draw
765 * @param bounds the container rectangle
766 * @param i the item index
767 * @param nameSpace the name space
770 public void drawItem(TimeGraphItem item
, Rectangle bounds
, ITimeDataProvider timeProvider
, int i
, int nameSpace
, GC gc
) {
771 long time0
= timeProvider
.getTime0();
772 long time1
= timeProvider
.getTime1();
773 long endTime
= timeProvider
.getEndTime();
774 long selectedTime
= timeProvider
.getSelectedTime();
776 Rectangle nameRect
= getNameRect(bounds
, i
, nameSpace
);
777 if (nameRect
.y
>= bounds
.y
+ bounds
.height
) {
781 if (item
._trace
.getTimeEventsIterator() == null) {
782 Rectangle statesRect
= getStatesRect(bounds
, i
, nameSpace
);
783 nameRect
.width
+= statesRect
.width
;
784 drawName(item
, nameRect
, gc
);
786 drawName(item
, nameRect
, gc
);
788 Rectangle rect
= getStatesRect(bounds
, i
, nameSpace
);
791 if (time1
<= time0
) {
792 gc
.setBackground(_colors
.getBkColor(false, false, false));
793 gc
.fillRectangle(rect
);
797 // Initialize _rect1 to same values as enclosing rectangle rect
798 Rectangle stateRect
= Utils
.clone(rect
);
799 boolean selected
= item
._selected
;
800 // K pixels per second
801 double pixelsPerNanoSec
= (rect
.width
<= RIGHT_MARGIN
) ?
0 : (double) (rect
.width
- RIGHT_MARGIN
) / (time1
- time0
);
803 boolean group
= item
._trace
.getTimeEventsIterator() == null;
806 // gc.setBackground(_colors.getBkColorGroup(selected, _isInFocus));
807 // gc.fillRectangle(rect);
809 ITimeGraphEntry trace
= item
._trace
;
812 long maxDuration
= (timeProvider
.getTimeSpace() == 0) ? Long
.MAX_VALUE
: 1 * (time1
- time0
) / timeProvider
.getTimeSpace();
813 Iterator
<ITimeEvent
> iterator
= trace
.getTimeEventsIterator(time0
, time1
, maxDuration
);
814 // Drawing rectangle is smaller than reserved space
816 stateRect
.height
-= 6;
818 // Clean up to empty line to draw on top
819 int xEnd
= rect
.x
+ rect
.width
;
820 fillSpace(rect
, gc
, selected
);
821 if (iterator
.hasNext()) {
822 ITimeEvent currEvent
= iterator
.next();
823 ITimeEvent nextEvent
= null;
824 long currEventTime
= currEvent
.getTime();
825 long currEventDuration
= currEvent
.getDuration();
827 long nextEventTime
= currEventTime
;
828 // x0 - Points to the beginning of the event being drawn
829 double step
= (double) ((currEventTime
- time0
) * pixelsPerNanoSec
);
831 // xEnd - Points to the end of the events rectangle
836 while (/* x0 <= xEnd && */null != currEvent
) {
837 boolean stopped
= false;// currEvent instanceof
838 // refresh current event duration as the loop moves
839 currEventDuration
= currEvent
.getDuration();
840 // TsfTmTraceDeadEvent;
841 if (iterator
.hasNext()) {
842 nextEvent
= iterator
.next();
843 nextEventTime
= nextEvent
.getTime();
844 } else if (stopped
) {
846 nextEventTime
= time1
;
849 nextEventTime
= endTime
;
852 // Calculate position to next event
853 xNext
= rect
.x
+ (double) ((nextEventTime
- time0
) * pixelsPerNanoSec
);
855 // Calculate end position of current event
856 if (currEventDuration
< 0) {
857 x1
= rect
.x
+ (double) ((nextEventTime
- time0
) * pixelsPerNanoSec
);
858 } else if (currEventDuration
== 0) {
861 x1
= x0
+ (double) ((currEventDuration
) * pixelsPerNanoSec
);
864 // If event end position x1 further away than start position
865 // of next event, cut width till next event
866 if (currEventDuration
!= 0) {
867 x1
= x1
> xNext ? xNext
: x1
;
869 // if event end boundary is within time range
870 if (x1
>= rect
.x
&& x0
<= xEnd
) {
871 if (currEventDuration
!= 0) {
872 x0
= (double) (x0
>= rect
.x ? x0
: rect
.x
);
873 stateRect
.width
= (int) ((x1
<= xEnd ? x1
: xEnd
) - x0
);
877 stateRect
.width
= Math
.max(getMinimumItemWidth(), stateRect
.width
);
878 stateRect
.x
= (int) x0
;
879 boolean timeSelected
= currEventTime
<= selectedTime
&& selectedTime
< nextEventTime
;
880 fTimeGraphProvider
.drawState(_colors
, currEvent
, stateRect
, gc
, selected
, false, timeSelected
);
881 // Advance rectangle to next start position and Fill
882 // with space until next event
883 stateRect
.x
+= stateRect
.width
;
887 // lastEvent = currEvent;
888 currEvent
= nextEvent
;
889 currEventTime
= nextEventTime
;
890 // Move x0 to the beginning of next event
891 x0
= rect
.x
+ (double) ((nextEventTime
- time0
) * pixelsPerNanoSec
);
897 void drawName(TimeGraphItem item
, Rectangle bounds
, GC gc
) {
898 boolean group
= item
._trace
.getTimeEventsIterator() == null;
900 gc
.setBackground(_colors
.getBkColorGroup(item
._selected
, _isInFocus
));
901 gc
.fillRectangle(bounds
);
902 if (item
._selected
&& _isInFocus
) {
903 gc
.setForeground(_colors
.getBkColor(item
._selected
, _isInFocus
, false));
904 gc
.drawRectangle(bounds
.x
, bounds
.y
, bounds
.width
- 1, bounds
.height
- 1);
907 gc
.setBackground(_colors
.getBkColor(item
._selected
, _isInFocus
, true));
908 gc
.setForeground(_colors
.getFgColor(item
._selected
, _isInFocus
));
909 gc
.fillRectangle(bounds
);
912 // No name to be drawn
913 if (_timeProvider
.getNameSpace() == 0) {
917 int leftMargin
= MARGIN
+ item
.level
* EXPAND_SIZE
;
918 if (item
._hasChildren
) {
919 gc
.setForeground(_colors
.getFgColorGroup(false, false));
920 gc
.setBackground(_colors
.getBkColor(false, false, false));
921 Rectangle rect
= Utils
.clone(bounds
);
922 rect
.x
+= leftMargin
;
923 rect
.y
+= (bounds
.height
- EXPAND_SIZE
) / 2;
924 rect
.width
= EXPAND_SIZE
;
925 rect
.height
= EXPAND_SIZE
;
926 gc
.fillRectangle(rect
);
927 gc
.drawRectangle(rect
.x
, rect
.y
, rect
.width
- 1, rect
.height
- 1);
928 int midy
= rect
.y
+ rect
.height
/ 2;
929 gc
.drawLine(rect
.x
+ 2, midy
, rect
.x
+ rect
.width
- 3, midy
);
930 if (!item
._expanded
) {
931 int midx
= rect
.x
+ rect
.width
/ 2;
932 gc
.drawLine(midx
, rect
.y
+ 2, midx
, rect
.y
+ rect
.height
- 3);
935 leftMargin
+= EXPAND_SIZE
+ MARGIN
;
937 Image img
= fTimeGraphProvider
.getItemImage(item
._trace
);
940 int imgHeight
= img
.getImageData().height
;
941 int imgWidth
= img
.getImageData().width
;
943 int y
= bounds
.y
+ (bounds
.height
- imgHeight
) / 2;
944 gc
.drawImage(img
, x
, y
);
945 leftMargin
+= imgWidth
+ MARGIN
;
947 String name
= item
._name
;
948 Point size
= gc
.stringExtent(name
);
949 if (_idealNameSpace
< leftMargin
+ size
.x
+ MARGIN
) {
950 _idealNameSpace
= leftMargin
+ size
.x
+ MARGIN
;
953 // cut long string with "..."
954 int width
= bounds
.width
- leftMargin
;
956 while (size
.x
> width
&& name
.length() > 1) {
958 name
= name
.substring(0, name
.length() - 1);
959 size
= gc
.stringExtent(name
+ "..."); //$NON-NLS-1$
962 name
+= "..."; //$NON-NLS-1$
965 Rectangle rect
= Utils
.clone(bounds
);
966 rect
.x
+= leftMargin
;
967 rect
.width
-= leftMargin
;
969 if (rect
.width
> 0) {
971 int textWidth
= Utils
.drawText(gc
, name
, rect
, true);
972 leftMargin
+= textWidth
+ MARGIN
;
977 int x
= bounds
.x
+ leftMargin
;
978 int width
= bounds
.width
- x
;
979 int midy
= bounds
.y
+ bounds
.height
/ 2;
980 gc
.setForeground(_colors
.getColor(TimeGraphColorScheme
.MID_LINE
));
981 gc
.drawLine(x
, midy
, x
+ width
, midy
);
986 public void drawState(TimeGraphColorScheme colors
, int colorIdx
,
987 Rectangle rect
, GC gc
, boolean selected
, boolean rectBound
,
988 boolean timeSelected
) {
990 boolean visible
= rect
.width
== 0 ?
false : true;
991 int colorIdx1
= colorIdx
;
993 timeSelected
= timeSelected
&& selected
;
995 colorIdx1
= colorIdx
+ TimeGraphColorScheme
.STATES_SEL0
- TimeGraphColorScheme
.STATES0
;
999 // fill all rect area
1003 gc
.setBackground(colors
.getColor(colorIdx1
));
1004 gc
.fillRectangle(rect
);
1005 colorIdx1
= colorIdx
+ TimeGraphColorScheme
.STATES_BORDER0
- TimeGraphColorScheme
.STATES0
;
1006 gc
.setForeground(colors
.getColor(colorIdx1
));
1009 if (!timeSelected
) {
1010 if (rectBound
&& rect
.width
>= 3) {
1011 gc
.drawRectangle(rect
.x
, rect
.y
, rect
.width
- 1, rect
.height
- 1);
1013 // Draw the top and bottom borders i.e. no side borders
1015 gc
.drawLine(rect
.x
, rect
.y
, rect
.x
+ rect
.width
- 1, rect
.y
);
1017 gc
.drawLine(rect
.x
, rect
.y
+ rect
.height
- 1, rect
.x
+ rect
.width
- 1, rect
.y
+ rect
.height
- 1);
1021 // selected rectangle area is not visible but can be represented
1022 // with a broken vertical line of specified width.
1025 // check if height is greater than zero.
1028 // colorIdx1 = TraceColorScheme.BLACK;
1029 gc
.setForeground(colors
.getColor(colorIdx
));
1030 int s
= gc
.getLineStyle();
1031 int w
= gc
.getLineWidth();
1032 gc
.setLineStyle(SWT
.LINE_DOT
);
1033 gc
.setLineWidth(width
);
1034 // Trace.debug("Reactangle not visible, drawing vertical line with: "
1035 // + rect.x + "," + rect.y + "," + rect.x + "," + rect.y
1037 gc
.drawLine(rect
.x
, rect
.y
, rect
.x
, rect
.y
+ rect
.height
);
1043 private void fillSpace(Rectangle rect
, GC gc
, boolean selected
) {
1044 gc
.setBackground(_colors
.getBkColor(selected
, _isInFocus
, false));
1045 gc
.fillRectangle(rect
);
1047 gc
.setForeground(_colors
.getColor(TimeGraphColorScheme
.MID_LINE
));
1048 int midy
= rect
.y
+ rect
.height
/ 2;
1049 gc
.drawLine(rect
.x
, midy
, rect
.x
+ rect
.width
, midy
);
1053 public void keyTraversed(TraverseEvent e
) {
1054 if ((e
.detail
== SWT
.TRAVERSE_TAB_NEXT
) || (e
.detail
== SWT
.TRAVERSE_TAB_PREVIOUS
))
1059 public void keyPressed(KeyEvent e
) {
1061 if (_data
._expandedItems
.length
== 0) {
1064 if (SWT
.HOME
== e
.keyCode
) {
1066 } else if (SWT
.END
== e
.keyCode
) {
1067 idx
= _data
._expandedItems
.length
- 1;
1068 } else if (SWT
.ARROW_DOWN
== e
.keyCode
) {
1069 idx
= getSelectedIndex();
1072 else if (idx
< _data
._expandedItems
.length
- 1)
1074 } else if (SWT
.ARROW_UP
== e
.keyCode
) {
1075 idx
= getSelectedIndex();
1080 } else if (SWT
.ARROW_LEFT
== e
.keyCode
) {
1082 } else if (SWT
.ARROW_RIGHT
== e
.keyCode
) {
1084 } else if (SWT
.PAGE_DOWN
== e
.keyCode
) {
1085 int page
= countPerPage();
1086 idx
= getSelectedIndex();
1090 if (idx
>= _data
._expandedItems
.length
)
1091 idx
= _data
._expandedItems
.length
- 1;
1092 } else if (SWT
.PAGE_UP
== e
.keyCode
) {
1093 int page
= countPerPage();
1094 idx
= getSelectedIndex();
1100 } else if (SWT
.CR
== e
.keyCode
) {
1101 idx
= getSelectedIndex();
1103 if (_data
._expandedItems
[idx
]._hasChildren
) {
1106 fireDefaultSelection();
1112 selectItem(idx
, false);
1113 fireSelectionChanged();
1118 public void keyReleased(KeyEvent e
) {
1122 public void focusGained(FocusEvent e
) {
1128 public void focusLost(FocusEvent e
) {
1130 if (DRAG_NONE
!= _dragState
) {
1132 _dragState
= DRAG_NONE
;
1137 public boolean isInFocus() {
1142 public void mouseMove(MouseEvent e
) {
1143 if (null == _timeProvider
)
1145 Point size
= getCtrlSize();
1146 if (DRAG_TRACE_ITEM
== _dragState
) {
1147 int nameWidth
= _timeProvider
.getNameSpace();
1148 int x
= e
.x
- nameWidth
;
1149 if (x
> 0 && size
.x
> nameWidth
&& _dragX
!= x
) {
1151 double pixelsPerNanoSec
= (size
.x
- nameWidth
<= RIGHT_MARGIN
) ?
0 : (double) (size
.x
- nameWidth
- RIGHT_MARGIN
) / (_time1bak
- _time0bak
);
1152 long timeDelta
= (long) ((pixelsPerNanoSec
== 0) ?
0 : ((_dragX
- _dragX0
) / pixelsPerNanoSec
));
1153 long time1
= _time1bak
- timeDelta
;
1154 long maxTime
= _timeProvider
.getMaxTime();
1155 if (time1
> maxTime
)
1157 long time0
= time1
- (_time1bak
- _time0bak
);
1158 if (time0
< _timeProvider
.getMinTime()) {
1159 time0
= _timeProvider
.getMinTime();
1160 time1
= time0
+ (_time1bak
- _time0bak
);
1162 _timeProvider
.setStartFinishTime(time0
, time1
);
1164 } else if (DRAG_SPLIT_LINE
== _dragState
) {
1166 _timeProvider
.setNameSpace(e
.x
);
1167 } else if (DRAG_NONE
== _dragState
) {
1168 boolean mouseOverSplitLine
= isOverSplitLine(e
.x
);
1169 if (_mouseOverSplitLine
!= mouseOverSplitLine
) {
1172 _mouseOverSplitLine
= mouseOverSplitLine
;
1173 // Make sure any time changes are notified to the application e.g.
1174 // getting back from the horizontal scroll bar or zoomed using the
1176 _timeProvider
.notifyStartFinishTime();
1178 updateCursor(e
.x
, e
.y
);
1182 public void mouseDoubleClick(MouseEvent e
) {
1183 if (null == _timeProvider
)
1185 if (1 == e
.button
) {
1186 if (isOverSplitLine(e
.x
) && _timeProvider
.getNameSpace() != 0) {
1187 _timeProvider
.setNameSpace(_idealNameSpace
);
1188 boolean mouseOverSplitLine
= isOverSplitLine(e
.x
);
1189 if (_mouseOverSplitLine
!= mouseOverSplitLine
) {
1192 _mouseOverSplitLine
= mouseOverSplitLine
;
1195 int idx
= getItemIndexAtY(e
.y
);
1197 selectItem(idx
, false);
1198 fireDefaultSelection();
1205 * If the x, y position is over the vertical split line (name to time
1206 * ranges), then change the cursor to a drag cursor to indicate the user the
1207 * possibility of resizing
1213 void updateCursor(int x
, int y
) {
1214 // if Wait cursor not active, check for the need to change to a drag
1216 if (_isWaitCursor
== false) {
1217 boolean isSplitLine
= isOverSplitLine(x
);
1218 // No dragcursor is name space is fixed to zero
1219 if (isSplitLine
&& !_isDragCursor3
&& _timeProvider
.getNameSpace() > 0) {
1220 setCursor(_dragCursor3
);
1221 _isDragCursor3
= true;
1222 } else if (!isSplitLine
&& _isDragCursor3
) {
1224 _isDragCursor3
= false;
1230 * Provide the possibilty to control the wait cursor externally e.g. data
1231 * requests in progress
1235 public void waitCursor(boolean waitInd
) {
1236 // Update cursor as indicated
1238 setCursor(_WaitCursor
);
1239 _isWaitCursor
= true;
1242 _isWaitCursor
= false;
1245 // Get ready for next mouse move
1246 _isDragCursor3
= false;
1250 public void mouseDown(MouseEvent e
) {
1251 if (null == _timeProvider
)
1254 if (1 == e
.button
) {
1255 int nameSpace
= _timeProvider
.getNameSpace();
1256 if (nameSpace
!= 0) {
1257 if (isOverSplitLine(e
.x
)) {
1258 _dragState
= DRAG_SPLIT_LINE
;
1259 _dragX
= _dragX0
= e
.x
;
1260 _time0bak
= _timeProvider
.getTime0();
1261 _time1bak
= _timeProvider
.getTime1();
1267 idx
= getItemIndexAtY(e
.y
);
1269 TimeGraphItem item
= _data
._expandedItems
[idx
];
1270 if (item
._hasChildren
&& e
.x
< nameSpace
&& e
.x
< MARGIN
+ (item
.level
+ 1) * EXPAND_SIZE
) {
1273 long hitTime
= getTimeAtX(e
.x
);
1275 // _timeProvider.setSelectedTimeInt(hitTime, false);
1277 _dragState
= DRAG_TRACE_ITEM
;
1278 _dragX
= _dragX0
= e
.x
- nameSpace
;
1279 _time0bak
= _timeProvider
.getTime0();
1280 _time1bak
= _timeProvider
.getTime1();
1283 selectItem(idx
, false);
1284 fireSelectionChanged();
1286 selectItem(idx
, false); // clear selection
1288 fireSelectionChanged();
1294 public void mouseUp(MouseEvent e
) {
1295 if (DRAG_NONE
!= _dragState
) {
1297 if (DRAG_TRACE_ITEM
== _dragState
) {
1298 // Notify time provider to check the need for listener
1300 _timeProvider
.notifyStartFinishTime();
1301 if (_dragX
== _dragX0
) { // click without drag
1302 long time
= getTimeAtX(e
.x
);
1303 _timeProvider
.setSelectedTimeInt(time
, false);
1305 } else if (DRAG_SPLIT_LINE
== _dragState
) {
1308 _dragState
= DRAG_NONE
;
1313 public void controlMoved(ControlEvent e
) {
1317 public void controlResized(ControlEvent e
) {
1322 public void widgetDefaultSelected(SelectionEvent e
) {
1326 public void widgetSelected(SelectionEvent e
) {
1327 if (e
.widget
== getVerticalBar()) {
1328 _topIndex
= getVerticalBar().getSelection();
1332 } else if (e
.widget
== getHorizontalBar() && null != _timeProvider
) {
1333 int start
= getHorizontalBar().getSelection();
1334 long time0
= _timeProvider
.getTime0();
1335 long time1
= _timeProvider
.getTime1();
1336 long timeMin
= _timeProvider
.getMinTime();
1337 long timeMax
= _timeProvider
.getMaxTime();
1338 long delta
= timeMax
- timeMin
;
1340 long range
= time1
- time0
;
1341 // _timeRangeFixed = true;
1342 time0
= timeMin
+ Math
.round(delta
* ((double) start
/ H_SCROLLBAR_MAX
));
1343 time1
= time0
+ range
;
1345 // TODO: Follow-up with Bug 310310
1346 // In Linux SWT.DRAG is the only value received
1347 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=310310
1348 if (e
.detail
== SWT
.DRAG
) {
1349 _timeProvider
.setStartFinishTime(time0
, time1
);
1351 _timeProvider
.setStartFinishTimeNotify(time0
, time1
);
1357 public void mouseEnter(MouseEvent e
) {
1358 if (mouseScrollFilterListener
== null) {
1359 mouseScrollFilterListener
= new Listener() {
1360 // This filter is used to prevent scrolling of the view when the
1361 // mouse wheel is used to zoom
1363 public void handleEvent(Event event
) {
1367 getDisplay().addFilter(SWT
.MouseWheel
, mouseScrollFilterListener
);
1372 public void mouseExit(MouseEvent e
) {
1373 if (mouseScrollFilterListener
!= null) {
1374 getDisplay().removeFilter(SWT
.MouseWheel
, mouseScrollFilterListener
);
1375 mouseScrollFilterListener
= null;
1377 if (_mouseOverSplitLine
) {
1378 _mouseOverSplitLine
= false;
1384 public void mouseHover(MouseEvent e
) {
1388 public void mouseScrolled(MouseEvent e
) {
1389 if ((mouseScrollFilterListener
== null) || _dragState
!= DRAG_NONE
) {
1392 if (e
.x
< _timeProvider
.getNameSpace()) {
1393 setTopIndex(getTopIndex() - e
.count
);
1397 } else if (e
.count
< 0) {
1403 public boolean isVisibleVerticalScroll() {
1404 return _visibleVerticalScroll
;
1408 public int getBorderWidth() {
1409 return _borderWidth
;
1412 public void setBorderWidth(int borderWidth
) {
1413 this._borderWidth
= borderWidth
;
1416 public int getHeaderHeight() {
1417 return _headerHeight
;
1420 public void setHeaderHeight(int headerHeight
) {
1421 this._headerHeight
= headerHeight
;
1424 public int getItemHeight() {
1428 public void setItemHeight(int rowHeight
) {
1429 this._itemHeight
= rowHeight
;
1432 public void setMinimumItemWidth(int width
) {
1433 this._minimumItemWidth
= width
;
1436 public int getMinimumItemWidth() {
1437 return _minimumItemWidth
;
1440 public Vector
<ITimeGraphEntry
> getFilteredOut() {
1441 return _data
.getFilteredOut();
1446 public void addSelectionChangedListener(ISelectionChangedListener listener
) {
1447 if (listener
!= null) {
1448 if (!_selectionChangedListeners
.contains(listener
)) {
1449 _selectionChangedListeners
.add(listener
);
1456 public void removeSelectionChangedListener(ISelectionChangedListener listener
) {
1457 if (listener
!= null) {
1458 _selectionChangedListeners
.remove(listener
);
1464 public void setSelection(ISelection selection
) {
1465 if (selection
instanceof TimeGraphSelection
) {
1466 TimeGraphSelection sel
= (TimeGraphSelection
) selection
;
1467 Object ob
= sel
.getFirstElement();
1468 if (ob
instanceof ITimeGraphEntry
) {
1469 ITimeGraphEntry trace
= (ITimeGraphEntry
) ob
;
1470 selectItem(trace
, false);
1479 public TimeGraphItem
[] _expandedItems
= new TimeGraphItem
[0];
1480 public TimeGraphItem
[] _items
= new TimeGraphItem
[0];
1481 private ITimeGraphEntry _traces
[] = new ITimeGraphEntry
[0];
1482 private boolean traceFilter
[] = new boolean[0];
1483 private Vector
<ITimeGraphEntry
> filteredOut
= new Vector
<ITimeGraphEntry
>();
1488 TimeGraphItem
findItem(ITimeGraphEntry entry
) {
1492 for (int i
= 0; i
< _items
.length
; i
++) {
1493 TimeGraphItem item
= _items
[i
];
1494 if (item
._trace
== entry
) {
1502 int findItemIndex(ITimeGraphEntry trace
) {
1506 for (int i
= 0; i
< _expandedItems
.length
; i
++) {
1507 TimeGraphItem item
= _expandedItems
[i
];
1508 if (item
._trace
== trace
) {
1516 public void refreshData() {
1517 List
<TimeGraphItem
> itemList
= new ArrayList
<TimeGraphItem
>();
1518 filteredOut
.clear();
1519 for (int i
= 0; i
< _traces
.length
; i
++) {
1520 ITimeGraphEntry entry
= _traces
[i
];
1521 refreshData(itemList
, null, 0, entry
);
1523 _items
= itemList
.toArray(new TimeGraphItem
[0]);
1524 updateExpandedItems();
1527 private void refreshData(List
<TimeGraphItem
> itemList
, TimeGraphItem parent
, int level
, ITimeGraphEntry entry
) {
1528 TimeGraphItem item
= new TimeGraphItem(entry
, entry
.getName(), level
);
1529 if (parent
!= null) {
1530 parent
.children
.add(item
);
1533 if (entry
.hasChildren()) {
1534 item
._expanded
= true;
1535 item
._hasChildren
= true;
1536 for (ITimeGraphEntry child
: entry
.getChildren()) {
1537 refreshData(itemList
, item
, level
+ 1, child
);
1542 public void updateExpandedItems() {
1543 List
<TimeGraphItem
> expandedItemList
= new ArrayList
<TimeGraphItem
>();
1544 for (int i
= 0; i
< _traces
.length
; i
++) {
1545 ITimeGraphEntry entry
= _traces
[i
];
1546 TimeGraphItem item
= findItem(entry
);
1547 refreshExpanded(expandedItemList
, item
);
1549 _expandedItems
= expandedItemList
.toArray(new TimeGraphItem
[0]);
1552 private void refreshExpanded(List
<TimeGraphItem
> expandedItemList
, TimeGraphItem item
) {
1553 expandedItemList
.add(item
);
1554 if (item
._hasChildren
&& item
._expanded
) {
1555 for (TimeGraphItem child
: item
.children
) {
1556 refreshExpanded(expandedItemList
, child
);
1561 public void expandItem(int idx
) {
1562 if (idx
< 0 || idx
>= _expandedItems
.length
)
1564 TimeGraphItem item
= (TimeGraphItem
) _expandedItems
[idx
];
1565 if (item
._hasChildren
&& !item
._expanded
) {
1566 item
._expanded
= true;
1567 updateExpandedItems();
1571 public void refreshData(ITimeGraphEntry traces
[]) {
1572 if (traces
== null || traces
.length
== 0) {
1574 } else if (traceFilter
== null || traces
.length
!= traceFilter
.length
) {
1575 traceFilter
= new boolean[traces
.length
];
1576 java
.util
.Arrays
.fill(traceFilter
, true);
1583 public Object
[] getTraces() {
1587 public boolean[] getTraceFilter() {
1591 public Vector
<ITimeGraphEntry
> getFilteredOut() {