tmf: Move plugins to their own sub-directory
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / views / histogram / HistogramView.java
1 /*******************************************************************************
2 * Copyright (c) 2009, 2015 Ericsson
3 *
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
8 *
9 * Contributors:
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 *******************************************************************************/
19
20 package org.eclipse.tracecompass.tmf.ui.views.histogram;
21
22 import java.util.Collection;
23
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;
76
77 /**
78 * The purpose of this view is to provide graphical time distribution statistics about the trace events.
79 * <p>
80 * The view is composed of two histograms and two controls:
81 * <ul>
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).
86 * </ul>
87 * The histograms x-axis show their respective time range.
88 *
89 * @version 2.0
90 * @author Francois Chouinard
91 */
92 public class HistogramView extends TmfView implements ITmfTimeAligned {
93
94 // ------------------------------------------------------------------------
95 // Constants
96 // ------------------------------------------------------------------------
97
98 /**
99 * The view ID as defined in plugin.xml
100 */
101 public static final @NonNull String ID = "org.eclipse.linuxtools.tmf.ui.views.histogram"; //$NON-NLS-1$
102
103 private static final Image LINK_IMG = Activator.getDefault().getImageFromPath(ITmfImageConstants.IMG_UI_LINK);
104
105 private static final int[] DEFAULT_WEIGHTS = {1, 3};
106
107 // ------------------------------------------------------------------------
108 // Attributes
109 // ------------------------------------------------------------------------
110
111 // The current trace
112 private ITmfTrace fTrace;
113
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;
122
123 // SashForm
124 private SashForm fSashForm;
125 private ScrolledComposite fScrollComposite;
126 private Composite fTimeControlsComposite;
127 private Composite fTimeRangeComposite;
128 private Listener fSashDragListener;
129
130 // Time controls
131 private HistogramTextControl fSelectionStartControl;
132 private HistogramTextControl fSelectionEndControl;
133 private HistogramTextControl fTimeSpanControl;
134
135 // Link
136 private Label fLinkButton;
137 private boolean fLinkState;
138
139 // Histogram/request for the full trace range
140 private static FullTraceHistogram fFullTraceHistogram;
141 private HistogramRequest fFullTraceRequest;
142
143 // Histogram/request for the selected time range
144 private static TimeRangeHistogram fTimeRangeHistogram;
145 private HistogramRequest fTimeRangeRequest;
146
147 // Legend area
148 private Composite fLegendArea;
149 private Image[] fLegendImages;
150
151 // Throttlers for the time sync and time-range sync signals
152 private final TmfSignalThrottler fTimeSyncThrottle;
153 private final TmfSignalThrottler fTimeRangeSyncThrottle;
154
155 // Action for toggle showing the lost events
156 private Action hideLostEventsAction;
157 // Action for toggle showing the traces
158 private Action showTraceAction;
159
160 // ------------------------------------------------------------------------
161 // Constructor
162 // ------------------------------------------------------------------------
163
164 /**
165 * Default constructor
166 */
167 public HistogramView() {
168 super(ID);
169 fTimeSyncThrottle = new TmfSignalThrottler(this, 200);
170 fTimeRangeSyncThrottle = new TmfSignalThrottler(this, 200);
171 }
172
173 @Override
174 public void dispose() {
175 if ((fTimeRangeRequest != null) && !fTimeRangeRequest.isCompleted()) {
176 fTimeRangeRequest.cancel();
177 }
178 if ((fFullTraceRequest != null) && !fFullTraceRequest.isCompleted()) {
179 fFullTraceRequest.cancel();
180 }
181 fFullTraceHistogram.dispose();
182 fTimeRangeHistogram.dispose();
183 fSelectionStartControl.dispose();
184 fSelectionEndControl.dispose();
185 fTimeSpanControl.dispose();
186 disposeLegendImages();
187
188 super.dispose();
189 }
190
191 private void disposeLegendImages() {
192 if (fLegendImages != null) {
193 for (Image i: fLegendImages) {
194 i.dispose();
195 }
196 }
197 fLegendImages = null;
198 }
199
200 // ------------------------------------------------------------------------
201 // TmfView
202 // ------------------------------------------------------------------------
203
204 @Override
205 public void createPartControl(Composite parent) {
206 super.createPartControl(parent);
207
208 // Control labels
209 final String selectionStartLabel = Messages.HistogramView_selectionStartLabel;
210 final String selectionEndLabel = Messages.HistogramView_selectionEndLabel;
211 final String windowSpanLabel = Messages.HistogramView_windowSpanLabel;
212
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);
222
223 // --------------------------------------------------------------------
224 // Add a sash for time controls and time range histogram
225 // --------------------------------------------------------------------
226
227 /*
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.
232 */
233 fSashForm = new SashForm(viewComposite, SWT.NONE) {
234 @Override
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);
239 }
240 return computedSize;
241 }
242 @Override
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);
247 }
248 return computedSize;
249 }
250 };
251 GridData gridData = new GridData(GridData.FILL, GridData.FILL, false, true);
252 fSashForm.setLayoutData(gridData);
253
254 // --------------------------------------------------------------------
255 // Time controls
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);
266
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);
273
274 Composite innerComp = new Composite(fTimeControlsComposite, SWT.NONE);
275
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);
284
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);
292
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);
298
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);
304
305 // Link button
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();
311
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);
317
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);
326
327 // Use remaining horizontal space
328 gridData = new GridData(GridData.FILL, GridData.FILL, true, true);
329 fTimeRangeComposite.setLayoutData(gridData);
330
331 // Histogram
332 fTimeRangeHistogram = new TimeRangeHistogram(this, fTimeRangeComposite, true);
333
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);
340
341 // Use remaining horizontal space
342 gridData = new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1);
343 fullRangeComposite.setLayoutData(gridData);
344
345 // Histogram
346 fFullTraceHistogram = new FullTraceHistogram(this, fullRangeComposite);
347
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());
351
352 // Add mouse wheel listener to time span control
353 MouseWheelListener listener = fFullTraceHistogram.getZoom();
354 fTimeSpanControl.addMouseWheelListener(listener);
355
356 // View Action Handling
357 contributeToActionBars();
358
359 ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace();
360 if (trace != null) {
361 traceSelected(new TmfTraceSelectedSignal(this, trace));
362 }
363
364 fSashForm.setVisible(true);
365 fSashForm.setWeights(DEFAULT_WEIGHTS);
366
367 fTimeControlsComposite.addPaintListener(new PaintListener() {
368 @Override
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() {
376 @Override
377 public void handleEvent(Event event) {
378 TmfSignalManager.dispatchSignal(new TmfTimeViewAlignmentSignal(fSashForm, getTimeViewAlignmentInfo()));
379 }
380 };
381 control.removePaintListener(this);
382 control.addListener(SWT.Selection, fSashDragListener);
383 // There should be only one sash
384 break;
385 }
386 }
387 }
388 }
389 });
390 }
391
392 @Override
393 public void setFocus() {
394 fFullTraceHistogram.fCanvas.setFocus();
395 }
396
397 void refresh() {
398 getParentComposite().layout(true);
399 }
400
401 /**
402 * @since 1.0
403 */
404 @Override
405 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
406 if (fSashForm == null) {
407 return null;
408 }
409 return new TmfTimeViewAlignmentInfo(fSashForm.getShell(), fSashForm.toDisplay(0, 0), getTimeAxisOffset());
410 }
411
412 private int getTimeAxisOffset() {
413 return fScrollComposite.getSize().x + fSashForm.getSashWidth() + fTimeRangeHistogram.getPointAreaOffset();
414 }
415
416 /**
417 * @since 1.0
418 */
419 @Override
420 public int getAvailableWidth(int requestedOffset) {
421 int pointAreaWidth = fTimeRangeHistogram.getPointAreaWidth();
422 int curTimeAxisOffset = getTimeAxisOffset();
423 if (pointAreaWidth <= 0) {
424 pointAreaWidth = fSashForm.getBounds().width - curTimeAxisOffset;
425 }
426 // 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
427 int endOffset = curTimeAxisOffset + pointAreaWidth;
428 GridLayout layout = (GridLayout) fTimeRangeComposite.getLayout();
429 int endOffsetWithoutMargin = endOffset + layout.marginRight;
430 int availableWidth = endOffsetWithoutMargin - requestedOffset;
431 availableWidth = Math.min(fSashForm.getBounds().width, Math.max(0, availableWidth));
432
433 return availableWidth;
434 }
435
436 /**
437 * @since 1.0
438 */
439 @Override
440 public void performAlign(int offset, int width) {
441 int total = fSashForm.getBounds().width;
442 int plotAreaOffset = fTimeRangeHistogram.getPointAreaOffset();
443 int width1 = Math.max(0, offset - plotAreaOffset - fSashForm.getSashWidth());
444 int width2 = Math.max(0, total - width1 - fSashForm.getSashWidth());
445 fSashForm.setWeights(new int[] { width1, width2 });
446 fSashForm.layout();
447
448 // calculate right margin
449 GridLayout layout = (GridLayout) fTimeRangeComposite.getLayout();
450 int timeBasedControlsWidth = fTimeRangeComposite.getSize().x;
451 int marginSize = timeBasedControlsWidth - width - plotAreaOffset;
452 layout.marginRight = Math.max(0, marginSize);
453 fTimeRangeComposite.layout();
454 }
455
456 // ------------------------------------------------------------------------
457 // Accessors
458 // ------------------------------------------------------------------------
459
460 /**
461 * Returns the current trace handled by the view
462 *
463 * @return the current trace
464 */
465 public ITmfTrace getTrace() {
466 return fTrace;
467 }
468
469 /**
470 * Returns the time range of the current selected window (base on default time scale).
471 *
472 * @return the time range of current selected window.
473 */
474 public TmfTimeRange getTimeRange() {
475 return new TmfTimeRange(
476 new TmfTimestamp(fWindowStartTime, ITmfTimestamp.NANOSECOND_SCALE),
477 new TmfTimestamp(fWindowEndTime, ITmfTimestamp.NANOSECOND_SCALE));
478 }
479
480 /**
481 * get the show lost events action
482 *
483 * @return The action object
484 */
485 public Action getShowLostEventsAction() {
486 if (hideLostEventsAction == null) {
487 /* show lost events */
488 hideLostEventsAction = new Action(Messages.HistogramView_hideLostEvents, IAction.AS_CHECK_BOX) {
489 @Override
490 public void run() {
491 HistogramScaledData.hideLostEvents = hideLostEventsAction.isChecked();
492 long maxNbEvents = HistogramScaledData.hideLostEvents ? fFullTraceHistogram.fScaledData.fMaxValue : fFullTraceHistogram.fScaledData.fMaxCombinedValue;
493 fFullTraceHistogram.setMaxNbEvents(maxNbEvents);
494 maxNbEvents = HistogramScaledData.hideLostEvents ? fTimeRangeHistogram.fScaledData.fMaxValue : fTimeRangeHistogram.fScaledData.fMaxCombinedValue;
495 fTimeRangeHistogram.setMaxNbEvents(maxNbEvents);
496 }
497 };
498 hideLostEventsAction.setText(Messages.HistogramView_hideLostEvents);
499 hideLostEventsAction.setToolTipText(Messages.HistogramView_hideLostEvents);
500 hideLostEventsAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SHOW_LOST_EVENTS));
501 }
502 return hideLostEventsAction;
503 }
504
505 /**
506 * get the show trace action
507 *
508 * @return The action object
509 */
510 public Action getShowTraceAction() {
511 if (showTraceAction == null) {
512 /* show lost events */
513 showTraceAction = new Action(Messages.HistogramView_showTraces, IAction.AS_CHECK_BOX) {
514 @Override
515 public void run() {
516 Histogram.showTraces = showTraceAction.isChecked();
517 fFullTraceHistogram.fCanvas.redraw();
518 fTimeRangeHistogram.fCanvas.redraw();
519 updateLegendArea();
520 }
521 };
522 showTraceAction.setChecked(true);
523 showTraceAction.setText(Messages.HistogramView_showTraces);
524 showTraceAction.setToolTipText(Messages.HistogramView_showTraces);
525 showTraceAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SHOW_HIST_TRACES));
526 }
527 return showTraceAction;
528 }
529
530 // ------------------------------------------------------------------------
531 // Operations
532 // ------------------------------------------------------------------------
533
534 /**
535 * Broadcast TmfSignal about new current selection time range.
536 * @param beginTime the begin time of current selection.
537 * @param endTime the end time of current selection.
538 */
539 void updateSelectionTime(long beginTime, long endTime) {
540 updateDisplayedSelectionTime(beginTime, endTime);
541 TmfTimestamp beginTs = new TmfTimestamp(beginTime, ITmfTimestamp.NANOSECOND_SCALE);
542 TmfTimestamp endTs = new TmfTimestamp(endTime, ITmfTimestamp.NANOSECOND_SCALE);
543 TmfSelectionRangeUpdatedSignal signal = new TmfSelectionRangeUpdatedSignal(this, beginTs, endTs);
544 fTimeSyncThrottle.queue(signal);
545 }
546
547 /**
548 * Get selection begin time
549 * @return the begin time of current selection
550 */
551 long getSelectionBegin() {
552 return fSelectionBeginTime;
553 }
554
555 /**
556 * Get selection end time
557 * @return the end time of current selection
558 */
559 long getSelectionEnd() {
560 return fSelectionEndTime;
561 }
562
563 /**
564 * Get the link state
565 * @return true if begin and end selection time should be linked
566 */
567 boolean getLinkState() {
568 return fLinkState;
569 }
570
571 /**
572 * Broadcast TmfSignal about new selection time range.
573 * @param startTime the new start time
574 * @param endTime the new end time
575 */
576 void updateTimeRange(long startTime, long endTime) {
577 if (fTrace != null) {
578 // Build the new time range; keep the current time
579 TmfTimeRange timeRange = new TmfTimeRange(
580 new TmfTimestamp(startTime, ITmfTimestamp.NANOSECOND_SCALE),
581 new TmfTimestamp(endTime, ITmfTimestamp.NANOSECOND_SCALE));
582 fTimeSpanControl.setValue(endTime - startTime);
583
584 updateDisplayedTimeRange(startTime, endTime);
585
586 // Send the FW signal
587 TmfWindowRangeUpdatedSignal signal = new TmfWindowRangeUpdatedSignal(this, timeRange);
588 fTimeRangeSyncThrottle.queue(signal);
589 }
590 }
591
592 /**
593 * Broadcast TmfSignal about new selected time range.
594 * @param newDuration new duration (relative to current start time)
595 */
596 public synchronized void updateTimeRange(long newDuration) {
597 if (fTrace != null) {
598 long delta = newDuration - fWindowSpan;
599 long newStartTime = fWindowStartTime - (delta / 2);
600 setNewRange(newStartTime, newDuration);
601 }
602 }
603
604 private void setNewRange(long startTime, long duration) {
605 long realStart = startTime;
606
607 if (realStart < fTraceStartTime) {
608 realStart = fTraceStartTime;
609 }
610
611 long endTime = realStart + duration;
612 if (endTime > fTraceEndTime) {
613 endTime = fTraceEndTime;
614 if ((endTime - duration) > fTraceStartTime) {
615 realStart = endTime - duration;
616 } else {
617 realStart = fTraceStartTime;
618 }
619 }
620 updateTimeRange(realStart, endTime);
621 }
622
623 // ------------------------------------------------------------------------
624 // Signal handlers
625 // ------------------------------------------------------------------------
626
627 /**
628 * Handles trace opened signal. Loads histogram if new trace time range is not
629 * equal <code>TmfTimeRange.NULL_RANGE</code>
630 * @param signal the trace opened signal
631 */
632 @TmfSignalHandler
633 public void traceOpened(TmfTraceOpenedSignal signal) {
634 assert (signal != null);
635 fTrace = signal.getTrace();
636 loadTrace();
637 }
638
639 /**
640 * Handles trace selected signal. Loads histogram if new trace time range is not
641 * equal <code>TmfTimeRange.NULL_RANGE</code>
642 * @param signal the trace selected signal
643 */
644 @TmfSignalHandler
645 public void traceSelected(TmfTraceSelectedSignal signal) {
646 assert (signal != null);
647 if (fTrace != signal.getTrace()) {
648 fTrace = signal.getTrace();
649 loadTrace();
650 }
651 }
652
653 private void loadTrace() {
654 initializeHistograms();
655 getParentComposite().redraw();
656 }
657
658 /**
659 * Handles trace closed signal. Clears the view and data model and cancels requests.
660 * @param signal the trace closed signal
661 */
662 @TmfSignalHandler
663 public void traceClosed(TmfTraceClosedSignal signal) {
664
665 if (signal.getTrace() != fTrace) {
666 return;
667 }
668
669 // Kill any running request
670 if ((fTimeRangeRequest != null) && !fTimeRangeRequest.isCompleted()) {
671 fTimeRangeRequest.cancel();
672 }
673 if ((fFullTraceRequest != null) && !fFullTraceRequest.isCompleted()) {
674 fFullTraceRequest.cancel();
675 }
676
677 // Initialize the internal data
678 fTrace = null;
679 fTraceStartTime = 0L;
680 fTraceEndTime = 0L;
681 fWindowStartTime = 0L;
682 fWindowEndTime = 0L;
683 fWindowSpan = 0L;
684 fSelectionBeginTime = 0L;
685 fSelectionEndTime = 0L;
686
687 // Clear the UI widgets
688 fFullTraceHistogram.clear();
689 fTimeRangeHistogram.clear();
690 fSelectionStartControl.setValue(Long.MIN_VALUE);
691 fSelectionEndControl.setValue(Long.MIN_VALUE);
692
693 fTimeSpanControl.setValue(Long.MIN_VALUE);
694
695 for (Control c: fLegendArea.getChildren()) {
696 c.dispose();
697 }
698 disposeLegendImages();
699 fLegendArea.layout();
700 fLegendArea.getParent().layout();
701 }
702
703 /**
704 * Handles trace range updated signal. Extends histogram according to the new time range. If a
705 * HistogramRequest is already ongoing, it will be cancelled and a new request with the new range
706 * will be issued.
707 *
708 * @param signal the trace range updated signal
709 */
710 @TmfSignalHandler
711 public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal) {
712
713 if (signal.getTrace() != fTrace) {
714 return;
715 }
716
717 TmfTimeRange fullRange = signal.getRange();
718
719 fTraceStartTime = fullRange.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
720 fTraceEndTime = fullRange.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
721
722 fFullTraceHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
723 fTimeRangeHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
724
725 sendFullRangeRequest(fullRange);
726 }
727
728 /**
729 * Handles the trace updated signal. Used to update time limits (start and end time)
730 * @param signal the trace updated signal
731 */
732 @TmfSignalHandler
733 public void traceUpdated(TmfTraceUpdatedSignal signal) {
734 if (signal.getTrace() != fTrace) {
735 return;
736 }
737 TmfTimeRange fullRange = signal.getTrace().getTimeRange();
738 fTraceStartTime = fullRange.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
739 fTraceEndTime = fullRange.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
740
741 fFullTraceHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
742 fTimeRangeHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
743
744 if ((fFullTraceRequest != null) && fFullTraceRequest.getRange().getEndTime().compareTo(signal.getRange().getEndTime()) < 0) {
745 sendFullRangeRequest(fullRange);
746 }
747 }
748
749 /**
750 * Handles the selection range updated signal. Sets the current time
751 * selection in the time range histogram as well as the full histogram.
752 *
753 * @param signal
754 * the signal to process
755 * @since 1.0
756 */
757 @TmfSignalHandler
758 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal) {
759 if (Display.getCurrent() == null) {
760 // Make sure the signal is handled in the UI thread
761 Display.getDefault().asyncExec(new Runnable() {
762 @Override
763 public void run() {
764 if (getParentComposite().isDisposed()) {
765 return;
766 }
767 selectionRangeUpdated(signal);
768 }
769 });
770 return;
771 }
772
773 // Update the selected time range
774 ITmfTimestamp beginTime = signal.getBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE);
775 ITmfTimestamp endTime = signal.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE);
776 updateDisplayedSelectionTime(beginTime.getValue(), endTime.getValue());
777 }
778
779 /**
780 * Updates the current window time range in the time range histogram and
781 * full range histogram.
782 *
783 * @param signal
784 * the signal to process
785 * @since 1.0
786 */
787 @TmfSignalHandler
788 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal) {
789 if (Display.getCurrent() == null) {
790 // Make sure the signal is handled in the UI thread
791 Display.getDefault().asyncExec(new Runnable() {
792 @Override
793 public void run() {
794 if (getParentComposite().isDisposed()) {
795 return;
796 }
797 windowRangeUpdated(signal);
798 }
799 });
800 return;
801 }
802
803 if (fTrace != null) {
804 // Validate the time range
805 TmfTimeRange range = signal.getCurrentRange().getIntersection(fTrace.getTimeRange());
806 if (range == null) {
807 return;
808 }
809
810 updateDisplayedTimeRange(
811 range.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue(),
812 range.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue());
813
814 // Send the event request to populate the small histogram
815 sendTimeRangeRequest(fWindowStartTime, fWindowEndTime);
816
817 fTimeSpanControl.setValue(fWindowSpan);
818 }
819 }
820
821 // ------------------------------------------------------------------------
822 // Helper functions
823 // ------------------------------------------------------------------------
824
825 private void initializeHistograms() {
826 TmfTimeRange fullRange = updateTraceTimeRange();
827
828 TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext();
829 long selectionBeginTime = ctx.getSelectionRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
830 long selectionEndTime = ctx.getSelectionRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
831 long startTime = ctx.getWindowRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
832 long duration = ctx.getWindowRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue() - startTime;
833
834 if ((fTimeRangeRequest != null) && !fTimeRangeRequest.isCompleted()) {
835 fTimeRangeRequest.cancel();
836 }
837 fTimeRangeHistogram.clear();
838 fTimeRangeHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
839 fTimeRangeHistogram.setTimeRange(startTime, duration);
840 fTimeRangeHistogram.setSelection(selectionBeginTime, selectionEndTime);
841 fTimeRangeHistogram.fDataModel.setTrace(fTrace);
842
843 if ((fFullTraceRequest != null) && !fFullTraceRequest.isCompleted()) {
844 fFullTraceRequest.cancel();
845 }
846 fFullTraceHistogram.clear();
847 fFullTraceHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
848 fFullTraceHistogram.setTimeRange(startTime, duration);
849 fFullTraceHistogram.setSelection(selectionBeginTime, selectionEndTime);
850 fFullTraceHistogram.fDataModel.setTrace(fTrace);
851
852 fWindowStartTime = startTime;
853 fWindowSpan = duration;
854 fWindowEndTime = startTime + duration;
855
856 fSelectionBeginTime = selectionBeginTime;
857 fSelectionEndTime = selectionEndTime;
858 fSelectionStartControl.setValue(fSelectionBeginTime);
859 fSelectionEndControl.setValue(fSelectionEndTime);
860
861 // make sure that the scrollbar is setup properly
862 fScrollComposite.setMinSize(fTimeControlsComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
863 fTimeSpanControl.setValue(duration);
864
865 Collection<ITmfTrace> traces = TmfTraceManager.getTraceSet(fTrace);
866 if (!traces.isEmpty()) {
867 this.showTraceAction.setEnabled(traces.size() < fFullTraceHistogram.getMaxNbTraces());
868 }
869 updateLegendArea();
870
871 if (!fullRange.equals(TmfTimeRange.NULL_RANGE)) {
872 sendTimeRangeRequest(startTime, startTime + duration);
873 sendFullRangeRequest(fullRange);
874 }
875 }
876
877 private void updateLegendArea() {
878 for (Control c: fLegendArea.getChildren()) {
879 c.dispose();
880 }
881 disposeLegendImages();
882 if (fFullTraceHistogram.showTraces()) {
883 Collection<ITmfTrace> traces = TmfTraceManager.getTraceSet(fTrace);
884 fLegendImages = new Image[traces.size()];
885 int traceIndex = 0;
886 for (ITmfTrace trace : traces) {
887 fLegendImages[traceIndex] = new Image(fLegendArea.getDisplay(), 16, 16);
888 GC gc = new GC(fLegendImages[traceIndex]);
889 gc.setBackground(fFullTraceHistogram.getTraceColor(traceIndex));
890 gc.fillRectangle(0, 0, 15, 15);
891 gc.setForeground(fLegendArea.getDisplay().getSystemColor(SWT.COLOR_BLACK));
892 gc.drawRectangle(0, 0, 15, 15);
893 gc.dispose();
894
895 CLabel label = new CLabel(fLegendArea, SWT.NONE);
896 label.setText(trace.getName());
897 label.setImage(fLegendImages[traceIndex]);
898 traceIndex++;
899 }
900 }
901 fLegendArea.layout();
902 fLegendArea.getParent().layout();
903 }
904
905 private void updateDisplayedSelectionTime(long beginTime, long endTime) {
906 fSelectionBeginTime = beginTime;
907 fSelectionEndTime = endTime;
908
909 fFullTraceHistogram.setSelection(fSelectionBeginTime, fSelectionEndTime);
910 fTimeRangeHistogram.setSelection(fSelectionBeginTime, fSelectionEndTime);
911 fSelectionStartControl.setValue(fSelectionBeginTime);
912 fSelectionEndControl.setValue(fSelectionEndTime);
913 }
914
915 private void updateDisplayedTimeRange(long start, long end) {
916 fWindowStartTime = start;
917 fWindowEndTime = end;
918 fWindowSpan = fWindowEndTime - fWindowStartTime;
919 fFullTraceHistogram.setTimeRange(fWindowStartTime, fWindowSpan);
920 }
921
922 private TmfTimeRange updateTraceTimeRange() {
923 fTraceStartTime = 0L;
924 fTraceEndTime = 0L;
925
926 TmfTimeRange timeRange = fTrace.getTimeRange();
927 if (!timeRange.equals(TmfTimeRange.NULL_RANGE)) {
928 fTraceStartTime = timeRange.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
929 fTraceEndTime = timeRange.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
930 }
931 return timeRange;
932 }
933
934 private void sendTimeRangeRequest(long startTime, long endTime) {
935 if ((fTimeRangeRequest != null) && !fTimeRangeRequest.isCompleted()) {
936 fTimeRangeRequest.cancel();
937 }
938 TmfTimestamp startTS = new TmfTimestamp(startTime, ITmfTimestamp.NANOSECOND_SCALE);
939 TmfTimestamp endTS = new TmfTimestamp(endTime, ITmfTimestamp.NANOSECOND_SCALE);
940 TmfTimeRange timeRange = new TmfTimeRange(startTS, endTS);
941
942 fTimeRangeHistogram.clear();
943 fTimeRangeHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
944 fTimeRangeHistogram.setTimeRange(startTime, endTime - startTime);
945
946 int cacheSize = fTrace.getCacheSize();
947 fTimeRangeRequest = new HistogramRequest(fTimeRangeHistogram.getDataModel(),
948 timeRange, 0, ITmfEventRequest.ALL_DATA, cacheSize, ExecutionType.FOREGROUND, false);
949 fTrace.sendRequest(fTimeRangeRequest);
950 }
951
952 private void sendFullRangeRequest(TmfTimeRange fullRange) {
953 if ((fFullTraceRequest != null) && !fFullTraceRequest.isCompleted()) {
954 fFullTraceRequest.cancel();
955 }
956 int cacheSize = fTrace.getCacheSize();
957 fFullTraceRequest = new HistogramRequest(fFullTraceHistogram.getDataModel(),
958 fullRange,
959 (int) fFullTraceHistogram.fDataModel.getNbEvents(),
960 ITmfEventRequest.ALL_DATA,
961 cacheSize,
962 ExecutionType.BACKGROUND, true);
963 fTrace.sendRequest(fFullTraceRequest);
964 }
965
966 private void contributeToActionBars() {
967 IActionBars bars = getViewSite().getActionBars();
968 bars.getToolBarManager().add(getShowLostEventsAction());
969 bars.getToolBarManager().add(getShowTraceAction());
970 bars.getToolBarManager().add(new Separator());
971 }
972
973 private void addLinkButtonListeners() {
974 fLinkButton.addMouseListener(new MouseAdapter() {
975 @Override
976 public void mouseDown(MouseEvent e) {
977 fSelectionEndControl.setEnabled(fLinkState);
978 fLinkState = !fLinkState;
979 fLinkButton.redraw();
980 }
981 });
982
983 fLinkButton.addPaintListener(new PaintListener() {
984 @Override
985 public void paintControl(PaintEvent e) {
986 if (fLinkState) {
987 Rectangle r = fLinkButton.getBounds();
988 r.x = -1;
989 r.y = -1;
990 e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
991 e.gc.drawRectangle(r);
992 r.x = 0;
993 r.y = 0;
994 e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_DARK_GRAY));
995 e.gc.drawRectangle(r);
996 }
997 }
998 });
999 }
1000
1001 private static class PackedScrolledComposite extends ScrolledComposite {
1002 Point fScrollBarSize; // Size of OS-specific scrollbar
1003
1004 public PackedScrolledComposite(Composite parent, int style) {
1005 super(parent, style);
1006 Composite composite = new Composite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
1007 composite.setSize(1, 1);
1008 fScrollBarSize = composite.computeSize(0, 0);
1009 composite.dispose();
1010 }
1011
1012 @Override
1013 public Point computeSize(int wHint, int hHint, boolean changed) {
1014 Point point = super.computeSize(wHint, hHint, changed);
1015 // Remove scrollbar size if applicable
1016 point.x += ((getStyle() & SWT.V_SCROLL) != 0) ? -fScrollBarSize.x : 0;
1017 point.y += ((getStyle() & SWT.H_SCROLL) != 0) ? -fScrollBarSize.y : 0;
1018 return point;
1019 }
1020 }
1021 }
This page took 0.052758 seconds and 6 git commands to generate.