From b23cbbfcdd55a705aa3d072b40738ad4457bcfed Mon Sep 17 00:00:00 2001 From: Marc-Andre Laperle Date: Wed, 28 Oct 2015 18:45:42 -0400 Subject: [PATCH] Latency: introduce latency density view 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 Signed-off-by: Marc-Andre Laperle Reviewed-on: https://git.eclipse.org/r/57573 Reviewed-by: Hudson CI Reviewed-by: Patrick Tasse Tested-by: Patrick Tasse --- .../icons/eview16/density.png | Bin 0 -> 143 bytes .../plugin.properties | 1 + .../plugin.xml | 16 +- .../latency/SystemCallDensityViewer.java | 42 ++ .../latency/SystemCallLatencyDensityView.java | 56 +++ .../META-INF/MANIFEST.MF | 4 +- .../build.properties | 3 +- .../icons/elcl16/zoomout_nav.gif | Bin 0 -> 560 bytes .../AnalysisTimingImageConstants.java | 23 ++ .../AbstractSegmentStoreDensityView.java | 140 +++++++ .../AbstractSegmentStoreDensityViewer.java | 387 ++++++++++++++++++ ...SegmentStoreDensityViewerDataListener.java | 36 ++ .../views/segmentstore/density/Messages.java | 49 +++ .../segmentstore/density/ZoomOutAction.java | 53 +++ .../segmentstore/density/messages.properties | 13 + .../segmentstore/density/package-info.java | 11 + .../analysis/timing/ui/Activator.java | 40 ++ .../density/BaseMouseProvider.java | 61 +++ .../density/DensityTimeFormat.java | 68 +++ .../views/segmentstore/density/Messages.java | 32 ++ .../density/MouseDragZoomProvider.java | 129 ++++++ .../density/MouseSelectionProvider.java | 174 ++++++++ .../density/SimpleTooltipProvider.java | 102 +++++ .../segmentstore/density/messages.properties | 10 + 24 files changed, 1447 insertions(+), 3 deletions(-) create mode 100644 analysis/org.eclipse.tracecompass.analysis.os.linux.ui/icons/eview16/density.png create mode 100644 analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/latency/SystemCallDensityViewer.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/latency/SystemCallLatencyDensityView.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/icons/elcl16/zoomout_nav.gif create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/AnalysisTimingImageConstants.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/AbstractSegmentStoreDensityView.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/AbstractSegmentStoreDensityViewer.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/ISegmentStoreDensityViewerDataListener.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/Messages.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/ZoomOutAction.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/messages.properties create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/package-info.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/BaseMouseProvider.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/DensityTimeFormat.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/Messages.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/MouseDragZoomProvider.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/MouseSelectionProvider.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/SimpleTooltipProvider.java create mode 100644 analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/messages.properties 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 index 0000000000000000000000000000000000000000..e3c9e1bd16f839670b81e97a8ceb64d14dc11c1a GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf!VPdneun-W{lVB5AJ#hiIhZ)24vn??u9m$Nc n3o2MOpBgRVp1`tVVmZU2qvA<>Kfa0sn#kbk>gTe~DWM4f + + @@ -102,6 +110,12 @@ class="org.eclipse.tracecompass.analysis.os.linux.core.latency.SystemCallLatencyAnalysis"> - + + + + 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 index 0000000000..aeb1646625 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/latency/SystemCallDensityViewer.java @@ -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 index 0000000000..5315c4fa92 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/latency/SystemCallLatencyDensityView.java @@ -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)); + } + +} diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/META-INF/MANIFEST.MF b/analysis/org.eclipse.tracecompass.analysis.timing.ui/META-INF/MANIFEST.MF index a660d59201..372e0939e5 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.ui/META-INF/MANIFEST.MF +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/META-INF/MANIFEST.MF @@ -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 diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/build.properties b/analysis/org.eclipse.tracecompass.analysis.timing.ui/build.properties index d126a1dcce..0690d9a3f9 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.ui/build.properties +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/build.properties @@ -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 index 0000000000000000000000000000000000000000..1f874009adf2835898ea0dd034adcbe41777815b GIT binary patch literal 560 zcmZ?wbhEHb6krfwc*elcnv?(H+4KMZ{y%;E?8Cdy{rxjvzxnv{*T2tSe!P19{?X&- z+jk%9pSJAD^LI;DZQFnJ;-A0&fBpXZ^VgrxU%owi{<3H4vKOyEJbC`+(bHG!w;yWi znQ`m>(@i@MPMW>w>aBZ^pTD~M@X4)v4;k||FlMY|Oj*iMx|OkX8)N?Z14mEXe(;!~ za@X$t2VTB?_u|dl$IoBfdGN5ItNZfJn=jtI`}zCVw;$g>fBmw3-}bHBw@jHn;qtZ9 z8@J4yzhK6{e}67rx^VI0`MrBq?b$JP-SXna^C}k3Z8~*q<+3GHx2~vB!>pOp|Nr~*`O}BFGpEh#s;>;ND-Uq&EXryt z%C7cz>M6|XDb1hT(fs4f=Z|mSbQR{bmlpp2|Nr;z-$0Uq+CcFq3nK$V3WE;FU{IVe zu=h5kG&Q%hwzxaG`FgsvH9Pn*2b&7}d-wTxFfs|)1SQ8iwK*pV8Vd=r3z=AXwYny$ zs3 data) { + updateTableModel(data); + } + + private void updateTableModel(@Nullable List data) { + final AbstractSegmentStoreTableViewer viewer = fTableViewer; + if (viewer != null && data != null) { + viewer.updateModel(data.toArray(new ISegment[] {})); + } + } + + @Override + public void dataSelectionChanged(List 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 index 0000000000..e5d7913d56 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/AbstractSegmentStoreDensityViewer.java @@ -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 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 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> computeDataAsync(final TmfTimeRange timeRange, final Range durationRange) { + return CompletableFuture.supplyAsync(() -> computeData(timeRange, durationRange)); + } + + private @Nullable ArrayList computeData(final TmfTimeRange timeRange, final Range durationRange) { + final AbstractSegmentStoreAnalysisModule analysisModule = fAnalysisModule; + if (analysisModule == null) { + return null; + } + final ISegmentStore results = analysisModule.getResults(); + if (results == null) { + return null; + } + + Iterator intersectingElements = results.getIntersectingElements(timeRange.getStartTime().getValue(), timeRange.getEndTime().getValue()).iterator(); + + if (durationRange.lower > Double.MIN_VALUE || durationRange.upper < Double.MAX_VALUE) { + Predicate predicate = new Predicate() { + @Override + public boolean apply(@Nullable ISegment input) { + return input != null && input.getLength() >= durationRange.lower && input.getLength() <= durationRange.upper; + } + }; + intersectingElements = Iterators. filter(intersectingElements, predicate); + } + + return Lists.newArrayList(intersectingElements); + } + + private void applyData(final @Nullable List 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 index 0000000000..a447feca2e --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/ISegmentStoreDensityViewerDataListener.java @@ -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 newData); + + /** + * Notification that the selection of the data changed in the viewer. + * + * @param newSelectionData + * the new selection of the data + */ + void dataSelectionChanged(List 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 index 0000000000..d36b02b098 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/Messages.java @@ -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 index 0000000000..9f5c01d45b --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/ZoomOutAction.java @@ -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 index 0000000000..878a434492 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/messages.properties @@ -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 index 0000000000..1f5779bee0 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/analysis/timing/ui/views/segmentstore/density/package-info.java @@ -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; diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/Activator.java b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/Activator.java index 3fa42809cd..ec79c2ae76 100644 --- a/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/Activator.java +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/Activator.java @@ -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 index 0000000000..6762bca577 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/BaseMouseProvider.java @@ -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 index 0000000000..c1c641cda8 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/DensityTimeFormat.java @@ -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 index 0000000000..57374a29a3 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/Messages.java @@ -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 index 0000000000..9001d9b384 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/MouseDragZoomProvider.java @@ -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 index 0000000000..8bc611bdbb --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/MouseSelectionProvider.java @@ -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 index 0000000000..91ee2400da --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/SimpleTooltipProvider.java @@ -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 index 0000000000..90d5305e71 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.timing.ui/src/org/eclipse/tracecompass/internal/analysis/timing/ui/views/segmentstore/density/messages.properties @@ -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} -- 2.34.1