1 /*******************************************************************************
2 * Copyright (c) 2009 2010 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Francois Chouinard - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.lttng
.ui
.views
.timeframe
;
15 import org
.eclipse
.linuxtools
.lttng
.core
.event
.LttngEvent
;
16 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimeRange
;
17 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimestamp
;
18 import org
.eclipse
.linuxtools
.tmf
.core
.experiment
.TmfExperiment
;
19 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentSelectedSignal
;
20 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentUpdatedSignal
;
21 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
22 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
24 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
25 import org
.eclipse
.swt
.SWT
;
26 import org
.eclipse
.swt
.layout
.GridData
;
27 import org
.eclipse
.swt
.layout
.GridLayout
;
28 import org
.eclipse
.swt
.widgets
.Composite
;
29 import org
.eclipse
.swt
.widgets
.Event
;
30 import org
.eclipse
.swt
.widgets
.Listener
;
31 import org
.eclipse
.swt
.widgets
.Slider
;
34 * <b><u>TimeFrameView</u></b>
36 * The TimeFrameView provides a set of spinners to monitor and set the start time, end time, the current time interval
37 * and current time of the trace set at the nanosecond level.
39 * It ensures that the following relations are always true:
41 * <li>[ startTime >= start time of the trace ]
42 * <li>[ endTime <= end time of the trace ]
43 * <li>[ startTime <= currentTime <= endTime ]
44 * <li>[ interval == (endTime - startTime) ]</li>
46 * It provides a slider to rapidly set the current time within the time range (i.e. between startTime and endTime).
48 * Finally, it allows modification of the time range and the current time. This triggers notifications to the other
51 * FIXME: The slider is very jumpy due to the large number of async updates FIXME: Revisit the control flow between
52 * View, Spinners and Slider
55 public class TimeFrameView
extends TmfView
{
57 public static final String ID
= "org.eclipse.linuxtools.lttng.ui.views.timeframe"; //$NON-NLS-1$
59 // ------------------------------------------------------------------------
61 // ------------------------------------------------------------------------
63 // The event log timestamp characteristics
64 private TmfTimestamp fTraceStartTime
= new TmfTimestamp();
65 private TmfTimestamp fTraceEndTime
= new TmfTimestamp();
67 private TmfTimestamp fCurrentTime
= new TmfTimestamp();
69 private TmfTimeRange fTraceTimeRange
= new TmfTimeRange(fTraceStartTime
, fTraceEndTime
);
70 private TmfTimeRange fTraceSpan
= new TmfTimeRange(fTraceStartTime
, fTraceEndTime
);
71 private byte fScale
= 0;
74 private static final String START_TIME_LABEL
= Messages
.TimeFrameView_WindowStartTime
;
75 private static final String END_TIME_LABEL
= Messages
.TimeFrameView_WindowEndTime
;
76 private static final String TIME_RANGE_LABEL
= Messages
.TimeFrameView_WindowRange
;
77 private static final String CURRENT_TIME_LABEL
= Messages
.TimeFrameView_CurrentTime
;
79 private static final int SLIDER_RANGE
= 10000;
81 private SpinnerGroup fStartGroup
;
82 private SpinnerGroup fEndGroup
;
83 private SpinnerGroup fRangeGroup
;
84 private SpinnerGroup fCurrentGroup
;
87 private Slider fSlider
;
89 // The current experiment
90 TmfExperiment
<LttngEvent
> fExperiment
= null;
92 // notify external listeners may not be needed if the update originated externally
93 private boolean fupdateExternalListeners
= true;
95 // ------------------------------------------------------------------------
97 // ------------------------------------------------------------------------
102 public TimeFrameView() {
103 super("TimeFrameView"); //$NON-NLS-1$
109 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets .Composite)
112 public void createPartControl(Composite parent
) {
114 // Set the view layout
115 GridLayout layout
= new GridLayout(4, true);
116 parent
.setLayout(layout
);
118 fStartGroup
= new SpinnerGroup(this, parent
, START_TIME_LABEL
, fTraceTimeRange
, fTraceStartTime
);
119 fEndGroup
= new SpinnerGroup(this, parent
, END_TIME_LABEL
, fTraceTimeRange
, fTraceEndTime
);
120 fRangeGroup
= new SpinnerGroup(this, parent
, TIME_RANGE_LABEL
, fTraceTimeRange
, fTraceEndTime
);
121 fCurrentGroup
= new SpinnerGroup(this, parent
, CURRENT_TIME_LABEL
, fTraceTimeRange
, fTraceStartTime
);
124 createSlider(parent
);
130 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
133 public void setFocus() {
134 // TODO Auto-generated method stub
137 // ------------------------------------------------------------------------
139 // ------------------------------------------------------------------------
142 * One of the spinners has been updated. Synchronize the other widgets.
144 public void synchTimeFrameWidgets(SpinnerGroup trigger
) {
145 boolean trangeUpdated
= false;
148 TmfTimestamp startTime
= fStartGroup
.getCurrentTime();
149 TmfTimestamp endTime
= fEndGroup
.getCurrentTime();
150 TmfTimestamp timeRange
= fRangeGroup
.getCurrentTime();
151 TmfTimestamp currentTime
= fCurrentGroup
.getCurrentTime();
153 // If startTime was set beyond endTime, adjust endTime and interval
154 if (trigger
== fStartGroup
) {
155 if (startTime
.compareTo(endTime
, false) > 0) {
157 trangeUpdated
= true;
161 // If endTime was set beyond startTime, adjust startTime and interval
162 if (trigger
== fEndGroup
) {
163 if (endTime
.compareTo(startTime
, false) < 0) {
165 trangeUpdated
= true;
169 // If timeRange was set, adjust endTime
170 if (trigger
== fRangeGroup
) {
171 long start
= startTime
.getValue();
172 long span
= timeRange
.getValue();
173 TmfTimestamp ts
= new TmfTimestamp(start
+ span
, startTime
.getScale(), 0);
174 if (ts
.compareTo(fTraceEndTime
, false) > 0) {
175 ts
= fTraceEndTime
.synchronize(fTraceEndTime
.getValue(), startTime
.getScale());
178 trangeUpdated
= true;
181 // Compute the new time range
182 TmfTimeRange subrange
= new TmfTimeRange(startTime
, endTime
);
183 byte scale
= startTime
.getScale();
184 TmfTimestamp interval
= new TmfTimestamp(startTime
.getAdjustment(endTime
, scale
), scale
, 0);
186 // Update the spinner groups
187 fStartGroup
.setContent(fTraceTimeRange
, startTime
);
188 fEndGroup
.setContent(fTraceTimeRange
, endTime
);
189 fRangeGroup
.setContent(fTraceSpan
, interval
);
190 fCurrentGroup
.setContent(subrange
, currentTime
);
192 updateSlider(subrange
, currentTime
);
193 // Notify other views, only if the update originated from this view
194 if (fupdateExternalListeners
) {
195 if (!fCurrentTime
.equals(currentTime
)) {
196 fCurrentTime
= currentTime
;
197 broadcast(new TmfTimeSynchSignal(this, currentTime
));
200 // Notify the views if the time range has been impacted
202 TmfTimeRange trange
= new TmfTimeRange(startTime
, endTime
);
203 broadcast(new TmfRangeSynchSignal(this, trange
, currentTime
));
208 // ------------------------------------------------------------------------
210 // ------------------------------------------------------------------------
215 private void createSlider(Composite parent
) {
216 fSlider
= new Slider(parent
, SWT
.SMOOTH
| SWT
.FILL
);
217 fSlider
.setMinimum(0);
218 fSlider
.setMaximum(SLIDER_RANGE
+ fSlider
.getThumb());
219 fSlider
.setIncrement(SLIDER_RANGE
/ 100);
220 fSlider
.setPageIncrement(SLIDER_RANGE
/ 10);
221 fSlider
.setSelection(0);
223 GridData gridData
= new GridData(SWT
.LEFT
, SWT
.TOP
, true, false);
224 gridData
.horizontalAlignment
= SWT
.FILL
;
225 gridData
.horizontalSpan
= 4;
226 fSlider
.setLayoutData(gridData
);
228 fSlider
.addListener(SWT
.Selection
, new Listener() {
230 public void handleEvent(Event event
) {
231 int ratio
= fSlider
.getSelection();
232 TmfTimestamp span
= fCurrentGroup
.getSpan();
233 long value
= span
.getValue() * ratio
/ SLIDER_RANGE
;
234 TmfTimestamp start
= fCurrentGroup
.getStartTime();
235 TmfTimestamp current
= new TmfTimestamp(start
.getValue() + value
, start
.getScale(), 0);
236 fCurrentGroup
.setValue(current
);
246 private void updateSlider(TmfTimeRange range
, TmfTimestamp timestamp
) {
248 // Ignore update if disposed
249 if (fSlider
.isDisposed())
252 // Determine the new relative position
253 byte scale
= range
.getEndTime().getScale();
254 long total
= range
.getStartTime().getAdjustment(range
.getEndTime(), scale
);
255 long relative
= range
.getStartTime().getAdjustment(timestamp
, scale
);
257 // Set the slider value
258 final long position
= (total
> 0) ?
(relative
* SLIDER_RANGE
/ total
) : 0;
260 // Update the slider on the UI thread
261 long current
= fSlider
.getSelection();
262 if (position
!= current
) {
263 fSlider
.getDisplay().asyncExec(new Runnable() {
266 fSlider
.setSelection((int) position
);
275 * @see java.lang.Object#toString()
278 @SuppressWarnings("nls")
279 public String
toString() {
280 return "[TimeFrameView]";
283 // ------------------------------------------------------------------------
285 // ------------------------------------------------------------------------
290 @SuppressWarnings("unchecked")
292 public void experimentSelected(TmfExperimentSelectedSignal
<LttngEvent
> signal
) {
294 // Update the trace reference
295 fExperiment
= (TmfExperiment
<LttngEvent
>) signal
.getExperiment();
297 // Update the time frame
298 fTraceTimeRange
= fExperiment
.getTimeRange();
299 fTraceStartTime
= fTraceTimeRange
.getStartTime();
300 fTraceEndTime
= fTraceTimeRange
.getEndTime();
301 fScale
= fTraceStartTime
.getScale();
303 // Update the widgets
304 fStartGroup
.setContent(fTraceTimeRange
, fTraceStartTime
);
305 fEndGroup
.setContent(fTraceTimeRange
, fTraceEndTime
);
306 fCurrentGroup
.setContent(fTraceTimeRange
, fTraceStartTime
);
308 fCurrentTime
= fTraceStartTime
;
310 TmfTimestamp delta
= new TmfTimestamp(fTraceStartTime
.getAdjustment(fTraceEndTime
, fScale
), fScale
, 0);
311 fTraceSpan
= new TmfTimeRange(new TmfTimestamp(0, fScale
, 0), delta
);
312 // fRangeGroup.setContent(fTraceSpan, delta);
313 TmfTimestamp start
= new TmfTimestamp(1, (byte) -1, 0);
314 fRangeGroup
.setContent(fTraceSpan
, start
);
321 public void experimentUpdated(TmfExperimentUpdatedSignal signal
) {
322 if (signal
.getExperiment() != fExperiment
) {
326 // Update the time frame
327 // fTraceTimeRange = signal.getTrace().getTimeRange();
328 fTraceTimeRange
= signal
.getExperiment().getTimeRange();
329 fTraceStartTime
= fTraceTimeRange
.getStartTime();
330 fTraceEndTime
= fTraceTimeRange
.getEndTime();
331 fScale
= fTraceStartTime
.getScale();
333 // Update the widgets
334 fStartGroup
.setContent(fTraceTimeRange
, fStartGroup
.getCurrentTime());
335 fEndGroup
.setContent(fTraceTimeRange
, fTraceEndTime
);
336 fCurrentGroup
.setContent(fTraceTimeRange
, fCurrentGroup
.getCurrentTime());
338 TmfTimestamp delta
= new TmfTimestamp(fTraceStartTime
.getAdjustment(fTraceEndTime
, fScale
), fScale
, 0);
339 fTraceSpan
= new TmfTimeRange(new TmfTimestamp(0, fScale
, 0), delta
);
340 fRangeGroup
.setContent(fTraceSpan
, delta
);
347 public void currentTimeRangeUpdated(TmfRangeSynchSignal signal
) {
348 if (signal
.getSource() != this) {
349 // Update the time frame
350 TmfTimeRange selTimeRange
= signal
.getCurrentRange();
351 TmfTimestamp selStart
= selTimeRange
.getStartTime().synchronize(0, fScale
);
352 TmfTimestamp selEnd
= selTimeRange
.getEndTime().synchronize(0, fScale
);
354 fupdateExternalListeners
= false;
355 // Update the widgets and prevent broadcast notifications to
356 // the views which have been notified already.
358 fStartGroup
.setContent(fTraceTimeRange
, selStart
);
359 fEndGroup
.setContent(fTraceTimeRange
, selEnd
);
361 TmfTimestamp delta
= new TmfTimestamp(selStart
.getAdjustment(selEnd
, fScale
), fScale
, 0);
363 fRangeGroup
.setContent(fTraceSpan
, delta
);
366 // restore the external notification flag
367 fupdateExternalListeners
= true;
376 public void currentTimeUpdated(TmfTimeSynchSignal signal
) {
377 if (signal
.getSource() != this) {
378 // prevent loop to external notifications
379 fupdateExternalListeners
= false;
380 fCurrentTime
= signal
.getCurrentTime().synchronize(0, fStartGroup
.getCurrentTime().getScale());
381 if (fStartGroup
.getCurrentTime().compareTo(fCurrentTime
, false) > 0) {
382 fStartGroup
.setContent(new TmfTimeRange(fCurrentTime
, fEndGroup
.getCurrentTime()), fCurrentTime
);
384 if (fEndGroup
.getCurrentTime().compareTo(fCurrentTime
, false) < 0) {
385 fEndGroup
.setContent(new TmfTimeRange(fStartGroup
.getCurrentTime(), fCurrentTime
), fCurrentTime
);
387 fCurrentGroup
.setContent(null, fCurrentTime
);
388 updateSlider(fCurrentGroup
.getTimeRange(), fCurrentTime
);
390 // Enable external notifications
391 fupdateExternalListeners
= true;