1 /*******************************************************************************
2 * Copyright (c) 2009, 2010, 2011, 2012 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 * William Bourque - Initial API and implementation
11 * Yuriy Vashchuk - GUI reorganisation, simplification and some related code improvements.
12 * Yuriy Vashchuk - Histograms optimisation.
13 * Yuriy Vashchuk - Histogram Canvas Heritage correction
14 * Francois Chouinard - Cleanup and refactoring
15 * Francois Chouinard - Moved from LTTng to TMF
16 *******************************************************************************/
18 package org
.eclipse
.linuxtools
.tmf
.ui
.views
.histogram
;
20 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
21 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
22 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimeRange
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimestamp
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfDataRequest
.ExecutionType
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfDataRequest
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalManager
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceClosedSignal
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceRangeUpdatedSignal
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceUpdatedSignal
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
36 import org
.eclipse
.linuxtools
.tmf
.ui
.editors
.ITmfTraceEditor
;
37 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
38 import org
.eclipse
.swt
.SWT
;
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
.ui
.IEditorPart
;
45 * The purpose of this view is to provide graphical time distribution statistics about the trace events.
47 * The view is composed of two histograms and two controls:
49 * <li>an event distribution histogram for the whole trace;
50 * <li>an event distribution histogram for current time window (window span);
51 * <li>the timestamp of the currently selected event;
52 * <li>the window span (size of the time window of the smaller histogram).
54 * The histograms x-axis show their respective time range.
57 * @author Francois Chouinard
59 public class HistogramView
extends TmfView
{
61 // ------------------------------------------------------------------------
63 // ------------------------------------------------------------------------
66 * The view ID as defined in plugin.xml
68 public static final String ID
= "org.eclipse.linuxtools.tmf.ui.views.histogram"; //$NON-NLS-1$
71 * The initial window span (in nanoseconds)
73 public static final long INITIAL_WINDOW_SPAN
= (1L * 100 * 1000 * 1000); // .1sec
75 // ------------------------------------------------------------------------
77 // ------------------------------------------------------------------------
80 private Composite fParent
;
83 private ITmfTrace fTrace
;
85 // Current timestamp/time window - everything in the TIME_SCALE
86 private long fTraceStartTime
;
87 private long fTraceEndTime
;
88 private long fWindowStartTime
;
89 private long fWindowEndTime
;
90 private long fWindowSpan
= INITIAL_WINDOW_SPAN
;
91 private long fCurrentTimestamp
;
94 private HistogramTextControl fCurrentEventTimeControl
;
95 private HistogramTextControl fTimeSpanControl
;
97 // Histogram/request for the full trace range
98 private static FullTraceHistogram fFullTraceHistogram
;
99 private HistogramRequest fFullTraceRequest
;
101 // Histogram/request for the selected time range
102 private static TimeRangeHistogram fTimeRangeHistogram
;
103 private HistogramRequest fTimeRangeRequest
;
105 // ------------------------------------------------------------------------
107 // ------------------------------------------------------------------------
110 * Default constructor
112 public HistogramView() {
117 public void dispose() {
118 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
119 fTimeRangeRequest
.cancel();
121 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
122 fFullTraceRequest
.cancel();
124 fFullTraceHistogram
.dispose();
125 fTimeRangeHistogram
.dispose();
126 fCurrentEventTimeControl
.dispose();
127 fTimeSpanControl
.dispose();
131 // ------------------------------------------------------------------------
133 // ------------------------------------------------------------------------
136 public void createPartControl(Composite parent
) {
141 final String currentEventLabel
= Messages
.HistogramView_currentEventLabel
;
142 final String windowSpanLabel
= Messages
.HistogramView_windowSpanLabel
;
144 // --------------------------------------------------------------------
145 // Set the HistogramView layout
146 // --------------------------------------------------------------------
148 Composite viewComposite
= new Composite(fParent
, SWT
.FILL
);
149 GridLayout gridLayout
= new GridLayout();
150 gridLayout
.numColumns
= 2;
151 gridLayout
.horizontalSpacing
= 5;
152 gridLayout
.verticalSpacing
= 0;
153 gridLayout
.marginHeight
= 0;
154 gridLayout
.marginWidth
= 0;
155 viewComposite
.setLayout(gridLayout
);
157 // Use all available space
158 GridData gridData
= new GridData();
159 gridData
.horizontalAlignment
= SWT
.FILL
;
160 gridData
.verticalAlignment
= SWT
.FILL
;
161 gridData
.grabExcessHorizontalSpace
= true;
162 viewComposite
.setLayoutData(gridData
);
164 // --------------------------------------------------------------------
166 // --------------------------------------------------------------------
168 Composite controlsComposite
= new Composite(viewComposite
, SWT
.FILL
);
169 gridLayout
= new GridLayout();
170 gridLayout
.numColumns
= 2;
171 gridLayout
.marginHeight
= 0;
172 gridLayout
.marginWidth
= 0;
173 gridLayout
.horizontalSpacing
= 5;
174 gridLayout
.verticalSpacing
= 0;
175 gridLayout
.makeColumnsEqualWidth
= false;
176 gridLayout
.marginLeft
= 5;
177 gridLayout
.marginRight
= 5;
178 controlsComposite
.setLayout(gridLayout
);
180 // Current event time control
181 gridData
= new GridData();
182 gridData
.horizontalAlignment
= SWT
.CENTER
;
183 gridData
.verticalAlignment
= SWT
.CENTER
;
184 fCurrentEventTimeControl
= new HistogramCurrentTimeControl(this, controlsComposite
, currentEventLabel
, 0L);
185 fCurrentEventTimeControl
.setLayoutData(gridData
);
186 fCurrentEventTimeControl
.setValue(0L);
188 // Window span time control
189 gridData
= new GridData();
190 gridData
.horizontalAlignment
= SWT
.CENTER
;
191 gridData
.verticalAlignment
= SWT
.CENTER
;
192 fTimeSpanControl
= new HistogramTimeRangeControl(this, controlsComposite
, windowSpanLabel
, 0L);
193 fTimeSpanControl
.setLayoutData(gridData
);
194 fTimeSpanControl
.setValue(0L);
196 // --------------------------------------------------------------------
197 // Time range histogram
198 // --------------------------------------------------------------------
200 Composite timeRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
201 gridLayout
= new GridLayout();
202 gridLayout
.numColumns
= 1;
203 gridLayout
.marginHeight
= 0;
204 gridLayout
.marginWidth
= 0;
205 gridLayout
.marginTop
= 5;
206 gridLayout
.horizontalSpacing
= 0;
207 gridLayout
.verticalSpacing
= 0;
208 gridLayout
.marginLeft
= 5;
209 gridLayout
.marginRight
= 5;
210 timeRangeComposite
.setLayout(gridLayout
);
212 // Use remaining horizontal space
213 gridData
= new GridData();
214 gridData
.horizontalAlignment
= SWT
.FILL
;
215 gridData
.verticalAlignment
= SWT
.FILL
;
216 gridData
.grabExcessHorizontalSpace
= true;
217 timeRangeComposite
.setLayoutData(gridData
);
220 fTimeRangeHistogram
= new TimeRangeHistogram(this, timeRangeComposite
);
222 // --------------------------------------------------------------------
223 // Full range histogram
224 // --------------------------------------------------------------------
226 Composite fullRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
227 gridLayout
= new GridLayout();
228 gridLayout
.numColumns
= 1;
229 gridLayout
.marginHeight
= 0;
230 gridLayout
.marginWidth
= 0;
231 gridLayout
.marginTop
= 5;
232 gridLayout
.horizontalSpacing
= 0;
233 gridLayout
.verticalSpacing
= 0;
234 gridLayout
.marginLeft
= 5;
235 gridLayout
.marginRight
= 5;
236 fullRangeComposite
.setLayout(gridLayout
);
238 // Use remaining horizontal space
239 gridData
= new GridData();
240 gridData
.horizontalAlignment
= SWT
.FILL
;
241 gridData
.verticalAlignment
= SWT
.FILL
;
242 gridData
.horizontalSpan
= 2;
243 gridData
.grabExcessHorizontalSpace
= true;
244 fullRangeComposite
.setLayoutData(gridData
);
247 fFullTraceHistogram
= new FullTraceHistogram(this, fullRangeComposite
);
249 IEditorPart editor
= getSite().getPage().getActiveEditor();
250 if (editor
instanceof ITmfTraceEditor
) {
251 ITmfTrace trace
= ((ITmfTraceEditor
) editor
).getTrace();
253 traceSelected(new TmfTraceSelectedSignal(this, trace
));
259 public void setFocus() {
260 fFullTraceHistogram
.fCanvas
.setFocus();
264 fParent
.layout(true);
267 // ------------------------------------------------------------------------
269 // ------------------------------------------------------------------------
272 * Returns the current trace handled by the view
274 * @return the current trace
277 public ITmfTrace
getTrace() {
282 * Returns the time range of the current selected window (base on default time scale).
284 * @return the time range of current selected window.
286 public TmfTimeRange
getTimeRange() {
287 return new TmfTimeRange(
288 new TmfTimestamp(fWindowStartTime
, ITmfTimestamp
.NANOSECOND_SCALE
),
289 new TmfTimestamp(fWindowEndTime
, ITmfTimestamp
.NANOSECOND_SCALE
));
292 // ------------------------------------------------------------------------
294 // ------------------------------------------------------------------------
297 * Broadcast TmfSignal about new current time value.
298 * @param newTime the new current time.
300 void updateCurrentEventTime(long newTime
) {
301 if (fTrace
!= null) {
302 TmfTimeRange timeRange
= new TmfTimeRange(new TmfTimestamp(newTime
, ITmfTimestamp
.NANOSECOND_SCALE
), TmfTimestamp
.BIG_CRUNCH
);
303 HistogramRequest request
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(), timeRange
, 0, 1, 0, ExecutionType
.FOREGROUND
) {
305 public void handleData(ITmfEvent event
) {
307 TmfTimeSynchSignal signal
= new TmfTimeSynchSignal(this, event
.getTimestamp());
308 TmfSignalManager
.dispatchSignal(signal
);
312 fTrace
.sendRequest(request
);
317 * Broadcast TmfSignal about new selected time range.
318 * @param startTime the new start time
319 * @param endTime the new end time
321 void updateTimeRange(long startTime
, long endTime
) {
322 if (fTrace
!= null) {
323 // Build the new time range; keep the current time
324 TmfTimeRange timeRange
= new TmfTimeRange(
325 new TmfTimestamp(startTime
, ITmfTimestamp
.NANOSECOND_SCALE
),
326 new TmfTimestamp(endTime
, ITmfTimestamp
.NANOSECOND_SCALE
));
327 ITmfTimestamp currentTime
= new TmfTimestamp(fCurrentTimestamp
, ITmfTimestamp
.NANOSECOND_SCALE
);
328 fTimeSpanControl
.setValue(endTime
- startTime
);
330 // Send the FW signal
331 TmfRangeSynchSignal signal
= new TmfRangeSynchSignal(this, timeRange
, currentTime
);
332 TmfSignalManager
.dispatchSignal(signal
);
337 * Broadcast TmfSignal about new selected time range.
338 * @param newDuration new duration (relative to current start time)
340 public synchronized void updateTimeRange(long newDuration
) {
341 if (fTrace
!= null) {
342 long delta
= newDuration
- fWindowSpan
;
343 long newStartTime
= fWindowStartTime
+ (delta
/ 2);
344 setNewRange(newStartTime
, newDuration
);
348 private void setNewRange(long startTime
, long duration
) {
349 if (startTime
< fTraceStartTime
) {
350 startTime
= fTraceStartTime
;
353 long endTime
= startTime
+ duration
;
354 if (endTime
> fTraceEndTime
) {
355 endTime
= fTraceEndTime
;
356 if ((endTime
- duration
) > fTraceEndTime
) {
357 startTime
= endTime
- duration
;
359 startTime
= fTraceStartTime
;
362 updateTimeRange(startTime
, endTime
);
365 // ------------------------------------------------------------------------
367 // ------------------------------------------------------------------------
370 * Handles trace opened signal. Loads histogram if new trace time range is not
371 * equal <code>TmfTimeRange.NULL_RANGE</code>
372 * @param signal the trace selected signal
376 public void traceOpened(TmfTraceOpenedSignal signal
) {
377 assert (signal
!= null);
378 fTrace
= signal
.getTrace();
383 * Handles trace selected signal. Loads histogram if new trace time range is not
384 * equal <code>TmfTimeRange.NULL_RANGE</code>
385 * @param signal the trace selected signal
389 public void traceSelected(TmfTraceSelectedSignal signal
) {
390 assert (signal
!= null);
391 if (fTrace
!= signal
.getTrace()) {
392 fTrace
= signal
.getTrace();
397 private void loadTrace() {
398 initializeHistograms();
403 * Handles trace closed signal. Clears the view and data model and cancels requests.
404 * @param signal the trace closed signal
408 public void traceClosed(TmfTraceClosedSignal signal
) {
410 if (signal
.getTrace() != fTrace
) {
414 // Kill any running request
415 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
416 fTimeRangeRequest
.cancel();
418 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
419 fFullTraceRequest
.cancel();
422 // Initialize the internal data
424 fTraceStartTime
= 0L;
426 fWindowStartTime
= 0L;
428 fWindowSpan
= INITIAL_WINDOW_SPAN
;
429 fCurrentTimestamp
= 0L;
431 // Clear the UI widgets
432 fFullTraceHistogram
.clear();
433 fTimeRangeHistogram
.clear();
434 fCurrentEventTimeControl
.setValue(0L);
436 fTimeSpanControl
.setValue(0);
440 * Handles trace range updated signal. Extends histogram according to the new time range. If a
441 * HistogramRequest is already ongoing, it will be cancelled and a new request with the new range
444 * @param signal the trace range updated signal
448 public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal
) {
450 if (signal
.getTrace() != fTrace
) {
454 boolean drawTimeRangeHistogram
= fTraceStartTime
== 0;
455 TmfTimeRange fullRange
= signal
.getRange();
457 fTraceStartTime
= fullRange
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
458 fTraceEndTime
= fullRange
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
460 fFullTraceHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
461 fTimeRangeHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
463 if (drawTimeRangeHistogram
) {
464 fCurrentTimestamp
= fTraceStartTime
;
465 fCurrentEventTimeControl
.setValue(fCurrentTimestamp
);
466 fFullTraceHistogram
.setTimeRange(fTraceStartTime
, INITIAL_WINDOW_SPAN
);
467 fTimeRangeHistogram
.setTimeRange(fTraceStartTime
, INITIAL_WINDOW_SPAN
);
468 sendTimeRangeRequest(fTraceStartTime
, fTraceStartTime
+ INITIAL_WINDOW_SPAN
);
471 sendFullRangeRequest(fullRange
);
475 * Handles the trace updated signal. Used to update time limits (start and end time)
476 * @param signal the trace updated signal
480 public void traceUpdated(TmfTraceUpdatedSignal signal
) {
481 if (signal
.getTrace() != fTrace
) {
484 TmfTimeRange fullRange
= signal
.getTrace().getTimeRange();
485 fTraceStartTime
= fullRange
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
486 fTraceEndTime
= fullRange
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
488 fFullTraceHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
489 fTimeRangeHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
491 fFullTraceHistogram
.setTimeRange(fTimeRangeHistogram
.getStartTime(), fWindowSpan
);
493 if ((fFullTraceRequest
!= null) && fFullTraceRequest
.getRange().getEndTime().compareTo(signal
.getRange().getEndTime()) < 0) {
494 sendFullRangeRequest(fullRange
);
499 * Handles the current time updated signal. Sets the current time in the time range
500 * histogram as well as the full histogram.
502 * @param signal the signal to process
505 public void currentTimeUpdated(TmfTimeSynchSignal signal
) {
506 // Because this can't happen :-)
507 assert (signal
!= null);
509 // Update the selected event time
510 ITmfTimestamp currentTime
= signal
.getCurrentTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
);
511 fCurrentTimestamp
= currentTime
.getValue();
513 // Notify the relevant widgets
514 fFullTraceHistogram
.setCurrentEvent(fCurrentTimestamp
);
515 fTimeRangeHistogram
.setCurrentEvent(fCurrentTimestamp
);
516 fCurrentEventTimeControl
.setValue(fCurrentTimestamp
);
520 * Updates the current time range in the time range histogram and full range histogram.
521 * @param signal the signal to process
524 public void timeRangeUpdated(TmfRangeSynchSignal signal
) {
525 // Because this can't happen :-)
526 assert (signal
!= null);
528 if (fTrace
!= null) {
529 // Update the time range
530 fWindowStartTime
= signal
.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
531 fWindowEndTime
= signal
.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
532 fWindowSpan
= fWindowEndTime
- fWindowStartTime
;
534 // Notify the relevant widgets
535 sendTimeRangeRequest(fWindowStartTime
, fWindowEndTime
);
536 fFullTraceHistogram
.setTimeRange(fWindowStartTime
, fWindowSpan
);
538 fTimeSpanControl
.setValue(fWindowSpan
);
542 // ------------------------------------------------------------------------
544 // ------------------------------------------------------------------------
546 private void initializeHistograms() {
547 TmfTimeRange fullRange
= updateTraceTimeRange();
549 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
550 fTimeRangeRequest
.cancel();
552 fTimeRangeHistogram
.clear();
553 fTimeRangeHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
554 fTimeRangeHistogram
.setTimeRange(fTraceStartTime
, INITIAL_WINDOW_SPAN
);
555 fTimeRangeHistogram
.setCurrentEvent(fTraceStartTime
);
557 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
558 fFullTraceRequest
.cancel();
560 fFullTraceHistogram
.clear();
561 fFullTraceHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
562 fFullTraceHistogram
.setTimeRange(fTraceStartTime
, INITIAL_WINDOW_SPAN
);
563 fFullTraceHistogram
.setCurrentEvent(fTraceStartTime
);
565 fWindowStartTime
= fTraceStartTime
;
566 fWindowSpan
= INITIAL_WINDOW_SPAN
;
567 fWindowEndTime
= fWindowStartTime
+ fWindowSpan
;
569 fCurrentEventTimeControl
.setValue(fTraceStartTime
);
571 fTimeSpanControl
.setValue(fWindowSpan
);
573 if (!fullRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
574 sendTimeRangeRequest(fTraceStartTime
, fTraceStartTime
+ fWindowSpan
);
575 sendFullRangeRequest(fullRange
);
579 private TmfTimeRange
updateTraceTimeRange() {
580 fTraceStartTime
= 0L;
582 fCurrentTimestamp
= 0L;
584 TmfTimeRange timeRange
= fTrace
.getTimeRange();
585 if (!timeRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
586 fTraceStartTime
= timeRange
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
587 fTraceEndTime
= timeRange
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
588 fCurrentTimestamp
= fTraceStartTime
;
593 private void sendTimeRangeRequest(long startTime
, long endTime
) {
594 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
595 fTimeRangeRequest
.cancel();
597 TmfTimestamp startTS
= new TmfTimestamp(startTime
, ITmfTimestamp
.NANOSECOND_SCALE
);
598 TmfTimestamp endTS
= new TmfTimestamp(endTime
, ITmfTimestamp
.NANOSECOND_SCALE
);
599 TmfTimeRange timeRange
= new TmfTimeRange(startTS
, endTS
);
601 fTimeRangeHistogram
.clear();
602 fTimeRangeHistogram
.setTimeRange(startTime
, endTime
- startTime
);
604 int cacheSize
= fTrace
.getCacheSize();
605 fTimeRangeRequest
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(), timeRange
, 0, TmfDataRequest
.ALL_DATA
, cacheSize
, ExecutionType
.FOREGROUND
);
606 fTrace
.sendRequest(fTimeRangeRequest
);
609 private void sendFullRangeRequest(TmfTimeRange fullRange
) {
610 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
611 fFullTraceRequest
.cancel();
613 int cacheSize
= fTrace
.getCacheSize();
614 fFullTraceRequest
= new HistogramRequest(fFullTraceHistogram
.getDataModel(), fullRange
, (int) fFullTraceHistogram
.fDataModel
.getNbEvents(),
615 TmfDataRequest
.ALL_DATA
, cacheSize
, ExecutionType
.BACKGROUND
);
616 fTrace
.sendRequest(fFullTraceRequest
);