tmf.xml: Move all .core and .ui packages to internal
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.analysis.xml.ui / src / org / eclipse / tracecompass / internal / tmf / analysis / xml / ui / views / xychart / XmlXYViewer.java
1 /*******************************************************************************
2 * Copyright (c) 2014, 2015 École Polytechnique de Montréal and others.
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
13 package org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.views.xychart;
14
15 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.LinkedList;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.regex.Pattern;
23
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.core.runtime.IStatus;
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.eclipse.swt.widgets.Composite;
29 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.ITmfXmlModelFactory;
30 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.ITmfXmlStateAttribute;
31 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.TmfXmlLocation;
32 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.model.readonly.TmfXmlReadOnlyModelFactory;
33 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
34 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.module.XmlUtils;
35 import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
36 import org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.Activator;
37 import org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.TmfXmlUiStrings;
38 import org.eclipse.tracecompass.internal.tmf.analysis.xml.ui.views.XmlViewInfo;
39 import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
40 import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
41 import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
42 import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
43 import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
44 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
45 import org.eclipse.tracecompass.tmf.core.statesystem.ITmfAnalysisModuleWithStateSystems;
46 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
47 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
48 import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.linecharts.TmfCommonXLineChartViewer;
49 import org.w3c.dom.Element;
50
51 /**
52 * Main viewer to display XML-defined xy charts. It uses an XML
53 * {@link TmfXmlUiStrings#XY_VIEW} element from an XML file. This element
54 * defines which entries from the state system will be shown and also gives
55 * additional information on the presentation of the view.
56 *
57 * @author Geneviève Bastien
58 */
59 public class XmlXYViewer extends TmfCommonXLineChartViewer {
60
61 private static final String SPLIT_STRING = "/"; //$NON-NLS-1$
62 /** Timeout between updates in the updateData thread */
63 private static final long BUILD_UPDATE_TIMEOUT = 500;
64
65 private static final 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
77 private enum DisplayType {
78 ABSOLUTE,
79 DELTA
80 }
81
82 /**
83 * The information related to one series on the chart
84 */
85 private class SeriesData {
86
87 private final double[] fYValues;
88 private final double @Nullable [] fYAbsoluteValues;
89 private final Integer fDisplayQuark;
90 private final String fName;
91 private final DisplayType fType;
92
93 public SeriesData(int length, int attributeQuark, String seriesName, DisplayType type) {
94 fYValues = new double[length];
95 fDisplayQuark = attributeQuark;
96 fName = seriesName;
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
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) {
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
146 }
147 }
148
149 private static class XmlXYEntry implements IXmlStateSystemContainer {
150
151 private final ITmfStateSystem fStateSystem;
152 private final String fPath;
153 private final DisplayType fType;
154
155 public XmlXYEntry(ITmfStateSystem stateSystem, String path, Element entryElement) {
156 fStateSystem = stateSystem;
157 fPath = path;
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 }
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 @NonNull Iterable<@NonNull TmfXmlLocation> getLocations() {
181 return Collections.EMPTY_SET;
182 }
183
184 public DisplayType getType() {
185 return fType;
186 }
187
188 public List<Integer> getQuarks() {
189 /* Get the list of quarks to process with this path */
190 String[] paths = fPath.split(SPLIT_STRING);
191 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
249 complete = ss.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
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, null);
264 try {
265 ITmfStateValue seriesNameValue = ss.querySingleState(start, seriesNameQuark).getStateValue();
266 if (!seriesNameValue.isNull()) {
267 seriesName = seriesNameValue.toString();
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 fSeriesData.put(quark, new SeriesData(xvalues.length, display.getAttributeQuark(quark, null), seriesName, entry.getType()));
281 }
282 for (int i = 0; i < xvalues.length; i++) {
283 if (monitor != null && monitor.isCanceled()) {
284 return;
285 }
286 double x = xvalues[i];
287 long time = (long) x + offset;
288 // make sure that time is in the trace range after double to
289 // long conversion
290 time = time < traceStart ? traceStart : time;
291 time = time > traceEnd ? traceEnd : time;
292
293 for (int quark : quarks) {
294 double yvalue = 0.0;
295 SeriesData data = checkNotNull(fSeriesData.get(quark));
296 try {
297 ITmfStateValue value = ss.querySingleState(time, data.getDisplayQuark()).getStateValue();
298 switch (value.getType()) {
299 case DOUBLE:
300 yvalue = value.unboxDouble();
301 break;
302 case LONG:
303 yvalue = value.unboxLong();
304 break;
305 case INTEGER:
306 yvalue = value.unboxInt();
307 break;
308 case NULL:
309 case STRING:
310 default:
311 break;
312 }
313 data.setYValue(i, yvalue);
314 } catch (TimeRangeException e) {
315 data.setYValue(i, 0);
316 }
317 }
318 }
319 for (int quark : quarks) {
320 SeriesData data = checkNotNull(fSeriesData.get(quark));
321 setSeries(data.getSeriesName(), data.getYValues());
322 }
323 updateDisplay();
324 } catch (AttributeNotFoundException | StateValueTypeException e) {
325 Activator.logError("Error updating the data of XML XY view", e); //$NON-NLS-1$
326 } catch (StateSystemDisposedException e) {
327 return;
328 }
329 }
330
331 }
332
333 @Override
334 protected void initializeDataSource() {
335 super.initializeDataSource();
336
337 ITmfTrace trace = this.getTrace();
338 if (trace == null) {
339 return;
340 }
341
342 Element viewElement = fViewInfo.getViewElement(TmfXmlUiStrings.XY_VIEW);
343 if (viewElement == null) {
344 return;
345 }
346
347 Iterable<String> analysisIds = fViewInfo.getViewAnalysisIds(viewElement);
348
349 List<ITmfAnalysisModuleWithStateSystems> stateSystemModules = new LinkedList<>();
350 if (!analysisIds.iterator().hasNext()) {
351 /*
352 * No analysis specified, take all state system analysis modules
353 */
354 for (ITmfAnalysisModuleWithStateSystems module : TmfTraceUtils.getAnalysisModulesOfClass(trace, ITmfAnalysisModuleWithStateSystems.class)) {
355 stateSystemModules.add(module);
356 }
357 } else {
358 for (String moduleId : analysisIds) {
359 ITmfAnalysisModuleWithStateSystems module = TmfTraceUtils.getAnalysisModuleOfClass(trace, ITmfAnalysisModuleWithStateSystems.class, moduleId);
360 if (module != null) {
361 stateSystemModules.add(module);
362 }
363 }
364 }
365
366 /** Initialize the data */
367 fDisplay = null;
368 fSeriesName = null;
369 ITmfStateSystem ss = null;
370 fEntry = null;
371
372 /* Schedule all state systems */
373 for (ITmfAnalysisModuleWithStateSystems module : stateSystemModules) {
374 IStatus status = module.schedule();
375 if (!status.isOK()) {
376 return;
377 }
378 if (!module.waitForInitialization()) {
379 return;
380 }
381 for (ITmfStateSystem ssq : module.getStateSystems()) {
382 ss = ssq;
383 break;
384 }
385 }
386 if (ss == null) {
387 return;
388 }
389
390 /*
391 * Initialize state attributes. There should be only one entry element
392 * for XY charts.
393 */
394 List<Element> entries = XmlUtils.getChildElements(viewElement, TmfXmlUiStrings.ENTRY_ELEMENT);
395 Element entryElement = entries.get(0);
396 String path = entryElement.getAttribute(TmfXmlUiStrings.PATH);
397 if (path.isEmpty()) {
398 path = TmfXmlStrings.WILDCARD;
399 }
400 XmlXYEntry entry = new XmlXYEntry(ss, path, entryElement);
401 fEntry = entry;
402
403 /* Get the display element to use */
404 List<@NonNull Element> displayElements = XmlUtils.getChildElements(entryElement, TmfXmlUiStrings.DISPLAY_ELEMENT);
405 if (displayElements.isEmpty()) {
406 Activator.logWarning(String.format("XML view: entry for %s should have a display element", path)); //$NON-NLS-1$
407 return;
408 }
409 Element displayElement = displayElements.get(0);
410 fDisplay = fFactory.createStateAttribute(displayElement, entry);
411
412 /* Get the series name element to use */
413 List<Element> seriesNameElements = XmlUtils.getChildElements(entryElement, TmfXmlUiStrings.NAME_ELEMENT);
414 if (!seriesNameElements.isEmpty()) {
415 Element seriesNameElement = seriesNameElements.get(0);
416 fSeriesName = fFactory.createStateAttribute(seriesNameElement, entry);
417 }
418
419 }
420
421 /**
422 * Tells the viewer that the view info has been updated and the viewer needs
423 * to be reinitialized
424 */
425 public void viewInfoUpdated() {
426 reinitialize();
427 }
428
429 }
This page took 0.045619 seconds and 6 git commands to generate.