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