ctf: improve testing of EventHeaderDeclaration
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.analysis.xml.ui / src / org / eclipse / tracecompass / internal / tmf / analysis / xml / ui / views / xychart / XmlXYViewer.java
CommitLineData
87c5447c
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
2bdf0193 13package org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.views.xychart;
87c5447c
GB
14
15import java.util.Collections;
16import java.util.HashMap;
17import java.util.LinkedList;
18import java.util.List;
19import java.util.Map;
20import java.util.regex.Pattern;
21
22import org.eclipse.core.runtime.IProgressMonitor;
e1c415b3 23import org.eclipse.core.runtime.IStatus;
87c5447c
GB
24import org.eclipse.jdt.annotation.NonNull;
25import org.eclipse.jdt.annotation.Nullable;
87c5447c 26import org.eclipse.swt.widgets.Composite;
2bdf0193
AM
27import org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.Activator;
28import org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.TmfXmlUiStrings;
29import org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.views.XmlViewInfo;
e894a508
AM
30import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
31import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
32import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
33import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
34import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
35import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
2bdf0193
AM
36import org.eclipse.tracecompass.tmf.analysis.xml.core.model.ITmfXmlModelFactory;
37import org.eclipse.tracecompass.tmf.analysis.xml.core.model.ITmfXmlStateAttribute;
38import org.eclipse.tracecompass.tmf.analysis.xml.core.model.TmfXmlLocation;
39import org.eclipse.tracecompass.tmf.analysis.xml.core.model.readonly.TmfXmlReadOnlyModelFactory;
40import org.eclipse.tracecompass.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
41import org.eclipse.tracecompass.tmf.analysis.xml.core.module.XmlUtils;
42import org.eclipse.tracecompass.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
43import org.eclipse.tracecompass.tmf.core.statesystem.ITmfAnalysisModuleWithStateSystems;
44import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
45import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
46import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.linecharts.TmfCommonXLineChartViewer;
87c5447c
GB
47import org.w3c.dom.Element;
48
49/**
50 * Main viewer to display XML-defined xy charts. It uses an XML
51 * {@link TmfXmlUiStrings#XY_VIEW} element from an XML file. This element
52 * defines which entries from the state system will be shown and also gives
53 * additional information on the presentation of the view.
54 *
55 * @author Geneviève Bastien
56 */
57public class XmlXYViewer extends TmfCommonXLineChartViewer {
58
59 private static final String SPLIT_STRING = "/"; //$NON-NLS-1$
aae89862
PT
60 /** Timeout between updates in the updateData thread */
61 private static final long BUILD_UPDATE_TIMEOUT = 500;
87c5447c
GB
62
63 @SuppressWarnings("null")
64 private static final @NonNull Pattern WILDCARD_PATTERN = Pattern.compile("\\*"); //$NON-NLS-1$
65
66 private final ITmfXmlModelFactory fFactory = TmfXmlReadOnlyModelFactory.getInstance();
67 private final Map<Integer, SeriesData> fSeriesData = new HashMap<>();
68
69 private final XmlViewInfo fViewInfo;
70
71 /** XML Model elements to use to create the series */
72 private @Nullable ITmfXmlStateAttribute fDisplay;
73 private @Nullable ITmfXmlStateAttribute fSeriesName;
74 private @Nullable XmlXYEntry fEntry;
75
e2ea8484
GB
76 private enum DisplayType {
77 ABSOLUTE,
78 DELTA
79 }
80
87c5447c
GB
81 /**
82 * The information related to one series on the chart
83 */
84 private class SeriesData {
85
86 private final double[] fYValues;
e2ea8484 87 private final @Nullable double[] fYAbsoluteValues;
87c5447c
GB
88 private final Integer fDisplayQuark;
89 private final String fName;
e2ea8484 90 private final DisplayType fType;
87c5447c 91
e2ea8484 92 public SeriesData(int length, int attributeQuark, String seriesName, DisplayType type) {
87c5447c
GB
93 fYValues = new double[length];
94 fDisplayQuark = attributeQuark;
95 fName = seriesName;
e2ea8484
GB
96 fType = type;
97 switch (fType) {
98 case DELTA:
99 fYAbsoluteValues = new double[length];
100 break;
101 case ABSOLUTE:
102 default:
103 fYAbsoluteValues = null;
104 break;
105 }
106
87c5447c
GB
107 }
108
109 public double[] getYValues() {
110 return fYValues;
111 }
112
113 public Integer getDisplayQuark() {
114 return fDisplayQuark;
115 }
116
117 public String getSeriesName() {
118 return fName;
119 }
120
121 public void setYValue(int i, double yvalue) {
e2ea8484
GB
122 switch (fType) {
123 case DELTA:
124 double[] absoluteVals = fYAbsoluteValues;
125 if (absoluteVals == null) {
126 throw new IllegalStateException();
127 }
128 absoluteVals[i] = yvalue;
129 /*
130 * At the first timestamp, the delta value should be 0 since we
131 * do not have the previous values
132 */
133 double prevValue = yvalue;
134 if (i > 0) {
135 prevValue = absoluteVals[i - 1];
136 }
137 fYValues[i] = yvalue - prevValue;
138 break;
139 case ABSOLUTE:
140 default:
141 fYValues[i] = yvalue;
142 break;
143 }
144
87c5447c
GB
145 }
146 }
147
e2ea8484 148 private static class XmlXYEntry implements IXmlStateSystemContainer {
87c5447c
GB
149
150 private final ITmfStateSystem fStateSystem;
151 private final String fPath;
e2ea8484 152 private final DisplayType fType;
87c5447c 153
e2ea8484 154 public XmlXYEntry(ITmfStateSystem stateSystem, String path, Element entryElement) {
87c5447c
GB
155 fStateSystem = stateSystem;
156 fPath = path;
e2ea8484
GB
157 switch (entryElement.getAttribute(TmfXmlUiStrings.DISPLAY_TYPE)) {
158 case TmfXmlUiStrings.DISPLAY_TYPE_DELTA:
159 fType = DisplayType.DELTA;
160 break;
161 case TmfXmlUiStrings.DISPLAY_TYPE_ABSOLUTE:
162 default:
163 fType = DisplayType.ABSOLUTE;
164 break;
165 }
87c5447c
GB
166 }
167
168 @Override
169 public @Nullable String getAttributeValue(@Nullable String name) {
170 return name;
171 }
172
173 @Override
174 public ITmfStateSystem getStateSystem() {
175 return fStateSystem;
176 }
177
178 @Override
179 public @Nullable Iterable<TmfXmlLocation> getLocations() {
180 return Collections.EMPTY_SET;
181 }
182
e2ea8484
GB
183 public DisplayType getType() {
184 return fType;
185 }
186
87c5447c
GB
187 public List<Integer> getQuarks() {
188 /* Get the list of quarks to process with this path */
189 String[] paths = fPath.split(SPLIT_STRING);
190 @SuppressWarnings("null")
191 @NonNull List<Integer> quarks = Collections.singletonList(IXmlStateSystemContainer.ROOT_QUARK);
192
193 try {
194 for (String path : paths) {
195 List<Integer> subQuarks = new LinkedList<>();
196 /* Replace * by .* to have a regex string */
197 String name = WILDCARD_PATTERN.matcher(path).replaceAll(".*"); //$NON-NLS-1$
198 for (int relativeQuark : quarks) {
199 subQuarks.addAll(fStateSystem.getSubAttributes(relativeQuark, false, name));
200 }
201 quarks = subQuarks;
202 }
203 } catch (AttributeNotFoundException e) {
204 /*
205 * We get all attributes from the state system itself, this
206 * should not happen.
207 */
208 throw new IllegalStateException();
209 }
210 return quarks;
211 }
212 }
213
214 /**
215 * Constructor
216 *
217 * @param parent
218 * parent view
219 * @param viewInfo
220 * The view info object
221 */
222 public XmlXYViewer(@Nullable Composite parent, XmlViewInfo viewInfo) {
223 super(parent, Messages.XmlXYViewer_DefaultViewerTitle, Messages.XmlXYViewer_DefaultXAxis, Messages.XmlXYViewer_DefaultYAxis);
224 fViewInfo = viewInfo;
225 }
226
227 @Override
228 protected void updateData(long start, long end, int nb, @Nullable IProgressMonitor monitor) {
229
230 ITmfXmlStateAttribute display = fDisplay;
231 ITmfXmlStateAttribute seriesNameAttrib = fSeriesName;
232 XmlXYEntry entry = fEntry;
233 if (getTrace() == null || display == null || entry == null) {
234 return;
235 }
236 ITmfStateSystem ss = entry.getStateSystem();
237
238 double[] xvalues = getXAxis(start, end, nb);
239 setXAxis(xvalues);
240
241 boolean complete = false;
242 long currentEnd = start;
243
244 while (!complete && currentEnd < end) {
245 if (monitor != null && monitor.isCanceled()) {
246 return;
247 }
248
aae89862 249 complete = ss.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
87c5447c
GB
250 currentEnd = ss.getCurrentEndTime();
251 try {
252 List<Integer> quarks = entry.getQuarks();
253 long traceStart = getStartTime();
254 long traceEnd = getEndTime();
255 long offset = this.getTimeOffset();
256
257 /* Initialize quarks and series names */
258 for (int quark : quarks) {
259 String seriesName = null;
260 if (seriesNameAttrib == null) {
261 seriesName = ss.getAttributeName(quark);
262 } else {
263 int seriesNameQuark = seriesNameAttrib.getAttributeQuark(quark);
264 try {
265 ITmfStateValue seriesNameValue = ss.querySingleState(start, seriesNameQuark).getStateValue();
266 if (!seriesNameValue.isNull()) {
e2ea8484 267 seriesName = seriesNameValue.toString();
87c5447c
GB
268 }
269 if (seriesName == null || seriesName.isEmpty()) {
270 seriesName = ss.getAttributeName(quark);
271 }
272 } catch (TimeRangeException e) {
273 /*
274 * The attribute did not exist at this point, simply
275 * use attribute name as series name
276 */
277 seriesName = ss.getAttributeName(quark);
278 }
279 }
280 if (seriesName == null) {
281 throw new IllegalStateException();
282 }
e2ea8484 283 fSeriesData.put(quark, new SeriesData(xvalues.length, display.getAttributeQuark(quark), seriesName, entry.getType()));
87c5447c
GB
284 }
285 double yvalue = 0.0;
286 for (int i = 0; i < xvalues.length; i++) {
287 if (monitor != null && monitor.isCanceled()) {
288 return;
289 }
290 double x = xvalues[i];
291 long time = (long) x + offset;
292 // make sure that time is in the trace range after double to
293 // long conversion
294 time = time < traceStart ? traceStart : time;
295 time = time > traceEnd ? traceEnd : time;
296
297 for (int quark : quarks) {
298 try {
299 yvalue = ss.querySingleState(time, fSeriesData.get(quark).getDisplayQuark()).getStateValue().unboxLong();
300 fSeriesData.get(quark).setYValue(i, yvalue);
301 } catch (TimeRangeException e) {
302 fSeriesData.get(quark).setYValue(i, 0);
303 }
304 }
305 }
306 for (int quark : quarks) {
307 setSeries(fSeriesData.get(quark).getSeriesName(), fSeriesData.get(quark).getYValues());
308 }
309 updateDisplay();
310 } catch (AttributeNotFoundException | StateValueTypeException e) {
311 Activator.logError("Error updating the data of XML XY view", e); //$NON-NLS-1$
312 } catch (StateSystemDisposedException e) {
313 return;
314 }
315 }
316
317 }
318
319 @Override
320 protected void initializeDataSource() {
321 super.initializeDataSource();
322
323 ITmfTrace trace = this.getTrace();
324 if (trace == null) {
325 return;
326 }
327
328 Element viewElement = fViewInfo.getViewElement(TmfXmlUiStrings.XY_VIEW);
329 if (viewElement == null) {
330 return;
331 }
332
333 Iterable<String> analysisIds = fViewInfo.getViewAnalysisIds(viewElement);
334
335 List<ITmfAnalysisModuleWithStateSystems> stateSystemModules = new LinkedList<>();
336 if (!analysisIds.iterator().hasNext()) {
337 /*
338 * No analysis specified, take all state system analysis modules
339 */
340 for (ITmfAnalysisModuleWithStateSystems module : trace.getAnalysisModulesOfClass(ITmfAnalysisModuleWithStateSystems.class)) {
341 stateSystemModules.add(module);
342 }
343 } else {
344 for (String moduleId : analysisIds) {
87c5447c
GB
345 ITmfAnalysisModuleWithStateSystems module = trace.getAnalysisModuleOfClass(ITmfAnalysisModuleWithStateSystems.class, moduleId);
346 if (module != null) {
347 stateSystemModules.add(module);
348 }
349 }
350 }
351
352 /** Initialize the data */
353 fDisplay = null;
354 fSeriesName = null;
355 ITmfStateSystem ss = null;
356 fEntry = null;
357
358 /* Schedule all state systems */
359 for (ITmfAnalysisModuleWithStateSystems module : stateSystemModules) {
e1c415b3
BH
360 IStatus status = module.schedule();
361 if (!status.isOK()) {
362 return;
363 }
87c5447c
GB
364 if (module instanceof TmfStateSystemAnalysisModule) {
365 ((TmfStateSystemAnalysisModule) module).waitForInitialization();
366 }
367 for (ITmfStateSystem ssq : module.getStateSystems()) {
368 if (ssq != null) {
369 ss = ssq;
370 break;
371 }
372 }
373 }
374 if (ss == null) {
375 return;
376 }
377
378 /*
379 * Initialize state attributes. There should be only one entry element
380 * for XY charts.
381 */
382 List<Element> entries = XmlUtils.getChildElements(viewElement, TmfXmlUiStrings.ENTRY_ELEMENT);
383 Element entryElement = entries.get(0);
384 String path = entryElement.getAttribute(TmfXmlUiStrings.PATH);
385 if (path.isEmpty()) {
386 path = TmfXmlStrings.WILDCARD;
387 }
e2ea8484 388 XmlXYEntry entry = new XmlXYEntry(ss, path, entryElement);
87c5447c
GB
389 fEntry = entry;
390
391 /* Get the display element to use */
392 List<Element> displayElements = XmlUtils.getChildElements(entryElement, TmfXmlUiStrings.DISPLAY_ELEMENT);
393 if (displayElements.isEmpty()) {
394 Activator.logWarning(String.format("XML view: entry for %s should have a display element", path)); //$NON-NLS-1$
395 return;
396 }
397 Element displayElement = displayElements.get(0);
398 fDisplay = fFactory.createStateAttribute(displayElement, entry);
399
400 /* Get the series name element to use */
401 List<Element> seriesNameElements = XmlUtils.getChildElements(entryElement, TmfXmlUiStrings.NAME_ELEMENT);
402 if (!seriesNameElements.isEmpty()) {
403 Element seriesNameElement = seriesNameElements.get(0);
404 fSeriesName = fFactory.createStateAttribute(seriesNameElement, entry);
405 }
406
407 }
408
409 /**
410 * Tells the viewer that the view info has been updated and the viewer needs
411 * to be reinitialized
412 */
413 public void viewInfoUpdated() {
414 reinitialize();
415 }
416
417}
This page took 0.073908 seconds and 5 git commands to generate.