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
.internal
.lttng
.core
.event
.LttngEvent
;
16 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
17 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimeRange
;
18 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimestamp
;
19 import org
.eclipse
.linuxtools
.tmf
.core
.experiment
.TmfExperiment
;
20 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentSelectedSignal
;
21 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentUpdatedSignal
;
22 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
25 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
26 import org
.eclipse
.swt
.SWT
;
27 import org
.eclipse
.swt
.layout
.GridData
;
28 import org
.eclipse
.swt
.layout
.GridLayout
;
29 import org
.eclipse
.swt
.widgets
.Composite
;
30 import org
.eclipse
.swt
.widgets
.Event
;
31 import org
.eclipse
.swt
.widgets
.Listener
;
32 import org
.eclipse
.swt
.widgets
.Slider
;
35 * <b><u>TimeFrameView</u></b>
37 * The TimeFrameView provides a set of spinners to monitor and set the start time, end time, the current time interval
38 * and current time of the trace 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) ]</li>
47 * It provides a slider to rapidly set the current time within the time range (i.e. between startTime and endTime).
49 * Finally, it allows modification of the time range and the current time. This triggers notifications to the other
52 * FIXME: The slider is very jumpy due to the large number of async updates FIXME: Revisit the control flow between
53 * View, Spinners and Slider
56 public class TimeFrameView
extends TmfView
{
58 public static final String ID
= "org.eclipse.linuxtools.lttng.ui.views.timeframe"; //$NON-NLS-1$
60 // ------------------------------------------------------------------------
62 // ------------------------------------------------------------------------
64 // The event log timestamp characteristics
65 private ITmfTimestamp fTraceStartTime
= new TmfTimestamp();
66 private ITmfTimestamp fTraceEndTime
= new TmfTimestamp();
68 private ITmfTimestamp fCurrentTime
= new TmfTimestamp();
70 private TmfTimeRange fTraceTimeRange
= new TmfTimeRange(fTraceStartTime
, fTraceEndTime
);
71 private TmfTimeRange fTraceSpan
= new TmfTimeRange(fTraceStartTime
, fTraceEndTime
);
72 private int fScale
= 0;
75 private static final String START_TIME_LABEL
= Messages
.TimeFrameView_WindowStartTime
;
76 private static final String END_TIME_LABEL
= Messages
.TimeFrameView_WindowEndTime
;
77 private static final String TIME_RANGE_LABEL
= Messages
.TimeFrameView_WindowRange
;
78 private static final String CURRENT_TIME_LABEL
= Messages
.TimeFrameView_CurrentTime
;
80 private static final int SLIDER_RANGE
= 10000;
82 private SpinnerGroup fStartGroup
;
83 private SpinnerGroup fEndGroup
;
84 private SpinnerGroup fRangeGroup
;
85 private SpinnerGroup fCurrentGroup
;
88 private Slider fSlider
;
90 // The current experiment
91 TmfExperiment
<LttngEvent
> fExperiment
= null;
93 // notify external listeners may not be needed if the update originated externally
94 private boolean fupdateExternalListeners
= true;
96 // ------------------------------------------------------------------------
98 // ------------------------------------------------------------------------
103 public TimeFrameView() {
104 super("TimeFrameView"); //$NON-NLS-1$
110 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets .Composite)
113 public void createPartControl(Composite parent
) {
115 // Set the view layout
116 GridLayout layout
= new GridLayout(4, true);
117 parent
.setLayout(layout
);
119 fStartGroup
= new SpinnerGroup(this, parent
, START_TIME_LABEL
, fTraceTimeRange
, fTraceStartTime
);
120 fEndGroup
= new SpinnerGroup(this, parent
, END_TIME_LABEL
, fTraceTimeRange
, fTraceEndTime
);
121 fRangeGroup
= new SpinnerGroup(this, parent
, TIME_RANGE_LABEL
, fTraceTimeRange
, fTraceEndTime
);
122 fCurrentGroup
= new SpinnerGroup(this, parent
, CURRENT_TIME_LABEL
, fTraceTimeRange
, fTraceStartTime
);
125 createSlider(parent
);
131 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
134 public void setFocus() {
135 // TODO Auto-generated method stub
138 // ------------------------------------------------------------------------
140 // ------------------------------------------------------------------------
143 * One of the spinners has been updated. Synchronize the other widgets.
145 public void synchTimeFrameWidgets(SpinnerGroup trigger
) {
146 boolean trangeUpdated
= false;
149 ITmfTimestamp startTime
= fStartGroup
.getCurrentTime();
150 ITmfTimestamp endTime
= fEndGroup
.getCurrentTime();
151 ITmfTimestamp timeRange
= fRangeGroup
.getCurrentTime();
152 ITmfTimestamp currentTime
= fCurrentGroup
.getCurrentTime();
154 // If startTime was set beyond endTime, adjust endTime and interval
155 if (trigger
== fStartGroup
) {
156 if (startTime
.compareTo(endTime
, false) > 0) {
158 trangeUpdated
= true;
162 // If endTime was set beyond startTime, adjust startTime and interval
163 if (trigger
== fEndGroup
) {
164 if (endTime
.compareTo(startTime
, false) < 0) {
166 trangeUpdated
= true;
170 // If timeRange was set, adjust endTime
171 if (trigger
== fRangeGroup
) {
172 long start
= startTime
.getValue();
173 long span
= timeRange
.getValue();
174 ITmfTimestamp ts
= new TmfTimestamp(start
+ span
, startTime
.getScale(), 0);
175 if (ts
.compareTo(fTraceEndTime
, false) > 0) {
176 ts
= fTraceEndTime
.clone();
179 trangeUpdated
= true;
182 // Compute the new time range
183 TmfTimeRange subrange
= new TmfTimeRange(startTime
, endTime
);
184 // int scale = startTime.getScale();
185 ITmfTimestamp interval
= (TmfTimestamp
) startTime
.getDelta(endTime
);
187 // Update the spinner groups
188 fStartGroup
.setContent(fTraceTimeRange
, startTime
);
189 fEndGroup
.setContent(fTraceTimeRange
, endTime
);
190 fRangeGroup
.setContent(fTraceSpan
, interval
);
191 fCurrentGroup
.setContent(subrange
, currentTime
);
193 updateSlider(subrange
, currentTime
);
194 // Notify other views, only if the update originated from this view
195 if (fupdateExternalListeners
) {
196 if (!fCurrentTime
.equals(currentTime
)) {
197 fCurrentTime
= currentTime
;
198 broadcast(new TmfTimeSynchSignal(this, currentTime
));
201 // Notify the views if the time range has been impacted
203 TmfTimeRange trange
= new TmfTimeRange(startTime
, endTime
);
204 broadcast(new TmfRangeSynchSignal(this, trange
, currentTime
));
209 // ------------------------------------------------------------------------
211 // ------------------------------------------------------------------------
216 private void createSlider(Composite parent
) {
217 fSlider
= new Slider(parent
, SWT
.SMOOTH
| SWT
.FILL
);
218 fSlider
.setMinimum(0);
219 fSlider
.setMaximum(SLIDER_RANGE
+ fSlider
.getThumb());
220 fSlider
.setIncrement(SLIDER_RANGE
/ 100);
221 fSlider
.setPageIncrement(SLIDER_RANGE
/ 10);
222 fSlider
.setSelection(0);
224 GridData gridData
= new GridData(SWT
.LEFT
, SWT
.TOP
, true, false);
225 gridData
.horizontalAlignment
= SWT
.FILL
;
226 gridData
.horizontalSpan
= 4;
227 fSlider
.setLayoutData(gridData
);
229 fSlider
.addListener(SWT
.Selection
, new Listener() {
231 public void handleEvent(Event event
) {
232 int ratio
= fSlider
.getSelection();
233 ITmfTimestamp span
= fCurrentGroup
.getSpan();
234 long value
= span
.getValue() * ratio
/ SLIDER_RANGE
;
235 ITmfTimestamp start
= fCurrentGroup
.getStartTime();
236 ITmfTimestamp current
= new TmfTimestamp(start
.getValue() + value
, start
.getScale(), 0);
237 fCurrentGroup
.setValue(current
);
247 private void updateSlider(TmfTimeRange range
, ITmfTimestamp timestamp
) {
249 // Ignore update if disposed
250 if (fSlider
.isDisposed())
253 // Determine the new relative position
254 // int scale = range.getEndTime().getScale();
255 long total
= range
.getStartTime().getDelta(range
.getEndTime()).getValue();
256 long relative
= range
.getStartTime().getDelta(timestamp
).getValue();
258 // Set the slider value
259 final long position
= (total
> 0) ?
(relative
* SLIDER_RANGE
/ total
) : 0;
261 // Update the slider on the UI thread
262 long current
= fSlider
.getSelection();
263 if (position
!= current
) {
264 fSlider
.getDisplay().asyncExec(new Runnable() {
267 fSlider
.setSelection((int) position
);
276 * @see java.lang.Object#toString()
279 @SuppressWarnings("nls")
280 public String
toString() {
281 return "[TimeFrameView]";
284 // ------------------------------------------------------------------------
286 // ------------------------------------------------------------------------
291 @SuppressWarnings("unchecked")
293 public void experimentSelected(TmfExperimentSelectedSignal
<LttngEvent
> signal
) {
295 // Update the trace reference
296 fExperiment
= (TmfExperiment
<LttngEvent
>) signal
.getExperiment();
298 // Update the time frame
299 fTraceTimeRange
= fExperiment
.getTimeRange();
300 fTraceStartTime
= fTraceTimeRange
.getStartTime();
301 fTraceEndTime
= fTraceTimeRange
.getEndTime();
302 fScale
= fTraceStartTime
.getScale();
304 // Update the widgets
305 fStartGroup
.setContent(fTraceTimeRange
, fTraceStartTime
);
306 fEndGroup
.setContent(fTraceTimeRange
, fTraceEndTime
);
307 fCurrentGroup
.setContent(fTraceTimeRange
, fTraceStartTime
);
309 fCurrentTime
= fTraceStartTime
;
311 ITmfTimestamp delta
= fTraceStartTime
.getDelta(fTraceEndTime
);
312 fTraceSpan
= new TmfTimeRange(new TmfTimestamp(0, fScale
, 0), delta
);
313 // fRangeGroup.setContent(fTraceSpan, delta);
314 ITmfTimestamp start
= new TmfTimestamp(1, (byte) -1, 0);
315 fRangeGroup
.setContent(fTraceSpan
, start
);
322 public void experimentUpdated(TmfExperimentUpdatedSignal signal
) {
323 if (signal
.getExperiment() != fExperiment
) {
327 // Update the time frame
328 // fTraceTimeRange = signal.getTrace().getTimeRange();
329 fTraceTimeRange
= signal
.getExperiment().getTimeRange();
330 fTraceStartTime
= fTraceTimeRange
.getStartTime();
331 fTraceEndTime
= fTraceTimeRange
.getEndTime();
332 fScale
= fTraceStartTime
.getScale();
334 // Update the widgets
335 fStartGroup
.setContent(fTraceTimeRange
, fStartGroup
.getCurrentTime());
336 fEndGroup
.setContent(fTraceTimeRange
, fTraceEndTime
);
337 fCurrentGroup
.setContent(fTraceTimeRange
, fCurrentGroup
.getCurrentTime());
339 ITmfTimestamp delta
= fTraceStartTime
.getDelta(fTraceEndTime
);
340 fTraceSpan
= new TmfTimeRange(new TmfTimestamp(0, fScale
, 0), delta
);
341 fRangeGroup
.setContent(fTraceSpan
, delta
);
348 public void currentTimeRangeUpdated(TmfRangeSynchSignal signal
) {
349 if (signal
.getSource() != this) {
350 // Update the time frame
351 TmfTimeRange selTimeRange
= signal
.getCurrentRange();
352 ITmfTimestamp selStart
= selTimeRange
.getStartTime().normalize(0, fScale
);
353 ITmfTimestamp selEnd
= selTimeRange
.getEndTime().normalize(0, fScale
);
355 fupdateExternalListeners
= false;
356 // Update the widgets and prevent broadcast notifications to
357 // the views which have been notified already.
359 fStartGroup
.setContent(fTraceTimeRange
, selStart
);
360 fEndGroup
.setContent(fTraceTimeRange
, selEnd
);
362 ITmfTimestamp delta
= selStart
.getDelta(selEnd
);
364 fRangeGroup
.setContent(fTraceSpan
, delta
);
367 // restore the external notification flag
368 fupdateExternalListeners
= true;
377 public void currentTimeUpdated(TmfTimeSynchSignal signal
) {
378 if (signal
.getSource() != this) {
379 // prevent loop to external notifications
380 fupdateExternalListeners
= false;
381 fCurrentTime
= signal
.getCurrentTime().normalize(0, fStartGroup
.getCurrentTime().getScale());
382 if (fStartGroup
.getCurrentTime().compareTo(fCurrentTime
, false) > 0) {
383 fStartGroup
.setContent(new TmfTimeRange(fCurrentTime
, fEndGroup
.getCurrentTime()), fCurrentTime
);
385 if (fEndGroup
.getCurrentTime().compareTo(fCurrentTime
, false) < 0) {
386 fEndGroup
.setContent(new TmfTimeRange(fStartGroup
.getCurrentTime(), fCurrentTime
), fCurrentTime
);
388 fCurrentGroup
.setContent(null, fCurrentTime
);
389 updateSlider(fCurrentGroup
.getTimeRange(), fCurrentTime
);
391 // Enable external notifications
392 fupdateExternalListeners
= true;