Latency: introduce latency density view
authorMarc-Andre Laperle <marc-andre.laperle@ericsson.com>
Wed, 28 Oct 2015 22:45:42 +0000 (18:45 -0400)
committerMatthew Khouzam <matthew.khouzam@ericsson.com>
Tue, 5 Jan 2016 21:10:45 +0000 (16:10 -0500)
This patch introduces a view to view segment densities. The
view is based on SWTChart's bar graph. Its x axis is NOT
time aligned as it is not on the main timeline. It takes
the liberty to display time in a more "human readable"
form showing a scale and up to 3 decimals max. (1.234 ms)

There is a second part to this view: a selection table.
This table shows the selected segments from a drag operation.

Follow up tasks for this can be to introduce other filters and
improve the tooltips.

An example implementation is provided for the SystemCall analysis.

Change-Id: I238a61dc8eeeefdca0da107424686a64fb63d8c3
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Signed-off-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/57573
Reviewed-by: Hudson CI
Reviewed-by: Patrick Tasse <patrick.tasse@gmail.com>
Tested-by: Patrick Tasse <patrick.tasse@gmail.com>
24 files changed:
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/icons/eview16/density.png [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.properties
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.xml
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/latency/SystemCallDensityViewer.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/latency/SystemCallLatencyDensityView.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/META-INF/MANIFEST.MF
analysis/org.eclipse.tracecompass.analysis.timing.ui/build.properties
analysis/org.eclipse.tracecompass.analysis.timing.ui/icons/elcl16/zoomout_nav.gif [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/AnalysisTimingImageConstants.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/AbstractSegmentStoreDensityView.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/AbstractSegmentStoreDensityViewer.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/ISegmentStoreDensityViewerDataListener.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/Messages.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/ZoomOutAction.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/messages.properties [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/package-info.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/Activator.java
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/BaseMouseProvider.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/DensityTimeFormat.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/Messages.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/MouseDragZoomProvider.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/MouseSelectionProvider.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/SimpleTooltipProvider.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/messages.properties [new file with mode: 0644]

diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/icons/eview16/density.png b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/icons/eview16/density.png
new file mode 100644 (file)
index 0000000..e3c9e1b
Binary files /dev/null and b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/icons/eview16/density.png differ
index b667d0c977f1c7a089af307eccd97f1b3b126fd8..683d4e48f64633354420c1512c2a0da086f2470c 100644 (file)
@@ -21,3 +21,4 @@ cpuusage.view.name = CPU Usage
 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
index e05255c09a4f4310b2e2102de34c042c1bf00162..3f33977ea90a246d388e0901eb409c41c0099faf 100644 (file)
             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>
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/latency/SystemCallDensityViewer.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/latency/SystemCallDensityViewer.java
new file mode 100644 (file)
index 0000000..aeb1646
--- /dev/null
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * 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);
+    }
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/latency/SystemCallLatencyDensityView.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/latency/SystemCallLatencyDensityView.java
new file mode 100644 (file)
index 0000000..5315c4f
--- /dev/null
@@ -0,0 +1,56 @@
+/******************************************************************************
+ * 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));
+    }
+
+}
index a660d592016421b08d6e975f442e32d05f5da266..372e0939e558c4168797b4bb765e06846337093f 100644 (file)
@@ -18,5 +18,7 @@ Require-Bundle: org.eclipse.ui,
  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
index d126a1dcce98b9b10e1d221c235cddb48ec21eb8..0690d9a3f9a7c4baea1d17d2ac70e6f7d70ff16e 100644 (file)
@@ -11,6 +11,7 @@ source.. = src/
 output.. = bin/
 bin.includes = META-INF/,\
                plugin.properties,\
-               .
+               .,\
+               icons/
 additional.bundles = org.eclipse.jdt.annotation
 jars.extra.classpath = platform:/plugin/org.eclipse.jdt.annotation
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/icons/elcl16/zoomout_nav.gif b/analysis/org.eclipse.tracecompass.analysis.timing.ui/icons/elcl16/zoomout_nav.gif
new file mode 100644 (file)
index 0000000..1f87400
Binary files /dev/null and b/analysis/org.eclipse.tracecompass.analysis.timing.ui/icons/elcl16/zoomout_nav.gif differ
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/AnalysisTimingImageConstants.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/AnalysisTimingImageConstants.java
new file mode 100644 (file)
index 0000000..bff0efb
--- /dev/null
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * 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";
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/AbstractSegmentStoreDensityView.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/AbstractSegmentStoreDensityView.java
new file mode 100644 (file)
index 0000000..f13c8b1
--- /dev/null
@@ -0,0 +1,140 @@
+/******************************************************************************
+ * 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
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/AbstractSegmentStoreDensityViewer.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/AbstractSegmentStoreDensityViewer.java
new file mode 100644 (file)
index 0000000..e5d7913
--- /dev/null
@@ -0,0 +1,387 @@
+/******************************************************************************
+ * 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
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/ISegmentStoreDensityViewerDataListener.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/ISegmentStoreDensityViewerDataListener.java
new file mode 100644 (file)
index 0000000..a447fec
--- /dev/null
@@ -0,0 +1,36 @@
+/******************************************************************************
+ * 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);
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/Messages.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/Messages.java
new file mode 100644 (file)
index 0000000..d36b02b
--- /dev/null
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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() {
+    }
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/ZoomOutAction.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/ZoomOutAction.java
new file mode 100644 (file)
index 0000000..9f5c01d
--- /dev/null
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * 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
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/messages.properties b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/messages.properties
new file mode 100644 (file)
index 0000000..878a434
--- /dev/null
@@ -0,0 +1,13 @@
+###############################################################################
+# 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
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/package-info.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/package-info.java
new file mode 100644 (file)
index 0000000..1f5779b
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * 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;
index 3fa42809cd1437c885ee9be75ac75f32303b5ab2..ec79c2ae768d883803f1ca79f763fd31084d44e3 100644 (file)
@@ -11,6 +11,8 @@ package org.eclipse.tracecompass.internal.analysis.timing.ui;
 
 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;
 
@@ -43,6 +45,44 @@ public class Activator extends AbstractUIPlugin {
         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
      *
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/BaseMouseProvider.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/BaseMouseProvider.java
new file mode 100644 (file)
index 0000000..6762bca
--- /dev/null
@@ -0,0 +1,61 @@
+/**********************************************************************
+ * 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
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/DensityTimeFormat.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/DensityTimeFormat.java
new file mode 100644 (file)
index 0000000..c1c641c
--- /dev/null
@@ -0,0 +1,68 @@
+/**********************************************************************
+ * 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
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/Messages.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/Messages.java
new file mode 100644 (file)
index 0000000..57374a2
--- /dev/null
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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() {
+    }
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/MouseDragZoomProvider.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/MouseDragZoomProvider.java
new file mode 100644 (file)
index 0000000..9001d9b
--- /dev/null
@@ -0,0 +1,129 @@
+/**********************************************************************
+ * 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
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/MouseSelectionProvider.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/MouseSelectionProvider.java
new file mode 100644 (file)
index 0000000..8bc611b
--- /dev/null
@@ -0,0 +1,174 @@
+/**********************************************************************
+ * 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;
+    }
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/SimpleTooltipProvider.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/SimpleTooltipProvider.java
new file mode 100644 (file)
index 0000000..91ee240
--- /dev/null
@@ -0,0 +1,102 @@
+/**********************************************************************
+ * 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
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/messages.properties b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/messages.properties
new file mode 100644 (file)
index 0000000..90d5305
--- /dev/null
@@ -0,0 +1,10 @@
+###############################################################################
+# 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}
This page took 0.066387 seconds and 5 git commands to generate.