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