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