TMF: Introduce the XML state system view for data driven outputs
authorFlorian Wininger <florian.wininger@polymtl.ca>
Mon, 10 Mar 2014 19:42:47 +0000 (15:42 -0400)
committerGenevieve Bastien <gbastien+lttng@versatic.net>
Thu, 24 Apr 2014 17:16:42 +0000 (13:16 -0400)
Change-Id: I3ecf738e918be7b52075706f85c3f842c737b712
Signed-off-by: Geneviève Bastien <gbastien+lttng@versatic.net>
Signed-off-by: Florian Wininger <florian.wininger@polymtl.ca>
Reviewed-on: https://git.eclipse.org/r/23161
Tested-by: Hudson CI
Reviewed-by: Alexandre Montplaisir <alexmonthy@voxpopuli.im>
16 files changed:
org.eclipse.linuxtools.tmf.analysis.xml.core.tests/test_xml_files/test_valid.xml
org.eclipse.linuxtools.tmf.analysis.xml.core/src/org/eclipse/linuxtools/tmf/analysis/xml/core/module/xmlDefinition.xsd
org.eclipse.linuxtools.tmf.analysis.xml.core/src/org/eclipse/linuxtools/tmf/analysis/xml/core/module/xmlStateSystemView.xsd [deleted file]
org.eclipse.linuxtools.tmf.analysis.xml.core/src/org/eclipse/linuxtools/tmf/analysis/xml/core/module/xmlTimeGraphView.xsd [new file with mode: 0644]
org.eclipse.linuxtools.tmf.analysis.xml.core/src/org/eclipse/linuxtools/tmf/analysis/xml/core/stateprovider/TmfXmlStrings.java
org.eclipse.linuxtools.tmf.analysis.xml.ui/META-INF/MANIFEST.MF
org.eclipse.linuxtools.tmf.analysis.xml.ui/plugin.properties
org.eclipse.linuxtools.tmf.analysis.xml.ui/plugin.xml
org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/internal/tmf/analysis/xml/ui/TmfXmlUiStrings.java
org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/module/TmfXmlAnalysisOutputSource.java
org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/module/TmfXmlViewOutput.java
org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/Messages.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/XmlEntry.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/XmlPresentationProvider.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/XmlTimeGraphView.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/messages.properties [new file with mode: 0644]

index 46911776a5c61da334cebc22670e47c41eae344a..c463896276732620400d0d6e0ce4db62832811af 100644 (file)
@@ -13,7 +13,7 @@
 <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" />
@@ -40,7 +40,7 @@
                                <name type="constant" value="Exec_name" />
                        </entry>
                </entry>
-       </stateSystemView>
+       </timeGraphView>
 
        <stateProvider id="kernel.linux.sp" version="1">
                <head>
index 1783836f20f5a323f5b22aa5dd98a0d7a9c8cb5a..5c81260b2240980f3347045a655f2cecc44aeb9e 100644 (file)
 
        <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>
diff --git a/org.eclipse.linuxtools.tmf.analysis.xml.core/src/org/eclipse/linuxtools/tmf/analysis/xml/core/module/xmlStateSystemView.xsd b/org.eclipse.linuxtools.tmf.analysis.xml.core/src/org/eclipse/linuxtools/tmf/analysis/xml/core/module/xmlStateSystemView.xsd
deleted file mode 100644 (file)
index 7064a9a..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<?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
diff --git a/org.eclipse.linuxtools.tmf.analysis.xml.core/src/org/eclipse/linuxtools/tmf/analysis/xml/core/module/xmlTimeGraphView.xsd b/org.eclipse.linuxtools.tmf.analysis.xml.core/src/org/eclipse/linuxtools/tmf/analysis/xml/core/module/xmlTimeGraphView.xsd
new file mode 100644 (file)
index 0000000..53f5903
--- /dev/null
@@ -0,0 +1,76 @@
+<?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
index b606c0a30334701c1aafe8425ba5e531bba9573f..7e1fa5d5053efb663e723d72660fc6a11f9e2a29 100644 (file)
@@ -34,11 +34,14 @@ public interface TmfXmlStrings {
     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";
index 50c8ed6439eb5d37e91d9e2fab4538a29cea0b1a..9de260d1983413c15aa932beaca0345760a81870 100644 (file)
@@ -15,4 +15,5 @@ Require-Bundle: org.eclipse.ui,
  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
index ffa8775069f05711171c2dcd3921c462c5273cd7..67a764c2a8b8076ea2fdd3291c6268ecc5e8ee13 100644 (file)
@@ -17,3 +17,5 @@ Bundle-Name = Linux Tools TMF XML Analysis UI Plug-in
 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
index 30429ee51443f36e670f2fe4197cd83f12b6b7a0..a285ef34a181fd055a27c8dd7b1316859629f5a4 100644 (file)
          </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>
index fdab48320c9b2729e30b9f43b3af9fe4f9dcf120..72af61dc615a2af6f8641484f05e14b6b4802d3b 100644 (file)
@@ -24,10 +24,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
 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 */
index 50bf81acbfaef97b01e1b5c80a7b4ee47c287374..0960c824dc39adb9c147e468c9486e7348e24eed 100644 (file)
@@ -14,6 +14,7 @@ package org.eclipse.linuxtools.tmf.analysis.xml.ui.module;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.List;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -21,10 +22,17 @@ import javax.xml.parsers.ParserConfigurationException;
 
 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;
 
 /**
@@ -58,8 +66,28 @@ public class TmfXmlAnalysisOutputSource implements ITmfNewAnalysisModuleListener
                 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$
             }
index 4ee6c64fc7c85a7d97813757a0a869c544cca0ad..e6a4e95dc28f4a0c47b8af5aff7c3cfb59d88084 100644 (file)
@@ -64,7 +64,7 @@ public class TmfXmlViewOutput extends TmfAnalysisViewOutput {
             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;
             }
diff --git a/org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/Messages.java b/org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/Messages.java
new file mode 100644 (file)
index 0000000..700937c
--- /dev/null
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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() {
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/XmlEntry.java b/org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/XmlEntry.java
new file mode 100644 (file)
index 0000000..7ce7739
--- /dev/null
@@ -0,0 +1,272 @@
+/*******************************************************************************
+ * 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;
+    }
+
+}
diff --git a/org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/XmlPresentationProvider.java b/org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/XmlPresentationProvider.java
new file mode 100644 (file)
index 0000000..6d41049
--- /dev/null
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * 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);
+    }
+
+}
diff --git a/org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/XmlTimeGraphView.java b/org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/XmlTimeGraphView.java
new file mode 100644 (file)
index 0000000..2c00f58
--- /dev/null
@@ -0,0 +1,547 @@
+/*******************************************************************************
+ * 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;
+    }
+
+}
diff --git a/org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/messages.properties b/org.eclipse.linuxtools.tmf.analysis.xml.ui/src/org/eclipse/linuxtools/tmf/analysis/xml/ui/views/timegraph/messages.properties
new file mode 100644 (file)
index 0000000..73b9566
--- /dev/null
@@ -0,0 +1,10 @@
+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
This page took 0.049733 seconds and 5 git commands to generate.