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
.event
.LttngEvent
;
16 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
17 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
18 import org
.eclipse
.linuxtools
.tmf
.experiment
.TmfExperiment
;
19 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfExperimentSelectedSignal
;
20 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfExperimentUpdatedSignal
;
21 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfRangeSynchSignal
;
22 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfSignalHandler
;
23 import org
.eclipse
.linuxtools
.tmf
.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
37 * time, end time, the current time interval and current time of the trace
38 * set at the nanosecond level.
40 * It ensures that the following relations are always true:
42 * <li>[ startTime >= start time of the trace ]
43 * <li>[ endTime <= end time of the trace ]
44 * <li>[ startTime <= currentTime <= endTime ]
45 * <li>[ interval == (endTime - startTime) ]
48 * It provides a slider to rapidly set the current time within the time range
49 * (i.e. between startTime and endTime).
51 * Finally, it allows modification of the time range and the current time. This
52 * triggers notifications to the other LTTng views.
54 * FIXME: The slider is very jumpy due to the large number of async updates
55 * FIXME: Revisit the control flow between View, Spinners and Slider
57 public class TimeFrameView
extends TmfView
{
59 public static final String ID
= "org.eclipse.linuxtools.lttng.ui.views.timeframe";
61 // ========================================================================
63 // ========================================================================
65 // The event log timestamp characteristics
66 private TmfTimestamp fTraceStartTime
= new TmfTimestamp();
67 private TmfTimestamp fTraceEndTime
= new TmfTimestamp();
69 private TmfTimestamp fCurrentTime
= new TmfTimestamp();
71 private TmfTimeRange fTraceTimeRange
= new TmfTimeRange(fTraceStartTime
, fTraceEndTime
);
72 private TmfTimeRange fTraceSpan
= new TmfTimeRange(fTraceStartTime
, fTraceEndTime
);
73 private byte fScale
= 0;
76 private static final String START_TIME_LABEL
= "Window Start Time";
77 private static final String END_TIME_LABEL
= "Window End Time";
78 private static final String TIME_RANGE_LABEL
= "Window Range";
79 private static final String CURRENT_TIME_LABEL
= "Current Time";
81 private static final int SLIDER_RANGE
= 10000;
83 private SpinnerGroup fStartGroup
;
84 private SpinnerGroup fEndGroup
;
85 private SpinnerGroup fRangeGroup
;
86 private SpinnerGroup fCurrentGroup
;
89 private Slider fSlider
;
91 // The current experiment
92 TmfExperiment
<LttngEvent
> fExperiment
= null;
93 // notify external listeners may not be needed if the update originated
95 private boolean fupdateExternalListeners
= true;
101 public TimeFrameView() {
102 super("TimeFrameView");
106 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
109 public void createPartControl(Composite parent
) {
111 // Set the view layout
112 GridLayout layout
= new GridLayout(4, true);
113 parent
.setLayout(layout
);
115 fStartGroup
= new SpinnerGroup(this, parent
, START_TIME_LABEL
, fTraceTimeRange
, fTraceStartTime
);
116 fEndGroup
= new SpinnerGroup(this, parent
, END_TIME_LABEL
, fTraceTimeRange
, fTraceEndTime
);
117 fRangeGroup
= new SpinnerGroup(this, parent
, TIME_RANGE_LABEL
, fTraceTimeRange
, fTraceEndTime
);
118 fCurrentGroup
= new SpinnerGroup(this, parent
, CURRENT_TIME_LABEL
, fTraceTimeRange
, fTraceStartTime
);
121 createSlider(parent
);
125 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
128 public void setFocus() {
129 // TODO Auto-generated method stub
132 // ========================================================================
134 // ========================================================================
137 * One of the spinners has been updated. Synchronize the other widgets.
139 public void synchTimeFrameWidgets(SpinnerGroup trigger
) {
140 boolean trangeUpdated
= false;
143 TmfTimestamp startTime
= fStartGroup
.getCurrentTime();
144 TmfTimestamp endTime
= fEndGroup
.getCurrentTime();
145 TmfTimestamp timeRange
= fRangeGroup
.getCurrentTime();
146 TmfTimestamp currentTime
= fCurrentGroup
.getCurrentTime();
148 // If startTime was set beyond endTime, adjust endTime and interval
149 if (trigger
== fStartGroup
) {
150 if (startTime
.compareTo(endTime
, false) > 0) {
152 trangeUpdated
= true;
156 // If endTime was set beyond startTime, adjust startTime and interval
157 if (trigger
== fEndGroup
) {
158 if (endTime
.compareTo(startTime
, false) < 0) {
160 trangeUpdated
= true;
164 // If timeRange was set, adjust endTime
165 if (trigger
== fRangeGroup
) {
166 long start
= startTime
.getValue();
167 long span
= timeRange
.getValue();
168 TmfTimestamp ts
= new TmfTimestamp(start
+ span
, startTime
.getScale(), 0);
169 if (ts
.compareTo(fTraceEndTime
, false) > 0) {
170 ts
= fTraceEndTime
.synchronize(fTraceEndTime
.getValue(), startTime
.getScale());
173 trangeUpdated
= true;
176 // Compute the new time range
177 TmfTimeRange subrange
= new TmfTimeRange(startTime
, endTime
);
178 byte scale
= startTime
.getScale();
179 TmfTimestamp interval
= new TmfTimestamp(startTime
.getAdjustment(endTime
, scale
), scale
, 0);
181 // Update the spinner groups
182 fStartGroup
.setContent(fTraceTimeRange
, startTime
);
183 fEndGroup
.setContent(fTraceTimeRange
, endTime
);
184 fRangeGroup
.setContent(fTraceSpan
, interval
);
185 fCurrentGroup
.setContent(subrange
, currentTime
);
187 updateSlider(subrange
, currentTime
);
188 // Notify other views, only if the update originated from this view
189 if (fupdateExternalListeners
) {
190 if (!fCurrentTime
.equals(currentTime
)) {
191 fCurrentTime
= currentTime
;
192 broadcast(new TmfTimeSynchSignal(this, currentTime
));
195 // Notify the views if the time range has been impacted
197 TmfTimeRange trange
= new TmfTimeRange(startTime
, endTime
);
198 broadcast(new TmfRangeSynchSignal(this, trange
, currentTime
));
203 // ========================================================================
205 // ========================================================================
210 private void createSlider(Composite parent
) {
211 fSlider
= new Slider(parent
, SWT
.SMOOTH
| SWT
.FILL
);
212 fSlider
.setMinimum(0);
213 fSlider
.setMaximum(SLIDER_RANGE
+ fSlider
.getThumb());
214 fSlider
.setIncrement(SLIDER_RANGE
/ 100);
215 fSlider
.setPageIncrement(SLIDER_RANGE
/ 10);
216 fSlider
.setSelection(0);
218 GridData gridData
= new GridData(SWT
.LEFT
, SWT
.TOP
, true, false);
219 gridData
.horizontalAlignment
= SWT
.FILL
;
220 gridData
.horizontalSpan
= 4;
221 fSlider
.setLayoutData(gridData
);
223 fSlider
.addListener(SWT
.Selection
, new Listener() {
224 public void handleEvent(Event event
) {
225 int ratio
= fSlider
.getSelection();
226 TmfTimestamp span
= fCurrentGroup
.getSpan();
227 long value
= span
.getValue() * ratio
/ SLIDER_RANGE
;
228 TmfTimestamp start
= fCurrentGroup
.getStartTime();
229 TmfTimestamp current
= new TmfTimestamp(start
.getValue() + value
, start
.getScale(), 0);
230 fCurrentGroup
.setValue(current
);
240 private void updateSlider(TmfTimeRange range
, TmfTimestamp timestamp
) {
242 // Determine the new relative position
243 byte scale
= range
.getEndTime().getScale();
244 long total
= range
.getStartTime().getAdjustment(range
.getEndTime(), scale
);
245 long relative
= range
.getStartTime().getAdjustment(timestamp
, scale
);
247 // Set the slider value
248 final long position
= (total
> 0) ?
(relative
* SLIDER_RANGE
/ total
) : 0;
250 // Update the slider on the UI thread
251 long current
= fSlider
.getSelection();
252 if (position
!= current
) {
253 fSlider
.getDisplay().asyncExec(new Runnable() {
255 fSlider
.setSelection((int) position
);
262 * @see java.lang.Object#toString()
265 public String
toString() {
266 return "[TimeFrameView]";
269 // ========================================================================
270 // TMF Signal Handling
271 // ========================================================================
276 @SuppressWarnings("unchecked")
278 public void experimentSelected(TmfExperimentSelectedSignal
<LttngEvent
> signal
) {
280 // Update the trace reference
281 fExperiment
= (TmfExperiment
<LttngEvent
>) signal
.getExperiment();
283 // Update the time frame
284 fTraceTimeRange
= fExperiment
.getTimeRange();
285 fTraceStartTime
= fTraceTimeRange
.getStartTime();
286 fTraceEndTime
= fTraceTimeRange
.getEndTime();
287 fScale
= fTraceStartTime
.getScale();
289 // Update the widgets
290 fStartGroup
.setContent(fTraceTimeRange
, fTraceStartTime
);
291 fEndGroup
.setContent(fTraceTimeRange
, fTraceEndTime
);
292 fCurrentGroup
.setContent(fTraceTimeRange
, fTraceStartTime
);
294 fCurrentTime
= fTraceStartTime
;
296 TmfTimestamp delta
= new TmfTimestamp(fTraceStartTime
.getAdjustment(fTraceEndTime
, fScale
), fScale
, 0);
297 fTraceSpan
= new TmfTimeRange(new TmfTimestamp(0, fScale
, 0), delta
);
298 // fRangeGroup.setContent(fTraceSpan, delta);
299 TmfTimestamp start
= new TmfTimestamp(1, (byte) -1, 0);
300 fRangeGroup
.setContent(fTraceSpan
, start
);
307 public void experimentUpdated(TmfExperimentUpdatedSignal signal
) {
309 // Update the time frame
310 // fTraceTimeRange = signal.getTrace().getTimeRange();
311 fTraceTimeRange
= signal
.getExperiment().getTimeRange();
312 fTraceStartTime
= fTraceTimeRange
.getStartTime();
313 fTraceEndTime
= fTraceTimeRange
.getEndTime();
314 fScale
= fTraceStartTime
.getScale();
316 // Update the widgets
317 fStartGroup
.setContent(fTraceTimeRange
, fStartGroup
.getCurrentTime());
318 fEndGroup
.setContent(fTraceTimeRange
, fTraceEndTime
);
319 fCurrentGroup
.setContent(fTraceTimeRange
, fCurrentGroup
.getCurrentTime());
321 TmfTimestamp delta
= new TmfTimestamp(fTraceStartTime
.getAdjustment(fTraceEndTime
, fScale
), fScale
, 0);
322 fTraceSpan
= new TmfTimeRange(new TmfTimestamp(0, fScale
, 0), delta
);
323 fRangeGroup
.setContent(fTraceSpan
, delta
);
330 public void currentTimeRangeUpdated(TmfRangeSynchSignal signal
) {
331 if (signal
.getSource() != this) {
332 // Update the time frame
333 TmfTimeRange selTimeRange
= signal
.getCurrentRange();
334 TmfTimestamp selStart
= selTimeRange
.getStartTime().synchronize(0,
336 TmfTimestamp selEnd
= selTimeRange
.getEndTime().synchronize(0,
339 fupdateExternalListeners
= false;
340 // Update the widgets and prevent broadcast notifications to
341 // the views which have been notified already.
343 fStartGroup
.setContent(fTraceTimeRange
, selStart
);
344 fEndGroup
.setContent(fTraceTimeRange
, selEnd
);
346 TmfTimestamp delta
= new TmfTimestamp(selStart
.getAdjustment(
347 selEnd
, fScale
), fScale
, 0);
349 fRangeGroup
.setContent(fTraceSpan
, delta
);
352 // restore the external notification flag
353 fupdateExternalListeners
= true;
362 public void currentTimeUpdated(TmfTimeSynchSignal signal
) {
363 if (signal
.getSource() != this) {
364 // prevent loop to external notifications
365 fupdateExternalListeners
= false;
366 fCurrentTime
= signal
.getCurrentTime().synchronize(0, fStartGroup
.getCurrentTime().getScale());
367 if (fStartGroup
.getCurrentTime().compareTo(fCurrentTime
, false) > 0) {
368 fStartGroup
.setContent(new TmfTimeRange(fCurrentTime
, fEndGroup
.getCurrentTime()), fCurrentTime
);
370 if (fEndGroup
.getCurrentTime().compareTo(fCurrentTime
, false) < 0) {
371 fEndGroup
.setContent(new TmfTimeRange(fStartGroup
.getCurrentTime(), fCurrentTime
), fCurrentTime
);
373 fCurrentGroup
.setContent(null, fCurrentTime
);
374 updateSlider(fCurrentGroup
.getTimeRange(), fCurrentTime
);
376 // Enable external notifications
377 fupdateExternalListeners
= true;