tmf.ctf.ui: test invalid trace validation (Bug 464329)
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / viewers / xycharts / linecharts / TmfCommonXLineChartViewer.java
CommitLineData
2e427755 1/*******************************************************************************
4e72adee 2 * Copyright (c) 2014, 2015 École Polytechnique de Montréal and others.
2e427755
GB
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 * Geneviève Bastien - Initial API and implementation
11 *******************************************************************************/
12
2bdf0193 13package org.eclipse.tracecompass.tmf.ui.viewers.xycharts.linecharts;
2e427755
GB
14
15import java.util.LinkedHashMap;
16import java.util.Map;
17import java.util.Map.Entry;
18
00968516
GB
19import org.eclipse.core.runtime.IProgressMonitor;
20import org.eclipse.core.runtime.NullProgressMonitor;
c85a741e 21import org.eclipse.swt.SWT;
2e427755
GB
22import org.eclipse.swt.widgets.Composite;
23import org.eclipse.swt.widgets.Display;
2bdf0193
AM
24import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
25import org.eclipse.tracecompass.tmf.ui.TmfUiRefreshHandler;
26import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.TmfChartTimeStampFormat;
27import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.TmfXYChartViewer;
2e427755
GB
28import org.swtchart.IAxisTick;
29import org.swtchart.ILineSeries;
30import org.swtchart.ILineSeries.PlotSymbolType;
31import org.swtchart.ISeries;
32import org.swtchart.ISeries.SeriesType;
c85a741e 33import org.swtchart.ISeriesSet;
2e427755
GB
34import org.swtchart.LineStyle;
35import org.swtchart.Range;
36
37/**
38 * Abstract line chart viewer class implementation. All series in this viewer
39 * use the same X axis values. They are automatically created as values are
40 * provided for a key. Series by default will be displayed as a line. Each
41 * series appearance can be overridden when creating it.
42 *
43 * @author - Geneviève Bastien
2e427755
GB
44 */
45public abstract class TmfCommonXLineChartViewer extends TmfXYChartViewer {
46
47 private static final double DEFAULT_MAXY = Double.MIN_VALUE;
48 private static final double DEFAULT_MINY = Double.MAX_VALUE;
49
50 /* The desired number of points per pixel */
51 private static final double RESOLUTION = 1.0;
52
c85a741e
GB
53 private static final int[] LINE_COLORS = { SWT.COLOR_BLUE, SWT.COLOR_RED, SWT.COLOR_GREEN,
54 SWT.COLOR_MAGENTA, SWT.COLOR_CYAN,
55 SWT.COLOR_DARK_BLUE, SWT.COLOR_DARK_RED, SWT.COLOR_DARK_GREEN,
56 SWT.COLOR_DARK_MAGENTA, SWT.COLOR_DARK_CYAN, SWT.COLOR_DARK_YELLOW,
57 SWT.COLOR_BLACK, SWT.COLOR_GRAY };
58 private static final LineStyle[] LINE_STYLES = { LineStyle.SOLID, LineStyle.DASH, LineStyle.DOT, LineStyle.DASHDOT };
59
2e427755
GB
60 private final Map<String, double[]> fSeriesValues = new LinkedHashMap<>();
61 private double[] fXValues;
9392459a 62 private double fResolution;
2e427755 63
00968516
GB
64 private UpdateThread fUpdateThread;
65
2e427755
GB
66 /**
67 * Constructor
68 *
69 * @param parent
70 * The parent composite
71 * @param title
72 * The title of the viewer
73 * @param xLabel
74 * The label of the xAxis
75 * @param yLabel
76 * The label of the yAXIS
77 */
78 public TmfCommonXLineChartViewer(Composite parent, String title, String xLabel, String yLabel) {
79 super(parent, title, xLabel, yLabel);
80
9392459a 81 setResolution(RESOLUTION);
2e427755
GB
82 setTooltipProvider(new TmfCommonXLineChartTooltipProvider(this));
83 }
84
9392459a
GB
85 /**
86 * Set the number of requests per pixel that should be done on this chart
87 *
88 * @param resolution
89 * The number of points per pixels
90 */
91 protected void setResolution(double resolution) {
92 fResolution = resolution;
93 }
94
2e427755
GB
95 @Override
96 public void loadTrace(ITmfTrace trace) {
97 super.loadTrace(trace);
47cb22a7
GB
98 reinitialize();
99 }
100
101 /**
102 * Forces a reinitialization of the data sources, even if it has already
103 * been initialized for this trace before
47cb22a7
GB
104 */
105 protected void reinitialize() {
2e427755
GB
106 fSeriesValues.clear();
107 Thread thread = new Thread() {
108 @Override
109 public void run() {
110 initializeDataSource();
aa9b2552
AM
111 TmfUiRefreshHandler.getInstance().queueUpdate(TmfCommonXLineChartViewer.this,
112 new Runnable() {
2e427755
GB
113 @Override
114 public void run() {
115 if (!getSwtChart().isDisposed()) {
116 /* Delete the old series */
117 clearContent();
118 createSeries();
119 }
120 }
121 });
122 }
123 };
124 thread.start();
125 }
126
127 /**
128 * Initialize the source of the data for this viewer. This method is run in
129 * a separate thread, so this is where for example one can execute an
130 * analysis module and wait for its completion to initialize the series
131 */
132 protected void initializeDataSource() {
133
134 }
135
00968516
GB
136 private class UpdateThread extends Thread {
137 private final IProgressMonitor fMonitor;
138 private final int fNumRequests;
139
140 public UpdateThread(int numRequests) {
141 super("Line chart update"); //$NON-NLS-1$
142 fNumRequests = numRequests;
143 fMonitor = new NullProgressMonitor();
144 }
145
146 @Override
147 public void run() {
148 updateData(getWindowStartTime(), getWindowEndTime(), fNumRequests, fMonitor);
149 updateThreadFinished(this);
150 }
151
152 public void cancel() {
153 fMonitor.setCanceled(true);
154 }
155 }
156
157 private synchronized void newUpdateThread() {
158 cancelUpdate();
159 final int numRequests = (int) (getSwtChart().getPlotArea().getBounds().width * fResolution);
160 fUpdateThread = new UpdateThread(numRequests);
161 fUpdateThread.start();
162 }
163
164 private synchronized void updateThreadFinished(UpdateThread thread) {
165 if (thread == fUpdateThread) {
166 fUpdateThread = null;
167 }
168 }
169
170 /**
171 * Cancels the currently running update thread. It is automatically called
172 * when the content is updated, but child viewers may want to call it
173 * manually to do some operations before calling
174 * {@link TmfCommonXLineChartViewer#updateContent}
175 */
176 protected synchronized void cancelUpdate() {
177 if (fUpdateThread != null) {
178 fUpdateThread.cancel();
179 }
180 }
181
2e427755
GB
182 @Override
183 protected void updateContent() {
184 getDisplay().asyncExec(new Runnable() {
2e427755
GB
185 @Override
186 public void run() {
00968516 187 newUpdateThread();
2e427755
GB
188 }
189 });
190 }
191
192 /**
193 * Convenience method to compute the values of the X axis for a given time
194 * range. This method will return nb values depending, equally separated
195 * from start to end.
196 *
197 * The returned time values are in internal time, ie to get trace time, the
198 * time offset needs to be added to those values.
199 *
200 * @param start
201 * The start time of the time range
202 * @param end
203 * End time of the range
204 * @param nb
205 * The number of steps in the x axis.
206 * @return The time values (converted to double) to match every step.
207 */
4e72adee 208 protected final static double[] getXAxis(long start, long end, int nb) {
2e427755
GB
209
210 double timestamps[] = new double[nb];
211 long steps = (end - start);
212 double step = steps / (double) nb;
213
214 double curTime = 1;
215 for (int i = 0; i < nb; i++) {
216 timestamps[i] = curTime;
217 curTime += step;
218 }
219 return timestamps;
220 }
221
222 /**
223 * Set the values of the x axis. There is only one array of values for the x
224 * axis for all series of a line chart so it needs to be set once here.
225 *
226 * @param xaxis
227 * The values for the x axis. The values must be in internal
228 * time, ie time offset have been subtracted from trace time
229 * values.
230 */
231 protected final void setXAxis(double[] xaxis) {
232 fXValues = xaxis;
233 }
234
235 /**
236 * Update the series data because the time range has changed. The x axis
237 * values for this data update can be computed using the
c85a741e
GB
238 * {@link TmfCommonXLineChartViewer#getXAxis(long, long, int)} method which
239 * will return a list of uniformely separated time values.
2e427755
GB
240 *
241 * Each series values should be set by calling the
242 * {@link TmfCommonXLineChartViewer#setSeries(String, double[])}.
243 *
244 * This method is responsible for calling the
c85a741e
GB
245 * {@link TmfCommonXLineChartViewer#updateDisplay()} when needed for the new
246 * values to be displayed.
2e427755
GB
247 *
248 * @param start
249 * The start time of the range for which the get the data
250 * @param end
251 * The end time of the range
252 * @param nb
253 * The number of 'points' in the chart.
00968516
GB
254 * @param monitor
255 * The progress monitor object
2e427755 256 */
00968516 257 protected abstract void updateData(long start, long end, int nb, IProgressMonitor monitor);
2e427755
GB
258
259 /**
260 * Set the data for a given series of the graph. The series does not need to
261 * be created before calling this, but it needs to have at least as many
262 * values as the x axis.
263 *
264 * If the series does not exist, it will automatically be created at display
265 * time, with the default values.
266 *
267 * @param seriesName
268 * The name of the series for which to set the values
269 * @param seriesValues
270 * The array of values for the series
271 */
272 protected void setSeries(String seriesName, double[] seriesValues) {
273 if (fXValues.length > seriesValues.length) {
274 throw new IllegalStateException();
275 }
276 fSeriesValues.put(seriesName, seriesValues);
277 }
278
279 /**
280 * Add a new series to the XY line chart. By default, it is a simple solid
281 * line.
282 *
2e427755
GB
283 * @param seriesName
284 * The name of the series to create
285 * @return The series so that the concrete viewer can modify its properties
286 * if required
287 */
288 protected ILineSeries addSeries(String seriesName) {
c85a741e
GB
289 ISeriesSet seriesSet = getSwtChart().getSeriesSet();
290 int seriesCount = seriesSet.getSeries().length;
291 ILineSeries series = (ILineSeries) seriesSet.createSeries(SeriesType.LINE, seriesName);
2e427755
GB
292 series.setVisible(true);
293 series.enableArea(false);
c85a741e 294 series.setLineStyle(LINE_STYLES[(seriesCount / (LINE_COLORS.length)) % LINE_STYLES.length]);
2e427755 295 series.setSymbolType(PlotSymbolType.NONE);
c85a741e 296 series.setLineColor(Display.getDefault().getSystemColor(LINE_COLORS[seriesCount % LINE_COLORS.length]));
2e427755
GB
297 return series;
298 }
299
300 /**
301 * Delete a series from the chart and its values from the viewer.
302 *
303 * @param seriesName
304 * Name of the series to delete
305 */
306 protected void deleteSeries(String seriesName) {
307 ISeries series = getSwtChart().getSeriesSet().getSeries(seriesName);
308 if (series != null) {
309 getSwtChart().getSeriesSet().deleteSeries(series.getId());
310 }
311 fSeriesValues.remove(seriesName);
312 }
313
314 /**
315 * Update the chart's values before refreshing the viewer
316 */
317 protected void updateDisplay() {
318 Display.getDefault().asyncExec(new Runnable() {
319 final TmfChartTimeStampFormat tmfChartTimeStampFormat = new TmfChartTimeStampFormat(getTimeOffset());
320
321 @Override
322 public void run() {
323 if (!getSwtChart().isDisposed()) {
324 double maxy = DEFAULT_MAXY;
325 double miny = DEFAULT_MINY;
326 for (Entry<String, double[]> entry : fSeriesValues.entrySet()) {
327 ILineSeries series = (ILineSeries) getSwtChart().getSeriesSet().getSeries(entry.getKey());
328 if (series == null) {
329 series = addSeries(entry.getKey());
330 }
331 series.setXSeries(fXValues);
332 /* Find the minimal and maximum values in this series */
333 for (double value : entry.getValue()) {
334 maxy = Math.max(maxy, value);
335 miny = Math.min(miny, value);
336 }
337 series.setYSeries(entry.getValue());
338 }
9392459a
GB
339 if (maxy == DEFAULT_MAXY) {
340 maxy = 1.0;
341 }
2e427755
GB
342
343 IAxisTick xTick = getSwtChart().getAxisSet().getXAxis(0).getTick();
344 xTick.setFormat(tmfChartTimeStampFormat);
345
346 final double start = fXValues[0];
347 int lastX = fXValues.length - 1;
348 double end = (start == fXValues[lastX]) ? start + 1 : fXValues[lastX];
349 getSwtChart().getAxisSet().getXAxis(0).setRange(new Range(start, end));
350 getSwtChart().getAxisSet().getXAxis(0).adjustRange();
351 if (maxy > miny) {
352 getSwtChart().getAxisSet().getYAxis(0).setRange(new Range(miny, maxy));
353 }
354 getSwtChart().redraw();
355 }
356 }
357 });
358 }
359
360 /**
361 * Create the series once the initialization of the viewer's data source is
362 * done. Series do not need to be created before setting their values, but
363 * if their appearance needs to be customized, this method is a good place
364 * to do so. It is called only once per trace.
365 */
366 protected void createSeries() {
367
368 }
369
370}
This page took 0.071124 seconds and 5 git commands to generate.