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