tmf.ui: Add a SWTbot condition for XY charts ready
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / viewers / xycharts / TmfXYChartViewer.java
1 /**********************************************************************
2 * Copyright (c) 2013, 2016 Ericsson, É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 * Bernd Hufmann - Initial API and implementation
11 * Geneviève Bastien - Moved some methods to TmfTimeViewer
12 * Patrick Tasse - Fix setFocus
13 **********************************************************************/
14 package org.eclipse.tracecompass.tmf.ui.viewers.xycharts;
15
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.events.MouseAdapter;
18 import org.eclipse.swt.events.MouseEvent;
19 import org.eclipse.swt.widgets.Composite;
20 import org.eclipse.swt.widgets.Control;
21 import org.eclipse.swt.widgets.Display;
22 import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
23 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
24 import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal;
25 import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
26 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
27 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext;
28 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
29 import org.eclipse.tracecompass.tmf.ui.viewers.TmfTimeViewer;
30 import org.swtchart.Chart;
31 import org.swtchart.IAxis;
32 import org.swtchart.ISeries;
33 import org.swtchart.ISeriesSet;
34 import org.swtchart.Range;
35
36 import com.google.common.annotations.VisibleForTesting;
37
38 /**
39 * Base class for a XY-Chart based on SWT chart. It provides a methods to define
40 * zoom, selection and tool tip providers. It also provides call backs to be
41 * notified by any changes caused by selection and zoom.
42 *
43 * @author Bernd Hufmann
44 */
45 public abstract class TmfXYChartViewer extends TmfTimeViewer implements ITmfChartTimeProvider {
46
47 // ------------------------------------------------------------------------
48 // Attributes
49 // ------------------------------------------------------------------------
50 /** The SWT Chart reference */
51 private Chart fSwtChart;
52 /** The mouse selection provider */
53 private TmfBaseProvider fMouseSelectionProvider;
54 /** The mouse drag zoom provider */
55 private TmfBaseProvider fMouseDragZoomProvider;
56 /** The mouse wheel zoom provider */
57 private TmfBaseProvider fMouseWheelZoomProvider;
58 /** The tooltip provider */
59 private TmfBaseProvider fToolTipProvider;
60 /** The middle mouse drag provider */
61 private TmfBaseProvider fMouseDragProvider;
62 /**
63 * Whether or not to send time alignment signals. This should be set to true
64 * for viewers that are part of an aligned view.
65 */
66 private boolean fSendTimeAlignSignals = false;
67
68
69 // ------------------------------------------------------------------------
70 // Constructors
71 // ------------------------------------------------------------------------
72
73 /**
74 * Constructs a TmfXYChartViewer.
75 *
76 * @param parent
77 * The parent composite
78 * @param title
79 * The title of the viewer
80 * @param xLabel
81 * The label of the xAxis
82 * @param yLabel
83 * The label of the yAXIS
84 */
85 public TmfXYChartViewer(Composite parent, String title, String xLabel, String yLabel) {
86 super(parent, title);
87 fSwtChart = new Chart(parent, SWT.NONE) {
88 @Override
89 public boolean setFocus() {
90 return fSwtChart.getPlotArea().setFocus();
91 }
92 };
93 fSwtChart.getPlotArea().addMouseListener(new MouseAdapter() {
94 @Override
95 public void mouseDown(MouseEvent e) {
96 fSwtChart.getPlotArea().setFocus();
97 }
98 });
99
100 IAxis xAxis = fSwtChart.getAxisSet().getXAxis(0);
101 IAxis yAxis = fSwtChart.getAxisSet().getYAxis(0);
102
103 /* Set the title/labels, or hide them if they are not provided */
104 if (title == null) {
105 fSwtChart.getTitle().setVisible(false);
106 } else {
107 fSwtChart.getTitle().setText(title);
108 }
109 if (xLabel == null) {
110 xAxis.getTitle().setVisible(false);
111 } else {
112 xAxis.getTitle().setText(xLabel);
113 }
114 if (yLabel == null) {
115 yAxis.getTitle().setVisible(false);
116 } else {
117 yAxis.getTitle().setText(yLabel);
118 }
119
120 fMouseSelectionProvider = new TmfMouseSelectionProvider(this);
121 fMouseDragZoomProvider = new TmfMouseDragZoomProvider(this);
122 fMouseWheelZoomProvider = new TmfMouseWheelZoomProvider(this);
123 fToolTipProvider = new TmfSimpleTooltipProvider(this);
124 fMouseDragProvider = new TmfMouseDragProvider(this);
125
126 fSwtChart.addDisposeListener((e) -> {
127 internalDispose();
128 });
129 }
130
131 // ------------------------------------------------------------------------
132 // Getter/Setters
133 // ------------------------------------------------------------------------
134
135 /**
136 * Sets the SWT Chart reference
137 *
138 * @param chart
139 * The SWT chart to set.
140 */
141 protected void setSwtChart(Chart chart) {
142 fSwtChart = chart;
143 }
144
145 /**
146 * Gets the SWT Chart reference
147 *
148 * @return the SWT chart to set.
149 */
150 protected Chart getSwtChart() {
151 return fSwtChart;
152 }
153
154 /**
155 * Sets a mouse selection provider. An existing provider will be
156 * disposed. Use <code>null</code> to disable the mouse selection provider.
157 *
158 * @param provider
159 * The selection provider to set
160 */
161 public void setSelectionProvider(TmfBaseProvider provider) {
162 if (fMouseSelectionProvider != null) {
163 fMouseSelectionProvider.dispose();
164 }
165 fMouseSelectionProvider = provider;
166 }
167
168 /**
169 * Sets a mouse drag zoom provider. An existing provider will be
170 * disposed. Use <code>null</code> to disable the mouse drag zoom provider.
171 *
172 * @param provider
173 * The mouse drag zoom provider to set
174 */
175 public void setMouseDragZoomProvider(TmfBaseProvider provider) {
176 if (fMouseDragZoomProvider != null) {
177 fMouseDragZoomProvider.dispose();
178 }
179 fMouseDragZoomProvider = provider;
180 }
181
182 /**
183 * Sets a mouse wheel zoom provider. An existing provider will be
184 * disposed. Use <code>null</code> to disable the mouse wheel zoom
185 * provider.
186 *
187 * @param provider
188 * The mouse wheel zoom provider to set
189 */
190 public void setMouseWheelZoomProvider(TmfBaseProvider provider) {
191 if (fMouseWheelZoomProvider != null) {
192 fMouseWheelZoomProvider.dispose();
193 }
194 fMouseWheelZoomProvider = provider;
195 }
196
197 /**
198 * Sets a tooltip provider. An existing provider will be
199 * disposed. Use <code>null</code> to disable the tooltip provider.
200 *
201 * @param provider
202 * The tooltip provider to set
203 */
204 public void setTooltipProvider(TmfBaseProvider provider) {
205 if (fToolTipProvider != null) {
206 fToolTipProvider.dispose();
207 }
208 fToolTipProvider = provider;
209 }
210
211 /**
212 * Sets a mouse drag provider. An existing provider will be
213 * disposed. Use <code>null</code> to disable the mouse drag provider.
214 *
215 * @param provider
216 * The mouse drag provider to set
217 */
218 public void setMouseDrageProvider(TmfBaseProvider provider) {
219 if (fMouseDragProvider != null) {
220 fMouseDragProvider.dispose();
221 }
222 fMouseDragProvider = provider;
223 }
224
225 // ------------------------------------------------------------------------
226 // ITmfChartTimeProvider
227 // ------------------------------------------------------------------------
228
229 @Override
230 public long getTimeOffset() {
231 return getWindowStartTime() - 1;
232 }
233
234 // ------------------------------------------------------------------------
235 // ITmfViewer interface
236 // ------------------------------------------------------------------------
237 @Override
238 public Control getControl() {
239 return fSwtChart;
240 }
241
242 @Override
243 public void refresh() {
244 fSwtChart.redraw();
245 }
246
247 // ------------------------------------------------------------------------
248 // TmfComponent
249 // ------------------------------------------------------------------------
250
251 @Override
252 public void dispose() {
253 fSwtChart.dispose();
254 }
255
256 private void internalDispose() {
257 super.dispose();
258
259 if (fMouseSelectionProvider != null) {
260 fMouseSelectionProvider.dispose();
261 }
262
263 if (fMouseDragZoomProvider != null) {
264 fMouseDragZoomProvider.dispose();
265 }
266
267 if (fMouseWheelZoomProvider != null) {
268 fMouseWheelZoomProvider.dispose();
269 }
270
271 if (fToolTipProvider != null) {
272 fToolTipProvider.dispose();
273 }
274
275 if (fMouseDragProvider != null) {
276 fMouseDragProvider.dispose();
277 }
278 }
279
280 // ------------------------------------------------------------------------
281 // Operations
282 // ------------------------------------------------------------------------
283 /**
284 * A Method to load a trace into the viewer.
285 *
286 * @param trace
287 * A trace to apply in the viewer
288 */
289 @Override
290 public void loadTrace(ITmfTrace trace) {
291 super.loadTrace(trace);
292 clearContent();
293 updateContent();
294 }
295
296 /**
297 * Resets the content of the viewer
298 */
299 @Override
300 public void reset() {
301 super.reset();
302 setStartTime(0);
303 setEndTime(0);
304 clearContent();
305 }
306
307 /**
308 * Method to implement to update the chart content.
309 */
310 protected abstract void updateContent();
311
312 /**
313 * Returns whether or not this chart viewer is dirty. The viewer is
314 * considered dirty if it has yet to completely update its model.
315 *
316 * This method is meant to be used by tests in order to know when it is safe
317 * to proceed.
318 *
319 * @return true if the time graph view has yet to completely update its
320 * model, false otherwise
321 * @since 2.2
322 */
323 @VisibleForTesting
324 public boolean isDirty() {
325 if (getTrace() == null) {
326 return false;
327 }
328
329 TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext();
330 long startTime = ctx.getWindowRange().getStartTime().toNanos();
331 long endTime = ctx.getWindowRange().getEndTime().toNanos();
332
333 // If the chart viewer hasn't updated all the way to the end of
334 // the window range then it's dirty. A refresh should happen later.
335 return (getWindowStartTime() != startTime || getWindowEndTime() != endTime);
336 }
337
338 // ------------------------------------------------------------------------
339 // Signal Handler
340 // ------------------------------------------------------------------------
341
342 /**
343 * Signal handler for handling of the time synch signal.
344 *
345 * @param signal
346 * The time synch signal {@link TmfSelectionRangeUpdatedSignal}
347 */
348 @Override
349 @TmfSignalHandler
350 public void selectionRangeUpdated(TmfSelectionRangeUpdatedSignal signal) {
351 super.selectionRangeUpdated(signal);
352 if (signal != null && (signal.getSource() != this) && (getTrace() != null)) {
353 if (fMouseSelectionProvider != null) {
354 fMouseSelectionProvider.refresh();
355 }
356 }
357 }
358
359 /**
360 * Signal handler for handling of the window range signal.
361 *
362 * @param signal
363 * The {@link TmfWindowRangeUpdatedSignal}
364 */
365 @Override
366 @TmfSignalHandler
367 public void windowRangeUpdated(TmfWindowRangeUpdatedSignal signal) {
368 super.windowRangeUpdated(signal);
369 updateContent();
370 }
371
372 /**
373 * Signal handler for handling the signal that notifies about an updated
374 * timestamp format.
375 *
376 * @param signal
377 * The trace updated signal
378 * {@link TmfTimestampFormatUpdateSignal}
379 */
380 @TmfSignalHandler
381 public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal) {
382 fSwtChart.getAxisSet().adjustRange();
383 fSwtChart.redraw();
384 }
385
386 // ------------------------------------------------------------------------
387 // Helper Methods
388 // ------------------------------------------------------------------------
389
390 /**
391 * Clears the view content.
392 */
393 protected void clearContent() {
394 if (!fSwtChart.isDisposed()) {
395 ISeriesSet set = fSwtChart.getSeriesSet();
396 ISeries[] series = set.getSeries();
397 for (int i = 0; i < series.length; i++) {
398 set.deleteSeries(series[i].getId());
399 }
400 for (IAxis axis: fSwtChart.getAxisSet().getAxes()){
401 axis.setRange(new Range(0,1));
402 }
403 fSwtChart.redraw();
404 }
405 }
406
407 /**
408 * Returns the current or default display.
409 *
410 * @return the current or default display
411 */
412 protected static Display getDisplay() {
413 Display display = Display.getCurrent();
414 // may be null if outside the UI thread
415 if (display == null) {
416 display = Display.getDefault();
417 }
418 return display;
419 }
420
421 /**
422 * Get the offset of the point area, relative to the XY chart viewer
423 * control. We consider the point area to be from where the first point
424 * could be drawn to where the last point could be drawn.
425 *
426 * @return the offset in pixels
427 *
428 * @since 1.0
429 */
430 public int getPointAreaOffset() {
431
432 int pixelCoordinate = 0;
433 IAxis[] xAxes = getSwtChart().getAxisSet().getXAxes();
434 if (xAxes.length > 0) {
435 IAxis axis = xAxes[0];
436 pixelCoordinate = axis.getPixelCoordinate(axis.getRange().lower);
437 }
438 return getSwtChart().toControl(getSwtChart().getPlotArea().toDisplay(pixelCoordinate, 0)).x;
439 }
440
441 /**
442 * Get the width of the point area. We consider the point area to be from
443 * where the first point could be drawn to where the last point could be
444 * drawn. The point area differs from the plot area because there might be a
445 * gap between where the plot area start and where the fist point is drawn.
446 * This also matches the width that the use can select.
447 *
448 * @return the width in pixels
449 *
450 * @since 1.0
451 */
452 public int getPointAreaWidth() {
453 IAxis[] xAxes = getSwtChart().getAxisSet().getXAxes();
454 if (xAxes.length > 0) {
455 IAxis axis = xAxes[0];
456 int x1 = getPointAreaOffset();
457 int x2 = axis.getPixelCoordinate(axis.getRange().upper);
458 x2 = getSwtChart().toControl(getSwtChart().getPlotArea().toDisplay(x2, 0)).x;
459 int width = x2 - x1;
460 return width;
461 }
462
463 return getSwtChart().getPlotArea().getSize().x;
464 }
465
466 /**
467 * Sets whether or not to send time alignment signals. This should be set to
468 * true for viewers that are part of an aligned view.
469 *
470 * @param sendTimeAlignSignals
471 * whether or not to send time alignment signals
472 * @since 1.0
473 */
474 public void setSendTimeAlignSignals(boolean sendTimeAlignSignals) {
475 fSendTimeAlignSignals = sendTimeAlignSignals;
476 }
477
478 /**
479 * Returns whether or not to send time alignment signals.
480 *
481 * @return whether or not to send time alignment signals.
482 * @since 1.0
483 */
484 public boolean isSendTimeAlignSignals() {
485 return fSendTimeAlignSignals;
486 }
487 }
This page took 0.043121 seconds and 5 git commands to generate.