| /****************************************************************************** |
| * Copyright (c) 2015, 2018 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.density; |
| |
| import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString; |
| |
| import java.text.Format; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.concurrent.CompletableFuture; |
| import java.util.function.Predicate; |
| |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.jface.resource.ColorRegistry; |
| 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.IAnalysisProgressListener; |
| import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider; |
| import org.eclipse.tracecompass.common.core.NonNullUtils; |
| import org.eclipse.tracecompass.common.core.format.SubSecondTimeWithUnitFormat; |
| 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.internal.analysis.timing.ui.views.segmentstore.table.SegmentStoreContentProvider.SegmentStoreWithRange; |
| 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.analysis.IAnalysisModule; |
| import org.eclipse.tracecompass.tmf.core.presentation.IYAppearance; |
| import org.eclipse.tracecompass.tmf.core.presentation.IYAppearance.Type; |
| import org.eclipse.tracecompass.tmf.core.presentation.RotatingPaletteProvider; |
| 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.colors.RGBAUtil; |
| import org.eclipse.tracecompass.tmf.ui.viewers.IImageSave; |
| import org.eclipse.tracecompass.tmf.ui.viewers.TmfViewer; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphColorScheme; |
| import org.swtchart.Chart; |
| import org.swtchart.IAxis; |
| import org.swtchart.IBarSeries; |
| import org.swtchart.ILegend; |
| import org.swtchart.ILineSeries; |
| import org.swtchart.ILineSeries.PlotSymbolType; |
| 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.annotations.VisibleForTesting; |
| |
| /** |
| * Displays the segment store provider data in a density chart. |
| * |
| * @author Matthew Khouzam |
| * @author Marc-Andre Laperle |
| * |
| * @since 2.0 |
| */ |
| @Deprecated |
| public abstract class AbstractSegmentStoreDensityViewer extends TmfViewer implements IImageSave { |
| |
| private static final Format DENSITY_TIME_FORMATTER = SubSecondTimeWithUnitFormat.getInstance(); |
| private static final RGB BAR_COLOR = new RGB(0x42, 0x85, 0xf4); |
| private static final ColorRegistry COLOR_REGISTRY = new ColorRegistry(); |
| private static final RotatingPaletteProvider PALETTE = new RotatingPaletteProvider.Builder().setSaturation(0.73f).setBrightness(0.957f).setNbColors(60).build(); |
| |
| /** The color scheme for the chart */ |
| private TimeGraphColorScheme fColorScheme = new TimeGraphColorScheme(); |
| private final Chart fChart; |
| private final MouseDragZoomProvider fDragZoomProvider; |
| private final MouseSelectionProvider fDragProvider; |
| private final SimpleTooltipProvider fTooltipProvider; |
| |
| private @Nullable ITmfTrace fTrace; |
| private Map<@NonNull String, @NonNull IAnalysisProgressListener> fProgressListeners = new HashMap<>(); |
| private final Map<@NonNull String, @NonNull ISegmentStoreProvider> fSegmentStoreProviders = new HashMap<>(); |
| private Range fCurrentDurationRange = new Range(AbstractSegmentStoreDensityView.DEFAULT_RANGE.getFirst(), AbstractSegmentStoreDensityView.DEFAULT_RANGE.getSecond()); |
| private TmfTimeRange fCurrentTimeRange = TmfTimeRange.NULL_RANGE; |
| private final List<ISegmentStoreDensityViewerDataListener> fListeners; |
| private int fOverrideNbPoints; |
| private String fSeriesType; |
| private final Set<@NonNull ITmfTrace> fTraces = new HashSet<>(); |
| |
| /** |
| * 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); |
| Color backgroundColor = fColorScheme.getColor(TimeGraphColorScheme.TOOL_BACKGROUND); |
| fChart.setBackground(backgroundColor); |
| backgroundColor = fColorScheme.getColor(TimeGraphColorScheme.BACKGROUND); |
| fChart.setBackgroundInPlotArea(backgroundColor); |
| parent.setBackground(backgroundColor); |
| Color foregroundColor = fColorScheme.getColor(TimeGraphColorScheme.TOOL_FOREGROUND); |
| fChart.setForeground(foregroundColor); |
| fChart.getLegend().setVisible(false); |
| fChart.getTitle().setVisible(false); |
| IAxis xAxis = fChart.getAxisSet().getXAxis(0); |
| IAxis yAxis = fChart.getAxisSet().getYAxis(0); |
| xAxis.getTitle().setText(nullToEmptyString(Messages.AbstractSegmentStoreDensityViewer_TimeAxisLabel)); |
| yAxis.getTitle().setText(nullToEmptyString(Messages.AbstractSegmentStoreDensityViewer_CountAxisLabel)); |
| xAxis.getTitle().setForeground(foregroundColor); |
| yAxis.getTitle().setForeground(foregroundColor); |
| xAxis.getTick().setForeground(foregroundColor); |
| yAxis.getTick().setForeground(foregroundColor); |
| xAxis.getGrid().setStyle(LineStyle.DOT); |
| yAxis.getGrid().setStyle(LineStyle.DOT); |
| fSeriesType = IYAppearance.Type.BAR; |
| |
| fDragZoomProvider = new MouseDragZoomProvider(this); |
| fDragZoomProvider.register(); |
| fDragProvider = new MouseSelectionProvider(this); |
| fDragProvider.register(); |
| fTooltipProvider = new SimpleTooltipProvider(this); |
| fTooltipProvider.register(); |
| |
| fChart.addDisposeListener(e -> internalDispose()); |
| } |
| |
| /** |
| * Returns the segment store provider |
| * |
| * @param trace |
| * The trace to consider |
| * @return the |
| */ |
| protected abstract @Nullable ISegmentStoreProvider getSegmentStoreProvider(ITmfTrace trace); |
| |
| @Nullable |
| private static ITmfTrace getTrace() { |
| return TmfTraceManager.getInstance().getActiveTrace(); |
| } |
| |
| /** |
| * Set the type of series you want |
| * @param type the type, bar or area |
| * @since 4.1 |
| */ |
| protected void setType(String type) { |
| switch (type) { |
| case Type.BAR: |
| fSeriesType = Type.BAR; |
| break; |
| case Type.AREA: |
| fSeriesType = Type.AREA; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| private synchronized void updateDisplay(String name, SegmentStoreWithRange<ISegment> data) { |
| ISeries series = fSeriesType.equals(Type.BAR) ? createSeries() : createAreaSeries(name); |
| int barWidth = 4; |
| int preWidth = fOverrideNbPoints == 0 ? fChart.getPlotArea().getBounds().width / barWidth : fOverrideNbPoints; |
| if (!fSeriesType.equals(Type.BAR)) { |
| preWidth += 2; |
| } |
| final int width = preWidth; |
| double[] xOrigSeries = new double[width]; |
| double[] yOrigSeries = new double[width]; |
| // Set a positive value that is greater than 0 and less than 1.0 |
| Arrays.fill(yOrigSeries, Double.MIN_VALUE); |
| data.setComparator(SegmentComparators.INTERVAL_LENGTH_COMPARATOR); |
| ISegment maxSegment = data.getElement(SegmentStoreWithRange.LAST); |
| long maxLength = Long.MIN_VALUE; |
| if (maxSegment != null) { |
| maxLength = maxSegment.getLength(); |
| } else { |
| for (ISegment segment : data) { |
| maxLength = Math.max(maxLength, segment.getLength()); |
| } |
| if (maxLength == Long.MIN_VALUE) { |
| maxLength = 1; |
| } |
| } |
| double maxFactor = 1.0 / (maxLength + 1.0); |
| long minX = Long.MAX_VALUE; |
| for (ISegment segment : data) { |
| double xBox = segment.getLength() * maxFactor * width; |
| if (yOrigSeries[(int) xBox] < 1) { |
| yOrigSeries[(int) xBox] = 1; |
| } else { |
| yOrigSeries[(int) xBox]++; |
| } |
| minX = Math.min(minX, segment.getLength()); |
| } |
| double timeWidth = (double) maxLength / (double) width; |
| for (int i = 0; i < width; i++) { |
| xOrigSeries[i] = i * timeWidth; |
| if (!fSeriesType.equals(Type.BAR)) { |
| xOrigSeries[i] += timeWidth / 2; |
| } |
| } |
| double maxY = Double.NEGATIVE_INFINITY; |
| 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. |
| */ |
| Range currentDurationRange = fCurrentDurationRange; |
| if (Double.isFinite(currentDurationRange.lower) && Double.isFinite(currentDurationRange.upper)) { |
| xAxis.setRange(currentDurationRange); |
| } else { |
| xAxis.adjustRange(); |
| } |
| |
| xAxis.getTick().setFormat(DENSITY_TIME_FORMATTER); |
| ILegend legend = fChart.getLegend(); |
| legend.setVisible(fSegmentStoreProviders.size() > 1); |
| legend.setPosition(SWT.BOTTOM); |
| /* |
| * Clamp range lower to 0.9 to make it log, 0.1 would be scientifically |
| * accurate, but we cannot have partial counts. |
| */ |
| for (ISeries internalSeries : fChart.getSeriesSet().getSeries()) { |
| double[] ySeries = internalSeries.getYSeries(); |
| for (int i = 0; i < ySeries.length; i++) { |
| maxY = Math.max(maxY, ySeries[i]); |
| } |
| } |
| fChart.getAxisSet().getYAxis(0).setRange(new Range(0.9, Math.max(1.0, maxY))); |
| fChart.getAxisSet().getYAxis(0).enableLogScale(true); |
| fChart.redraw(); |
| new Thread(() -> { |
| for (ISegmentStoreDensityViewerDataListener l : fListeners) { |
| l.chartUpdated(); |
| } |
| }).start(); |
| |
| } |
| |
| private ISeries createSeries() { |
| IBarSeries series = (IBarSeries) fChart.getSeriesSet().createSeries(SeriesType.BAR, Messages.AbstractSegmentStoreDensityViewer_SeriesLabel); |
| series.setVisible(true); |
| series.setBarPadding(0); |
| series.setBarColor(getColorForRGB(BAR_COLOR)); |
| return series; |
| } |
| |
| private ISeries createAreaSeries(String name) { |
| ILineSeries series = (ILineSeries) fChart.getSeriesSet().createSeries(SeriesType.LINE, name); |
| series.setVisible(true); |
| series.enableStep(true); |
| series.enableArea(true); |
| series.setSymbolType(PlotSymbolType.NONE); |
| RGB rgb = getColorForItem(name); |
| Color color = getColorForRGB(rgb); |
| series.setLineColor(color); |
| return series; |
| } |
| |
| private static Color getColorForRGB(RGB rgb) { |
| String rgbString = rgb.toString(); |
| Color color = COLOR_REGISTRY.get(rgbString); |
| if (color == null) { |
| COLOR_REGISTRY.put(rgbString, rgb); |
| color = Objects.requireNonNull(COLOR_REGISTRY.get(rgbString)); |
| } |
| return color; |
| } |
| |
| /** |
| * Get the color for a series |
| * |
| * @param name |
| * the series name |
| * @return The color in RGB |
| * @since 4.1 |
| */ |
| public RGB getColorForItem(String name) { |
| if (fSegmentStoreProviders.size() == 1) { |
| return BAR_COLOR; |
| } |
| Set<String> keys = fSegmentStoreProviders.keySet(); |
| int i = 0; |
| for (String key : keys) { |
| if (key.equals(name)) { |
| break; |
| } |
| i++; |
| } |
| float pos = (float) i / keys.size(); |
| int index = Math.max((int) (PALETTE.getNbColors() * pos), 0) % PALETTE.getNbColors(); |
| return Objects.requireNonNull(RGBAUtil.fromRGBAColor(PALETTE.get().get(index)).rgb); |
| } |
| |
| @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(final Range durationRange) { |
| fCurrentDurationRange = durationRange; |
| final TmfTimeRange timeRange = fCurrentTimeRange; |
| computeDataAsync(timeRange, durationRange).thenAccept(data -> { |
| synchronized (fListeners) { |
| if (fCurrentTimeRange.equals(timeRange) && fCurrentDurationRange.equals(durationRange)) { |
| for (ISegmentStoreDensityViewerDataListener listener : fListeners) { |
| for (SegmentStoreWithRange<ISegment> value : data.values()) { |
| listener.selectedDataChanged(value); |
| } |
| } |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Zoom to a range of latency durations in the viewer. |
| * |
| * @param durationRange |
| * a range of latency durations |
| */ |
| public void zoom(final Range durationRange) { |
| fCurrentDurationRange = durationRange; |
| final TmfTimeRange timeRange = fCurrentTimeRange; |
| computeDataAsync(timeRange, durationRange).thenAccept(data -> { |
| synchronized (fListeners) { |
| if (fCurrentTimeRange.equals(timeRange) && fCurrentDurationRange.equals(durationRange)) { |
| applyData(data); |
| } |
| } |
| }); |
| } |
| |
| private CompletableFuture<Map<String, SegmentStoreWithRange<ISegment>>> computeDataAsync(final TmfTimeRange timeRange, final Range durationRange) { |
| return CompletableFuture.supplyAsync(() -> computeData(timeRange, durationRange)); |
| } |
| |
| private @Nullable Map<String, SegmentStoreWithRange<ISegment>> computeData(final TmfTimeRange timeRange, final Range durationRange) { |
| Map<String, SegmentStoreWithRange<ISegment>> retVal = new HashMap<>(); |
| for (Entry<String, ISegmentStoreProvider> entry : fSegmentStoreProviders.entrySet()) { |
| final ISegmentStoreProvider segmentProvider = Objects.requireNonNull(entry.getValue()); |
| final ISegmentStore<ISegment> segStore = segmentProvider.getSegmentStore(); |
| if (segStore == null) { |
| continue; |
| } |
| |
| // Filter on the segment duration if necessary |
| if (durationRange.lower > Double.MIN_VALUE || durationRange.upper < Double.MAX_VALUE) { |
| Predicate<ISegment> predicate = segment -> segment.getLength() >= durationRange.lower && segment.getLength() <= durationRange.upper; |
| retVal.put(entry.getKey(), new SegmentStoreWithRange<>(segStore, timeRange, predicate)); |
| } else { |
| retVal.put(entry.getKey(), new SegmentStoreWithRange<>(segStore, timeRange)); |
| } |
| } |
| return retVal; |
| } |
| |
| private void applyData(final Map<String, SegmentStoreWithRange<ISegment>> map) { |
| Set<Entry<String, SegmentStoreWithRange<ISegment>>> entrySet = map.entrySet(); |
| entrySet.parallelStream().forEach(entry -> { |
| SegmentStoreWithRange<ISegment> data = Objects.requireNonNull(entry.getValue()); |
| data.setComparator(SegmentComparators.INTERVAL_LENGTH_COMPARATOR); |
| Display.getDefault().asyncExec(() -> updateDisplay(entry.getKey(), data)); |
| if (fSegmentStoreProviders.size() > 1) { |
| setType(Type.AREA); |
| } else { |
| setType(Type.BAR); |
| } |
| for (ISegmentStoreDensityViewerDataListener l : fListeners) { |
| l.viewDataChanged(data); |
| } |
| }); |
| } |
| |
| /** |
| * Sets the segment store provider |
| * |
| * @param ssp |
| * The segment store provider to give to this view |
| * |
| * @since 1.2 |
| */ |
| @VisibleForTesting |
| public void setSegmentProvider(@Nullable ISegmentStoreProvider ssp) { |
| fSegmentStoreProviders.clear(); |
| if (ssp != null) { |
| fSegmentStoreProviders.put("", ssp); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * 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 parent = getTrace(); |
| if (parent == null) { |
| return; |
| } |
| fCurrentTimeRange = NonNullUtils.checkNotNull(signal.getCurrentRange()); |
| updateWindowRange(fCurrentTimeRange, false); |
| updateWithRange(fCurrentTimeRange); |
| } |
| |
| /** |
| * Update the display range |
| * |
| * @param timeRange |
| * the range |
| * @since 1.2 |
| */ |
| @VisibleForTesting |
| public void updateWithRange(final TmfTimeRange timeRange) { |
| fCurrentTimeRange = timeRange; |
| final Range durationRange = getDefaultRange(); |
| fCurrentDurationRange = durationRange; |
| computeDataAsync(timeRange, durationRange).thenAccept(data -> { |
| synchronized (fListeners) { |
| if (fCurrentTimeRange.equals(timeRange) && fCurrentDurationRange.equals(durationRange)) { |
| applyData(data); |
| } |
| } |
| }); |
| } |
| |
| @Override |
| public void refresh() { |
| fChart.redraw(); |
| } |
| |
| @Override |
| public void dispose() { |
| if (!fChart.isDisposed()) { |
| fChart.dispose(); |
| } |
| } |
| |
| private void internalDispose() { |
| fSegmentStoreProviders.entrySet().forEach(entry -> { |
| IAnalysisProgressListener listener = fProgressListeners.get(entry.getKey()); |
| if (listener != null) { |
| Objects.requireNonNull(entry.getValue()).removeListener(listener); |
| } |
| }); |
| fProgressListeners.clear(); |
| 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) { |
| if (fTrace != signal.getTrace()) { |
| loadTrace(getTrace()); |
| fTrace = signal.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()) { |
| loadTrace(getTrace()); |
| fTrace = signal.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(); |
| TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext(); |
| TmfTimeRange windowRange = ctx.getWindowRange(); |
| innerLoadTrace(trace); |
| updateWindowRange(windowRange, true); |
| fTrace = trace; |
| fCurrentTimeRange = windowRange; |
| zoom(getDefaultRange()); |
| } |
| |
| private void innerLoadTrace(@Nullable ITmfTrace trace) { |
| Set<ISegmentStoreProvider> sps = new HashSet<>(); |
| |
| if (trace != null) { |
| boolean newTrace = !Objects.equals(trace, fTrace) || fSegmentStoreProviders.isEmpty(); |
| if (newTrace) { |
| fTraces.clear(); |
| fSegmentStoreProviders.clear(); |
| for (ITmfTrace child : TmfTraceManager.getTraceSet(trace)) { |
| fTraces.add(child); |
| ISegmentStoreProvider segmentStoreProvider = getSegmentStoreProvider(child); |
| String name = child.getName(); |
| if (segmentStoreProvider != null && name != null) { |
| fSegmentStoreProviders.put(name, segmentStoreProvider); |
| sps.add(segmentStoreProvider); |
| } |
| } |
| ISegmentStoreProvider segmentStoreProvider = getSegmentStoreProvider(trace); |
| String name = trace.getName(); |
| if (segmentStoreProvider != null && name != null && !sps.contains(segmentStoreProvider)) { |
| fSegmentStoreProviders.put(name, segmentStoreProvider); |
| } |
| } |
| } |
| } |
| |
| private void updateWindowRange(TmfTimeRange windowRange, boolean updateListeners) { |
| |
| for (Entry<@NonNull String, @NonNull ISegmentStoreProvider> entry : fSegmentStoreProviders.entrySet()) { |
| ISegmentStoreProvider provider = Objects.requireNonNull(entry.getValue()); |
| if (updateListeners) { |
| IAnalysisProgressListener listener = (segmentProvider, data) -> updateWithRange(windowRange); |
| provider.addListener(listener); |
| fProgressListeners.put(entry.getKey(), listener); |
| } |
| if (provider instanceof IAnalysisModule) { |
| ((IAnalysisModule) provider).schedule(); |
| } |
| } |
| } |
| |
| private static Range getDefaultRange() { |
| return new Range(AbstractSegmentStoreDensityView.DEFAULT_RANGE.getFirst(), AbstractSegmentStoreDensityView.DEFAULT_RANGE.getSecond()); |
| } |
| |
| /** |
| * 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(); |
| } |
| } |
| |
| /** |
| * Force the number of points to a fixed value |
| * |
| * @param nbPoints |
| * The number of points to display, cannot be negative. 0 means use |
| * native resolution. any positive integer means that number of |
| * points |
| * @since 2.2 |
| */ |
| public synchronized void setNbPoints(int nbPoints) { |
| if (nbPoints < 0) { |
| throw new IllegalArgumentException("Number of points cannot be negative"); //$NON-NLS-1$ |
| } |
| fOverrideNbPoints = nbPoints; |
| updateWithRange(fCurrentTimeRange); |
| } |
| |
| /** |
| * 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); |
| } |
| } |