1 /*******************************************************************************
2 * Copyright (c) 2009, 2015 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 * Patrick Tasse - Update for mouse wheel zoom
17 * Xavier Raynaud - Support multi-trace coloring
18 *******************************************************************************/
20 package org
.eclipse
.tracecompass
.tmf
.ui
.views
.histogram
;
22 import java
.util
.Collection
;
24 import org
.eclipse
.jdt
.annotation
.NonNull
;
25 import org
.eclipse
.jface
.action
.Action
;
26 import org
.eclipse
.jface
.action
.IAction
;
27 import org
.eclipse
.jface
.action
.Separator
;
28 import org
.eclipse
.swt
.SWT
;
29 import org
.eclipse
.swt
.custom
.CLabel
;
30 import org
.eclipse
.swt
.custom
.SashForm
;
31 import org
.eclipse
.swt
.custom
.ScrolledComposite
;
32 import org
.eclipse
.swt
.events
.MouseAdapter
;
33 import org
.eclipse
.swt
.events
.MouseEvent
;
34 import org
.eclipse
.swt
.events
.MouseWheelListener
;
35 import org
.eclipse
.swt
.events
.PaintEvent
;
36 import org
.eclipse
.swt
.events
.PaintListener
;
37 import org
.eclipse
.swt
.graphics
.GC
;
38 import org
.eclipse
.swt
.graphics
.Image
;
39 import org
.eclipse
.swt
.graphics
.Point
;
40 import org
.eclipse
.swt
.graphics
.Rectangle
;
41 import org
.eclipse
.swt
.layout
.GridData
;
42 import org
.eclipse
.swt
.layout
.GridLayout
;
43 import org
.eclipse
.swt
.layout
.RowLayout
;
44 import org
.eclipse
.swt
.widgets
.Composite
;
45 import org
.eclipse
.swt
.widgets
.Control
;
46 import org
.eclipse
.swt
.widgets
.Display
;
47 import org
.eclipse
.swt
.widgets
.Event
;
48 import org
.eclipse
.swt
.widgets
.Label
;
49 import org
.eclipse
.swt
.widgets
.Listener
;
50 import org
.eclipse
.swt
.widgets
.Sash
;
51 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Activator
;
52 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.ITmfImageConstants
;
53 import org
.eclipse
.tracecompass
.tmf
.core
.request
.ITmfEventRequest
;
54 import org
.eclipse
.tracecompass
.tmf
.core
.request
.ITmfEventRequest
.ExecutionType
;
55 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSelectionRangeUpdatedSignal
;
56 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
57 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalManager
;
58 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalThrottler
;
59 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceClosedSignal
;
60 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
61 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceRangeUpdatedSignal
;
62 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
63 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceUpdatedSignal
;
64 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfWindowRangeUpdatedSignal
;
65 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
66 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimeRange
;
67 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
68 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
69 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceContext
;
70 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
71 import org
.eclipse
.tracecompass
.tmf
.ui
.signal
.TmfTimeViewAlignmentInfo
;
72 import org
.eclipse
.tracecompass
.tmf
.ui
.signal
.TmfTimeViewAlignmentSignal
;
73 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.ITmfTimeAligned
;
74 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.TmfView
;
75 import org
.eclipse
.ui
.IActionBars
;
78 * The purpose of this view is to provide graphical time distribution statistics about the trace events.
80 * The view is composed of two histograms and two controls:
82 * <li>an event distribution histogram for the whole trace;
83 * <li>an event distribution histogram for current time window (window span);
84 * <li>the timestamp of the currently selected event;
85 * <li>the window span (size of the time window of the smaller histogram).
87 * The histograms x-axis show their respective time range.
90 * @author Francois Chouinard
92 public class HistogramView
extends TmfView
implements ITmfTimeAligned
{
94 // ------------------------------------------------------------------------
96 // ------------------------------------------------------------------------
99 * The view ID as defined in plugin.xml
101 public static final @NonNull String ID
= "org.eclipse.linuxtools.tmf.ui.views.histogram"; //$NON-NLS-1$
103 private static final Image LINK_IMG
= Activator
.getDefault().getImageFromPath(ITmfImageConstants
.IMG_UI_LINK
);
105 private static final int[] DEFAULT_WEIGHTS
= {1, 3};
107 // ------------------------------------------------------------------------
109 // ------------------------------------------------------------------------
112 private ITmfTrace fTrace
;
114 // Current timestamp/time window - everything in the TIME_SCALE
115 private long fTraceStartTime
;
116 private long fTraceEndTime
;
117 private long fWindowStartTime
;
118 private long fWindowEndTime
;
119 private long fWindowSpan
;
120 private long fSelectionBeginTime
;
121 private long fSelectionEndTime
;
124 private SashForm fSashForm
;
125 private ScrolledComposite fScrollComposite
;
126 private Composite fTimeControlsComposite
;
127 private Composite fTimeRangeComposite
;
128 private Listener fSashDragListener
;
131 private HistogramTextControl fSelectionStartControl
;
132 private HistogramTextControl fSelectionEndControl
;
133 private HistogramTextControl fTimeSpanControl
;
136 private Label fLinkButton
;
137 private boolean fLinkState
;
139 // Histogram/request for the full trace range
140 private static FullTraceHistogram fFullTraceHistogram
;
141 private HistogramRequest fFullTraceRequest
;
143 // Histogram/request for the selected time range
144 private static TimeRangeHistogram fTimeRangeHistogram
;
145 private HistogramRequest fTimeRangeRequest
;
148 private Composite fLegendArea
;
149 private Image
[] fLegendImages
;
151 // Throttlers for the time sync and time-range sync signals
152 private final TmfSignalThrottler fTimeSyncThrottle
;
153 private final TmfSignalThrottler fTimeRangeSyncThrottle
;
155 // Action for toggle showing the lost events
156 private Action hideLostEventsAction
;
157 // Action for toggle showing the traces
158 private Action showTraceAction
;
160 // ------------------------------------------------------------------------
162 // ------------------------------------------------------------------------
165 * Default constructor
167 public HistogramView() {
169 fTimeSyncThrottle
= new TmfSignalThrottler(this, 200);
170 fTimeRangeSyncThrottle
= new TmfSignalThrottler(this, 200);
174 public void dispose() {
175 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
176 fTimeRangeRequest
.cancel();
178 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
179 fFullTraceRequest
.cancel();
181 fFullTraceHistogram
.dispose();
182 fTimeRangeHistogram
.dispose();
183 fSelectionStartControl
.dispose();
184 fSelectionEndControl
.dispose();
185 fTimeSpanControl
.dispose();
186 disposeLegendImages();
191 private void disposeLegendImages() {
192 if (fLegendImages
!= null) {
193 for (Image i
: fLegendImages
) {
197 fLegendImages
= null;
200 // ------------------------------------------------------------------------
202 // ------------------------------------------------------------------------
205 public void createPartControl(Composite parent
) {
206 super.createPartControl(parent
);
209 final String selectionStartLabel
= Messages
.HistogramView_selectionStartLabel
;
210 final String selectionEndLabel
= Messages
.HistogramView_selectionEndLabel
;
211 final String windowSpanLabel
= Messages
.HistogramView_windowSpanLabel
;
213 // --------------------------------------------------------------------
214 // Set the HistogramView layout
215 // --------------------------------------------------------------------
216 Composite viewComposite
= new Composite(getParentComposite(), SWT
.FILL
);
217 GridLayout gridLayout
= new GridLayout(1, false);
218 gridLayout
.verticalSpacing
= 0;
219 gridLayout
.marginHeight
= 0;
220 gridLayout
.marginWidth
= 0;
221 viewComposite
.setLayout(gridLayout
);
223 // --------------------------------------------------------------------
224 // Add a sash for time controls and time range histogram
225 // --------------------------------------------------------------------
228 * The ScrolledComposite preferred size can be larger than its visible
229 * width. This affects the preferred width of the SashForm. Set the
230 * preferred width to 1 to prevent it from affecting the preferred width
231 * of the view composite.
233 fSashForm
= new SashForm(viewComposite
, SWT
.NONE
) {
235 public Point
computeSize(int wHint
, int hHint
) {
236 Point computedSize
= super.computeSize(wHint
, hHint
);
237 if (wHint
== SWT
.DEFAULT
) {
238 return new Point(1, computedSize
.y
);
243 public Point
computeSize(int wHint
, int hHint
, boolean changed
) {
244 Point computedSize
= super.computeSize(wHint
, hHint
, changed
);
245 if (wHint
== SWT
.DEFAULT
) {
246 return new Point(1, computedSize
.y
);
251 GridData gridData
= new GridData(GridData
.FILL
, GridData
.FILL
, false, true);
252 fSashForm
.setLayoutData(gridData
);
254 // --------------------------------------------------------------------
256 // --------------------------------------------------------------------
257 fScrollComposite
= new PackedScrolledComposite(fSashForm
, SWT
.H_SCROLL
| SWT
.V_SCROLL
);
258 fTimeControlsComposite
= new Composite(fScrollComposite
, SWT
.NONE
);
259 fScrollComposite
.setContent(fTimeControlsComposite
);
260 gridLayout
= new GridLayout(1, false);
261 gridLayout
.marginHeight
= 0;
262 gridLayout
.marginWidth
= 0;
263 fScrollComposite
.setLayout(gridLayout
);
264 fScrollComposite
.setExpandHorizontal(true);
265 fScrollComposite
.setExpandVertical(true);
267 gridLayout
= new GridLayout(1, false);
268 gridLayout
.marginHeight
= 0;
269 gridLayout
.marginWidth
= 0;
270 fTimeControlsComposite
.setLayout(gridLayout
);
271 gridData
= new GridData(GridData
.FILL
, GridData
.CENTER
, false, true);
272 fTimeControlsComposite
.setLayoutData(gridData
);
274 Composite innerComp
= new Composite(fTimeControlsComposite
, SWT
.NONE
);
276 gridLayout
= new GridLayout(2, false);
277 innerComp
.setLayout(gridLayout
);
278 gridLayout
.marginHeight
= 0;
279 gridLayout
.marginWidth
= 0;
280 gridLayout
.horizontalSpacing
= 5;
281 gridLayout
.verticalSpacing
= 1;
282 gridData
= new GridData(GridData
.FILL
, GridData
.CENTER
, false, true);
283 innerComp
.setLayoutData(gridData
);
285 Composite selectionGroup
= new Composite(innerComp
, SWT
.BORDER
);
286 gridLayout
= new GridLayout(1, false);
287 gridLayout
.marginHeight
= 0;
288 gridLayout
.marginWidth
= 0;
289 selectionGroup
.setLayout(gridLayout
);
290 gridData
= new GridData(GridData
.BEGINNING
, GridData
.CENTER
, false, false);
291 selectionGroup
.setLayoutData(gridData
);
293 // Selection start control
294 gridData
= new GridData(GridData
.FILL
, GridData
.CENTER
, false, false);
295 fSelectionStartControl
= new HistogramSelectionStartControl(this, selectionGroup
, selectionStartLabel
, 0L);
296 fSelectionStartControl
.setLayoutData(gridData
);
297 fSelectionStartControl
.setValue(Long
.MIN_VALUE
);
299 // Selection end control
300 gridData
= new GridData(GridData
.FILL
, GridData
.CENTER
, false, false);
301 fSelectionEndControl
= new HistogramSelectionEndControl(this, selectionGroup
, selectionEndLabel
, 0L);
302 fSelectionEndControl
.setLayoutData(gridData
);
303 fSelectionEndControl
.setValue(Long
.MIN_VALUE
);
306 gridData
= new GridData(GridData
.BEGINNING
, GridData
.CENTER
, false, false);
307 fLinkButton
= new Label(innerComp
, SWT
.NONE
);
308 fLinkButton
.setImage(LINK_IMG
);
309 fLinkButton
.setLayoutData(gridData
);
310 addLinkButtonListeners();
312 // Window span time control
313 gridData
= new GridData(GridData
.FILL
, GridData
.CENTER
, false, false);
314 fTimeSpanControl
= new HistogramTimeRangeControl(this, innerComp
, windowSpanLabel
, 0L);
315 fTimeSpanControl
.setLayoutData(gridData
);
316 fTimeSpanControl
.setValue(Long
.MIN_VALUE
);
318 // --------------------------------------------------------------------
319 // Time range histogram
320 // --------------------------------------------------------------------
321 fTimeRangeComposite
= new Composite(fSashForm
, SWT
.NONE
);
322 gridLayout
= new GridLayout(1, true);
323 gridLayout
.marginTop
= 0;
324 gridLayout
.marginWidth
= 0;
325 fTimeRangeComposite
.setLayout(gridLayout
);
327 // Use remaining horizontal space
328 gridData
= new GridData(GridData
.FILL
, GridData
.FILL
, true, true);
329 fTimeRangeComposite
.setLayoutData(gridData
);
332 fTimeRangeHistogram
= new TimeRangeHistogram(this, fTimeRangeComposite
, true);
334 // --------------------------------------------------------------------
335 // Full range histogram
336 // --------------------------------------------------------------------
337 final Composite fullRangeComposite
= new Composite(viewComposite
, SWT
.FILL
);
338 gridLayout
= new GridLayout(1, true);
339 fullRangeComposite
.setLayout(gridLayout
);
341 // Use remaining horizontal space
342 gridData
= new GridData(GridData
.FILL
, GridData
.FILL
, true, true, 2, 1);
343 fullRangeComposite
.setLayoutData(gridData
);
346 fFullTraceHistogram
= new FullTraceHistogram(this, fullRangeComposite
);
348 fLegendArea
= new Composite(viewComposite
, SWT
.FILL
);
349 fLegendArea
.setLayoutData(new GridData(SWT
.BEGINNING
, SWT
.BEGINNING
, true, false, 2, 1));
350 fLegendArea
.setLayout(new RowLayout());
352 // Add mouse wheel listener to time span control
353 MouseWheelListener listener
= fFullTraceHistogram
.getZoom();
354 fTimeSpanControl
.addMouseWheelListener(listener
);
356 // View Action Handling
357 contributeToActionBars();
359 ITmfTrace trace
= TmfTraceManager
.getInstance().getActiveTrace();
361 traceSelected(new TmfTraceSelectedSignal(this, trace
));
364 fSashForm
.setVisible(true);
365 fSashForm
.setWeights(DEFAULT_WEIGHTS
);
367 fTimeControlsComposite
.addPaintListener(new PaintListener() {
369 public void paintControl(PaintEvent e
) {
370 // Sashes in a SashForm are being created on layout so add the
371 // drag listener here
372 if (fSashDragListener
== null) {
373 for (Control control
: fSashForm
.getChildren()) {
374 if (control
instanceof Sash
) {
375 fSashDragListener
= new Listener() {
377 public void handleEvent(Event event
) {
378 TmfSignalManager
.dispatchSignal(new TmfTimeViewAlignmentSignal(fSashForm
, getTimeViewAlignmentInfo()));
381 control
.removePaintListener(this);
382 control
.addListener(SWT
.Selection
, fSashDragListener
);
383 // There should be only one sash
393 public void setFocus() {
394 fFullTraceHistogram
.fCanvas
.setFocus();
398 getParentComposite().layout(true);
405 public TmfTimeViewAlignmentInfo
getTimeViewAlignmentInfo() {
406 if (fSashForm
== null) {
409 return new TmfTimeViewAlignmentInfo(fSashForm
.getShell(), fSashForm
.toDisplay(0, 0), getTimeAxisOffset());
412 private int getTimeAxisOffset() {
413 int[] weights
= fSashForm
.getWeights();
414 int width
= (int) (((float) weights
[0] / (weights
[0] + weights
[1])) * fSashForm
.getBounds().width
);
415 int curTimeAxisOffset
= width
+ fSashForm
.getSashWidth() + fTimeRangeHistogram
.getPointAreaOffset();
416 return curTimeAxisOffset
;
423 public int getAvailableWidth(int requestedOffset
) {
424 int pointAreaWidth
= fTimeRangeHistogram
.getPointAreaWidth();
425 int curTimeAxisOffset
= getTimeAxisOffset();
426 if (pointAreaWidth
<= 0) {
427 pointAreaWidth
= fSashForm
.getBounds().width
- curTimeAxisOffset
;
429 // TODO this is just an approximation that assumes that the end will be at the same position but that can change for a different data range/scaling
430 int endOffset
= curTimeAxisOffset
+ pointAreaWidth
;
431 GridLayout layout
= (GridLayout
) fTimeRangeComposite
.getLayout();
432 int endOffsetWithoutMargin
= endOffset
+ layout
.marginRight
;
433 int availableWidth
= endOffsetWithoutMargin
- requestedOffset
;
434 availableWidth
= Math
.min(fSashForm
.getBounds().width
, Math
.max(0, availableWidth
));
436 return availableWidth
;
443 public void performAlign(int offset
, int width
) {
444 int total
= fSashForm
.getBounds().width
;
445 int plotAreaOffset
= fTimeRangeHistogram
.getPointAreaOffset();
446 int width1
= Math
.max(0, offset
- plotAreaOffset
- fSashForm
.getSashWidth());
447 int width2
= Math
.max(0, total
- width1
- fSashForm
.getSashWidth());
448 fSashForm
.setWeights(new int[] { width1
, width2
});
451 // calculate right margin
452 GridLayout layout
= (GridLayout
) fTimeRangeComposite
.getLayout();
453 int timeBasedControlsWidth
= fTimeRangeComposite
.getSize().x
;
454 int marginSize
= timeBasedControlsWidth
- width
- plotAreaOffset
;
455 layout
.marginRight
= Math
.max(0, marginSize
);
456 fTimeRangeComposite
.layout();
459 // ------------------------------------------------------------------------
461 // ------------------------------------------------------------------------
464 * Returns the current trace handled by the view
466 * @return the current trace
468 public ITmfTrace
getTrace() {
473 * Returns the time range of the current selected window (base on default time scale).
475 * @return the time range of current selected window.
477 public TmfTimeRange
getTimeRange() {
478 return new TmfTimeRange(
479 new TmfTimestamp(fWindowStartTime
, ITmfTimestamp
.NANOSECOND_SCALE
),
480 new TmfTimestamp(fWindowEndTime
, ITmfTimestamp
.NANOSECOND_SCALE
));
484 * get the show lost events action
486 * @return The action object
488 public Action
getShowLostEventsAction() {
489 if (hideLostEventsAction
== null) {
490 /* show lost events */
491 hideLostEventsAction
= new Action(Messages
.HistogramView_hideLostEvents
, IAction
.AS_CHECK_BOX
) {
494 HistogramScaledData
.hideLostEvents
= hideLostEventsAction
.isChecked();
495 long maxNbEvents
= HistogramScaledData
.hideLostEvents ? fFullTraceHistogram
.fScaledData
.fMaxValue
: fFullTraceHistogram
.fScaledData
.fMaxCombinedValue
;
496 fFullTraceHistogram
.setMaxNbEvents(maxNbEvents
);
497 maxNbEvents
= HistogramScaledData
.hideLostEvents ? fTimeRangeHistogram
.fScaledData
.fMaxValue
: fTimeRangeHistogram
.fScaledData
.fMaxCombinedValue
;
498 fTimeRangeHistogram
.setMaxNbEvents(maxNbEvents
);
501 hideLostEventsAction
.setText(Messages
.HistogramView_hideLostEvents
);
502 hideLostEventsAction
.setToolTipText(Messages
.HistogramView_hideLostEvents
);
503 hideLostEventsAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_SHOW_LOST_EVENTS
));
505 return hideLostEventsAction
;
509 * get the show trace action
511 * @return The action object
513 public Action
getShowTraceAction() {
514 if (showTraceAction
== null) {
515 /* show lost events */
516 showTraceAction
= new Action(Messages
.HistogramView_showTraces
, IAction
.AS_CHECK_BOX
) {
519 Histogram
.showTraces
= showTraceAction
.isChecked();
520 fFullTraceHistogram
.fCanvas
.redraw();
521 fTimeRangeHistogram
.fCanvas
.redraw();
525 showTraceAction
.setChecked(true);
526 showTraceAction
.setText(Messages
.HistogramView_showTraces
);
527 showTraceAction
.setToolTipText(Messages
.HistogramView_showTraces
);
528 showTraceAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_SHOW_HIST_TRACES
));
530 return showTraceAction
;
533 // ------------------------------------------------------------------------
535 // ------------------------------------------------------------------------
538 * Broadcast TmfSignal about new current selection time range.
539 * @param beginTime the begin time of current selection.
540 * @param endTime the end time of current selection.
542 void updateSelectionTime(long beginTime
, long endTime
) {
543 updateDisplayedSelectionTime(beginTime
, endTime
);
544 TmfTimestamp beginTs
= new TmfTimestamp(beginTime
, ITmfTimestamp
.NANOSECOND_SCALE
);
545 TmfTimestamp endTs
= new TmfTimestamp(endTime
, ITmfTimestamp
.NANOSECOND_SCALE
);
546 TmfSelectionRangeUpdatedSignal signal
= new TmfSelectionRangeUpdatedSignal(this, beginTs
, endTs
);
547 fTimeSyncThrottle
.queue(signal
);
551 * Get selection begin time
552 * @return the begin time of current selection
554 long getSelectionBegin() {
555 return fSelectionBeginTime
;
559 * Get selection end time
560 * @return the end time of current selection
562 long getSelectionEnd() {
563 return fSelectionEndTime
;
568 * @return true if begin and end selection time should be linked
570 boolean getLinkState() {
575 * Broadcast TmfSignal about new selection time range.
576 * @param startTime the new start time
577 * @param endTime the new end time
579 void updateTimeRange(long startTime
, long endTime
) {
580 if (fTrace
!= null) {
581 // Build the new time range; keep the current time
582 TmfTimeRange timeRange
= new TmfTimeRange(
583 new TmfTimestamp(startTime
, ITmfTimestamp
.NANOSECOND_SCALE
),
584 new TmfTimestamp(endTime
, ITmfTimestamp
.NANOSECOND_SCALE
));
585 fTimeSpanControl
.setValue(endTime
- startTime
);
587 updateDisplayedTimeRange(startTime
, endTime
);
589 // Send the FW signal
590 TmfWindowRangeUpdatedSignal signal
= new TmfWindowRangeUpdatedSignal(this, timeRange
);
591 fTimeRangeSyncThrottle
.queue(signal
);
596 * Broadcast TmfSignal about new selected time range.
597 * @param newDuration new duration (relative to current start time)
599 public synchronized void updateTimeRange(long newDuration
) {
600 if (fTrace
!= null) {
601 long delta
= newDuration
- fWindowSpan
;
602 long newStartTime
= fWindowStartTime
- (delta
/ 2);
603 setNewRange(newStartTime
, newDuration
);
607 private void setNewRange(long startTime
, long duration
) {
608 long realStart
= startTime
;
610 if (realStart
< fTraceStartTime
) {
611 realStart
= fTraceStartTime
;
614 long endTime
= realStart
+ duration
;
615 if (endTime
> fTraceEndTime
) {
616 endTime
= fTraceEndTime
;
617 if ((endTime
- duration
) > fTraceStartTime
) {
618 realStart
= endTime
- duration
;
620 realStart
= fTraceStartTime
;
623 updateTimeRange(realStart
, endTime
);
626 // ------------------------------------------------------------------------
628 // ------------------------------------------------------------------------
631 * Handles trace opened signal. Loads histogram if new trace time range is not
632 * equal <code>TmfTimeRange.NULL_RANGE</code>
633 * @param signal the trace opened signal
636 public void traceOpened(TmfTraceOpenedSignal signal
) {
637 assert (signal
!= null);
638 fTrace
= signal
.getTrace();
643 * Handles trace selected signal. Loads histogram if new trace time range is not
644 * equal <code>TmfTimeRange.NULL_RANGE</code>
645 * @param signal the trace selected signal
648 public void traceSelected(TmfTraceSelectedSignal signal
) {
649 assert (signal
!= null);
650 if (fTrace
!= signal
.getTrace()) {
651 fTrace
= signal
.getTrace();
656 private void loadTrace() {
657 initializeHistograms();
658 getParentComposite().redraw();
662 * Handles trace closed signal. Clears the view and data model and cancels requests.
663 * @param signal the trace closed signal
666 public void traceClosed(TmfTraceClosedSignal signal
) {
668 if (signal
.getTrace() != fTrace
) {
672 // Kill any running request
673 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
674 fTimeRangeRequest
.cancel();
676 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
677 fFullTraceRequest
.cancel();
680 // Initialize the internal data
682 fTraceStartTime
= 0L;
684 fWindowStartTime
= 0L;
687 fSelectionBeginTime
= 0L;
688 fSelectionEndTime
= 0L;
690 // Clear the UI widgets
691 fFullTraceHistogram
.clear();
692 fTimeRangeHistogram
.clear();
693 fSelectionStartControl
.setValue(Long
.MIN_VALUE
);
694 fSelectionEndControl
.setValue(Long
.MIN_VALUE
);
696 fTimeSpanControl
.setValue(Long
.MIN_VALUE
);
698 for (Control c
: fLegendArea
.getChildren()) {
701 disposeLegendImages();
702 fLegendArea
.layout();
703 fLegendArea
.getParent().layout();
707 * Handles trace range updated signal. Extends histogram according to the new time range. If a
708 * HistogramRequest is already ongoing, it will be cancelled and a new request with the new range
711 * @param signal the trace range updated signal
714 public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal
) {
716 if (signal
.getTrace() != fTrace
) {
720 TmfTimeRange fullRange
= signal
.getRange();
722 fTraceStartTime
= fullRange
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
723 fTraceEndTime
= fullRange
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
725 fFullTraceHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
726 fTimeRangeHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
728 sendFullRangeRequest(fullRange
);
732 * Handles the trace updated signal. Used to update time limits (start and end time)
733 * @param signal the trace updated signal
736 public void traceUpdated(TmfTraceUpdatedSignal signal
) {
737 if (signal
.getTrace() != fTrace
) {
740 TmfTimeRange fullRange
= signal
.getTrace().getTimeRange();
741 fTraceStartTime
= fullRange
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
742 fTraceEndTime
= fullRange
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
744 fFullTraceHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
745 fTimeRangeHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
747 if ((fFullTraceRequest
!= null) && fFullTraceRequest
.getRange().getEndTime().compareTo(signal
.getRange().getEndTime()) < 0) {
748 sendFullRangeRequest(fullRange
);
753 * Handles the selection range updated signal. Sets the current time
754 * selection in the time range histogram as well as the full histogram.
757 * the signal to process
761 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal
) {
762 if (Display
.getCurrent() == null) {
763 // Make sure the signal is handled in the UI thread
764 Display
.getDefault().asyncExec(new Runnable() {
767 if (getParentComposite().isDisposed()) {
770 selectionRangeUpdated(signal
);
776 // Update the selected time range
777 ITmfTimestamp beginTime
= signal
.getBeginTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
);
778 ITmfTimestamp endTime
= signal
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
);
779 updateDisplayedSelectionTime(beginTime
.getValue(), endTime
.getValue());
783 * Updates the current window time range in the time range histogram and
784 * full range histogram.
787 * the signal to process
791 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal
) {
792 if (Display
.getCurrent() == null) {
793 // Make sure the signal is handled in the UI thread
794 Display
.getDefault().asyncExec(new Runnable() {
797 if (getParentComposite().isDisposed()) {
800 windowRangeUpdated(signal
);
806 if (fTrace
!= null) {
807 // Validate the time range
808 TmfTimeRange range
= signal
.getCurrentRange().getIntersection(fTrace
.getTimeRange());
813 updateDisplayedTimeRange(
814 range
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue(),
815 range
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue());
817 // Send the event request to populate the small histogram
818 sendTimeRangeRequest(fWindowStartTime
, fWindowEndTime
);
820 fTimeSpanControl
.setValue(fWindowSpan
);
824 // ------------------------------------------------------------------------
826 // ------------------------------------------------------------------------
828 private void initializeHistograms() {
829 TmfTimeRange fullRange
= updateTraceTimeRange();
831 TmfTraceContext ctx
= TmfTraceManager
.getInstance().getCurrentTraceContext();
832 long selectionBeginTime
= ctx
.getSelectionRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
833 long selectionEndTime
= ctx
.getSelectionRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
834 long startTime
= ctx
.getWindowRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
835 long duration
= ctx
.getWindowRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue() - startTime
;
837 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
838 fTimeRangeRequest
.cancel();
840 fTimeRangeHistogram
.clear();
841 fTimeRangeHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
842 fTimeRangeHistogram
.setTimeRange(startTime
, duration
);
843 fTimeRangeHistogram
.setSelection(selectionBeginTime
, selectionEndTime
);
844 fTimeRangeHistogram
.fDataModel
.setTrace(fTrace
);
846 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
847 fFullTraceRequest
.cancel();
849 fFullTraceHistogram
.clear();
850 fFullTraceHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
851 fFullTraceHistogram
.setTimeRange(startTime
, duration
);
852 fFullTraceHistogram
.setSelection(selectionBeginTime
, selectionEndTime
);
853 fFullTraceHistogram
.fDataModel
.setTrace(fTrace
);
855 fWindowStartTime
= startTime
;
856 fWindowSpan
= duration
;
857 fWindowEndTime
= startTime
+ duration
;
859 fSelectionBeginTime
= selectionBeginTime
;
860 fSelectionEndTime
= selectionEndTime
;
861 fSelectionStartControl
.setValue(fSelectionBeginTime
);
862 fSelectionEndControl
.setValue(fSelectionEndTime
);
864 // make sure that the scrollbar is setup properly
865 fScrollComposite
.setMinSize(fTimeControlsComposite
.computeSize(SWT
.DEFAULT
, SWT
.DEFAULT
));
866 fTimeSpanControl
.setValue(duration
);
868 Collection
<ITmfTrace
> traces
= TmfTraceManager
.getTraceSet(fTrace
);
869 if (!traces
.isEmpty()) {
870 this.showTraceAction
.setEnabled(traces
.size() < fFullTraceHistogram
.getMaxNbTraces());
874 if (!fullRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
875 sendTimeRangeRequest(startTime
, startTime
+ duration
);
876 sendFullRangeRequest(fullRange
);
880 private void updateLegendArea() {
881 for (Control c
: fLegendArea
.getChildren()) {
884 disposeLegendImages();
885 if (fFullTraceHistogram
.showTraces()) {
886 Collection
<ITmfTrace
> traces
= TmfTraceManager
.getTraceSet(fTrace
);
887 fLegendImages
= new Image
[traces
.size()];
889 for (ITmfTrace trace
: traces
) {
890 fLegendImages
[traceIndex
] = new Image(fLegendArea
.getDisplay(), 16, 16);
891 GC gc
= new GC(fLegendImages
[traceIndex
]);
892 gc
.setBackground(fFullTraceHistogram
.getTraceColor(traceIndex
));
893 gc
.fillRectangle(0, 0, 15, 15);
894 gc
.setForeground(fLegendArea
.getDisplay().getSystemColor(SWT
.COLOR_BLACK
));
895 gc
.drawRectangle(0, 0, 15, 15);
898 CLabel label
= new CLabel(fLegendArea
, SWT
.NONE
);
899 label
.setText(trace
.getName());
900 label
.setImage(fLegendImages
[traceIndex
]);
904 fLegendArea
.layout();
905 fLegendArea
.getParent().layout();
908 private void updateDisplayedSelectionTime(long beginTime
, long endTime
) {
909 fSelectionBeginTime
= beginTime
;
910 fSelectionEndTime
= endTime
;
912 fFullTraceHistogram
.setSelection(fSelectionBeginTime
, fSelectionEndTime
);
913 fTimeRangeHistogram
.setSelection(fSelectionBeginTime
, fSelectionEndTime
);
914 fSelectionStartControl
.setValue(fSelectionBeginTime
);
915 fSelectionEndControl
.setValue(fSelectionEndTime
);
918 private void updateDisplayedTimeRange(long start
, long end
) {
919 fWindowStartTime
= start
;
920 fWindowEndTime
= end
;
921 fWindowSpan
= fWindowEndTime
- fWindowStartTime
;
922 fFullTraceHistogram
.setTimeRange(fWindowStartTime
, fWindowSpan
);
925 private TmfTimeRange
updateTraceTimeRange() {
926 fTraceStartTime
= 0L;
929 TmfTimeRange timeRange
= fTrace
.getTimeRange();
930 if (!timeRange
.equals(TmfTimeRange
.NULL_RANGE
)) {
931 fTraceStartTime
= timeRange
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
932 fTraceEndTime
= timeRange
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
937 private void sendTimeRangeRequest(long startTime
, long endTime
) {
938 if ((fTimeRangeRequest
!= null) && !fTimeRangeRequest
.isCompleted()) {
939 fTimeRangeRequest
.cancel();
941 TmfTimestamp startTS
= new TmfTimestamp(startTime
, ITmfTimestamp
.NANOSECOND_SCALE
);
942 TmfTimestamp endTS
= new TmfTimestamp(endTime
, ITmfTimestamp
.NANOSECOND_SCALE
);
943 TmfTimeRange timeRange
= new TmfTimeRange(startTS
, endTS
);
945 fTimeRangeHistogram
.clear();
946 fTimeRangeHistogram
.setFullRange(fTraceStartTime
, fTraceEndTime
);
947 fTimeRangeHistogram
.setTimeRange(startTime
, endTime
- startTime
);
949 int cacheSize
= fTrace
.getCacheSize();
950 fTimeRangeRequest
= new HistogramRequest(fTimeRangeHistogram
.getDataModel(),
951 timeRange
, 0, ITmfEventRequest
.ALL_DATA
, cacheSize
, ExecutionType
.FOREGROUND
, false);
952 fTrace
.sendRequest(fTimeRangeRequest
);
955 private void sendFullRangeRequest(TmfTimeRange fullRange
) {
956 if ((fFullTraceRequest
!= null) && !fFullTraceRequest
.isCompleted()) {
957 fFullTraceRequest
.cancel();
959 int cacheSize
= fTrace
.getCacheSize();
960 fFullTraceRequest
= new HistogramRequest(fFullTraceHistogram
.getDataModel(),
962 (int) fFullTraceHistogram
.fDataModel
.getNbEvents(),
963 ITmfEventRequest
.ALL_DATA
,
965 ExecutionType
.BACKGROUND
, true);
966 fTrace
.sendRequest(fFullTraceRequest
);
969 private void contributeToActionBars() {
970 IActionBars bars
= getViewSite().getActionBars();
971 bars
.getToolBarManager().add(getShowLostEventsAction());
972 bars
.getToolBarManager().add(getShowTraceAction());
973 bars
.getToolBarManager().add(new Separator());
976 private void addLinkButtonListeners() {
977 fLinkButton
.addMouseListener(new MouseAdapter() {
979 public void mouseDown(MouseEvent e
) {
980 fSelectionEndControl
.setEnabled(fLinkState
);
981 fLinkState
= !fLinkState
;
982 fLinkButton
.redraw();
986 fLinkButton
.addPaintListener(new PaintListener() {
988 public void paintControl(PaintEvent e
) {
990 Rectangle r
= fLinkButton
.getBounds();
993 e
.gc
.setForeground(e
.display
.getSystemColor(SWT
.COLOR_WIDGET_NORMAL_SHADOW
));
994 e
.gc
.drawRectangle(r
);
997 e
.gc
.setForeground(e
.display
.getSystemColor(SWT
.COLOR_DARK_GRAY
));
998 e
.gc
.drawRectangle(r
);
1004 private static class PackedScrolledComposite
extends ScrolledComposite
{
1005 Point fScrollBarSize
; // Size of OS-specific scrollbar
1007 public PackedScrolledComposite(Composite parent
, int style
) {
1008 super(parent
, style
);
1009 Composite composite
= new Composite(parent
, SWT
.H_SCROLL
| SWT
.V_SCROLL
);
1010 composite
.setSize(1, 1);
1011 fScrollBarSize
= composite
.computeSize(0, 0);
1012 composite
.dispose();
1016 public Point
computeSize(int wHint
, int hHint
, boolean changed
) {
1017 Point point
= super.computeSize(wHint
, hHint
, changed
);
1018 // Remove scrollbar size if applicable
1019 point
.x
+= ((getStyle() & SWT
.V_SCROLL
) != 0) ?
-fScrollBarSize
.x
: 0;
1020 point
.y
+= ((getStyle() & SWT
.H_SCROLL
) != 0) ?
-fScrollBarSize
.y
: 0;