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