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