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 * Alexander N. Alexeev, Intel - Add monitors statistics support
12 * Alvaro Sanchez-Leon - Adapted for TMF
13 * Patrick Tasse - Refactoring
15 *****************************************************************************/
17 package org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
;
19 import java
.util
.ArrayList
;
21 import org
.eclipse
.jface
.viewers
.ISelectionProvider
;
22 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.dialogs
.TimeGraphLegend
;
23 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
24 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
25 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.ITimeDataProvider
;
26 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphControl
;
27 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphScale
;
28 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphTooltipHandler
;
29 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphColorScheme
;
30 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
;
31 import org
.eclipse
.swt
.SWT
;
32 import org
.eclipse
.swt
.events
.ControlAdapter
;
33 import org
.eclipse
.swt
.events
.ControlEvent
;
34 import org
.eclipse
.swt
.events
.SelectionAdapter
;
35 import org
.eclipse
.swt
.events
.SelectionEvent
;
36 import org
.eclipse
.swt
.events
.SelectionListener
;
37 import org
.eclipse
.swt
.graphics
.Rectangle
;
38 import org
.eclipse
.swt
.layout
.FillLayout
;
39 import org
.eclipse
.swt
.layout
.GridData
;
40 import org
.eclipse
.swt
.layout
.GridLayout
;
41 import org
.eclipse
.swt
.widgets
.Composite
;
42 import org
.eclipse
.swt
.widgets
.Control
;
43 import org
.eclipse
.swt
.widgets
.ScrollBar
;
44 import org
.eclipse
.swt
.widgets
.Slider
;
46 public class TimeGraphViewer
implements ITimeDataProvider
, SelectionListener
{
49 private long _minTimeInterval
;
50 private long _selectedTime
;
51 private ITimeGraphEntry _selectedEntry
;
52 private long _beginTime
;
53 private long _endTime
;
58 private long _time0_extSynch
= 0;
59 private long _time1_extSynch
= 0;
60 private boolean _timeRangeFixed
;
61 private int _nameWidthPref
= 200;
62 private int _minNameWidth
= 6;
63 private int _nameWidth
;
64 private Composite _dataViewer
;
66 private TimeGraphControl _stateCtrl
;
67 private TimeGraphScale _timeScaleCtrl
;
68 private Slider _verticalScrollBar
;
69 private TimeGraphTooltipHandler _threadTip
;
70 private TimeGraphColorScheme _colors
;
71 private ITimeGraphProvider fTimeGraphProvider
;
73 ArrayList
<ITimeGraphSelectionListener
> fSelectionListeners
= new ArrayList
<ITimeGraphSelectionListener
>();
74 ArrayList
<ITimeGraphTimeListener
> fTimeListeners
= new ArrayList
<ITimeGraphTimeListener
>();
75 ArrayList
<ITimeGraphRangeListener
> fRangeListeners
= new ArrayList
<ITimeGraphRangeListener
>();
77 // Calender Time format, using Epoch reference or Relative time
79 private boolean calendarTimeFormat
= false;
80 private int borderWidth
= 4;
81 private int timeScaleHeight
= 22;
84 public TimeGraphViewer(Composite parent
, int style
) {
85 createDataViewer(parent
, style
);
89 * Sets the timegraph provider used by this timegraph viewer.
91 * @param timeGraphProvider the timegraph provider
93 public void setTimeGraphProvider(ITimeGraphProvider timeGraphProvider
) {
94 fTimeGraphProvider
= timeGraphProvider
;
95 _stateCtrl
.setTimeGraphProvider(timeGraphProvider
);
96 _threadTip
= new TimeGraphTooltipHandler(_dataViewer
.getShell(), fTimeGraphProvider
, this);
97 _threadTip
.activateHoverHelp(_stateCtrl
);
100 public void setInput(ITimeGraphEntry
[] input
) {
101 if (null != _stateCtrl
) {
103 input
= new ITimeGraphEntry
[0];
106 _verticalScrollBar
.setEnabled(true);
108 refreshAllData(input
);
112 public void refresh() {
114 _timeScaleCtrl
.redraw();
117 public void controlMoved(ControlEvent e
) {
120 public void controlResized(ControlEvent e
) {
124 // called from the display order in the API
125 public void modelUpdate(ITimeGraphEntry
[] traces
, long start
,
126 long end
, boolean updateTimeBounds
) {
127 if (null != _stateCtrl
) {
129 updateInternalData(traces
, start
, end
);
130 if (updateTimeBounds
) {
131 _timeRangeFixed
= true;
132 // set window to match limits
133 setStartFinishTime(_time0_
, _time1_
);
136 _timeScaleCtrl
.redraw();
141 public void selectionChanged() {
144 protected String
getViewTypeStr() {
145 return "viewoption.threads"; //$NON-NLS-1$
148 int getMarginWidth(int idx
) {
152 int getMarginHeight(int idx
) {
157 _minTimeInterval
= 1;
159 _nameWidth
= Utils
.loadIntOption(getPreferenceString("namewidth"), //$NON-NLS-1$
160 _nameWidthPref
, _minNameWidth
, 1000);
164 Utils
.saveIntOption(getPreferenceString("namewidth"), _nameWidth
); //$NON-NLS-1$
167 protected Control
createDataViewer(Composite parent
, int style
) {
169 _colors
= new TimeGraphColorScheme();
170 _dataViewer
= new Composite(parent
, style
);
171 GridLayout gl
= new GridLayout(2, false);
172 gl
.marginHeight
= borderWidth
;
174 gl
.verticalSpacing
= 0;
175 gl
.horizontalSpacing
= 0;
176 _dataViewer
.setLayout(gl
);
178 _timeScaleCtrl
= new TimeGraphScale(_dataViewer
, _colors
);
179 _timeScaleCtrl
.setTimeProvider(this);
180 _timeScaleCtrl
.setLayoutData(new GridData(SWT
.FILL
, SWT
.DEFAULT
, true, false));
181 _timeScaleCtrl
.setHeight(timeScaleHeight
);
183 _verticalScrollBar
= new Slider(_dataViewer
, SWT
.VERTICAL
| SWT
.NO_FOCUS
);
184 _verticalScrollBar
.setLayoutData(new GridData(SWT
.DEFAULT
, SWT
.FILL
, false, true, 1, 2));
185 _verticalScrollBar
.addSelectionListener(new SelectionAdapter() {
187 public void widgetSelected(SelectionEvent e
) {
188 setTopIndex(_verticalScrollBar
.getSelection());
191 _verticalScrollBar
.setEnabled(false);
193 _stateCtrl
= createTimeGraphControl();
195 _stateCtrl
.setTimeProvider(this);
196 _stateCtrl
.addSelectionListener(this);
197 _stateCtrl
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true, 1, 2));
199 Composite filler
= new Composite(_dataViewer
, SWT
.NONE
);
200 GridData gd
= new GridData(SWT
.DEFAULT
, SWT
.DEFAULT
, false, false);
201 gd
.heightHint
= _stateCtrl
.getHorizontalBar().getSize().y
;
202 filler
.setLayoutData(gd
);
203 filler
.setLayout(new FillLayout());
205 _stateCtrl
.addControlListener(new ControlAdapter() {
207 public void controlResized(ControlEvent event
) {
212 _dataViewer
.update();
213 adjustVerticalScrollBar();
217 public void dispose() {
219 _stateCtrl
.dispose();
220 _dataViewer
.dispose();
224 protected TimeGraphControl
createTimeGraphControl() {
225 return new TimeGraphControl(_dataViewer
, _colors
);
228 public void resizeControls() {
229 Rectangle r
= _dataViewer
.getClientArea();
234 if (_nameWidth
> width
- _minNameWidth
)
235 _nameWidth
= width
- _minNameWidth
;
236 if (_nameWidth
< _minNameWidth
)
237 _nameWidth
= _minNameWidth
;
238 adjustVerticalScrollBar();
241 /** Tries to set most convenient time range for display. */
242 void setTimeRange(Object traces
[]) {
246 for (int i
= 0; i
< traces
.length
; i
++) {
247 ITimeGraphEntry entry
= (ITimeGraphEntry
) traces
[i
];
248 if (entry
.getStopTime() >= entry
.getStartTime() && entry
.getStopTime() > 0) {
249 if (_beginTime
< 0 || entry
.getStartTime() < _beginTime
) {
250 _beginTime
= entry
.getStartTime();
252 if (entry
.getStopTime() > _endTime
) {
253 _endTime
= entry
.getStopTime();
257 * This is not needed if entry startTime and stopTime are properly set!
258 List<TimeEvent> list = entry.getTraceEvents();
259 int len = list.size();
261 event = (ITimeEvent) list.get(0);
262 if (_beginTime < 0 || event.getTime() < _beginTime) {
263 _beginTime = event.getTime();
265 event = (ITimeEvent) list.get(list.size() - 1);
266 long eventEndTime = event.getTime() + (event.getDuration() > 0 ? event.getDuration() : 0);
267 if (eventEndTime > _endTime) {
268 _endTime = eventEndTime;
278 void setTimeBounds() {
279 //_time0_ = _beginTime - (long) ((_endTime - _beginTime) * 0.02);
280 _time0_
= _beginTime
;
283 // _time1_ = _time0_ + (_endTime - _time0_) * 1.05;
285 // _time0_ = Math.floor(_time0_);
286 // _time1_ = Math.ceil(_time1_);
287 if (!_timeRangeFixed
) {
291 if (_time1
- _time0
< _minTimeInterval
) {
292 _time1
= _time0
+ _minTimeInterval
;
301 void updateInternalData(ITimeGraphEntry
[] traces
, long start
, long end
) {
303 traces
= new ITimeGraphEntry
[0];
304 if ((start
== 0 && end
== 0) || start
< 0 || end
< 0) {
305 // Start and end time are unspecified and need to be determined from
306 // individual processes
307 setTimeRange(traces
);
313 refreshAllData(traces
);
319 private void refreshAllData(ITimeGraphEntry
[] traces
) {
321 if (_selectedTime
< _beginTime
) {
322 _selectedTime
= _beginTime
;
323 } else if (_selectedTime
> _endTime
) {
324 _selectedTime
= _endTime
;
326 _stateCtrl
.refreshData(traces
);
327 adjustVerticalScrollBar();
330 public void setFocus() {
331 if (null != _stateCtrl
)
332 _stateCtrl
.setFocus();
335 public boolean isInFocus() {
336 return _stateCtrl
.isInFocus();
339 public ITimeGraphEntry
getSelection() {
340 return _stateCtrl
.getSelectedTrace();
343 public int getSelectionIndex() {
344 return _stateCtrl
.getSelectedIndex();
348 public long getTime0() {
353 public long getTime1() {
358 public long getMinTimeInterval() {
359 return _minTimeInterval
;
363 public int getNameSpace() {
368 public void setNameSpace(int width
) {
370 width
= _stateCtrl
.getClientArea().width
;
371 if (_nameWidth
> width
- 6)
372 _nameWidth
= width
- 6;
375 _stateCtrl
.adjustScrolls();
377 _timeScaleCtrl
.redraw();
381 public int getTimeSpace() {
382 int w
= _stateCtrl
.getClientArea().width
;
383 return w
- _nameWidth
;
387 public long getSelectedTime() {
388 return _selectedTime
;
392 public long getBeginTime() {
397 public long getEndTime() {
402 public long getMaxTime() {
407 public long getMinTime() {
415 * org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.widgets.ITimeDataProvider
416 * #setStartFinishTimeNotify(long, long)
419 public void setStartFinishTimeNotify(long time0
, long time1
) {
420 setStartFinishTime(time0
, time1
);
421 notifyRangeListeners(time0
, time1
);
426 * @see org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.widgets.ITimeDataProvider#notifyStartFinishTime()
429 public void notifyStartFinishTime() {
430 notifyRangeListeners(_time0
, _time1
);
437 * org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.widgets.ITimeDataProvider
438 * #setStartFinishTime(long, long)
441 public void setStartFinishTime(long time0
, long time1
) {
443 if (_time0
< _time0_
)
445 if (_time0
> _time1_
)
448 if (_time1
< _time0_
)
450 if (_time1
> _time1_
)
452 if (_time1
- _time0
< _minTimeInterval
)
453 _time1
= _time0
+ _minTimeInterval
;
454 _timeRangeFixed
= true;
455 _stateCtrl
.adjustScrolls();
457 _timeScaleCtrl
.redraw();
460 public void setTimeBounds(long beginTime
, long endTime
) {
461 _beginTime
= beginTime
;
465 _stateCtrl
.adjustScrolls();
469 public void resetStartFinishTime() {
470 setStartFinishTimeNotify(_time0_
, _time1_
);
471 _timeRangeFixed
= false;
475 public void setSelectedTimeInt(long time
, boolean ensureVisible
) {
476 // Trace.debug("currentTime:" + _selectedTime + " new time:" + time);
477 if (time
> _endTime
) {
481 if (time
< _beginTime
) {
488 double timeSpace
= (_time1
- _time0
) * .02;
489 double timeMid
= (_time1
- _time0
) * .1;
490 if (time
< _time0
+ timeSpace
) {
491 long dt
= (long) (_time0
- time
+ timeMid
);
494 } else if (time
> _time1
- timeSpace
) {
495 long dt
= (long) (time
- _time1
+ timeMid
);
499 if (_time0
< _time0_
) {
500 _time1
= Math
.min(_time1_
, _time1
+ (_time0_
- _time0
));
502 } else if (_time1
> _time1_
) {
503 _time0
= Math
.max(_time0_
, _time0
- (_time1
- _time1_
));
507 if (_time1
- _time0
< _minTimeInterval
) {
508 _time1
= _time0
+ _minTimeInterval
;
510 _stateCtrl
.adjustScrolls();
512 _timeScaleCtrl
.redraw();
513 if (time0
!= _time0
|| time1
!= _time1
) {
514 notifyRangeListeners(_time0
, _time1
);
516 if (time
!= _selectedTime
) {
517 _selectedTime
= time
;
518 notifyTimeListeners(_selectedTime
);
523 public void widgetDefaultSelected(SelectionEvent e
) {
524 if (_selectedEntry
!= getSelection()) {
525 _selectedEntry
= getSelection();
526 notifySelectionListeners(_selectedEntry
);
531 public void widgetSelected(SelectionEvent e
) {
532 if (_selectedEntry
!= getSelection()) {
533 _selectedEntry
= getSelection();
534 notifySelectionListeners(_selectedEntry
);
538 public void selectNextEvent() {
539 _stateCtrl
.selectNextEvent();
540 adjustVerticalScrollBar();
543 public void selectPrevEvent() {
544 _stateCtrl
.selectPrevEvent();
545 adjustVerticalScrollBar();
548 public void selectNextTrace() {
549 _stateCtrl
.selectNextTrace();
550 adjustVerticalScrollBar();
553 public void selectPrevTrace() {
554 _stateCtrl
.selectPrevTrace();
555 adjustVerticalScrollBar();
558 public void showLegend() {
559 if (_dataViewer
== null || _dataViewer
.isDisposed())
562 TimeGraphLegend
.open(_dataViewer
.getShell(), fTimeGraphProvider
);
565 public void zoomIn() {
569 public void zoomOut() {
570 _stateCtrl
.zoomOut();
573 private String
getPreferenceString(String string
) {
574 return getViewTypeStr() + "." + string
; //$NON-NLS-1$
577 public void addSelectionListener(ITimeGraphSelectionListener listener
) {
578 fSelectionListeners
.add(listener
);
581 public void removeSelectionListener(ITimeGraphSelectionListener listener
) {
582 fSelectionListeners
.remove(listener
);
585 private void notifySelectionListeners(ITimeGraphEntry selection
) {
586 TimeGraphSelectionEvent event
= new TimeGraphSelectionEvent(this, selection
);
588 for (ITimeGraphSelectionListener listener
: fSelectionListeners
) {
589 listener
.selectionChanged(event
);
593 public void addTimeListener(ITimeGraphTimeListener listener
) {
594 fTimeListeners
.add(listener
);
597 public void removeTimeListener(ITimeGraphTimeListener listener
) {
598 fTimeListeners
.remove(listener
);
601 private void notifyTimeListeners(long time
) {
602 TimeGraphTimeEvent event
= new TimeGraphTimeEvent(this, time
);
604 for (ITimeGraphTimeListener listener
: fTimeListeners
) {
605 listener
.timeSelected(event
);
609 public void addRangeListener(ITimeGraphRangeListener listener
) {
610 fRangeListeners
.add(listener
);
613 public void removeRangeListener(ITimeGraphRangeListener listener
) {
614 fRangeListeners
.remove(listener
);
617 private void notifyRangeListeners(long startTime
, long endTime
) {
618 // Check if the time has actually changed from last notification
619 if (startTime
!= _time0_extSynch
|| endTime
!= _time1_extSynch
) {
620 // Notify Time Scale Selection Listeners
621 TimeGraphRangeUpdateEvent event
= new TimeGraphRangeUpdateEvent(this, startTime
, endTime
);
623 for (ITimeGraphRangeListener listener
: fRangeListeners
) {
624 listener
.timeRangeUpdated(event
);
627 // update external synch timers
628 updateExtSynchTimers();
632 public void setSelectedTime(long time
, boolean ensureVisible
, Object source
) {
633 if (this == source
) {
637 setSelectedTimeInt(time
, ensureVisible
);
640 public void setSelectedEvent(ITimeEvent event
, Object source
) {
641 if (event
== null || source
== this) {
644 ITimeGraphEntry trace
= event
.getEntry();
646 _stateCtrl
.selectItem(trace
, false);
649 setSelectedTimeInt(event
.getTime(), true);
650 adjustVerticalScrollBar();
653 public void setSelectedTraceTime(ITimeGraphEntry trace
, long time
, Object source
) {
654 if (trace
== null || source
== this) {
659 _stateCtrl
.selectItem(trace
, false);
662 setSelectedTimeInt(time
, true);
665 public void setSelection(ITimeGraphEntry trace
) {
666 _stateCtrl
.selectItem(trace
, false);
667 adjustVerticalScrollBar();
670 public void setSelectVisTimeWindow(long time0
, long time1
, Object source
) {
671 if (source
== this) {
675 setStartFinishTime(time0
, time1
);
677 // update notification time values since we are now in synch with the
678 // external application
679 updateExtSynchTimers();
683 * update the cache timers used to identify the need to send a time window
684 * update to external registered listeners
686 private void updateExtSynchTimers() {
687 // last time notification cache
688 _time0_extSynch
= _time0
;
689 _time1_extSynch
= _time1
;
692 public void setTimeCalendarFormat(boolean toAbsoluteCaltime
) {
693 calendarTimeFormat
= toAbsoluteCaltime
;
697 public boolean isCalendarFormat() {
698 return calendarTimeFormat
;
701 public int getBorderWidth() {
705 public void setBorderWidth(int borderWidth
) {
706 if (borderWidth
> -1) {
707 this.borderWidth
= borderWidth
;
708 GridLayout gl
= (GridLayout
)_dataViewer
.getLayout();
709 gl
.marginHeight
= borderWidth
;
713 public int getHeaderHeight() {
714 return timeScaleHeight
;
717 public void setHeaderHeight(int headerHeight
) {
718 if (headerHeight
> -1) {
719 this.timeScaleHeight
= headerHeight
;
720 _timeScaleCtrl
.setHeight(headerHeight
);
724 public int getItemHeight() {
725 if (_stateCtrl
!= null) {
726 return _stateCtrl
.getItemHeight();
731 public void setItemHeight(int rowHeight
) {
732 if (_stateCtrl
!= null) {
733 _stateCtrl
.setItemHeight(rowHeight
);
737 public void setMinimumItemWidth(int width
) {
738 if (_stateCtrl
!= null) {
739 _stateCtrl
.setMinimumItemWidth(width
);
743 public void setNameWidthPref(int width
) {
744 _nameWidthPref
= width
;
751 public int getNameWidthPref(int width
) {
752 return _nameWidthPref
;
756 * Returns the primary control associated with this viewer.
758 * @return the SWT control which displays this viewer's content
760 public Control
getControl() {
765 * Returns the time graph control associated with this viewer.
767 * @return the time graph control
769 TimeGraphControl
getTimeGraphControl() {
774 * Get the selection provider
776 * @return the selection provider
778 public ISelectionProvider
getSelectionProvider() {
786 * org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.ITimeAnalysisViewer
787 * #waitCursor(boolean)
789 public void waitCursor(boolean waitInd
) {
790 _stateCtrl
.waitCursor(waitInd
);
793 public ScrollBar
getHorizontalBar() {
794 return _stateCtrl
.getHorizontalBar();
797 public Slider
getVerticalBar() {
798 return _verticalScrollBar
;
801 public void setTopIndex(int index
) {
802 _stateCtrl
.setTopIndex(index
);
803 adjustVerticalScrollBar();
806 public int getTopIndex() {
807 return _stateCtrl
.getTopIndex();
810 public void setExpandedState(ITimeGraphEntry entry
, boolean expanded
) {
811 _stateCtrl
.setExpandedState(entry
, expanded
);
812 adjustVerticalScrollBar();
815 public void addTreeListener(ITimeGraphTreeListener listener
) {
816 _stateCtrl
.addTreeListener(listener
);
819 public void removeTreeListener(ITimeGraphTreeListener listener
) {
820 _stateCtrl
.removeTreeListener(listener
);
823 private void adjustVerticalScrollBar() {
824 int topIndex
= _stateCtrl
.getTopIndex();
825 int countPerPage
= _stateCtrl
.countPerPage();
826 int expandedElementCount
= _stateCtrl
.getExpandedElementCount();
827 if (topIndex
+ countPerPage
> expandedElementCount
) {
828 _stateCtrl
.setTopIndex(Math
.max(0, expandedElementCount
- countPerPage
));
831 int selection
= _stateCtrl
.getTopIndex();
833 int max
= Math
.max(1, expandedElementCount
- 1);
834 int thumb
= Math
.min(max
, Math
.max(1, countPerPage
- 1));
836 int pageIncrement
= Math
.max(1, countPerPage
);
837 _verticalScrollBar
.setValues(selection
, min
, max
, thumb
, increment
, pageIncrement
);