latency.view.name = System Call Latencies
latency.scatter.view.name = Systemt Call Latency vs Time
latency.stats.view.name = System Call Latency Statistics
+latency.density.view.name = System Call Density
name="%latency.stats.view.name"
restorable="true">
</view>
+ <view
+ category="org.eclipse.linuxtools.lttng2.ui.views.category"
+ class="org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.latency.SystemCallLatencyDensityView"
+ icon="icons/eview16/density.png"
+ id="org.eclipse.tracecompass.analysis.os.linux.views.latency.density"
+ name="%latency.density.view.name"
+ restorable="true">
+ </view>
</extension>
<extension
point="org.eclipse.linuxtools.tmf.core.analysis">
class="org.eclipse.tracecompass.analysis.os.linux.core.latency.SystemCallLatencyAnalysis">
</analysisModuleClass>
</output>
-
+ <output
+ class="org.eclipse.tracecompass.tmf.ui.analysis.TmfAnalysisViewOutput"
+ id="org.eclipse.tracecompass.analysis.os.linux.views.latency.density">
+ <analysisModuleClass
+ class="org.eclipse.tracecompass.analysis.os.linux.core.latency.SystemCallLatencyAnalysis">
+ </analysisModuleClass>
+ </output>
</extension>
</plugin>
--- /dev/null
+/******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.latency;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tracecompass.analysis.os.linux.core.latency.SystemCallLatencyAnalysis;
+import org.eclipse.tracecompass.analysis.timing.core.segmentstore.AbstractSegmentStoreAnalysisModule;
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density.AbstractSegmentStoreDensityViewer;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
+
+/**
+ * System Call density viewer
+ *
+ * @author Matthew Khouzam
+ * @author Marc-Andre Laperle
+ */
+public class SystemCallDensityViewer extends AbstractSegmentStoreDensityViewer {
+
+ /**
+ * Constructs a new density viewer.
+ *
+ * @param parent
+ * the parent of the viewer
+ */
+ public SystemCallDensityViewer(Composite parent) {
+ super(parent);
+ }
+
+ @Override
+ protected @Nullable AbstractSegmentStoreAnalysisModule getSegmentStoreAnalysisModule(ITmfTrace trace) {
+ return TmfTraceUtils.getAnalysisModuleOfClass(trace, SystemCallLatencyAnalysis.class, SystemCallLatencyAnalysis.ID);
+ }
+}
--- /dev/null
+/******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.latency;
+
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.AbstractSegmentStoreTableViewer;
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density.AbstractSegmentStoreDensityView;
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density.AbstractSegmentStoreDensityViewer;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+
+/**
+ * System Call Density view
+ *
+ * @author Matthew Khouzam
+ * @author Marc-Andre Laperle
+ */
+public class SystemCallLatencyDensityView extends AbstractSegmentStoreDensityView {
+
+ /** The view's ID */
+ public static final String ID = "org.eclipse.tracecompass.analysis.os.linux.views.latency.density"; //$NON-NLS-1$
+
+ /**
+ * Constructs a new density view.
+ */
+ public SystemCallLatencyDensityView() {
+ super(ID);
+ }
+
+ @Override
+ protected AbstractSegmentStoreTableViewer createSegmentStoreTableViewer(Composite parent) {
+ return new SystemCallLatencyTableViewer(new TableViewer(parent, SWT.FULL_SELECTION | SWT.VIRTUAL)) {
+ @Override
+ protected void createAnalysisColumns() {
+ super.createAnalysisColumns();
+ Table t = (Table) getControl();
+ t.setColumnOrder(new int[] { 2, 3, 0, 1 });
+ }
+ };
+ }
+
+ @Override
+ protected AbstractSegmentStoreDensityViewer createSegmentStoreDensityViewer(Composite parent) {
+ return new SystemCallDensityViewer(NonNullUtils.checkNotNull(parent));
+ }
+
+}
org.eclipse.tracecompass.tmf.ui,
org.swtchart
Export-Package: org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore,
+ org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density,
org.eclipse.tracecompass.internal.analysis.timing.ui,
- org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore
+ org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore,
+ org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density
output.. = bin/
bin.includes = META-INF/,\
plugin.properties,\
- .
+ .,\
+ icons/
additional.bundles = org.eclipse.jdt.annotation
jars.extra.classpath = platform:/plugin/org.eclipse.jdt.annotation
--- /dev/null
+/******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore;
+
+/**
+ * Names for images used in this plugin
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ */
+@SuppressWarnings({"nls", "javadoc"})
+public interface AnalysisTimingImageConstants {
+
+ String ICONS_PATH = "icons/"; //$NON-NLS-1$
+
+ String IMG_UI_ZOOM_OUT_MENU = ICONS_PATH + "elcl16/zoomout_nav.gif";
+}
--- /dev/null
+/******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density;
+
+import java.util.List;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.AbstractSegmentStoreTableViewer;
+import org.eclipse.tracecompass.segmentstore.core.ISegment;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+
+/**
+ * Displays the segment store analysis data in a density chart and a table
+ * corresponding to the selected latencies.
+ *
+ * @author Matthew Khouzam
+ * @author Marc-Andre Laperle
+ */
+public abstract class AbstractSegmentStoreDensityView extends TmfView {
+
+ private static final int[] DEFAULT_WEIGHTS = new int[] { 4, 6 };
+
+ private @Nullable AbstractSegmentStoreDensityViewer fDensityViewer;
+ private @Nullable AbstractSegmentStoreTableViewer fTableViewer;
+
+ /**
+ * Constructs a segment store density view
+ *
+ * @param viewName
+ * the name of the view
+ */
+ public AbstractSegmentStoreDensityView(String viewName) {
+ super(viewName);
+ }
+
+ /**
+ * Used to keep the table in sync with the density viewer.
+ */
+ private final class DataChangedListener implements ISegmentStoreDensityViewerDataListener {
+ @Override
+ public void dataChanged(List<ISegment> data) {
+ updateTableModel(data);
+ }
+
+ private void updateTableModel(@Nullable List<ISegment> data) {
+ final AbstractSegmentStoreTableViewer viewer = fTableViewer;
+ if (viewer != null && data != null) {
+ viewer.updateModel(data.toArray(new ISegment[] {}));
+ }
+ }
+
+ @Override
+ public void dataSelectionChanged(List<ISegment> data) {
+ updateTableModel(data);
+ }
+ }
+
+ @Override
+ public void createPartControl(@Nullable Composite parent) {
+ super.createPartControl(parent);
+
+ final SashForm sashForm = new SashForm(parent, SWT.NONE);
+
+ fTableViewer = createSegmentStoreTableViewer(sashForm);
+ fDensityViewer = createSegmentStoreDensityViewer(sashForm);
+ fDensityViewer.addDataListener(new DataChangedListener());
+
+ sashForm.setWeights(DEFAULT_WEIGHTS);
+
+ Action zoomOut = new ZoomOutAction(this);
+ IToolBarManager toolBar = getViewSite().getActionBars().getToolBarManager();
+ toolBar.add(zoomOut);
+ ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace();
+ if (trace != null && fDensityViewer != null) {
+ fDensityViewer.loadTrace(trace);
+ }
+ }
+
+ /**
+ * Create a table viewer suitable for displaying the segment store content.
+ *
+ * @param parent
+ * the parent composite
+ * @return the table viewer
+ */
+ abstract protected AbstractSegmentStoreTableViewer createSegmentStoreTableViewer(Composite parent);
+
+ /**
+ * Create a density viewer suitable for displaying the segment store
+ * content.
+ *
+ * @param parent
+ * the parent composite
+ * @return the density viewer
+ */
+ abstract protected AbstractSegmentStoreDensityViewer createSegmentStoreDensityViewer(Composite parent);
+
+ @Override
+ public void setFocus() {
+ final AbstractSegmentStoreDensityViewer viewer = fDensityViewer;
+ if (viewer != null) {
+ viewer.getControl().setFocus();
+ }
+ }
+
+ @Override
+ public void dispose() {
+ final AbstractSegmentStoreDensityViewer densityViewer = fDensityViewer;
+ if (densityViewer != null) {
+ densityViewer.dispose();
+ }
+
+ final AbstractSegmentStoreTableViewer tableViewer = fTableViewer;
+ if (tableViewer != null) {
+ tableViewer.dispose();
+ }
+
+ super.dispose();
+ }
+
+ // Package-visible on purpose for ZoomOutAction
+ @Nullable
+ AbstractSegmentStoreDensityViewer getDensityViewer() {
+ return fDensityViewer;
+ }
+}
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.analysis.timing.core.segmentstore.AbstractSegmentStoreAnalysisModule;
+import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density.DensityTimeFormat;
+import org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density.MouseDragZoomProvider;
+import org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density.MouseSelectionProvider;
+import org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density.SimpleTooltipProvider;
+import org.eclipse.tracecompass.segmentstore.core.ISegment;
+import org.eclipse.tracecompass.segmentstore.core.ISegmentStore;
+import org.eclipse.tracecompass.segmentstore.core.SegmentComparators;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.ui.viewers.TmfViewer;
+import org.swtchart.Chart;
+import org.swtchart.IAxis;
+import org.swtchart.IBarSeries;
+import org.swtchart.ISeries;
+import org.swtchart.ISeries.SeriesType;
+import org.swtchart.ISeriesSet;
+import org.swtchart.LineStyle;
+import org.swtchart.Range;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+
+/**
+ * Displays the segment store analysis data in a density chart.
+ *
+ * @author Matthew Khouzam
+ * @author Marc-Andre Laperle
+ *
+ * @since 2.0
+ */
+public abstract class AbstractSegmentStoreDensityViewer extends TmfViewer {
+
+ private static final DensityTimeFormat DENSITY_TIME_FORMATTER = new DensityTimeFormat();
+ private static final RGB BAR_COLOR = new RGB(0x42, 0x85, 0xf4);
+ private final Chart fChart;
+ private final MouseDragZoomProvider fDragZoomProvider;
+ private final MouseSelectionProvider fDragProvider;
+ private final SimpleTooltipProvider fTooltipProvider;
+
+ private @Nullable ITmfTrace fTrace;
+ private @Nullable IAnalysisProgressListener fListener;
+ private @Nullable AbstractSegmentStoreAnalysisModule fAnalysisModule;
+ private TmfTimeRange fCurrentTimeRange = TmfTimeRange.NULL_RANGE;
+ private List<ISegmentStoreDensityViewerDataListener> fListeners;
+
+ /**
+ * Constructs a new density viewer.
+ *
+ * @param parent
+ * the parent of the viewer
+ */
+ public AbstractSegmentStoreDensityViewer(Composite parent) {
+ super(parent);
+ fListeners = new ArrayList<>();
+ fChart = new Chart(parent, SWT.NONE);
+ fChart.getLegend().setVisible(false);
+ fChart.getTitle().setVisible(false);
+ fChart.getAxisSet().getXAxis(0).getTitle().setText(nullToEmptyString(Messages.AbstractSegmentStoreDensityViewer_TimeAxisLabel));
+ fChart.getAxisSet().getYAxis(0).getTitle().setText(nullToEmptyString(Messages.AbstractSegmentStoreDensityViewer_CountAxisLabel));
+ fChart.getAxisSet().getXAxis(0).getGrid().setStyle(LineStyle.NONE);
+ fChart.getAxisSet().getYAxis(0).getGrid().setStyle(LineStyle.NONE);
+
+ fDragZoomProvider = new MouseDragZoomProvider(this);
+ fDragZoomProvider.register();
+ fDragProvider = new MouseSelectionProvider(this);
+ fDragProvider.register();
+ fTooltipProvider = new SimpleTooltipProvider(this);
+ fTooltipProvider.register();
+ }
+
+ /**
+ * Returns the segment store analysis module
+ *
+ * @param trace
+ * The trace to consider
+ * @return the analysis module
+ */
+ protected @Nullable abstract AbstractSegmentStoreAnalysisModule getSegmentStoreAnalysisModule(ITmfTrace trace);
+
+ @Nullable
+ private static ITmfTrace getTrace() {
+ return TmfTraceManager.getInstance().getActiveTrace();
+ }
+
+ private void updateDisplay(List<ISegment> data) {
+ if (data.isEmpty()) {
+ return;
+ }
+ IBarSeries series = (IBarSeries) fChart.getSeriesSet().createSeries(SeriesType.BAR, Messages.AbstractSegmentStoreDensityViewer_SeriesLabel);
+ series.setVisible(true);
+ series.setBarPadding(0);
+
+ series.setBarColor(new Color(Display.getDefault(), BAR_COLOR));
+ int barWidth = 4;
+ final int width = fChart.getPlotArea().getBounds().width / barWidth;
+ double[] xOrigSeries = new double[width];
+ double[] yOrigSeries = new double[width];
+ Arrays.fill(yOrigSeries, 1.0);
+ long maxLength = data.get(data.size() - 1).getLength();
+ double maxFactor = 1.0 / (maxLength + 1.0);
+ long minX = Long.MAX_VALUE;
+ for (ISegment segment : data) {
+ double xBox = segment.getLength() * maxFactor * width;
+ yOrigSeries[(int) xBox]++;
+ minX = Math.min(minX, segment.getLength());
+ }
+ for (int i = 0; i < width; i++) {
+ xOrigSeries[i] = i * maxLength / width;
+ }
+ double maxY = Double.MIN_VALUE;
+ for (int i = 0; i < width; i++) {
+ maxY = Math.max(maxY, yOrigSeries[i]);
+ }
+ if (minX == maxLength) {
+ maxLength++;
+ minX--;
+ }
+ series.setYSeries(yOrigSeries);
+ series.setXSeries(xOrigSeries);
+ final IAxis xAxis = fChart.getAxisSet().getXAxis(0);
+ /*
+ * adjustrange appears to bring origin back since we pad the series with
+ * 0s, not interesting.
+ */
+ xAxis.adjustRange();
+ Range range = xAxis.getRange();
+ // fix for overly aggressive lower after an adjust range
+ range.lower = minX - range.upper + maxLength;
+ xAxis.setRange(range);
+ xAxis.getTick().setFormat(DENSITY_TIME_FORMATTER);
+ fChart.getAxisSet().getYAxis(0).setRange(new Range(1.0, maxY));
+ fChart.getAxisSet().getYAxis(0).enableLogScale(true);
+ fChart.redraw();
+ }
+
+ @Override
+ public Chart getControl() {
+ return fChart;
+ }
+
+ /**
+ * Select a range of latency durations in the viewer.
+ *
+ * @param durationRange
+ * a range of latency durations
+ */
+ public void select(Range durationRange) {
+ computeDataAsync(fCurrentTimeRange, durationRange).thenAccept((data) -> {
+ for (ISegmentStoreDensityViewerDataListener listener : fListeners) {
+ listener.dataSelectionChanged(data);
+ }
+ });
+ }
+
+ /**
+ * Zoom to a range of latency durations in the viewer.
+ *
+ * @param durationRange
+ * a range of latency durations
+ */
+ public void zoom(Range durationRange) {
+ computeDataAsync(fCurrentTimeRange, durationRange).thenAccept((data) -> applyData(data));
+ }
+
+ private CompletableFuture<List<ISegment>> computeDataAsync(final TmfTimeRange timeRange, final Range durationRange) {
+ return CompletableFuture.supplyAsync(() -> computeData(timeRange, durationRange));
+ }
+
+ private @Nullable ArrayList<ISegment> computeData(final TmfTimeRange timeRange, final Range durationRange) {
+ final AbstractSegmentStoreAnalysisModule analysisModule = fAnalysisModule;
+ if (analysisModule == null) {
+ return null;
+ }
+ final ISegmentStore<ISegment> results = analysisModule.getResults();
+ if (results == null) {
+ return null;
+ }
+
+ Iterator<ISegment> intersectingElements = results.getIntersectingElements(timeRange.getStartTime().getValue(), timeRange.getEndTime().getValue()).iterator();
+
+ if (durationRange.lower > Double.MIN_VALUE || durationRange.upper < Double.MAX_VALUE) {
+ Predicate<? super ISegment> predicate = new Predicate<ISegment>() {
+ @Override
+ public boolean apply(@Nullable ISegment input) {
+ return input != null && input.getLength() >= durationRange.lower && input.getLength() <= durationRange.upper;
+ }
+ };
+ intersectingElements = Iterators.<ISegment> filter(intersectingElements, predicate);
+ }
+
+ return Lists.newArrayList(intersectingElements);
+ }
+
+ private void applyData(final @Nullable List<ISegment> data) {
+ if (data != null) {
+ Collections.sort(data, SegmentComparators.INTERVAL_LENGTH_COMPARATOR);
+ Display.getDefault().asyncExec(() -> updateDisplay(data));
+ for (ISegmentStoreDensityViewerDataListener l : fListeners) {
+ l.dataChanged(data);
+ }
+ }
+ }
+
+ /**
+ * Signal handler for handling of the window range signal.
+ *
+ * @param signal
+ * The {@link TmfWindowRangeUpdatedSignal}
+ */
+ @TmfSignalHandler
+ public void windowRangeUpdated(@Nullable TmfWindowRangeUpdatedSignal signal) {
+ if (signal == null) {
+ return;
+ }
+ ITmfTrace trace = getTrace();
+ if (trace == null) {
+ return;
+ }
+ fAnalysisModule = getSegmentStoreAnalysisModule(trace);
+ fCurrentTimeRange = NonNullUtils.checkNotNull(signal.getCurrentRange());
+ updateWithRange(fCurrentTimeRange);
+ }
+
+ private void updateWithRange(final TmfTimeRange range) {
+ computeDataAsync(range, new Range(Double.MIN_VALUE, Double.MAX_VALUE)).thenAccept((data) -> applyData(data));
+ }
+
+ @Override
+ public void refresh() {
+ fChart.redraw();
+ }
+
+ @Override
+ public void dispose() {
+ if (fAnalysisModule != null && fListener != null) {
+ fAnalysisModule.removeListener(fListener);
+ }
+ fDragZoomProvider.deregister();
+ fTooltipProvider.deregister();
+ fDragProvider.deregister();
+ super.dispose();
+ }
+
+ /**
+ * Signal handler for handling of the trace opened signal.
+ *
+ * @param signal
+ * The trace opened signal {@link TmfTraceOpenedSignal}
+ */
+ @TmfSignalHandler
+ public void traceOpened(TmfTraceOpenedSignal signal) {
+ fTrace = signal.getTrace();
+ loadTrace(getTrace());
+ }
+
+ /**
+ * Signal handler for handling of the trace selected signal.
+ *
+ * @param signal
+ * The trace selected signal {@link TmfTraceSelectedSignal}
+ */
+ @TmfSignalHandler
+ public void traceSelected(TmfTraceSelectedSignal signal) {
+ if (fTrace != signal.getTrace()) {
+ fTrace = signal.getTrace();
+ loadTrace(getTrace());
+ }
+ }
+
+ /**
+ * Signal handler for handling of the trace closed signal.
+ *
+ * @param signal
+ * The trace closed signal {@link TmfTraceClosedSignal}
+ */
+ @TmfSignalHandler
+ public void traceClosed(TmfTraceClosedSignal signal) {
+
+ if (signal.getTrace() != fTrace) {
+ return;
+ }
+
+ fTrace = null;
+ clearContent();
+ }
+
+ /**
+ * A Method to load a trace into the viewer.
+ *
+ * @param trace
+ * A trace to apply in the viewer
+ */
+ protected void loadTrace(@Nullable ITmfTrace trace) {
+ clearContent();
+
+ fTrace = trace;
+ TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext();
+ TmfTimeRange windowRange = ctx.getWindowRange();
+ fCurrentTimeRange = windowRange;
+
+ if (trace != null) {
+ fAnalysisModule = getSegmentStoreAnalysisModule(trace);
+ final AbstractSegmentStoreAnalysisModule module = fAnalysisModule;
+ if (module != null) {
+ fListener = (activeAnalysis, data) -> updateWithRange(windowRange);
+ module.addListener(fListener);
+ module.schedule();
+ }
+ }
+ zoom(new Range(0, Long.MAX_VALUE));
+ }
+
+ /**
+ * Clears the view content.
+ */
+ private void clearContent() {
+ final Chart chart = fChart;
+ if (!chart.isDisposed()) {
+ ISeriesSet set = chart.getSeriesSet();
+ ISeries[] series = set.getSeries();
+ for (int i = 0; i < series.length; i++) {
+ set.deleteSeries(series[i].getId());
+ }
+ for (IAxis axis : chart.getAxisSet().getAxes()) {
+ axis.setRange(new Range(0, 1));
+ }
+ chart.redraw();
+ }
+ }
+
+ /**
+ * Add a data listener.
+ *
+ * @param dataListener
+ * the data listener to add
+ */
+ public void addDataListener(ISegmentStoreDensityViewerDataListener dataListener) {
+ fListeners.add(dataListener);
+ }
+
+ /**
+ * Remove a data listener.
+ *
+ * @param dataListener
+ * the data listener to remove
+ */
+ public void removeDataListener(ISegmentStoreDensityViewerDataListener dataListener) {
+ fListeners.remove(dataListener);
+ }
+}
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density;
+
+import java.util.List;
+
+import org.eclipse.tracecompass.segmentstore.core.ISegment;
+
+/**
+ * A listener that gets notified when the viewer sees its data changed or its
+ * data selection change.
+ */
+public interface ISegmentStoreDensityViewerDataListener {
+ /**
+ * Notification that the data changed in the viewer.
+ *
+ * @param newData
+ * the new data
+ */
+ void dataChanged(List<ISegment> newData);
+
+ /**
+ * Notification that the selection of the data changed in the viewer.
+ *
+ * @param newSelectionData
+ * the new selection of the data
+ */
+ void dataSelectionChanged(List<ISegment> newSelectionData);
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @author Marc-Andre Laperle
+ */
+@NonNullByDefault({})
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density.messages"; //$NON-NLS-1$
+
+ /**
+ * Label for the count axis of the density chart.
+ */
+ public static String AbstractSegmentStoreDensityViewer_CountAxisLabel;
+
+ /**
+ * Label for the time axis of the density chart.
+ */
+ public static String AbstractSegmentStoreDensityViewer_TimeAxisLabel;
+
+ /**
+ * Tool-tip for the Zoom out action
+ */
+ public static String AbstractSegmentStoreDensityViewer_ZoomOutActionToolTipText;
+
+ /**
+ * Label for the series of the density chart.
+ */
+ public static String AbstractSegmentStoreDensityViewer_SeriesLabel;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
--- /dev/null
+/******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.AnalysisTimingImageConstants;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.swtchart.Range;
+import org.eclipse.tracecompass.internal.analysis.timing.ui.Activator;
+
+/**
+ * Zoom action for the density view
+ */
+class ZoomOutAction extends Action {
+
+ private final AbstractSegmentStoreDensityView fView;
+
+ /**
+ * Constructors a ZoomOutAction.
+ *
+ * @param densityViewer
+ * The parent density viewer
+ */
+ public ZoomOutAction(AbstractSegmentStoreDensityView densityViewer) {
+ fView = densityViewer;
+ }
+
+ @Override
+ public void run() {
+ final AbstractSegmentStoreDensityViewer chart = fView.getDensityViewer();
+ if (chart != null) {
+ chart.zoom(new Range(0, Long.MAX_VALUE));
+ }
+ }
+
+ @Override
+ public ImageDescriptor getImageDescriptor() {
+ return NonNullUtils.checkNotNull(Activator.getDefault().getImageDescripterFromPath(AnalysisTimingImageConstants.IMG_UI_ZOOM_OUT_MENU));
+ }
+
+ @Override
+ public String getToolTipText() {
+ return NonNullUtils.checkNotNull(Messages.AbstractSegmentStoreDensityViewer_ZoomOutActionToolTipText);
+ }
+}
\ No newline at end of file
--- /dev/null
+###############################################################################
+# Copyright (c) 2015 Ericsson
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+###############################################################################
+
+AbstractSegmentStoreDensityViewer_CountAxisLabel=Count
+AbstractSegmentStoreDensityViewer_TimeAxisLabel=Duration
+AbstractSegmentStoreDensityViewer_ZoomOutActionToolTipText=Zoom Out
+AbstractSegmentStoreDensityViewer_SeriesLabel=Latencies
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
super.stop(context);
}
+ /**
+ * Get the image object from a given path
+ *
+ * @param path
+ * The path to the image file
+ * @return The Image object
+ */
+ public Image getImageFromPath(String path) {
+ return getImageDescripterFromPath(path).createImage();
+ }
+
+ /**
+ * Get the ImageDescriptor from a given path
+ *
+ * @param path
+ * The path to the image file
+ * @return The ImageDescriptor object
+ */
+ public ImageDescriptor getImageDescripterFromPath(String path) {
+ return AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path);
+ }
+
+ /**
+ * Get the Image from a registry
+ *
+ * @param path
+ * The path to the image registry
+ * @return The Image object
+ */
+ public Image getImageFromImageRegistry(String path) {
+ Image icon = getImageRegistry().get(path);
+ if (icon == null) {
+ icon = getImageDescripterFromPath(path).createImage();
+ plugin.getImageRegistry().put(path, icon);
+ }
+ return icon;
+ }
+
/**
* Returns the shared instance
*
--- /dev/null
+/**********************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ **********************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density;
+
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density.AbstractSegmentStoreDensityViewer;
+import org.swtchart.Chart;
+
+/**
+ * Base class for any mouse provider such as tool tip, zoom and selection providers.
+ *
+ * @author Bernd Hufmann
+ * @author Marc-Andre Laperle
+ */
+public abstract class BaseMouseProvider {
+
+ private AbstractSegmentStoreDensityViewer fDensityViewer;
+
+ /**
+ * Standard constructor.
+ *
+ * @param densityViewer
+ * The parent density viewer
+ */
+ public BaseMouseProvider(AbstractSegmentStoreDensityViewer densityViewer) {
+ fDensityViewer = densityViewer;
+ }
+
+ /**
+ * Method to register the provider to the viewer.
+ */
+ protected abstract void register();
+
+ /**
+ * Method to deregister the provider from the viewer.
+ */
+ protected abstract void deregister();
+
+ /**
+ * @return the density viewer
+ */
+ public AbstractSegmentStoreDensityViewer getDensityViewer() {
+ return fDensityViewer;
+ }
+
+ /**
+ * Returns the SWT chart reference
+ *
+ * @return SWT chart reference.
+ */
+ protected Chart getChart() {
+ return fDensityViewer.getControl();
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/**********************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ **********************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density;
+
+import java.text.DecimalFormat;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParsePosition;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+
+/**
+ * Density format, it will take a time in NanoSeconds and convert it to a string
+ * with 3 digits.
+ *
+ * @author Matthew Khouzam
+ */
+public final class DensityTimeFormat extends Format {
+
+
+ private static final long serialVersionUID = -5147827135781459548L;
+
+ private static final String SECONDS = "s"; //$NON-NLS-1$
+ private static final String NANOSECONDS = "ns"; //$NON-NLS-1$
+ private static final String MILLISECONDS = "ms"; //$NON-NLS-1$
+ private static final String MICROSECONDS = "\u00B5" + SECONDS; //$NON-NLS-1$
+
+ private static final int NANOS_PER_SEC = 1000000000;
+ private static final int NANOS_PER_MILLI = 1000000;
+ private static final int NANOS_PER_MICRO = 1000;
+
+ private final DecimalFormat fDecimalFormat = new DecimalFormat("#.###"); //$NON-NLS-1$
+
+ @Override
+ public Object parseObject(@Nullable String source, @Nullable ParsePosition pos) {
+ return source == null ? "" : source; //$NON-NLS-1$
+ }
+
+ @Override
+ public StringBuffer format(@Nullable Object obj, @Nullable StringBuffer toAppendTo, @Nullable FieldPosition pos) {
+ final @Nullable StringBuffer appender = toAppendTo;
+ if ((obj != null) && (obj instanceof Double || obj instanceof Long)) {
+ double formattedTime = obj instanceof Long ? ((Long) obj).doubleValue() : ((Double) obj).doubleValue();
+ String unit = NANOSECONDS;
+ if (formattedTime > NANOS_PER_SEC) {
+ unit = SECONDS;
+ formattedTime /= NANOS_PER_SEC;
+ } else if (formattedTime > NANOS_PER_MILLI) {
+ unit = MILLISECONDS;
+ formattedTime /= NANOS_PER_MILLI;
+ } else if (formattedTime > NANOS_PER_MICRO) {
+ unit = MICROSECONDS;
+ formattedTime /= NANOS_PER_MICRO;
+ }
+ String timeString = fDecimalFormat.format(formattedTime);
+ return appender == null ? new StringBuffer() : NonNullUtils.checkNotNull(appender.append(timeString).append(' ').append(unit));
+ }
+ return new StringBuffer();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @author Marc-Andre Laperle
+ */
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density.messages"; //$NON-NLS-1$
+
+ /**
+ * Tool-tip text when hovering on bars in the density viewer.
+ */
+ public static String SimpleTooltipProvider_toolTipText;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
--- /dev/null
+/**********************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ **********************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density.AbstractSegmentStoreDensityViewer;
+import org.swtchart.IAxis;
+import org.swtchart.ICustomPaintListener;
+import org.swtchart.IPlotArea;
+import org.swtchart.Range;
+
+/**
+ * Class for providing zooming based on mouse drag with right mouse button.
+ * It also notifies the viewer about a change of range.
+ *
+ * @author Bernd Hufmann
+ * @author Marc-Andre Laperle
+ */
+public class MouseDragZoomProvider extends BaseMouseProvider implements MouseListener, MouseMoveListener, ICustomPaintListener {
+
+ /** Cached start coordinate */
+ private double fStartCoordinate;
+ /** Cached end coordinate */
+ private double fEndCoordinate;
+ /** Flag indicating that an update is ongoing */
+ private boolean fIsUpdate;
+
+ /**
+ * Default constructor
+ *
+ * @param densityViewer
+ * the density viewer reference.
+ */
+ public MouseDragZoomProvider(AbstractSegmentStoreDensityViewer densityViewer) {
+ super(densityViewer);
+ register();
+ }
+
+ @Override
+ public void register() {
+ getChart().getPlotArea().addMouseListener(this);
+ getChart().getPlotArea().addMouseMoveListener(this);
+ ((IPlotArea) getChart().getPlotArea()).addCustomPaintListener(this);
+ }
+
+ @Override
+ public void deregister() {
+ if (!getChart().isDisposed()) {
+ getChart().getPlotArea().removeMouseListener(this);
+ getChart().getPlotArea().removeMouseMoveListener(this);
+ ((IPlotArea) getChart().getPlotArea()).removeCustomPaintListener(this);
+ }
+ }
+
+ @Override
+ public void mouseDoubleClick(@Nullable MouseEvent e) {
+ }
+
+ @Override
+ public void mouseDown(@Nullable MouseEvent e) {
+ if (e != null && e.button == 3) {
+ IAxis xAxis = getChart().getAxisSet().getXAxis(0);
+ fStartCoordinate = xAxis.getDataCoordinate(e.x);
+ fEndCoordinate = fStartCoordinate;
+ fIsUpdate = true;
+ }
+ }
+
+ @Override
+ public void mouseUp(@Nullable MouseEvent e) {
+ if ((fIsUpdate) && (fStartCoordinate != fEndCoordinate)) {
+ if (fStartCoordinate > fEndCoordinate) {
+ double tmp = fStartCoordinate;
+ fStartCoordinate = fEndCoordinate;
+ fEndCoordinate = tmp;
+ }
+ getDensityViewer().zoom(new Range(fStartCoordinate, fEndCoordinate));
+ }
+
+ if (fIsUpdate) {
+ getChart().redraw();
+ }
+ fIsUpdate = false;
+ }
+
+ @Override
+ public void mouseMove(@Nullable MouseEvent e) {
+ if (e != null && fIsUpdate) {
+ IAxis xAxis = getChart().getAxisSet().getXAxis(0);
+ fEndCoordinate = xAxis.getDataCoordinate(e.x);
+ getChart().redraw();
+ }
+ }
+
+ @Override
+ public void paintControl(@Nullable PaintEvent e) {
+ if (e != null && fIsUpdate && (fStartCoordinate != fEndCoordinate)) {
+ IAxis xAxis = getChart().getAxisSet().getXAxis(0);
+ int startX = xAxis.getPixelCoordinate(fStartCoordinate);
+ int endX = xAxis.getPixelCoordinate(fEndCoordinate);
+
+ e.gc.setBackground(getChart().getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND));
+ if (fStartCoordinate < fEndCoordinate) {
+ e.gc.fillRectangle(startX, 0, endX - startX, e.height);
+ } else {
+ e.gc.fillRectangle(endX, 0, startX - endX, e.height);
+ }
+ e.gc.drawLine(startX, 0, startX, e.height);
+ e.gc.drawLine(endX, 0, endX, e.height);
+ }
+ }
+
+ @Override
+ public boolean drawBehindSeries() {
+ return true;
+ }
+}
\ No newline at end of file
--- /dev/null
+/**********************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ **********************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density.AbstractSegmentStoreDensityViewer;
+import org.swtchart.IAxis;
+import org.swtchart.ICustomPaintListener;
+import org.swtchart.IPlotArea;
+import org.swtchart.Range;
+
+/**
+ * Class for providing selection with the left mouse button. It also notifies
+ * the viewer about a change of selection.
+ *
+ * @author Bernd Hufmann
+ * @author Marc-Andre Laperle
+ */
+public class MouseSelectionProvider extends BaseMouseProvider implements MouseListener, MouseMoveListener, ICustomPaintListener {
+
+ /** Cached start coordinate */
+ private double fStartCoordinate;
+ /** Cached end coordinate */
+ private double fEndCoordinate;
+ /** Flag indicating that an update is ongoing */
+ private boolean fIsUpdate;
+ /** Flag indicating that the begin marker is dragged */
+ private boolean fDragBeginMarker;
+
+ /**
+ * Constructor for a mouse selection provider.
+ *
+ * @param densityViewer
+ * The parent density viewer
+ */
+ public MouseSelectionProvider(AbstractSegmentStoreDensityViewer densityViewer) {
+ super(densityViewer);
+ register();
+ }
+
+ @Override
+ public void register() {
+ getChart().getPlotArea().addMouseListener(this);
+ getChart().getPlotArea().addMouseMoveListener(this);
+ ((IPlotArea) getChart().getPlotArea()).addCustomPaintListener(this);
+ }
+
+ @Override
+ public void deregister() {
+ if (!getChart().isDisposed()) {
+ getChart().getPlotArea().removeMouseListener(this);
+ getChart().getPlotArea().removeMouseMoveListener(this);
+ ((IPlotArea) getChart().getPlotArea()).removeCustomPaintListener(this);
+ }
+ }
+
+ @Override
+ public void mouseDoubleClick(@Nullable MouseEvent e) {
+ }
+
+ @Override
+ public void mouseDown(@Nullable MouseEvent e) {
+ if (e != null && (e.button == 1)) {
+ fDragBeginMarker = false;
+ if (((e.stateMask & SWT.SHIFT) != SWT.SHIFT) || (fEndCoordinate == fStartCoordinate)) {
+ IAxis xAxis = getChart().getAxisSet().getXAxis(0);
+ fStartCoordinate = xAxis.getDataCoordinate(e.x);
+ fEndCoordinate = fStartCoordinate;
+ } else {
+ double selectionBegin = fStartCoordinate;
+ double selectionEnd = fEndCoordinate;
+ IAxis xAxis = getChart().getAxisSet().getXAxis(0);
+ double time = xAxis.getDataCoordinate(e.x);
+ if (Math.abs(time - selectionBegin) < Math.abs(time - selectionEnd)) {
+ fDragBeginMarker = true;
+ fStartCoordinate = time;
+ fEndCoordinate = selectionEnd;
+ } else {
+ fStartCoordinate = selectionBegin;
+ fEndCoordinate = time;
+ }
+ }
+ fIsUpdate = true;
+ }
+ }
+
+ @Override
+ public void mouseUp(@Nullable MouseEvent e) {
+ if ((fIsUpdate)) {
+ if (fStartCoordinate > fEndCoordinate) {
+ double tmp = fStartCoordinate;
+ fStartCoordinate = fEndCoordinate;
+ fEndCoordinate = tmp;
+ }
+ if (!isEmptySelection()) {
+ getDensityViewer().select(new Range(Double.MIN_VALUE, Double.MAX_VALUE));
+ } else {
+ getDensityViewer().select(new Range(fStartCoordinate, fEndCoordinate));
+ }
+ fIsUpdate = false;
+ getChart().redraw();
+ }
+ }
+
+ @Override
+ public void mouseMove(@Nullable MouseEvent e) {
+ if (e != null && fIsUpdate) {
+ IAxis xAxis = getChart().getAxisSet().getXAxis(0);
+ if (fDragBeginMarker) {
+ fStartCoordinate = xAxis.getDataCoordinate(e.x);
+ } else {
+ fEndCoordinate = xAxis.getDataCoordinate(e.x);
+ }
+ getChart().redraw();
+ }
+ }
+
+ private boolean isEmptySelection() {
+ IAxis xAxis = getChart().getAxisSet().getXAxis(0);
+ int begin = xAxis.getPixelCoordinate(fStartCoordinate);
+ int end = xAxis.getPixelCoordinate(fEndCoordinate);
+
+ return Math.abs(end - begin) > 2;
+ }
+
+ @Override
+ public void paintControl(@Nullable PaintEvent e) {
+ if (e == null || !isEmptySelection()) {
+ return;
+ }
+
+ Display display = getChart().getDisplay();
+
+ IAxis xAxis = getChart().getAxisSet().getXAxis(0);
+ e.gc.setBackground(display.getSystemColor(SWT.COLOR_BLUE));
+ e.gc.setForeground(display.getSystemColor(SWT.COLOR_BLUE));
+ e.gc.setLineStyle(SWT.LINE_SOLID);
+ int begin = xAxis.getPixelCoordinate(fStartCoordinate);
+ e.gc.drawLine(begin, 0, begin, e.height);
+
+ int end = xAxis.getPixelCoordinate(fEndCoordinate);
+ e.gc.drawLine(end, 0, end, e.height);
+
+ e.gc.setAlpha(150);
+ if (Math.abs(fEndCoordinate - fStartCoordinate) > 1) {
+ e.gc.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
+ int beginX = xAxis.getPixelCoordinate(fStartCoordinate);
+ int endX = xAxis.getPixelCoordinate(fEndCoordinate);
+ if (fEndCoordinate > fStartCoordinate) {
+ e.gc.fillRectangle(beginX + 1, 0, endX - beginX - 1, e.height);
+ } else {
+ e.gc.fillRectangle(endX + 1, 0, beginX - endX - 1, e.height);
+ }
+ }
+ }
+
+ @Override
+ public boolean drawBehindSeries() {
+ return false;
+ }
+}
--- /dev/null
+/**********************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ **********************************************************************/
+package org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.density;
+
+import java.text.Format;
+import java.text.MessageFormat;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density.AbstractSegmentStoreDensityViewer;
+import org.swtchart.IAxis;
+import org.swtchart.IBarSeries;
+import org.swtchart.ISeries;
+
+/**
+ * Tool tip provider for density viewer. It displays the x and y value of the
+ * current mouse position.
+ *
+ * @author Bernd Hufmann
+ * @author Marc-Andre Laperle
+ */
+public class SimpleTooltipProvider extends BaseMouseProvider implements MouseTrackListener {
+
+ private static final Format FORMAT = new DensityTimeFormat();
+
+ /**
+ * Constructor for a tool tip provider.
+ *
+ * @param densityViewer
+ * The parent density viewer
+ */
+ public SimpleTooltipProvider(AbstractSegmentStoreDensityViewer densityViewer) {
+ super(densityViewer);
+ register();
+ }
+
+ @Override
+ public void register() {
+ getChart().getPlotArea().addMouseTrackListener(this);
+ }
+
+ @Override
+ public void deregister() {
+ if (!getChart().isDisposed()) {
+ getChart().getPlotArea().removeMouseTrackListener(this);
+ }
+ }
+
+ @Override
+ public void mouseEnter(@Nullable MouseEvent e) {
+ }
+
+ @Override
+ public void mouseExit(@Nullable MouseEvent e) {
+ }
+
+ @Override
+ public void mouseHover(@Nullable MouseEvent e) {
+ if (e == null || getChart().getAxisSet().getXAxes().length == 0 || getChart().getAxisSet().getYAxes().length == 0 || getDensityViewer().getControl().getSeriesSet().getSeries().length == 0) {
+ return;
+ }
+ ISeries series = getDensityViewer().getControl().getSeriesSet().getSeries()[0];
+ getChart().getPlotArea().setToolTipText(null);
+ if (series instanceof IBarSeries) {
+ IBarSeries barSeries = (IBarSeries) series;
+ // Note: getBounds is broken in SWTChart 0.9.0
+ Rectangle[] bounds = barSeries.getBounds();
+
+ if (barSeries.getXSeries().length < 2) {
+ return;
+ }
+ double delta = barSeries.getXSeries()[1] - barSeries.getXSeries()[0];
+ for (int i = 0; i < bounds.length; i++) {
+ Rectangle rec = bounds[i];
+ if (rec == null) {
+ continue;
+ }
+ int start = rec.x;
+ int end = start + rec.width;
+ if (e.x >= start && e.x <= end) {
+ long x1 = (long) barSeries.getXSeries()[i];
+ long x2 = (long) (x1 + delta);
+ IAxis yAxis = getChart().getAxisSet().getYAxes()[0];
+ long y = Math.round(yAxis.getDataCoordinate(rec.y)) - 1;
+ if (y > 0) {
+ String toolTipText = MessageFormat.format(Messages.SimpleTooltipProvider_toolTipText, FORMAT.format(x1), FORMAT.format(x2), y);
+ getChart().getPlotArea().setToolTipText(toolTipText);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+###############################################################################
+# Copyright (c) 2015 Ericsson
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+###############################################################################
+
+SimpleTooltipProvider_toolTipText=Duration: [{0}, {1}]\nCount: {2}