timing.ui: make Scatter chart not update the UI in update data
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.timing.ui / src / org / eclipse / tracecompass / analysis / timing / ui / views / segmentstore / scatter / AbstractSegmentStoreScatterGraphViewer.java
CommitLineData
03c96217 1/******************************************************************************
edded5c1 2 * Copyright (c) 2015, 2016 Ericsson
03c96217
BH
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * France Lapointe Nguyen - Initial API and implementation
11 * Bernd Hufmann - Extracted abstract class from LatencyScatterGraphViewer
12 *******************************************************************************/
13
edded5c1 14package org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.scatter;
03c96217 15
21c917fe 16import java.text.Format;
03c96217
BH
17import java.util.ArrayList;
18import java.util.Collection;
19import java.util.Collections;
20import java.util.Iterator;
21import java.util.List;
22
23import org.eclipse.core.runtime.IProgressMonitor;
24import org.eclipse.core.runtime.IStatus;
25import org.eclipse.core.runtime.Status;
26import org.eclipse.core.runtime.jobs.Job;
27import org.eclipse.jdt.annotation.Nullable;
03c96217
BH
28import org.eclipse.swt.widgets.Composite;
29import org.eclipse.swt.widgets.Display;
03c96217 30import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener;
0f769d2b 31import org.eclipse.tracecompass.analysis.timing.core.segmentstore.ISegmentStoreProvider;
21c917fe 32import org.eclipse.tracecompass.analysis.timing.ui.views.segmentstore.SubSecondTimeWithUnitFormat;
03c96217
BH
33import org.eclipse.tracecompass.common.core.NonNullUtils;
34import org.eclipse.tracecompass.internal.analysis.timing.ui.Activator;
edded5c1 35import org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.scatter.Messages;
21c917fe 36import org.eclipse.tracecompass.internal.analysis.timing.ui.views.segmentstore.scatter.SegmentStoreScatterGraphTooltipProvider;
03c96217
BH
37import org.eclipse.tracecompass.segmentstore.core.ISegment;
38import org.eclipse.tracecompass.segmentstore.core.ISegmentStore;
39import org.eclipse.tracecompass.segmentstore.core.SegmentComparators;
0f769d2b 40import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
03c96217 41import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
03c96217
BH
42import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
43import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
44import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
45import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
03c96217
BH
46import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
47import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
48import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
03c96217 49import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.linecharts.TmfCommonXLineChartViewer;
03c96217
BH
50import org.swtchart.ILineSeries;
51import org.swtchart.ILineSeries.PlotSymbolType;
52import org.swtchart.ISeries.SeriesType;
53import org.swtchart.ISeriesSet;
54import org.swtchart.LineStyle;
85ca1cfe
MK
55
56import com.google.common.primitives.Doubles;
03c96217
BH
57
58/**
0f769d2b 59 * Displays the segment store provider data in a scatter graph
03c96217
BH
60 *
61 * @author France Lapointe Nguyen
62 * @author Matthew Khouzam - reduced memory usage
63 * @since 2.0
64 */
65public abstract class AbstractSegmentStoreScatterGraphViewer extends TmfCommonXLineChartViewer {
03c96217 66
21c917fe
MK
67 private static final Format FORMAT = new SubSecondTimeWithUnitFormat();
68
03c96217
BH
69 private final class CompactingSegmentStoreQuery extends Job {
70 private static final long MAX_POINTS = 1000;
71 private final TmfTimeRange fCurrentRange;
72
73 private CompactingSegmentStoreQuery(TmfTimeRange currentRange) {
74 super(Messages.SegmentStoreScatterGraphViewer_compactTitle);
75 fCurrentRange = currentRange;
76 }
77
78 @Override
79 protected IStatus run(@Nullable IProgressMonitor monitor) {
80 final IProgressMonitor statusMonitor = monitor;
81 if (statusMonitor == null) {
82 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Monitor is null"); //$NON-NLS-1$
83 }
84
0f769d2b 85 ISegmentStoreProvider segmentProvider = getSegmentProvider();
16801c72
MK
86 final long startTimeInNanos = fCurrentRange.getStartTime().toNanos();
87 final long endTimeInNanos = fCurrentRange.getEndTime().toNanos();
0f769d2b 88 if (segmentProvider == null) {
03c96217 89 setWindowRange(startTimeInNanos, endTimeInNanos);
df2597e0 90 redraw(statusMonitor, startTimeInNanos, startTimeInNanos, Collections.EMPTY_LIST);
0f769d2b 91 return new Status(IStatus.WARNING, Activator.PLUGIN_ID, "segment provider not available"); //$NON-NLS-1$
03c96217
BH
92 }
93
0f769d2b 94 final ISegmentStore<ISegment> segStore = segmentProvider.getSegmentStore();
73c74de7 95 if (segStore == null) {
03c96217 96 setWindowRange(startTimeInNanos, endTimeInNanos);
df2597e0 97 redraw(statusMonitor, startTimeInNanos, startTimeInNanos, Collections.EMPTY_LIST);
0f769d2b 98 return new Status(IStatus.INFO, Activator.PLUGIN_ID, "Segment provider does not have segments"); //$NON-NLS-1$
03c96217
BH
99 }
100
101 final long startTime = fCurrentRange.getStartTime().getValue();
102 final long endTime = fCurrentRange.getEndTime().getValue();
103 fPixelStart = startTime;
61d830e8 104 fPixelSize = Math.max(1, (endTime - startTime) / MAX_POINTS);
73c74de7 105 final Iterable<ISegment> intersectingElements = segStore.getIntersectingElements(startTime, endTime);
03c96217
BH
106
107 final List<ISegment> list = convertIterableToList(intersectingElements, statusMonitor);
108 final List<ISegment> displayData = (!list.isEmpty()) ? compactList(startTime, list, statusMonitor) : list;
109
110 setWindowRange(startTimeInNanos, endTimeInNanos);
111 redraw(statusMonitor, startTime, endTime, displayData);
112
113 if (statusMonitor.isCanceled()) {
0e4f957e 114 return Status.CANCEL_STATUS;
03c96217 115 }
0e4f957e 116 return Status.OK_STATUS;
03c96217
BH
117
118 }
119
120 private void redraw(final IProgressMonitor statusMonitor, final long startTime, final long endTime, final List<ISegment> displayData) {
121 fDisplayData = displayData;
122 Display.getDefault().asyncExec(new Runnable() {
123
124 @Override
125 public void run() {
126 updateData(startTime, endTime, displayData.size(), statusMonitor);
127 }
128 });
129 }
130
131 private List<ISegment> compactList(final long startTime, final List<ISegment> listToCompact, final IProgressMonitor statusMonitor) {
132 List<ISegment> displayData = new ArrayList<>();
133 ISegment last = listToCompact.get(0);
134 if (last.getStart() >= startTime) {
135 displayData.add(last);
136 }
137 for (ISegment next : listToCompact) {
138 if (next.getStart() < startTime) {
139 continue;
140 }
141 if (statusMonitor.isCanceled()) {
df2597e0 142 return Collections.EMPTY_LIST;
03c96217
BH
143 }
144 if (!overlaps(last, next)) {
145 displayData.add(next);
146 last = next;
147 }
148 }
149 return displayData;
150 }
151
152 private List<ISegment> convertIterableToList(final Iterable<ISegment> iterable, final IProgressMonitor statusMonitor) {
153 final List<ISegment> list = new ArrayList<>();
154 for (ISegment seg : iterable) {
155 if (statusMonitor.isCanceled()) {
df2597e0 156 return Collections.EMPTY_LIST;
03c96217
BH
157 }
158 list.add(seg);
159 }
160 Collections.sort(list, SegmentComparators.INTERVAL_START_COMPARATOR);
161 return list;
162 }
163
164 private boolean overlaps(ISegment last, ISegment next) {
165 long timePerPix = fPixelSize;
166 final long start = last.getStart();
167 final long pixelStart = fPixelStart;
168 final long pixelDuration = start - pixelStart;
169 long startPixBoundL = pixelDuration / timePerPix * timePerPix + pixelStart;
170 long startPixBoundR = startPixBoundL + timePerPix;
171 final long currentStart = next.getStart();
172 if (currentStart >= startPixBoundL && currentStart <= startPixBoundR) {
173 long length = last.getLength();
174 long lengthNext = next.getLength();
175 long lengthLow = length / timePerPix * timePerPix;
176 long lengthHigh = lengthLow + timePerPix;
177 return (lengthNext >= lengthLow && lengthNext <= lengthHigh);
178 }
179 return false;
180 }
181 }
182
183 // ------------------------------------------------------------------------
184 // Attributes
185 // ------------------------------------------------------------------------
186
187 /**
0f769d2b
MK
188 * Listener to update the model with the segment store provider results once
189 * its segment store is fully completed
03c96217 190 */
0f769d2b 191 private final class SegmentStoreProviderProgressListener implements IAnalysisProgressListener {
03c96217
BH
192
193 @Override
0f769d2b 194 public void onComplete(ISegmentStoreProvider segmentProvider, ISegmentStore<ISegment> segmentStore) {
03c96217 195 // Only update the model if trace that was analyzed is active trace
0f769d2b
MK
196 if (segmentProvider.equals(getSegmentProvider())) {
197 updateModel(segmentStore);
03c96217
BH
198 updateRange(TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange());
199 }
200 }
201 }
202
203 private long fPixelSize = -1;
204
205 private long fPixelStart = 0;
206 /**
207 * Data to display
208 */
df2597e0 209 private Collection<ISegment> fDisplayData = Collections.EMPTY_LIST;
03c96217
BH
210
211 /**
0f769d2b 212 * Provider completion listener
03c96217 213 */
0f769d2b 214 private SegmentStoreProviderProgressListener fListener;
03c96217
BH
215
216 /**
0f769d2b 217 * Current segment provider
03c96217 218 */
0f769d2b 219 private @Nullable ISegmentStoreProvider fSegmentProvider;
03c96217
BH
220
221 private @Nullable Job fCompactingJob;
222
223 // ------------------------------------------------------------------------
224 // Constructor
225 // ------------------------------------------------------------------------
226
227 /**
228 * Constructor
229 *
230 * @param parent
231 * parent composite
232 * @param title
233 * name of the graph
234 * @param xLabel
235 * name of the x axis
236 * @param yLabel
237 * name of the y axis
238 */
239 public AbstractSegmentStoreScatterGraphViewer(Composite parent, String title, String xLabel, String yLabel) {
240 super(parent, title, xLabel, yLabel);
a2de198a 241 setTooltipProvider(new SegmentStoreScatterGraphTooltipProvider(this));
0f769d2b 242 fListener = new SegmentStoreProviderProgressListener();
03c96217 243 ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace();
0f769d2b 244 initializeProvider(trace);
03c96217 245 getSwtChart().getLegend().setVisible(false);
21c917fe 246 getSwtChart().getAxisSet().getYAxis(0).getTick().setFormat(FORMAT);
03c96217
BH
247 }
248
0f769d2b 249 private final void initializeProvider(@Nullable ITmfTrace trace) {
03c96217 250 if (trace != null) {
0f769d2b
MK
251 final ISegmentStoreProvider segmentStoreProvider = getSegmentStoreProvider(trace);
252 if (segmentStoreProvider != null) {
253 segmentStoreProvider.addListener(fListener);
254 setData(segmentStoreProvider);
03c96217
BH
255 updateRange(TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange());
256 }
257 }
258 }
259
260 // ------------------------------------------------------------------------
261 // Operations
262 // ------------------------------------------------------------------------
263
264 /**
265 * Update the data in the graph
266 *
267 * @param dataInput
268 * new model
269 */
270 public void updateModel(@Nullable ISegmentStore<ISegment> dataInput) {
271 // Update new window range
272 TmfTimeRange currentRange = TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange();
16801c72
MK
273 long currentStart = currentRange.getStartTime().toNanos();
274 long currentEnd = currentRange.getEndTime().toNanos();
03c96217
BH
275 if (dataInput == null) {
276 if (!getDisplay().isDisposed()) {
277 Display.getDefault().syncExec(new Runnable() {
278 @Override
279 public void run() {
280 clearContent();
281 }
282 });
283 }
df2597e0 284 fDisplayData = Collections.EMPTY_LIST;
03c96217
BH
285 } else {
286 Collection<ISegment> elements = (Collection<ISegment>) dataInput.getIntersectingElements(currentStart, currentEnd);
287 // getIntersectingElements can return an unsorted iterable, make
288 // sure our collection is sorted
289 ArrayList<ISegment> list = new ArrayList<>(elements);
290 Collections.sort(list, SegmentComparators.INTERVAL_START_COMPARATOR);
291 fDisplayData = list;
292 }
293 setWindowRange(currentStart, currentEnd);
294 updateRange(currentRange);
295 }
296
297 @Override
298 protected void initializeDataSource() {
299 ITmfTrace trace = getTrace();
0f769d2b 300 initializeProvider(trace);
03c96217 301 if (trace != null) {
0f769d2b 302 setData(getSegmentStoreProvider(trace));
03c96217
BH
303 }
304 }
305
306 @Override
307 protected void updateData(final long start, final long end, int nb, @Nullable IProgressMonitor monitor) {
308 // Third parameter is not used by implementation
309 // Determine data that needs to be visible
310 Collection<ISegment> data = fDisplayData;
311
312 final int dataSize = (nb == 0) ? data.size() : nb;
313 if (dataSize == 0 || end == start) {
314 return;
315 }
316
85ca1cfe
MK
317 List<Double> xSeries = new ArrayList<>(dataSize);
318 List<Double> ySeries = new ArrayList<>(dataSize);
03c96217
BH
319 // For each visible segments, add start time to x value and duration
320 // for y value
321 Iterator<ISegment> modelIter = data.iterator();
85ca1cfe
MK
322 while (modelIter.hasNext()) {
323 ISegment segment = modelIter.next();
324 xSeries.add((double) (segment.getStart() - start));
325 ySeries.add((double) segment.getLength());
03c96217 326 }
85ca1cfe
MK
327 setXAxis(Doubles.toArray(xSeries));
328 setSeries(Messages.SegmentStoreScatterGraphViewer_legend, Doubles.toArray(ySeries)); // $NON-NLS-1$
329 updateDisplay();
03c96217
BH
330 }
331
332 @Override
333 protected void setWindowRange(final long windowStartTime, final long windowEndTime) {
334 super.setWindowRange(windowStartTime, windowEndTime);
335 }
336
337 @Override
338 protected ILineSeries addSeries(@Nullable String seriesName) {
339 ISeriesSet seriesSet = getSwtChart().getSeriesSet();
340 ILineSeries series = (ILineSeries) seriesSet.createSeries(SeriesType.LINE, seriesName);
341 series.setVisible(true);
342 series.enableArea(false);
343 series.setLineStyle(LineStyle.NONE);
344 series.setSymbolType(PlotSymbolType.DIAMOND);
345 return series;
346 }
347
348 /**
0f769d2b
MK
349 * Set the data into the viewer. If the provider is an analysis, it will
350 * update the model if the analysis is completed or run the analysis if not
351 * completed
03c96217 352 *
0f769d2b
MK
353 * @param provider
354 * Segment store provider
03c96217 355 */
0f769d2b
MK
356 public void setData(@Nullable ISegmentStoreProvider provider) {
357 if (provider == null) {
03c96217
BH
358 updateModel(null);
359 return;
360 }
0f769d2b
MK
361 ISegmentStore<ISegment> segStore = provider.getSegmentStore();
362 // If results are not null, then segment store is completed and model
363 // can be updated
73c74de7
JCK
364 if (segStore != null) {
365 updateModel(segStore);
0f769d2b 366 setSegmentProvider(provider);
03c96217
BH
367 return;
368 }
369 updateModel(null);
0f769d2b
MK
370 provider.addListener(fListener);
371 if (provider instanceof IAnalysisModule) {
372 ((IAnalysisModule) provider).schedule();
373 }
374 setSegmentProvider(provider);
03c96217
BH
375 }
376
377 /**
0f769d2b 378 * Returns the segment store provider
df2597e0 379 *
03c96217
BH
380 * @param trace
381 * The trace to consider
0f769d2b 382 * @return the segment store provider
03c96217 383 */
0f769d2b 384 protected @Nullable abstract ISegmentStoreProvider getSegmentStoreProvider(ITmfTrace trace);
03c96217 385
03c96217
BH
386 // ------------------------------------------------------------------------
387 // Signal handlers
388 // ------------------------------------------------------------------------
389
390 /**
391 * @param signal
392 * Signal received when a different trace is selected
393 */
394 @Override
395 @TmfSignalHandler
396 public void traceSelected(@Nullable TmfTraceSelectedSignal signal) {
397 super.traceSelected(signal);
398 if (signal == null) {
399 return;
400 }
401 ITmfTrace trace = signal.getTrace();
402 setTrace(trace);
403 if (trace != null) {
404 final TmfTimeRange timeRange = TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange();
405 setWindowRange(
16801c72
MK
406 timeRange.getStartTime().toNanos(),
407 timeRange.getEndTime().toNanos());
0f769d2b 408 setData(getSegmentStoreProvider(trace));
03c96217
BH
409 updateRange(timeRange);
410 }
411 }
412
413 /**
414 * @param signal
415 * Signal received when trace is opened
416 */
417 @Override
418 @TmfSignalHandler
419 public void traceOpened(@Nullable TmfTraceOpenedSignal signal) {
420 super.traceOpened(signal);
421 if (signal == null) {
422 return;
423 }
424 ITmfTrace trace = signal.getTrace();
425 setTrace(trace);
426 if (trace != null) {
427
0f769d2b 428 final ISegmentStoreProvider segmentStoreProvider = getSegmentStoreProvider(trace);
03c96217
BH
429 final TmfTimeRange timeRange = TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange();
430 setWindowRange(
16801c72
MK
431 timeRange.getStartTime().toNanos(),
432 timeRange.getEndTime().toNanos());
0f769d2b 433 setData(segmentStoreProvider);
03c96217
BH
434 }
435
436 }
437
438 private void updateRange(final @Nullable TmfTimeRange timeRange) {
439 Job compactingJob = fCompactingJob;
440 if (compactingJob != null && compactingJob.getState() == Job.RUNNING) {
441 compactingJob.cancel();
442 }
443 compactingJob = new CompactingSegmentStoreQuery(NonNullUtils.checkNotNull(timeRange));
444 fCompactingJob = compactingJob;
445 compactingJob.schedule();
446 }
447
448 /**
449 * @param signal
450 * Signal received when last opened trace is closed
451 */
452 @Override
453 @TmfSignalHandler
454 public void traceClosed(@Nullable TmfTraceClosedSignal signal) {
455 super.traceClosed(signal);
456 if (signal != null) {
457 // Check if there is no more opened trace
458 if (TmfTraceManager.getInstance().getActiveTrace() == null) {
0f769d2b
MK
459 ISegmentStoreProvider provider = getSegmentProvider();
460 if (provider != null) {
461 provider.removeListener(fListener);
03c96217
BH
462 }
463 clearContent();
464 }
465 }
466 refresh();
467 }
468
469 /**
470 * @param signal
471 * Signal received when window range is updated
472 */
473 @Override
474 @TmfSignalHandler
475 public void windowRangeUpdated(@Nullable TmfWindowRangeUpdatedSignal signal) {
476 super.windowRangeUpdated(signal);
477 if (signal == null) {
478 return;
479 }
480 if (getTrace() != null) {
481 final TmfTimeRange currentRange = signal.getCurrentRange();
482 updateRange(currentRange);
483 } else {
484 Activator.getDefault().logInfo("No Trace to update"); //$NON-NLS-1$
485 }
486 }
487
0f769d2b
MK
488 private @Nullable ISegmentStoreProvider getSegmentProvider() {
489 return fSegmentProvider;
03c96217
BH
490 }
491
0f769d2b
MK
492 private void setSegmentProvider(ISegmentStoreProvider provider) {
493 fSegmentProvider = provider;
03c96217 494 }
03c96217 495}
This page took 0.063913 seconds and 5 git commands to generate.