<tmfxml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="xmlDefinition.xsd">
- <stateSystemView id="org.eclipse.linuxtools.tmf.analysis.xml.ui.views.statesystem">
+ <timeGraphView id="org.eclipse.linuxtools.tmf.analysis.xml.ui.views.statesystem">
<head>
<analysis id="kernel.linux.sp" />
<label value="Xml Sample Kernel View" />
<name type="constant" value="Exec_name" />
</entry>
</entry>
- </stateSystemView>
+ </timeGraphView>
<stateProvider id="kernel.linux.sp" version="1">
<head>
<xs:include schemaLocation="xmlCommon.xsd" />
<xs:include schemaLocation="xmlStateProvider.xsd" />
- <xs:include schemaLocation="xmlStateSystemView.xsd" />
+ <xs:include schemaLocation="xmlTimeGraphView.xsd" />
<xs:element name="tmfxml">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
- <xs:element maxOccurs="unbounded" minOccurs="0" name="stateSystemView" type="stateSystemView" />
+ <xs:element maxOccurs="unbounded" minOccurs="0" name="timeGraphView" type="timeGraphView" />
<xs:element maxOccurs="unbounded" minOccurs="0" name="stateProvider" type="stateProvider" />
</xs:choice>
</xs:complexType>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- ***************************************************************************
- * Copyright (c) 2014 École Polytechnique de Montréal
- *
- * All rights reserved. This program and the accompanying materials are
- * made available under the terms of the Eclipse Public License v1.0 which
- * accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Florian Wininger - Initial API and implementation
- *************************************************************************** -->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
- attributeFormDefault="unqualified" elementFormDefault="qualified">
-
- <xs:complexType name="stateSystemView">
- <xs:sequence>
- <xs:element maxOccurs="1" minOccurs="0" name="head" type="headOutput" />
- <xs:element maxOccurs="unbounded" minOccurs="0" name="definedValue" type="definedValue" />
- <xs:element maxOccurs="unbounded" minOccurs="0" name="entry" type="viewEntry" />
- </xs:sequence>
- <xs:attribute name="id" type="xs:string" use="required" />
- </xs:complexType>
-
- <xs:complexType name="headOutput">
- <xs:sequence>
- <xs:element maxOccurs="unbounded" minOccurs="0" name="analysis">
- <xs:complexType>
- <xs:attribute name="id" type="xs:string" use="required" />
- <xs:attribute name="ssid" type="xs:string" use="optional" />
- </xs:complexType>
- </xs:element>
- <xs:element maxOccurs="1" minOccurs="0" name="label">
- <xs:complexType>
- <xs:attribute name="value" use="required" />
- </xs:complexType>
- </xs:element>
- </xs:sequence>
- </xs:complexType>
-
- <xs:complexType name="viewEntry">
- <xs:sequence>
- <xs:element maxOccurs="1" minOccurs="0" name="display" type="viewStateAttribute" />
- <xs:element maxOccurs="1" minOccurs="0" name="id" type="viewStateAttribute" />
- <xs:element maxOccurs="1" minOccurs="0" name="parent" type="viewStateAttribute" />
- <xs:element maxOccurs="1" minOccurs="0" name="name" type="viewStateAttribute" />
- <xs:element maxOccurs="unbounded" minOccurs="0" name="entry" type="viewEntry" />
- </xs:sequence>
- <xs:attribute name="path" type="xs:string" use="required" />
- </xs:complexType>
-
- <xs:complexType name="viewStateAttribute">
- <xs:sequence>
- <xs:element maxOccurs="unbounded" minOccurs="0" name="stateAttribute" type="stateAttribute" />
- </xs:sequence>
- <xs:attribute name="type" use="required">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:enumeration value="constant" />
- <xs:enumeration value="location" />
- <xs:enumeration value="query" />
- <xs:enumeration value="self" />
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- <xs:attribute name="value" type="xs:string" />
- <xs:attribute name="reference" use="optional" default="relative">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:enumeration value="relative" />
- <xs:enumeration value="absolute" />
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
-</xs:schema>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- ***************************************************************************
+ * Copyright (c) 2014 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Florian Wininger - Initial API and implementation
+ *************************************************************************** -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ attributeFormDefault="unqualified" elementFormDefault="qualified">
+
+ <xs:complexType name="timeGraphView">
+ <xs:sequence>
+ <xs:element maxOccurs="1" minOccurs="0" name="head" type="headOutput" />
+ <xs:element maxOccurs="unbounded" minOccurs="0" name="definedValue" type="definedValue" />
+ <xs:element maxOccurs="unbounded" minOccurs="0" name="entry" type="viewEntry" />
+ </xs:sequence>
+ <xs:attribute name="id" type="xs:string" use="required" />
+ </xs:complexType>
+
+ <xs:complexType name="headOutput">
+ <xs:sequence>
+ <xs:element maxOccurs="unbounded" minOccurs="0" name="analysis">
+ <xs:complexType>
+ <xs:attribute name="id" type="xs:string" use="required" />
+ <xs:attribute name="ssid" type="xs:string" use="optional" />
+ </xs:complexType>
+ </xs:element>
+ <xs:element maxOccurs="1" minOccurs="0" name="label">
+ <xs:complexType>
+ <xs:attribute name="value" use="required" />
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="viewEntry">
+ <xs:sequence>
+ <xs:element maxOccurs="1" minOccurs="0" name="display" type="viewStateAttribute" />
+ <xs:element maxOccurs="1" minOccurs="0" name="id" type="viewStateAttribute" />
+ <xs:element maxOccurs="1" minOccurs="0" name="parent" type="viewStateAttribute" />
+ <xs:element maxOccurs="1" minOccurs="0" name="name" type="viewStateAttribute" />
+ <xs:element maxOccurs="unbounded" minOccurs="0" name="entry" type="viewEntry" />
+ </xs:sequence>
+ <xs:attribute name="path" type="xs:string" use="required" />
+ </xs:complexType>
+
+ <xs:complexType name="viewStateAttribute">
+ <xs:sequence>
+ <xs:element maxOccurs="unbounded" minOccurs="0" name="stateAttribute" type="stateAttribute" />
+ </xs:sequence>
+ <xs:attribute name="type" use="required">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="constant" />
+ <xs:enumeration value="location" />
+ <xs:enumeration value="query" />
+ <xs:enumeration value="self" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="value" type="xs:string" />
+ <xs:attribute name="reference" use="optional" default="relative">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="relative" />
+ <xs:enumeration value="absolute" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+</xs:schema>
\ No newline at end of file
static final String TRACETYPE = "traceType";
static final String ID = "id";
static final String LABEL = "label";
+ static final String ANALYSIS = "analysis";
/* XML String */
static final String NULL = "";
static final String WILDCARD = "*";
static final String VARIABLE_PREFIX = "$";
+ static final String COLOR = "color";
+ static final String COLOR_PREFIX = "#";
/* XML Element Name */
static final String STATE_PROVIDER = "stateProvider";
org.eclipse.linuxtools.tmf.analysis.xml.core
Export-Package: org.eclipse.linuxtools.internal.tmf.analysis.xml.ui;x-friends:="org.eclipse.linuxtools.tmf.analysis.xml.ui.tests",
org.eclipse.linuxtools.internal.tmf.analysis.xml.ui.handler;x-internal:=true,
- org.eclipse.linuxtools.tmf.analysis.xml.ui.module
+ org.eclipse.linuxtools.tmf.analysis.xml.ui.module,
+ org.eclipse.linuxtools.tmf.analysis.xml.ui.views.timegraph
command.xml.import = Import XML analysis
command.xml.import.mnemonic = I
command.xml.import.description = Import an XML file containing analysis information
+
+xmltimegraph.view.name = XML Time Graph View
</activeWhen>
</handler>
</extension>
+ <extension
+ point="org.eclipse.ui.views">
+ <view
+ allowMultiple="false"
+ category="org.eclipse.linuxtools.lttng2.ui.views.category"
+ class="org.eclipse.linuxtools.tmf.analysis.xml.ui.views.timegraph.XmlTimeGraphView"
+ id="org.eclipse.linuxtools.tmf.analysis.xml.ui.views.timegraph"
+ name="%xmltimegraph.view.name"
+ restorable="true">
+ </view>
+ </extension>
</plugin>
public interface TmfXmlUiStrings {
/* XML generic Element attribute names */
- static final String STATE_PROVIDER_VIEW = "stateSystemView";
+ static final String TIME_GRAPH_VIEW = "timeGraphView";
/* View elements and attributes */
- static final String SSV_LINE = "line";
static final String ENTRY_ELEMENT = "entry";
/* Elements and attributes of view entries */
import java.io.File;
import java.io.IOException;
+import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.eclipse.core.runtime.IPath;
import org.eclipse.linuxtools.internal.tmf.analysis.xml.ui.Activator;
+import org.eclipse.linuxtools.internal.tmf.analysis.xml.ui.TmfXmlUiStrings;
import org.eclipse.linuxtools.tmf.analysis.xml.core.module.XmlUtils;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.eclipse.linuxtools.tmf.analysis.xml.ui.views.timegraph.XmlTimeGraphView;
import org.eclipse.linuxtools.tmf.core.analysis.IAnalysisModule;
+import org.eclipse.linuxtools.tmf.core.analysis.IAnalysisOutput;
import org.eclipse.linuxtools.tmf.core.analysis.ITmfNewAnalysisModuleListener;
+import org.eclipse.linuxtools.tmf.core.statesystem.TmfStateSystemAnalysisModule;
import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
doc.getDocumentElement().normalize();
/* get state provider views if the analysis has state systems */
- /* TODO: Code here will come in later patch */
+ if (module instanceof TmfStateSystemAnalysisModule) {
+ NodeList ssViewNodes = doc.getElementsByTagName(TmfXmlUiStrings.TIME_GRAPH_VIEW);
+ for (int i = 0; i < ssViewNodes.getLength(); i++) {
+ Element node = (Element) ssViewNodes.item(i);
+ /* Check if analysis is the right one */
+ List<Element> headNodes = XmlUtils.getChildElements(node, TmfXmlStrings.HEAD);
+ if (headNodes.size() != 1) {
+ continue;
+ }
+
+ List<Element> analysisNodes = XmlUtils.getChildElements(headNodes.get(0), TmfXmlStrings.ANALYSIS);
+ for (Element analysis : analysisNodes) {
+ String analysisId = analysis.getAttribute(TmfXmlStrings.ID);
+ if (analysisId.equals(module.getId())) {
+ IAnalysisOutput output = new TmfXmlViewOutput(XmlTimeGraphView.ID);
+ output.setOutputProperty(TmfXmlUiStrings.XML_OUTPUT_DATA, node.getAttribute(TmfXmlStrings.ID) + DATA_SEPARATOR + xmlFile.getAbsolutePath(), false);
+ module.registerOutput(output);
+ }
+ }
+ }
+ }
} catch (ParserConfigurationException | SAXException | IOException e) {
Activator.logError("Error opening XML file", e); //$NON-NLS-1$
}
if ((viewId == null) || (filePath == null)) {
return;
}
- Element viewElement = XmlUtils.getElementInFile(filePath, TmfXmlUiStrings.STATE_PROVIDER_VIEW, viewId);
+ Element viewElement = XmlUtils.getElementInFile(filePath, TmfXmlUiStrings.TIME_GRAPH_VIEW, viewId);
if (viewElement == null) {
return;
}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.analysis.xml.ui.views.timegraph;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Message for the XML state system view
+ *
+ * @author Geneviève Bastien
+ */
+@SuppressWarnings("javadoc")
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.linuxtools.tmf.analysis.xml.ui.views.timegraph.messages"; //$NON-NLS-1$
+
+ public static String XmlPresentationProvider_MultipleStates;
+
+ /* Default text messages */
+ public static String XmlTimeGraphView_ColumnId;
+ public static String XmlTimeGraphView_ColumnName;
+ public static String XmlTimeGraphView_ColumnParentId;
+ public static String XmlTimeGraphView_DefaultTitle;
+
+ /* Text and tooltips of the view */
+ public static String XmlTimeGraphView_NextText;
+ public static String XmlTimeGraphView_NextTooltip;
+ public static String XmlTimeGraphView_PreviousInterval;
+ public static String XmlTimeGraphView_PreviousText;
+
+ /* Errors and warnings messages */
+ public static String XmlTimeGraphView_UselessEndPath;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Florian Wininger - Initial API and implementation
+ * Geneviève Bastien - Review of the initial implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.analysis.xml.ui.views.timegraph;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.linuxtools.internal.tmf.analysis.xml.ui.TmfXmlUiStrings;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.model.ITmfXmlModelFactory;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.model.ITmfXmlStateAttribute;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.model.TmfXmlLocation;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.model.readonly.TmfXmlReadOnlyModelFactory;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.module.XmlUtils;
+import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
+import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
+import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
+import org.w3c.dom.Element;
+
+/**
+ * An XML-defined entry, or row, to display in the XML state system view
+ *
+ * @author Florian Wininger
+ */
+public class XmlEntry extends TimeGraphEntry implements IXmlStateSystemContainer {
+
+ private static final String EMPTY_STRING = ""; //$NON-NLS-1$
+
+ /** Type of resource */
+ public static enum EntryDisplayType {
+ /** Entries without events to display (filler rows, etc.) */
+ NULL,
+ /** Entries with time events */
+ DISPLAY
+ }
+
+ private final ITmfTrace fTrace;
+ private final EntryDisplayType fType;
+ private final int fBaseQuark;
+ private final int fDisplayQuark;
+ private final String fParentId;
+ private final String fId;
+ private final @NonNull ITmfStateSystem fSs;
+ private final Element fElement;
+
+ /**
+ * Constructor
+ *
+ * @param baseQuark
+ * The quark matching this entry, or <code>-1</code> if no quark
+ * @param displayQuark
+ * The quark containing the value to display. It was needed by
+ * the caller to get the start and end time of this entry, so we
+ * receive it as parameter from him.
+ * @param trace
+ * The trace on which we are working (FIXME: is this parameter
+ * useful?)
+ * @param name
+ * The name of this entry. It will be overridden if a "name" XML
+ * tag is specified in the entryElement. It will also be used as
+ * the ID of this entry if no "id" XML tag is specified. It
+ * typically is the attribute name corresponding the the base
+ * quark.
+ * @param startTime
+ * The start time of this entry lifetime
+ * @param endTime
+ * The end time of this entry
+ * @param type
+ * The display type of this entry
+ * @param ss
+ * The state system this entry belongs to
+ * @param entryElement
+ * The XML element describing this entry. This element will be
+ * used to determine, if available, the parent, ID, name and
+ * other display option of this entry
+ */
+ public XmlEntry(int baseQuark, int displayQuark, ITmfTrace trace, String name, long startTime, long endTime, EntryDisplayType type, @NonNull ITmfStateSystem ss, Element entryElement) {
+ super(name, startTime, endTime);
+ fTrace = trace;
+ fType = type;
+ fBaseQuark = baseQuark;
+ fDisplayQuark = displayQuark;
+ fSs = ss;
+ fElement = entryElement;
+
+ /* Get the parent if specified */
+ List<Element> elements = XmlUtils.getChildElements(fElement, TmfXmlUiStrings.PARENT_ELEMENT);
+ if (elements.size() > 0) {
+ fParentId = getFirstValue(elements.get(0));
+ } else {
+ fParentId = EMPTY_STRING;
+ }
+
+ /* Get the name of this entry */
+ elements = XmlUtils.getChildElements(fElement, TmfXmlUiStrings.NAME_ELEMENT);
+ if (elements.size() > 0) {
+ String nameFromSs = getFirstValue(elements.get(0));
+ if (!nameFromSs.isEmpty()) {
+ setName(nameFromSs);
+ }
+ }
+
+ /* Get the id of this entry */
+ elements = XmlUtils.getChildElements(fElement, TmfXmlUiStrings.ID_ELEMENT);
+ if (elements.size() > 0) {
+ fId = getFirstValue(elements.get(0));
+ } else {
+ fId = name;
+ }
+
+ }
+
+ /**
+ * Constructor
+ *
+ * @param baseQuark
+ * The quark matching this entry, or <code>-1</code> if no quark
+ * @param trace
+ * The trace on which we are working
+ * @param name
+ * The exec_name of this entry
+ * @param ss
+ * The state system this entry belongs to
+ */
+ public XmlEntry(int baseQuark, ITmfTrace trace, String name, @NonNull ITmfStateSystem ss) {
+ super(name, ss.getStartTime(), ss.getCurrentEndTime());
+ fTrace = trace;
+ fType = EntryDisplayType.NULL;
+ fBaseQuark = baseQuark;
+ fDisplayQuark = baseQuark;
+ fSs = ss;
+ fElement = null;
+ fParentId = EMPTY_STRING;
+ fId = name;
+ }
+
+ /** Return the state value of the first interval with a non-null value */
+ private String getFirstValue(Element stateAttribute) {
+ ITmfXmlModelFactory factory = TmfXmlReadOnlyModelFactory.getInstance();
+ ITmfXmlStateAttribute display = factory.createStateAttribute(stateAttribute, this);
+ int quark = display.getAttributeQuark(fBaseQuark);
+ if (quark != IXmlStateSystemContainer.ERROR_QUARK) {
+ try {
+ /* Find the first attribute with a parent */
+ List<ITmfStateInterval> execNameIntervals = fSs.queryHistoryRange(quark, getStartTime(), getEndTime());
+ for (ITmfStateInterval execNameInterval : execNameIntervals) {
+
+ if (!execNameInterval.getStateValue().isNull()) {
+ return execNameInterval.getStateValue().toString();
+ }
+ }
+ } catch (AttributeNotFoundException | StateSystemDisposedException e) {
+ }
+ }
+ return EMPTY_STRING;
+ }
+
+ /**
+ * Get the trace this entry was taken from
+ *
+ * @return the entry's trace
+ */
+ public ITmfTrace getTrace() {
+ return fTrace;
+ }
+
+ /**
+ * Get the entry Type of this entry. Uses the inner EntryDisplayType enum.
+ *
+ * @return The entry type
+ */
+ public EntryDisplayType getType() {
+ return fType;
+ }
+
+ /**
+ * Get the quark from which to get the time event intervals for this entry.
+ *
+ * @return The attribute quark containing the intervals to display
+ */
+ public int getDisplayQuark() {
+ return fDisplayQuark;
+ }
+
+ /**
+ * Get this entry's ID
+ *
+ * @return The id of the entry.
+ */
+ public String getId() {
+ return fId;
+ }
+
+ /**
+ * Return the entry's parent ID. It corresponds to another entry's ID
+ * received from the {@link #getId()} method.
+ *
+ * @return The parent ID of this entry
+ */
+ public String getParentId() {
+ return fParentId;
+ }
+
+ @Override
+ public boolean hasTimeEvents() {
+ if (fType == EntryDisplayType.NULL) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Add a child to this entry of type XmlEntry
+ *
+ * @param entry
+ * The entry to add
+ */
+ public void addChild(XmlEntry entry) {
+ int index;
+ for (index = 0; index < getChildren().size(); index++) {
+ XmlEntry other = (XmlEntry) getChildren().get(index);
+ if (entry.getType().compareTo(other.getType()) < 0) {
+ break;
+ } else if (entry.getType().equals(other.getType())) {
+ if (entry.getName().compareTo(other.getName()) < 0) {
+ break;
+ }
+ }
+ }
+
+ entry.setParent(this);
+ getChildren().add(index, entry);
+ }
+
+ /**
+ * Return the state system this entry is associated to
+ *
+ * @return The state system, or <code>null</code> if the state system can't
+ * be found.
+ */
+ @Override
+ @NonNull
+ public ITmfStateSystem getStateSystem() {
+ return fSs;
+ }
+
+ @Override
+ public String getAttributeValue(String name) {
+ return name;
+ }
+
+ @Override
+ public Iterable<TmfXmlLocation> getLocations() {
+ return Collections.EMPTY_SET;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Florian Wininger - Initial API and implementation
+ * Geneviève Bastien - Review of the initial implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.analysis.xml.ui.views.timegraph;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.linuxtools.internal.tmf.analysis.xml.ui.TmfXmlUiStrings;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.module.XmlUtils;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.eclipse.linuxtools.tmf.analysis.xml.ui.views.timegraph.XmlEntry.EntryDisplayType;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.StateItem;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.TimeEvent;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
+import org.w3c.dom.Element;
+
+/**
+ * Presentation provider for the XML view, based on the generic TMF presentation
+ * provider.
+ *
+ * TODO: This should support colors/states defined for each entry element in the
+ * XML element. Also, event values may not be integers only (for instance, this
+ * wouldn't support yet the callstack view)
+ *
+ * @author Florian Wininger
+ */
+public class XmlPresentationProvider extends TimeGraphPresentationProvider {
+
+ private List<StateItem> stateValues = new ArrayList<>();
+ /*
+ * Maps the value of an event with the corresponding index in the
+ * stateValues list
+ */
+ private Map<Integer, Integer> stateIndex = new HashMap<>();
+
+ @Override
+ public int getStateTableIndex(ITimeEvent event) {
+ if (event instanceof TimeEvent && ((TimeEvent) event).hasValue()) {
+ TimeEvent tcEvent = (TimeEvent) event;
+
+ XmlEntry entry = (XmlEntry) event.getEntry();
+ int value = tcEvent.getValue();
+
+ if (entry.getType() == EntryDisplayType.DISPLAY) {
+ Integer index = stateIndex.get(value);
+ if (index == null) {
+ /* Colors won't be refreshed yet, return something known */
+ index = TRANSPARENT;
+ stateIndex.put(value, stateValues.size());
+ StateItem item = new StateItem(calcColor(stateValues.size()), String.valueOf(value));
+ stateValues.add(item);
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ fireColorSettingsChanged();
+ }
+ });
+ }
+ return index;
+ }
+ }
+
+ return INVISIBLE;
+ }
+
+ @Override
+ public StateItem[] getStateTable() {
+ return stateValues.toArray(new StateItem[stateValues.size()]);
+ }
+
+ @Override
+ public String getEventName(ITimeEvent event) {
+ if (event instanceof TimeEvent && ((TimeEvent) event).hasValue()) {
+ TimeEvent tcEvent = (TimeEvent) event;
+
+ XmlEntry entry = (XmlEntry) event.getEntry();
+ int value = tcEvent.getValue();
+
+ if (entry.getType() == EntryDisplayType.DISPLAY) {
+ Integer index = stateIndex.get(value);
+ String rgb = stateValues.get(index).getStateString();
+ return rgb;
+ }
+ return null;
+ }
+ return Messages.XmlPresentationProvider_MultipleStates;
+ }
+
+ @Override
+ public Map<String, String> getEventHoverToolTipInfo(ITimeEvent event, long hoverTime) {
+ /*
+ * TODO: Add the XML elements to support adding extra information in the
+ * tooltips and implement this
+ */
+ return Collections.EMPTY_MAP;
+ }
+
+ @Override
+ public void postDrawEvent(ITimeEvent event, Rectangle bounds, GC gc) {
+ /*
+ * TODO Add the XML elements to support texts in intervals and implement
+ * this
+ */
+ }
+
+ @Override
+ public void postDrawEntry(ITimeGraphEntry entry, Rectangle bounds, GC gc) {
+ }
+
+ /**
+ * Loads the states from a {@link TmfXmlUiStrings#TIME_GRAPH_VIEW} XML
+ * element
+ *
+ * @param viewElement
+ * The XML view element
+ */
+ public void loadNewStates(@NonNull Element viewElement) {
+ stateValues.clear();
+ stateIndex.clear();
+ List<Element> states = XmlUtils.getChildElements(viewElement, TmfXmlStrings.DEFINED_VALUE);
+
+ for (Element state : states) {
+ int value = Integer.parseInt(state.getAttribute(TmfXmlStrings.VALUE));
+ String name = state.getAttribute(TmfXmlStrings.NAME);
+ String color = state.getAttribute(TmfXmlStrings.COLOR);
+
+ // FIXME Allow this case
+ if (value < 0) {
+ return;
+ }
+
+ RGB colorRGB = new RGB(255, 0, 0);
+ if (color.startsWith(TmfXmlStrings.COLOR_PREFIX)) {
+ Integer hex = Integer.parseInt(color.substring(1), 16);
+ int hex1 = hex.intValue() % 256;
+ int hex2 = (hex.intValue() / 256) % 256;
+ int hex3 = (hex.intValue() / (256 * 256)) % 256;
+ colorRGB = new RGB(hex3, hex2, hex1);
+ } else {
+ colorRGB = calcColor(value);
+ }
+
+ StateItem item = new StateItem(colorRGB, name);
+
+ Integer index = stateIndex.get(value);
+ if (index == null) {
+ /* Add the new state value */
+ stateIndex.put(value, stateValues.size());
+ stateValues.add(item);
+ } else {
+ /* Override a previous state value */
+ stateValues.set(index, item);
+ }
+ }
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ fireColorSettingsChanged();
+ }
+ });
+ }
+
+ private static RGB calcColor(int value) {
+ int x = (value * 97) % 1530;
+ int r = 0, g = 0, b = 0;
+ if (x >= 0 && x < 255) {
+ r = 255;
+ g = x;
+ b = 0;
+ }
+ if (x >= 255 && x < 510) {
+ r = 510 - x;
+ g = 255;
+ b = 0;
+ }
+ if (x >= 510 && x < 765) {
+ r = 0;
+ g = 255;
+ b = x - 510;
+ }
+ if (x >= 765 && x < 1020) {
+ r = 0;
+ g = 1020 - x;
+ b = 255;
+ }
+ if (x >= 1020 && x < 1275) {
+ r = x - 1020;
+ g = 0;
+ b = 255;
+ }
+ if (x >= 1275 && x <= 1530) {
+ r = 255;
+ g = 0;
+ b = 1530 - x;
+ }
+ return new RGB(r, g, b);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Florian Wininger - Initial API and implementation
+ * Geneviève Bastien - Review of the initial implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.analysis.xml.ui.views.timegraph;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.linuxtools.internal.tmf.analysis.xml.ui.Activator;
+import org.eclipse.linuxtools.internal.tmf.analysis.xml.ui.TmfXmlUiStrings;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.model.ITmfXmlModelFactory;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.model.ITmfXmlStateAttribute;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.model.readonly.TmfXmlReadOnlyModelFactory;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.module.IXmlStateSystemContainer;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.module.XmlUtils;
+import org.eclipse.linuxtools.tmf.analysis.xml.core.stateprovider.TmfXmlStrings;
+import org.eclipse.linuxtools.tmf.analysis.xml.ui.module.TmfXmlAnalysisOutputSource;
+import org.eclipse.linuxtools.tmf.analysis.xml.ui.views.timegraph.XmlEntry.EntryDisplayType;
+import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
+import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
+import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
+import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
+import org.eclipse.linuxtools.tmf.core.statesystem.ITmfAnalysisModuleWithStateSystems;
+import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
+import org.eclipse.linuxtools.tmf.core.statesystem.TmfStateSystemAnalysisModule;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
+import org.eclipse.linuxtools.tmf.ui.views.timegraph.AbstractTimeGraphView;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider2;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ILinkEvent;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.NullTimeEvent;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.TimeEvent;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
+import org.eclipse.swt.widgets.Display;
+import org.w3c.dom.Element;
+
+/**
+ * This view displays state system data in a time graph view. It uses an XML
+ * {@link TmfXmlUiStrings#TIME_GRAPH_VIEW} element from an XML file. This
+ * element defines which entries from the state system will be shown and also
+ * gives additional information on the presentation of the view (states, colors,
+ * etc)
+ *
+ * @author Florian Wininger
+ */
+public class XmlTimeGraphView extends AbstractTimeGraphView {
+
+ /** View ID. */
+ public static final String ID = "org.eclipse.linuxtools.tmf.analysis.xml.ui.views.timegraph"; //$NON-NLS-1$
+
+ private static final String XML_VIEW_ID_PROPERTY = "XmlViewId"; //$NON-NLS-1$
+ private static final String XML_VIEW_FILE_PROPERTY = "XmlViewFile"; //$NON-NLS-1$
+
+ private static final String[] DEFAULT_COLUMN_NAMES = new String[] {
+ Messages.XmlTimeGraphView_ColumnName,
+ Messages.XmlTimeGraphView_ColumnId,
+ Messages.XmlTimeGraphView_ColumnParentId,
+ };
+
+ private static final String[] DEFAULT_FILTER_COLUMN_NAMES = new String[] {
+ Messages.XmlTimeGraphView_ColumnName,
+ Messages.XmlTimeGraphView_ColumnId
+ };
+
+ /** The relative weight of the sash */
+ private static final int[] fWeight = { 1, 2 };
+
+ private static final String EMPTY_STRING = ""; //$NON-NLS-1$
+ private static final String SPLIT_STRING = "/"; //$NON-NLS-1$
+
+ private String fId = null;
+ private String fFilePath = null;
+ private final ITmfXmlModelFactory fFactory;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default constructor
+ */
+ public XmlTimeGraphView() {
+ super(ID, new XmlPresentationProvider());
+ setWeight(fWeight);
+ setTreeColumns(DEFAULT_COLUMN_NAMES);
+ setTreeLabelProvider(new XmlTreeLabelProvider());
+ setFilterColumns(DEFAULT_FILTER_COLUMN_NAMES);
+ setFilterLabelProvider(new XmlTreeLabelProvider());
+ setEntryComparator(new XmlEntryComparator());
+ this.addPartPropertyListener(new IPropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ if (event.getProperty().equals(TmfXmlUiStrings.XML_OUTPUT_DATA)) {
+ String data = (String) event.getNewValue();
+ String[] idFile = data.split(TmfXmlAnalysisOutputSource.DATA_SEPARATOR);
+ fId = (idFile.length > 0) ? idFile[0] : null;
+ fFilePath = (idFile.length > 1) ? idFile[1] : null;
+ loadNewXmlView();
+ savePersistentData();
+ }
+ }
+ });
+ IDialogSettings settings = getPersistentPropertyStore();
+
+ fId = settings.get(XML_VIEW_ID_PROPERTY);
+ fFilePath = settings.get(XML_VIEW_FILE_PROPERTY);
+ fFactory = TmfXmlReadOnlyModelFactory.getInstance();
+ }
+
+ @NonNull
+ private IDialogSettings getPersistentPropertyStore() {
+ IDialogSettings settings = Activator.getDefault().getDialogSettings();
+ IDialogSettings section = settings.getSection(getClass().getName());
+ if (section == null) {
+ section = settings.addNewSection(getClass().getName());
+ if (section == null) {
+ throw new IllegalStateException();
+ }
+ }
+ return section;
+ }
+
+ private void savePersistentData() {
+ IDialogSettings settings = getPersistentPropertyStore();
+
+ settings.put(XML_VIEW_ID_PROPERTY, fId);
+ settings.put(XML_VIEW_FILE_PROPERTY, fFilePath);
+ }
+
+ private void loadNewXmlView() {
+ rebuild();
+ }
+
+ private void setViewTitle(final String title) {
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ setPartName(title);
+ }
+ });
+
+ }
+
+ @Override
+ protected String getNextText() {
+ return Messages.XmlTimeGraphView_NextText;
+ }
+
+ @Override
+ protected String getNextTooltip() {
+ return Messages.XmlTimeGraphView_NextTooltip;
+ }
+
+ @Override
+ protected String getPrevText() {
+ return Messages.XmlTimeGraphView_PreviousText;
+ }
+
+ @Override
+ protected String getPrevTooltip() {
+ return Messages.XmlTimeGraphView_PreviousInterval;
+ }
+
+ /**
+ * Default label provider, it shows name, id and parent columns
+ *
+ * TODO: There should be a way to define columns in the XML
+ * */
+ private static class XmlTreeLabelProvider extends TreeLabelProvider {
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ XmlEntry entry = (XmlEntry) element;
+
+ if (DEFAULT_COLUMN_NAMES[columnIndex].equals(Messages.XmlTimeGraphView_ColumnName)) {
+ return entry.getName();
+ } else if (DEFAULT_COLUMN_NAMES[columnIndex].equals(Messages.XmlTimeGraphView_ColumnId)) {
+ return entry.getId();
+ } else if (DEFAULT_COLUMN_NAMES[columnIndex].equals(Messages.XmlTimeGraphView_ColumnParentId)) {
+ return entry.getParentId();
+ }
+ return EMPTY_STRING;
+ }
+
+ }
+
+ private static class XmlEntryComparator implements Comparator<ITimeGraphEntry> {
+
+ @Override
+ public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
+
+ int result = 0;
+
+ if ((o1 instanceof XmlEntry) && (o2 instanceof XmlEntry)) {
+ XmlEntry entry1 = (XmlEntry) o1;
+ XmlEntry entry2 = (XmlEntry) o2;
+ result = entry1.getTrace().getStartTime().compareTo(entry2.getTrace().getStartTime());
+ if (result == 0) {
+ result = entry1.getTrace().getName().compareTo(entry2.getTrace().getName());
+ }
+ if (result == 0) {
+ result = entry1.getName().compareTo(entry2.getName());
+ }
+ }
+
+ if (result == 0) {
+ result = o1.getStartTime() < o2.getStartTime() ? -1 : o1.getStartTime() > o2.getStartTime() ? 1 : 0;
+ }
+
+ return result;
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Internal
+ // ------------------------------------------------------------------------
+
+ @Override
+ protected void buildEventList(ITmfTrace trace, ITmfTrace parentTrace, IProgressMonitor monitor) {
+
+ /*
+ * Get the view element from the XML file. If the element can't be
+ * found, return.
+ */
+ String id = fId;
+ if (id == null) {
+ return;
+ }
+ Element viewElement = XmlUtils.getElementInFile(fFilePath, TmfXmlUiStrings.TIME_GRAPH_VIEW, id);
+ if (viewElement == null) {
+ return;
+ }
+ ITimeGraphPresentationProvider2 pres = this.getPresentationProvider();
+ if (pres instanceof XmlPresentationProvider) {
+ /*
+ * TODO: Each entry of a line could have their own states/color.
+ * That will require an update to the presentation provider
+ */
+ ((XmlPresentationProvider) pres).loadNewStates(viewElement);
+ }
+
+ List<Element> heads = XmlUtils.getChildElements(viewElement, TmfXmlStrings.HEAD);
+
+ List<String> analysisIds = new LinkedList<>();
+ if (!heads.isEmpty()) {
+ Element head = heads.get(0);
+ /* Set the title of this view from the label in the header */
+ List<Element> labels = XmlUtils.getChildElements(head, TmfXmlStrings.LABEL);
+ String title = Messages.XmlTimeGraphView_DefaultTitle;
+ for (Element label : labels) {
+ if (!label.getAttribute(TmfXmlStrings.VALUE).equals(EMPTY_STRING)) {
+ title = label.getAttribute(TmfXmlStrings.VALUE);
+ }
+ break;
+ }
+ setViewTitle(title);
+
+ /* Get the application analysis from the view's XML header */
+ List<Element> applicableAnalysis = XmlUtils.getChildElements(head, TmfXmlStrings.ANALYSIS);
+ for (Element oneAnalysis : applicableAnalysis) {
+ analysisIds.add(oneAnalysis.getAttribute(TmfXmlStrings.ID));
+ }
+ }
+ List<Element> entries = XmlUtils.getChildElements(viewElement, TmfXmlUiStrings.ENTRY_ELEMENT);
+ Set<XmlEntry> entryList = new TreeSet<>(getEntryComparator());
+ for (ITmfTrace aTrace : TmfTraceManager.getTraceSet(trace)) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+
+ List<ITmfAnalysisModuleWithStateSystems> stateSystemModules = new LinkedList<>();
+ if (analysisIds.isEmpty()) {
+ /*
+ * No analysis specified, take all state system analysis modules
+ */
+ for (ITmfAnalysisModuleWithStateSystems module : aTrace.getAnalysisModulesOfClass(ITmfAnalysisModuleWithStateSystems.class)) {
+ stateSystemModules.add(module);
+ }
+ } else {
+ for (String moduleId : analysisIds) {
+ ITmfAnalysisModuleWithStateSystems module = aTrace.getAnalysisModuleOfClass(ITmfAnalysisModuleWithStateSystems.class, moduleId);
+ if (module != null) {
+ stateSystemModules.add(module);
+ }
+ }
+ }
+
+ for (ITmfAnalysisModuleWithStateSystems module : stateSystemModules) {
+ module.schedule();
+ if (module instanceof TmfStateSystemAnalysisModule) {
+ ((TmfStateSystemAnalysisModule) module).waitForInitialization();
+ }
+ for (ITmfStateSystem ssq : module.getStateSystems()) {
+ if (ssq == null) {
+ return;
+ }
+ ssq.waitUntilBuilt();
+
+ long startTime = ssq.getStartTime();
+ long endTime = ssq.getCurrentEndTime();
+ XmlEntry groupEntry = new XmlEntry(-1, aTrace, aTrace.getName(), ssq);
+ entryList.add(groupEntry);
+ setStartTime(Math.min(getStartTime(), startTime));
+ setEndTime(Math.max(getEndTime(), endTime));
+
+ /* Add children entry of this entry for each line */
+ for (Element entry : entries) {
+ buildEntry(entry, groupEntry, -1);
+ }
+ }
+ }
+ }
+ putEntryList(trace, new ArrayList<TimeGraphEntry>(entryList));
+
+ if (trace.equals(getTrace())) {
+ refresh();
+ }
+ for (XmlEntry traceEntry : entryList) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+ long startTime = traceEntry.getStateSystem().getStartTime();
+ long endTime = traceEntry.getStateSystem().getCurrentEndTime() + 1;
+ buildStatusEvent(traceEntry, monitor, startTime, endTime);
+ }
+ }
+
+ private void buildEntry(Element entryElement, XmlEntry parentEntry, int baseQuark) {
+ /* Get the attribute string to display */
+ String path = entryElement.getAttribute(TmfXmlUiStrings.PATH);
+ if (path.isEmpty()) {
+ path = TmfXmlStrings.WILDCARD;
+ }
+
+ /*
+ * Make sure the XML element has either a display attribute or entries,
+ * otherwise issue a warning
+ */
+
+ List<Element> displayElements = XmlUtils.getChildElements(entryElement, TmfXmlUiStrings.DISPLAY_ELEMENT);
+ List<Element> entryElements = XmlUtils.getChildElements(entryElement, TmfXmlUiStrings.ENTRY_ELEMENT);
+
+ if (displayElements.isEmpty() && entryElements.isEmpty()) {
+ Activator.logWarning(String.format("XML view: entry for %s should have either a display element or entry elements", path)); //$NON-NLS-1$
+ return;
+ }
+
+ ITmfStateSystem ss = parentEntry.getStateSystem();
+
+ /* Get the list of quarks to process with this path */
+ String[] paths = path.split(SPLIT_STRING);
+ int i = 0;
+ List<Integer> quarks = Collections.singletonList(baseQuark);
+
+ try {
+ while (i < paths.length) {
+ List<Integer> subQuarks = new LinkedList<>();
+ /* Replace * by .* to have a regex string */
+ String name = paths[i].replaceAll("\\*", ".*"); //$NON-NLS-1$ //$NON-NLS-2$
+ for (int relativeQuark : quarks) {
+ for (int quark : ss.getSubAttributes(relativeQuark, false, name)) {
+ subQuarks.add(quark);
+ }
+ }
+ quarks = subQuarks;
+ i++;
+ }
+
+ /* Process each quark */
+ XmlEntry currentEntry = parentEntry;
+ Element displayElement = null;
+ Map<String, XmlEntry> entryMap = new HashMap<>();
+ if (!displayElements.isEmpty()) {
+ displayElement = displayElements.get(0);
+ }
+ for (int quark : quarks) {
+ currentEntry = parentEntry;
+ /* Process the current entry, if specified */
+ if (displayElement != null) {
+ currentEntry = processEntry(entryElement, displayElement, parentEntry, quark, ss);
+ entryMap.put(currentEntry.getId(), currentEntry);
+ }
+ /* Process the children entry of this entry */
+ for (Element subEntryEl : entryElements) {
+ buildEntry(subEntryEl, currentEntry, quark);
+ }
+ }
+ if (!entryMap.isEmpty()) {
+ buildTree(entryMap, parentEntry);
+ }
+ } catch (AttributeNotFoundException e) {
+ }
+ }
+
+ private XmlEntry processEntry(@NonNull Element entryElement, @NonNull Element displayEl,
+ XmlEntry parentEntry, int quark, ITmfStateSystem ss) {
+ /*
+ * Get the start time and end time of this entry from the display
+ * attribute
+ */
+ ITmfXmlStateAttribute display = fFactory.createStateAttribute(displayEl, parentEntry);
+ int displayQuark = display.getAttributeQuark(quark);
+ if (displayQuark == IXmlStateSystemContainer.ERROR_QUARK) {
+ return new XmlEntry(quark, parentEntry.getTrace(),
+ String.format("Unknown display quark for %s", ss.getAttributeName(quark)), ss); //$NON-NLS-1$
+ }
+
+ long entryStart = ss.getStartTime();
+ long entryEnd = ss.getCurrentEndTime();
+ try {
+ boolean first = true;
+ List<ITmfStateInterval> execNameIntervals = ss.queryHistoryRange(displayQuark, ss.getStartTime(), ss.getCurrentEndTime());
+
+ for (ITmfStateInterval execNameInterval : execNameIntervals) {
+
+ if (!execNameInterval.getStateValue().isNull()) {
+ if (first) {
+ entryStart = execNameInterval.getStartTime();
+ first = false;
+ }
+ entryEnd = execNameInterval.getEndTime();
+ }
+ }
+ } catch (AttributeNotFoundException | StateSystemDisposedException e) {
+ }
+
+ return new XmlEntry(quark, displayQuark, parentEntry.getTrace(), ss.getAttributeName(quark),
+ entryStart, entryEnd, EntryDisplayType.DISPLAY, ss, entryElement);
+ }
+
+ private void buildStatusEvent(XmlEntry traceEntry, IProgressMonitor monitor, long start, long end) {
+ long resolution = (end - start) / getDisplayWidth();
+ long startTime = Math.max(start, traceEntry.getStartTime());
+ long endTime = Math.min(end + 1, traceEntry.getEndTime());
+ List<ITimeEvent> eventList = getEventList(traceEntry, startTime, endTime, resolution, monitor);
+ if (monitor.isCanceled()) {
+ return;
+ }
+ traceEntry.setEventList(eventList);
+ redraw();
+
+ for (TimeGraphEntry entry : traceEntry.getChildren()) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+ XmlEntry xmlEntry = (XmlEntry) entry;
+ buildStatusEvent(xmlEntry, monitor, start, end);
+ }
+ }
+
+ /** Build a tree using getParentId() and getId() */
+ private static void buildTree(Map<String, XmlEntry> entryMap, XmlEntry rootEntry) {
+ for (XmlEntry entry : entryMap.values()) {
+ boolean root = true;
+ if (!entry.getParentId().isEmpty()) {
+ XmlEntry parent = entryMap.get(entry.getParentId());
+ if (parent != null &&
+ entry.getStartTime() >= parent.getStartTime() &&
+ entry.getStartTime() <= parent.getEndTime()) {
+ parent.addChild(entry);
+ root = false;
+ }
+ }
+ if (root) {
+ rootEntry.addChild(entry);
+ }
+ }
+ }
+
+ @Override
+ protected List<ITimeEvent> getEventList(TimeGraphEntry entry, long startTime, long endTime, long resolution, IProgressMonitor monitor) {
+ if (!(entry instanceof XmlEntry)) {
+ return Collections.EMPTY_LIST;
+ }
+ XmlEntry xmlEntry = (XmlEntry) entry;
+ ITmfStateSystem ssq = xmlEntry.getStateSystem();
+ final long realStart = Math.max(startTime, entry.getStartTime());
+ final long realEnd = Math.min(endTime, entry.getEndTime());
+ if (realEnd <= realStart) {
+ return null;
+ }
+ List<ITimeEvent> eventList = null;
+ int quark = xmlEntry.getDisplayQuark();
+
+ try {
+ if (xmlEntry.getType() == EntryDisplayType.DISPLAY) {
+
+ List<ITmfStateInterval> statusIntervals = ssq.queryHistoryRange(quark, realStart, realEnd - 1, resolution, monitor);
+ eventList = new ArrayList<>(statusIntervals.size());
+ long lastEndTime = -1;
+ for (ITmfStateInterval statusInterval : statusIntervals) {
+ if (monitor.isCanceled()) {
+ return null;
+ }
+ int status = statusInterval.getStateValue().unboxInt();
+ long time = statusInterval.getStartTime();
+ long duration = statusInterval.getEndTime() - time + 1;
+ if (!statusInterval.getStateValue().isNull()) {
+ if (lastEndTime != time && lastEndTime != -1) {
+ eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
+ }
+ eventList.add(new TimeEvent(entry, time, duration, status));
+ } else if (lastEndTime == -1 || time + duration >= endTime) {
+ // add null event if it intersects the start or end time
+ eventList.add(new NullTimeEvent(entry, time, duration));
+ }
+ lastEndTime = time + duration;
+ }
+ }
+ } catch (AttributeNotFoundException | TimeRangeException | StateValueTypeException | StateSystemDisposedException e) {
+ /* Ignored */
+ }
+ return eventList;
+ }
+
+ @Override
+ protected List<ILinkEvent> getLinkList(long startTime, long endTime, long resolution, IProgressMonitor monitor) {
+ /* TODO: not implemented yet, need XML to go along */
+ return Collections.EMPTY_LIST;
+ }
+
+}
--- /dev/null
+XmlPresentationProvider_MultipleStates=(multiple)
+XmlTimeGraphView_ColumnId=ID
+XmlTimeGraphView_ColumnName=Name
+XmlTimeGraphView_ColumnParentId=ParentID
+XmlTimeGraphView_DefaultTitle=Xml State Provider
+XmlTimeGraphView_NextText=Next Interval
+XmlTimeGraphView_NextTooltip=Select next interval in time graph
+XmlTimeGraphView_PreviousInterval=Select previous interval in time graph
+XmlTimeGraphView_PreviousText=Previous Interval
+XmlTimeGraphView_UselessEndPath=There should be an XML <entry > for path {0} in the view's XML otherwise the last level is useless