analysis.lami: Add support for user-defined LAMI analyses
authorPhilippe Proulx <pproulx@efficios.com>
Fri, 29 Apr 2016 02:57:53 +0000 (22:57 -0400)
committerAlexandre Montplaisir <alexmonthy@efficios.com>
Tue, 17 May 2016 21:18:47 +0000 (17:18 -0400)
This patch adds support for adding user-defined LAMI analyses,
as well as removing them, through the UI (project explorer).

A .properties file is created in the workspace for each added
user-defined analysis.

To add a new external analysis, right-click the External Analyses
item in the Project Explorer View, and click Add External Analysis.

To remove an external analysis, right-click the item to remove,
and click Remove External Analysis.

Change-Id: I067f0faf679d2384121a32845864d886ee64e241
Signed-off-by: Philippe Proulx <pproulx@efficios.com>
Signed-off-by: Alexandre Montplaisir <alexmonthy@efficios.com>
Reviewed-on: https://git.eclipse.org/r/72103
Reviewed-by: Patrick Tasse <patrick.tasse@gmail.com>
Tested-by: Patrick Tasse <patrick.tasse@gmail.com>
Reviewed-by: Hudson CI
25 files changed:
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/analysis/lami/core/Activator.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/LamiConfigUtils.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/ShellUtils.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/ConfigFileLamiAnalysisFactory.java [deleted file]
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/LamiAnalysisFactoryException.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/LamiAnalysisFactoryFromConfigFile.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.lami.ui/plugin.properties
analysis/org.eclipse.tracecompass.analysis.lami.ui/plugin.xml
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/AddAnalysisDialog.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/AddAnalysisHandler.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/HandlerUtils.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/Messages.java
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/RemoveAnalysisHandler.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/RunAnalysisHandler.java
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/messages.properties
lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/Activator.java
lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/LttngAnalysesLoader.java
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/analysis/ondemand/OnDemandAnalysisManager.java
tmf/org.eclipse.tracecompass.tmf.ui/icons/ovr16/built_in_ondemand_ovr.gif [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/icons/ovr16/user_defined_ondemand_ovr.gif [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfBuiltInOnDemandAnalysisElement.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfOnDemandAnalysesElement.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfOnDemandAnalysisElement.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfProjectModelIcons.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfUserDefinedOnDemandAnalysisElement.java [new file with mode: 0644]

index 2ae27202a63ea11d3e967a16fef77be82546f8d5..9f7ab8aa585b9fe738a2649cbcf522a532eb8723 100644 (file)
@@ -9,7 +9,15 @@
 
 package org.eclipse.tracecompass.internal.analysis.lami.core;
 
+import java.nio.file.Path;
+import java.util.List;
+
 import org.eclipse.tracecompass.common.core.TraceCompassActivator;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.LamiConfigUtils;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiAnalysis;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiAnalysisFactoryException;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiAnalysisFactoryFromConfigFile;
+import org.eclipse.tracecompass.tmf.core.analysis.ondemand.OnDemandAnalysisManager;
 
 /**
  * Plugin activator
@@ -34,8 +42,23 @@ public class Activator extends TraceCompassActivator {
         super(PLUGIN_ID);
     }
 
+    private void loadUserDefinedAnalyses() {
+        final Path configDirPath = LamiConfigUtils.getConfigDirPath();
+
+        try {
+            final List<LamiAnalysis> analyses = LamiAnalysisFactoryFromConfigFile.buildFromConfigDir(configDirPath, true, trace -> true);
+
+            OnDemandAnalysisManager manager = OnDemandAnalysisManager.getInstance();
+            analyses.forEach(manager::registerAnalysis);
+
+        } catch (LamiAnalysisFactoryException e) {
+            logWarning("Cannot load user-defined external analyses", e); //$NON-NLS-1$
+        }
+    }
+
     @Override
     protected void startActions() {
+        loadUserDefinedAnalyses();
     }
 
     @Override
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/LamiConfigUtils.java b/analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/LamiConfigUtils.java
new file mode 100644 (file)
index 0000000..60f34c0
--- /dev/null
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Philippe Proulx
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.analysis.lami.core;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Date;
+import java.util.Properties;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.tracecompass.internal.analysis.lami.core.Activator;
+
+/**
+ * Utilities related to user-defined LAMI analysis configuration
+ * files.
+ *
+ * @author Philippe Proulx
+ */
+public class LamiConfigUtils {
+
+    private static final String CONFIG_DIR = "user-defined-configs"; //$NON-NLS-1$
+
+    private LamiConfigUtils() {
+    }
+
+    /**
+     * Returns the path of the directory, in the workspace, where
+     * configuration files are stored.
+     *
+     * @return Path to configuration directory
+     */
+    public static Path getConfigDirPath() {
+        IPath path = Activator.instance().getStateLocation();
+        path = path.addTrailingSeparator().append(CONFIG_DIR);
+
+        /* Check if directory exists, otherwise create it */
+        final File dir = path.toFile();
+
+        if (!dir.exists() || !dir.isDirectory()) {
+            dir.mkdirs();
+        }
+
+        return checkNotNull(dir.toPath());
+    }
+
+    private static Path getConfigFilePath(String name) {
+        final Path configDirPath = getConfigDirPath();
+        String normName = name.replaceAll("\\s+", "-"); //$NON-NLS-1$ //$NON-NLS-2$
+        normName = normName.replaceAll("[^a-zA-Z0-9_]", ""); //$NON-NLS-1$ //$NON-NLS-2$
+
+        return checkNotNull(Paths.get(configDirPath.toString(), normName + ".properties")); //$NON-NLS-1$
+    }
+
+    /**
+     * Creates a new configuration file in the configuration directory.
+     *
+     * @param name
+     *            Name of the external analysis
+     * @param command
+     *            Command of the external analysis
+     * @return Path of created configuration file
+     * @throws IOException
+     *             If the file cannot be found or read
+     */
+    public static Path createConfigFile(String name, String command) throws IOException {
+        final Properties props = new Properties();
+
+        props.setProperty(LamiConfigFileStrings.PROP_NAME, name);
+        props.setProperty(LamiConfigFileStrings.PROP_COMMAND, command);
+        final Path configFilePath = getConfigFilePath(name);
+
+        if (Files.exists(configFilePath)) {
+            throw new IOException(String.format("Configuration file \"%s\" exists", configFilePath.toString())); //$NON-NLS-1$
+        }
+
+        try (final FileOutputStream out = new FileOutputStream(configFilePath.toFile())) {
+            String userName = System.getProperty("user.name"); //$NON-NLS-1$
+
+            if (userName == null) {
+                userName = "unknown user"; //$NON-NLS-1$
+            }
+
+            final Date curDate = new Date();
+            final String comment = String.format("Trace Compass external analysis descriptor created by user %s on %s", userName, curDate); //$NON-NLS-1$
+            props.store(out, comment);
+        }
+
+        return configFilePath;
+    }
+
+    /**
+     * Removes the configuration file which corresponds to the analysis named
+     * {@code name}.
+     *
+     * @param name
+     *            Analysis name
+     * @throws IOException
+     *             If there was an error attempting to delete the file
+     */
+    public static void removeConfigFile(String name) throws IOException {
+        Path configFilePath = getConfigFilePath(name);
+        Files.delete(configFilePath);
+    }
+
+}
index 937c994e5a9d585eb57d874ede455e26a53c481d..22644dce1c9a9e04b051b057045fb3f2c24133ca 100644 (file)
@@ -32,14 +32,14 @@ public class ShellUtils {
     public static List<String> commandStringToArgs(String command) {
         int index = 0;
         boolean inQuotes = false;
-        List<String> args = new ArrayList<>();
-        StringBuilder sb = new StringBuilder();
+        final List<String> args = new ArrayList<>();
+        final StringBuilder sb = new StringBuilder();
 
         while (index < command.length()) {
-            char ch = command.charAt(index);
+            final char ch = command.charAt(index);
 
             if (ch == '\\' && index < command.length() - 1) {
-                char escaped = command.charAt(index + 1);
+                final char escaped = command.charAt(index + 1);
 
                 if (escaped == '\\' || escaped == '"') {
                     // Valid escaped character
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/ConfigFileLamiAnalysisFactory.java b/analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/ConfigFileLamiAnalysisFactory.java
deleted file mode 100644 (file)
index eb9c683..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 EfficiOS Inc., Philippe Proulx
- *
- * 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
- *******************************************************************************/
-
-package org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-import java.util.function.Predicate;
-
-import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.LamiConfigFileStrings;
-import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.ShellUtils;
-import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
-
-/**
- * Factory which builds {@link LamiAnalysis} objects out of configuration
- * files.
- *
- * @author Philippe Proulx
- */
-public final class ConfigFileLamiAnalysisFactory {
-
-    /**
-     * Class-specific exception, for when things go wrong with the
-     * {@link ConfigFileLamiAnalysisFactory}.
-     */
-    public static class ConfigFileLamiAnalysisFactoryException extends Exception {
-
-        private static final long serialVersionUID = 1349804105078874111L;
-
-        /**
-         * Default constructor
-         */
-        public ConfigFileLamiAnalysisFactoryException() {
-            super();
-        }
-
-        /**
-         * Constructor specifying a message
-         *
-         * @param message
-         *            The exception message
-         */
-        public ConfigFileLamiAnalysisFactoryException(String message) {
-            super(message);
-        }
-
-        /**
-         * Constructor specifying both a cause and a message
-         *
-         * @param message
-         *            The exception message
-         * @param cause
-         *            The exception that caused this one
-         */
-        public ConfigFileLamiAnalysisFactoryException(String message, Throwable cause) {
-            super(message, cause);
-        }
-
-        /**
-         * Constructor specifying a cause
-         *
-         * @param cause
-         *            The exception that caused this one
-         */
-        public ConfigFileLamiAnalysisFactoryException(Throwable cause) {
-            super(cause);
-        }
-
-    }
-
-    private ConfigFileLamiAnalysisFactory() {
-    }
-
-    private static String getProperty(Properties props, String propName) throws ConfigFileLamiAnalysisFactoryException {
-        String prop = props.getProperty(propName);
-
-        if (prop == null) {
-            throw new ConfigFileLamiAnalysisFactoryException(String.format("Cannot find \"%s\" property", propName)); //$NON-NLS-1$
-        }
-
-        prop = prop.trim();
-
-        if (prop.isEmpty()) {
-            throw new ConfigFileLamiAnalysisFactoryException(String.format("\"%s\" property cannot be empty", propName)); //$NON-NLS-1$
-        }
-
-        return prop;
-    }
-
-    /**
-     * Builds a {@link LamiAnalysis} object from an input stream providing the
-     * content of a configuration file.
-     * <p>
-     * The caller is responsible for opening and closing {@code inputStream}.
-     *
-     * @param inputStream
-     *            Input stream for reading the configuration file; the stream is
-     *            not closed by this method
-     * @param isUserDefined
-     *            {@code true} if the analysis to build is user-defined
-     * @param appliesTo
-     *            Predicate to use to check whether or not this analysis applies
-     *            to a given trace
-     * @return Built {@link LamiAnalysis} object
-     * @throws ConfigFileLamiAnalysisFactoryException
-     *             If something go wrong
-     */
-    public static LamiAnalysis buildFromInputStream(InputStream inputStream, boolean isUserDefined,
-            Predicate<ITmfTrace> appliesTo) throws ConfigFileLamiAnalysisFactoryException {
-        Properties props = new Properties();
-
-        // Load properties
-        try {
-            props.load(inputStream);
-        } catch (IOException e) {
-            throw new ConfigFileLamiAnalysisFactoryException(e);
-        }
-
-        // Get analysis' name and command
-        String name = getProperty(props, LamiConfigFileStrings.PROP_NAME);
-        String command = getProperty(props, LamiConfigFileStrings.PROP_COMMAND);
-
-        // Get individual arguments from command string
-        List<String> args = ShellUtils.commandStringToArgs(command);
-
-        return new LamiAnalysis(name, isUserDefined, appliesTo, args);
-    }
-
-    /**
-     * Builds a {@link LamiAnalysis} object from a configuration file.
-     *
-     * @param configFilePath
-     *            Configuration file path
-     * @param isUserDefined
-     *            {@code true} if the analysis to build is user-defined
-     * @param appliesTo
-     *            Predicate to use to check whether or not this analysis applies
-     *            to a given trace
-     * @return Built {@link LamiAnalysis} object
-     * @throws ConfigFileLamiAnalysisFactoryException
-     *             If something go wrong
-     */
-    public static LamiAnalysis buildFromConfigFile(Path configFilePath, boolean isUserDefined,
-            Predicate<ITmfTrace> appliesTo) throws ConfigFileLamiAnalysisFactoryException {
-        try (FileInputStream propsStream = new FileInputStream(configFilePath.toFile())) {
-            return buildFromInputStream(propsStream, isUserDefined, appliesTo);
-        } catch (IOException e) {
-            throw new ConfigFileLamiAnalysisFactoryException(e);
-        }
-    }
-
-    /**
-     * Builds a list of {@link LamiAnalysis} objects from a directory containing
-     * configuration files.
-     *
-     * @param configDir
-     *            Configuration directory containing the configuration files to
-     *            load
-     * @param isUserDefined
-     *            {@code true} if the analyses to build are user-defined
-     * @param appliesTo
-     *            Predicate to use to check whether or not those analyses apply
-     *            to a given trace
-     * @return List of built {@link LamiAnalysis} objects
-     * @throws ConfigFileLamiAnalysisFactoryException
-     *             If something go wrong
-     */
-    public static List<LamiAnalysis> buildFromConfigDir(Path configDir, boolean isUserDefined,
-            Predicate<ITmfTrace> appliesTo) throws ConfigFileLamiAnalysisFactoryException {
-        List<LamiAnalysis> analyses = new ArrayList<>();
-
-        try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(configDir)) {
-            for (Path path : directoryStream) {
-                analyses.add(buildFromConfigFile(path, isUserDefined, appliesTo));
-            }
-        } catch (IOException e) {
-            throw new ConfigFileLamiAnalysisFactoryException(e);
-        }
-
-        return analyses;
-    }
-
-}
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/LamiAnalysisFactoryException.java b/analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/LamiAnalysisFactoryException.java
new file mode 100644 (file)
index 0000000..c1dc638
--- /dev/null
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Philippe Proulx
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module;
+
+/**
+ * Class-specific exception, for when things go wrong with the
+ * {@link LamiAnalysisFactoryFromConfigFile}.
+ */
+public class LamiAnalysisFactoryException extends Exception {
+
+    private static final long serialVersionUID = 1349804105078874111L;
+
+    /**
+     * Default constructor
+     */
+    public LamiAnalysisFactoryException() {
+        super();
+    }
+
+    /**
+     * Constructor specifying a message
+     *
+     * @param message
+     *            The exception message
+     */
+    public LamiAnalysisFactoryException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructor specifying both a cause and a message
+     *
+     * @param message
+     *            The exception message
+     * @param cause
+     *            The exception that caused this one
+     */
+    public LamiAnalysisFactoryException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructor specifying a cause
+     *
+     * @param cause
+     *            The exception that caused this one
+     */
+    public LamiAnalysisFactoryException(Throwable cause) {
+        super(cause);
+    }
+
+}
\ No newline at end of file
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/LamiAnalysisFactoryFromConfigFile.java b/analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/LamiAnalysisFactoryFromConfigFile.java
new file mode 100644 (file)
index 0000000..593e2e6
--- /dev/null
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Philippe Proulx
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.function.Predicate;
+
+import org.eclipse.tracecompass.internal.analysis.lami.core.Activator;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.LamiConfigFileStrings;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.ShellUtils;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+/**
+ * Factory which builds {@link LamiAnalysis} objects out of configuration
+ * files.
+ *
+ * @author Philippe Proulx
+ */
+public final class LamiAnalysisFactoryFromConfigFile {
+
+    private LamiAnalysisFactoryFromConfigFile() {}
+
+    private static String getProperty(Properties props, String propName) throws LamiAnalysisFactoryException {
+        String prop = props.getProperty(propName);
+
+        if (prop == null) {
+            throw new LamiAnalysisFactoryException(String.format("Cannot find \"%s\" property", propName)); //$NON-NLS-1$
+        }
+
+        prop = prop.trim();
+
+        if (prop.isEmpty()) {
+            throw new LamiAnalysisFactoryException(String.format("\"%s\" property cannot be empty", propName)); //$NON-NLS-1$
+        }
+
+        return prop;
+    }
+
+    /**
+     * Builds a {@link LamiAnalysis} object from an input stream providing the
+     * content of a configuration file.
+     * <p>
+     * The caller is responsible for opening and closing {@code inputStream}.
+     *
+     * @param inputStream
+     *            Input stream for reading the configuration file; the stream is
+     *            not closed by this method
+     * @param isUserDefined
+     *            {@code true} if the analysis to build is user-defined
+     * @param appliesTo
+     *            Predicate to use to check whether or not this analysis applies
+     *            to a given trace
+     * @return Built {@link LamiAnalysis} object
+     * @throws LamiAnalysisFactoryException
+     *             If something went wrong reading the input stream
+     */
+    public static LamiAnalysis buildFromInputStream(InputStream inputStream, boolean isUserDefined,
+            Predicate<ITmfTrace> appliesTo) throws LamiAnalysisFactoryException {
+        final Properties props = new Properties();
+
+        // Load properties
+        try {
+            props.load(inputStream);
+        } catch (IOException e) {
+            throw new LamiAnalysisFactoryException(e);
+        }
+
+        // Get analysis' name and command
+        final String name = getProperty(props, LamiConfigFileStrings.PROP_NAME);
+        final String command = getProperty(props, LamiConfigFileStrings.PROP_COMMAND);
+
+        // Get individual arguments from command string
+        final List<String> args = ShellUtils.commandStringToArgs(command);
+
+        return new LamiAnalysis(name, isUserDefined, appliesTo, args);
+    }
+
+    /**
+     * Builds a {@link LamiAnalysis} object from a configuration file.
+     *
+     * @param configFilePath
+     *            Configuration file path
+     * @param isUserDefined
+     *            {@code true} if the analysis to build is user-defined
+     * @param appliesTo
+     *            Predicate to use to check whether or not this analysis applies
+     *            to a given trace
+     * @return Built {@link LamiAnalysis} object
+     * @throws LamiAnalysisFactoryException
+     *             If something went wrong reading the file
+     */
+    public static LamiAnalysis buildFromConfigFile(Path configFilePath, boolean isUserDefined,
+            Predicate<ITmfTrace> appliesTo) throws LamiAnalysisFactoryException {
+        try (final FileInputStream propsStream = new FileInputStream(configFilePath.toFile())) {
+            return buildFromInputStream(propsStream, isUserDefined, appliesTo);
+        } catch (IOException e) {
+            throw new LamiAnalysisFactoryException(e);
+        }
+    }
+
+    /**
+     * Builds a list of {@link LamiAnalysis} objects from a directory containing
+     * configuration files.
+     *
+     * @param configDir
+     *            Configuration directory containing the configuration files to
+     *            load
+     * @param isUserDefined
+     *            {@code true} if the analyses to build are user-defined
+     * @param appliesTo
+     *            Predicate to use to check whether or not those analyses apply
+     *            to a given trace
+     * @return List of built {@link LamiAnalysis} objects
+     * @throws LamiAnalysisFactoryException
+     *             If something went wrong reading the directory
+     */
+    public static List<LamiAnalysis> buildFromConfigDir(Path configDir, boolean isUserDefined,
+            Predicate<ITmfTrace> appliesTo) throws LamiAnalysisFactoryException {
+        final List<LamiAnalysis> analyses = new ArrayList<>();
+
+        try (final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(configDir)) {
+            for (final Path path : directoryStream) {
+                try {
+                    analyses.add(buildFromConfigFile(path, isUserDefined, appliesTo));
+                } catch (LamiAnalysisFactoryException e) {
+                    Activator.instance().logWarning(String.format("Cannot load external analysis \"%s\"", path)); //$NON-NLS-1$
+                }
+            }
+        } catch (IOException e) {
+            throw new LamiAnalysisFactoryException(e);
+        }
+
+        return analyses;
+    }
+
+}
index 31bd0be0719ca49cb274cf6d7649e262f4e8c346..b2696c8a39c069194f9f5a644f6020da1ba9b683 100644 (file)
@@ -14,6 +14,14 @@ command.analysis_run = Run External Analysis
 command.analysis_run.mnemonic = R
 command.analysis_run.description = Run External Analysis
 
+command.analysis_remove = Remove External Analysis
+command.analysis_remove.mnemonic = m
+command.analysis_remove.description = Remove External Analysis
+
+command.analysis_add = Add External Analysis
+command.analysis_add.mnemonic = A
+command.analysis_add.description = Add External Analysis
+
 command.report_open = Open Report
 command.report_open.mnemonic = O
 command.report_open.description = Open the views in the report into the workspace
index a8a026f43157713f50ced7bd40e64ebb6001677b..94a8b829d075a2e497723c72fd09785ef72191ef 100644 (file)
             </and>
          </activeWhen>
       </handler>
+      <handler
+            class="org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.handler.RemoveAnalysisHandler"
+            commandId="org.eclipse.tracecompass.tmf.ui.command.analysis_remove">
+         <activeWhen>
+            <and>
+               <iterate
+                     ifEmpty="false"
+                     operator="and">
+                  <instanceof
+                        value="org.eclipse.tracecompass.tmf.ui.project.model.TmfUserDefinedOnDemandAnalysisElement">
+                  </instanceof>
+               </iterate>
+            </and>
+         </activeWhen>
+      </handler>
+      <handler
+            class="org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.handler.AddAnalysisHandler"
+            commandId="org.eclipse.tracecompass.tmf.ui.command.analysis_add">
+         <activeWhen>
+            <and>
+               <count
+                     value="1">
+               </count>
+               <iterate
+                     operator="and">
+                  <instanceof
+                        value="org.eclipse.tracecompass.tmf.ui.project.model.TmfOnDemandAnalysesElement">
+                  </instanceof>
+               </iterate>
+            </and>
+         </activeWhen>
+      </handler>
    </extension>
    <extension
          point="org.eclipse.ui.commands">
             id="org.eclipse.tracecompass.tmf.ui.command.analysis_run"
             name="%command.analysis_run">
       </command>
+      <command
+            categoryId="org.eclipse.linuxtools.tmf.ui.commands.category"
+            description="%command.analysis_remove.description"
+            id="org.eclipse.tracecompass.tmf.ui.command.analysis_remove"
+            name="%command.analysis_remove">
+      </command>
+      <command
+            categoryId="org.eclipse.linuxtools.tmf.ui.commands.category"
+            description="%command.analysis_add.description"
+            id="org.eclipse.tracecompass.tmf.ui.command.analysis_add"
+            name="%command.analysis_add">
+      </command>
       <command
             categoryId="org.eclipse.linuxtools.tmf.ui.commands.category"
             description="%command.report_open.description"
             </visibleWhen>
          </command>
       </menuContribution>
+      <menuContribution
+            locationURI="popup:org.eclipse.ui.popup.any?after=additions">
+         <command
+               commandId="org.eclipse.tracecompass.tmf.ui.command.analysis_remove"
+               label="%command.analysis_remove"
+               mnemonic="%command.analysis_remove.mnemonic"
+               style="push"
+               tooltip="%command.analysis_remove.description">
+            <visibleWhen
+                  checkEnabled="false">
+               <with
+                     variable="selection">
+                  <iterate
+                        ifEmpty="false">
+                     <instanceof
+                           value="org.eclipse.tracecompass.tmf.ui.project.model.TmfUserDefinedOnDemandAnalysisElement">
+                     </instanceof>
+                  </iterate>
+               </with>
+            </visibleWhen>
+         </command>
+      </menuContribution>
+      <menuContribution
+            locationURI="popup:org.eclipse.ui.popup.any?after=additions">
+         <command
+               commandId="org.eclipse.tracecompass.tmf.ui.command.analysis_add"
+               label="%command.analysis_add"
+               mnemonic="%command.analysis_add.mnemonic"
+               style="push"
+               tooltip="%command.analysis_add.description">
+            <visibleWhen
+                  checkEnabled="false">
+               <with
+                     variable="selection">
+                  <count
+                        value="1">
+                  </count>
+                  <iterate>
+                     <instanceof
+                           value="org.eclipse.tracecompass.tmf.ui.project.model.TmfOnDemandAnalysesElement">
+                     </instanceof>
+                  </iterate>
+               </with>
+            </visibleWhen>
+         </command>
+      </menuContribution>
       <menuContribution
             allPopups="false"
             locationURI="popup:org.eclipse.ui.popup.any?after=additions">
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/AddAnalysisDialog.java b/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/AddAnalysisDialog.java
new file mode 100644 (file)
index 0000000..0ce1044
--- /dev/null
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 EfficiOS Inc., Philippe Proulx
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.handler;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.resource.FontDescriptor;
+import org.eclipse.jface.resource.StringConverter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Dialog to set a name and a command when creating a custom
+ * analysis entry.
+ *
+ * @author Philippe Proulx
+ */
+@NonNullByDefault({})
+class AddAnalysisDialog extends Dialog {
+
+    private final String title;
+    private String fName = ""; //$NON-NLS-1$
+    private String fCommand = ""; //$NON-NLS-1$
+    private final IInputValidator fNameValidator;
+    private final IInputValidator fCommandValidator;
+    private Button fOkButton;
+    private Text fNameText;
+    private Text fCommandText;
+    private Label fNameErrorLabel;
+    private Label fCommandErrorLabel;
+
+    public AddAnalysisDialog(Shell parentShell,
+            String dialogTitle,
+            IInputValidator nameValidator,
+            IInputValidator commandValidator) {
+        super(parentShell);
+        this.title = dialogTitle;
+        fNameValidator = nameValidator;
+        fCommandValidator = commandValidator;
+    }
+
+    @Override
+    protected void buttonPressed(int buttonId) {
+        if (buttonId == IDialogConstants.OK_ID) {
+            fName = fNameText.getText();
+            fCommand = fCommandText.getText();
+        } else {
+            fName = null;
+            fCommand = null;
+        }
+        super.buttonPressed(buttonId);
+    }
+
+    @Override
+    protected boolean isResizable() {
+        return true;
+    }
+
+    @Override
+    protected void configureShell(Shell shell) {
+        super.configureShell(shell);
+        if (title != null) {
+            shell.setText(title);
+        }
+    }
+
+    @Override
+    protected void createButtonsForButtonBar(Composite parent) {
+        fOkButton = createButton(parent, IDialogConstants.OK_ID,
+                IDialogConstants.OK_LABEL, true);
+        createButton(parent, IDialogConstants.CANCEL_ID,
+                IDialogConstants.CANCEL_LABEL, false);
+        validateInputs();
+        fNameText.setFocus();
+    }
+
+    private static void createSubtitleLabel(Composite parent, String text) {
+        final Label label = new Label(parent, SWT.WRAP);
+        label.setText(text + ':');
+        final FontDescriptor boldDescriptor = FontDescriptor.createFrom(parent.getFont()).setStyle(SWT.BOLD);
+        final Font boldFont = boldDescriptor.createFont(parent.getDisplay());
+        label.setFont(boldFont);
+        label.addDisposeListener(event -> boldDescriptor.destroyFont(boldFont));
+    }
+
+    private static Label createErrorLabel(Composite parent) {
+        final Label label = new Label(parent, SWT.WRAP);
+        Color color = new Color(parent.getDisplay(), 0xe7, 0x4c, 0x3c);
+        label.setForeground(color);
+        final FontDescriptor fd = FontDescriptor.createFrom(parent.getFont());
+        fd.setHeight(9);
+        Font font = fd.createFont(parent.getDisplay());
+        label.setFont(font);
+
+        label.addDisposeListener(e -> {
+            color.dispose();
+            fd.destroyFont(font);
+        });
+
+        return label;
+    }
+
+    @Override
+    protected Control createDialogArea(Composite parent) {
+        // create composite
+        final Composite composite = (Composite) super.createDialogArea(parent);
+
+        // create label for name text
+        createSubtitleLabel(composite, Messages.AddAnalysisDialog_Name);
+
+        // create name text
+        fNameText = new Text(composite, getInputTextStyle());
+        fNameText.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
+                | GridData.HORIZONTAL_ALIGN_FILL));
+        fNameText.addModifyListener(e -> validateInputs());
+
+        // create name error text
+        fNameErrorLabel = createErrorLabel(composite);
+
+        // spacer
+        new Label(composite, SWT.WRAP);
+
+        // create label for command text
+        createSubtitleLabel(composite, Messages.AddAnalysisDialog_Command);
+
+        // create command text
+        fCommandText = new Text(composite, getInputTextStyle());
+        fCommandText.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
+                | GridData.HORIZONTAL_ALIGN_FILL));
+        final Font mono = new Font(parent.getDisplay(), "Monospace", 9, SWT.NONE); //$NON-NLS-1$
+        fCommandText.setFont(mono);
+        fCommandText.addModifyListener(e -> validateInputs());
+        fCommandText.addDisposeListener(e -> mono.dispose());
+
+        // create command error text
+        fCommandErrorLabel = createErrorLabel(composite);
+
+        applyDialogFont(composite);
+        return composite;
+    }
+
+    @Override
+    public void create() {
+        super.create();
+        Shell shell = getShell();
+        shell.setMinimumSize(shell.getSize());
+    }
+
+    /**
+     * Returns the value of the name text.
+     *
+     * @return the name text's value
+     */
+    public String getName() {
+        return fName;
+    }
+
+    /**
+     * Returns the value of the command text.
+     *
+     * @return the command text's value
+     */
+    public String getCommand() {
+        return fCommand;
+    }
+
+    protected boolean validateInput(IInputValidator validator, Text text, Label errorLabel) {
+        final String errMsg = validator.isValid(text.getText());
+        setErrorLabel(errorLabel, errMsg);
+
+        return errMsg == null;
+    }
+
+    protected void validateInputs() {
+        boolean valid = true;
+
+        valid &= validateInput(fNameValidator, fNameText, fNameErrorLabel);
+        valid &= validateInput(fCommandValidator, fCommandText, fCommandErrorLabel);
+        fOkButton.setEnabled(valid);
+    }
+
+    protected void setErrorLabel(Label label, String errorMessage) {
+        if (label != null && !label.isDisposed()) {
+            label.setText(errorMessage == null ? " \n " : errorMessage); //$NON-NLS-1$
+            final boolean hasError = errorMessage != null && (StringConverter.removeWhiteSpaces(errorMessage)).length() > 0;
+            label.setEnabled(hasError);
+            label.setVisible(hasError);
+            label.getParent().update();
+            Control button = getButton(IDialogConstants.OK_ID);
+
+            if (button != null) {
+                button.setEnabled(errorMessage == null);
+            }
+        }
+    }
+
+    protected int getInputTextStyle() {
+        return SWT.SINGLE | SWT.BORDER;
+    }
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/AddAnalysisHandler.java b/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/AddAnalysisHandler.java
new file mode 100644 (file)
index 0000000..490771c
--- /dev/null
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 EfficiOS Inc., Philippe Proulx
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.handler;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.LamiConfigUtils;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiAnalysis;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiAnalysisFactoryException;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiAnalysisFactoryFromConfigFile;
+import org.eclipse.tracecompass.tmf.core.analysis.ondemand.OnDemandAnalysisManager;
+import org.eclipse.tracecompass.tmf.ui.project.model.TmfOnDemandAnalysesElement;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * The command handler for the "Add External Analysis" menu option.
+ *
+ * @author Philippe Proulx
+ */
+public class AddAnalysisHandler extends AbstractHandler {
+
+    private static void showErrorBox(@Nullable Shell shell, Throwable e) {
+        Display.getDefault().asyncExec(() -> {
+            MessageDialog.openError(shell,
+                    Messages.AddAnalysisDialog_ErrorBoxTitle,
+                    Messages.AddAnalysisDialog_ErrorBoxMessage + ":\n" + e.toString()); //$NON-NLS-1$
+        });
+    }
+
+    @Override
+    public @Nullable Object execute(@Nullable ExecutionEvent event) throws ExecutionException {
+        final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+        final AddAnalysisDialog dialog = new AddAnalysisDialog(shell, Messages.AddAnalysisDialog_Title,
+                NAME_INPUT_VALIDATOR, COMMAND_INPUT_VALIDATOR);
+
+        if (dialog.open() != Window.OK) {
+            // User clicked Cancel, cancel the add operation
+            return null;
+        }
+
+        Path configFilePath;
+
+        try {
+            configFilePath = LamiConfigUtils.createConfigFile(checkNotNull(dialog.getName().trim()),
+                    checkNotNull(dialog.getCommand().trim()));
+        } catch (IOException e) {
+            showErrorBox(shell, e);
+            return null;
+        }
+
+        try {
+            final LamiAnalysis analysis = LamiAnalysisFactoryFromConfigFile.buildFromConfigFile(configFilePath, true, trace -> true);
+            OnDemandAnalysisManager.getInstance().registerAnalysis(analysis);
+        } catch (LamiAnalysisFactoryException e) {
+            showErrorBox(shell, e);
+            return null;
+        }
+
+        final Object elem = HandlerUtils.getSelectedModelElement();
+
+        if (elem != null && elem instanceof TmfOnDemandAnalysesElement) {
+            final TmfOnDemandAnalysesElement analysesElem = (TmfOnDemandAnalysesElement) elem;
+            analysesElem.refresh();
+        }
+
+        return null;
+    }
+
+    private static final IInputValidator NAME_INPUT_VALIDATOR = text -> {
+        if (text.trim().isEmpty()) {
+            return Messages.AddAnalysisDialog_NameEmptyErrorMessage;
+        }
+
+        return null;
+    };
+
+    private static final IInputValidator COMMAND_INPUT_VALIDATOR = text -> {
+        if (text.trim().isEmpty()) {
+            return Messages.AddAnalysisDialog_CommandEmptyErrorMessage;
+        }
+
+        return null;
+    };
+
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/HandlerUtils.java b/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/HandlerUtils.java
new file mode 100644 (file)
index 0000000..334b3d6
--- /dev/null
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir, Philippe Proulx
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.handler;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Utilities for UI handlers
+ *
+ * @author Philippe Proulx
+ */
+public final class HandlerUtils {
+
+    private HandlerUtils() {
+    }
+
+    /**
+     * Get the current selected UI element. Can be used instead of
+     * {@link org.eclipse.ui.handlers.HandlerUtil#getCurrentSelection} when an
+     * ExecutionEvent is not available.
+     *
+     * @return The element consisting of the selection
+     */
+    public static @Nullable Object getSelectedModelElement() {
+        // Check if we are closing down
+        final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+        if (window == null) {
+            return null;
+        }
+
+        // Get the selection
+        final IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+        final IWorkbenchPart part = page.getActivePart();
+        if (part == null) {
+            return null;
+        }
+        final ISelectionProvider selectionProvider = part.getSite().getSelectionProvider();
+        if (selectionProvider == null) {
+            return null;
+        }
+        final ISelection selection = selectionProvider.getSelection();
+
+        if (selection instanceof TreeSelection) {
+            final TreeSelection sel = (TreeSelection) selection;
+            // There should be only one item selected as per the plugin.xml
+            return sel.getFirstElement();
+        }
+
+        return null;
+    }
+
+}
index 31d460baa5bca0470255d9ecf8b2d0e05754b5eb..d1811eb7c38329a2cf6f9fceb07b95731d5992ef 100644 (file)
@@ -32,6 +32,13 @@ public class Messages extends NLS {
     public static String ParameterDialog_ReportNameSuffix;
     public static String ParameterDialog_Error;
     public static String ParameterDialog_ErrorMessage;
+    public static String AddAnalysisDialog_Name;
+    public static String AddAnalysisDialog_Command;
+    public static String AddAnalysisDialog_NameEmptyErrorMessage;
+    public static String AddAnalysisDialog_CommandEmptyErrorMessage;
+    public static String AddAnalysisDialog_Title;
+    public static String AddAnalysisDialog_ErrorBoxTitle;
+    public static String AddAnalysisDialog_ErrorBoxMessage;
 
     static {
         // initialize resource bundle
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/RemoveAnalysisHandler.java b/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/handler/RemoveAnalysisHandler.java
new file mode 100644 (file)
index 0000000..589d914
--- /dev/null
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 EfficiOS Inc., Philippe Proulx
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.handler;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.LamiConfigUtils;
+import org.eclipse.tracecompass.tmf.core.analysis.ondemand.OnDemandAnalysisManager;
+import org.eclipse.tracecompass.tmf.ui.project.model.TmfOnDemandAnalysesElement;
+import org.eclipse.tracecompass.tmf.ui.project.model.TmfUserDefinedOnDemandAnalysisElement;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * The command handler for the "Remove External Analysis" menu option.
+ *
+ * @author Philippe Proulx
+ */
+public class RemoveAnalysisHandler extends AbstractHandler {
+
+    @Override
+    public @Nullable Object execute(@Nullable ExecutionEvent event) throws ExecutionException {
+        ISelection selection = HandlerUtil.getCurrentSelectionChecked(event);
+
+        // Selection type should have been validated by the plugin.xml
+        if (!(selection instanceof IStructuredSelection)) {
+            throw new IllegalStateException("Handler called on invalid selection"); //$NON-NLS-1$
+        }
+        IStructuredSelection sel = (IStructuredSelection) selection;
+        List<?> elements = sel.toList();
+
+        OnDemandAnalysisManager mgr = OnDemandAnalysisManager.getInstance();
+
+        List<TmfUserDefinedOnDemandAnalysisElement> analysisElements = elements.stream()
+                .filter(elem -> elem instanceof TmfUserDefinedOnDemandAnalysisElement)
+                .map(elem -> (TmfUserDefinedOnDemandAnalysisElement) elem)
+                .collect(Collectors.toList());
+
+        final TmfOnDemandAnalysesElement parentElement = analysisElements.get(0).getParent();
+
+        analysisElements.stream()
+            .map(analysisElem -> analysisElem.getAnalysis())
+            .forEach(analysis -> {
+                /* Unregister from the manager */
+                mgr.unregisterAnalysis(analysis);
+
+                /* Remove the corresponding configuration file */
+                try {
+                    LamiConfigUtils.removeConfigFile(analysis.getName());
+                } catch (IOException e) {
+                    // Ignore this: not the end of the world
+                }
+            });
+
+        /* Refresh the project explorer */
+        parentElement.refresh();
+
+        return null;
+    }
+
+}
index 8ad78e94b8362eb93cd2a8ed9d963e9edcfdc1c7..10458b1793fb977284f74538c7afbc79556789fb 100644 (file)
@@ -25,7 +25,6 @@ import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.jface.dialogs.IInputValidator;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionProvider;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.window.Window;
 import org.eclipse.swt.widgets.Display;
@@ -43,9 +42,6 @@ import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
 import org.eclipse.tracecompass.tmf.ui.project.model.TmfCommonProjectElement;
 import org.eclipse.tracecompass.tmf.ui.project.model.TmfOnDemandAnalysisElement;
 import org.eclipse.tracecompass.tmf.ui.project.model.TmfReportsElement;
-import org.eclipse.ui.IWorkbenchPage;
-import org.eclipse.ui.IWorkbenchPart;
-import org.eclipse.ui.IWorkbenchWindow;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.handlers.HandlerUtil;
@@ -59,28 +55,14 @@ public class RunAnalysisHandler extends AbstractHandler {
 
     @Override
     public boolean isEnabled() {
-        // Check if we are closing down
-        final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
-        if (window == null) {
+        final Object element = HandlerUtils.getSelectedModelElement();
+        if (element == null) {
             return false;
         }
 
-        // Get the selection
-        final IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
-        final IWorkbenchPart part = page.getActivePart();
-        if (part == null) {
-            return false;
-        }
-        final ISelectionProvider selectionProvider = part.getSite().getSelectionProvider();
-        if (selectionProvider == null) {
-            return false;
-        }
-        final ISelection selection = selectionProvider.getSelection();
-
         /*
          * plugin.xml should have done type verifications already
          */
-        final Object element = ((IStructuredSelection) selection).getFirstElement();
         TmfOnDemandAnalysisElement elem = (TmfOnDemandAnalysisElement) element;
         if (elem.getAnalysis() instanceof LamiAnalysis && elem.canRun()) {
             return true;
index 113dbb7642ff15ff3afd8c55fc79838d5da27230..2af7ae71951c7c5a189a4007f9e63afeb97e449b 100644 (file)
@@ -16,3 +16,11 @@ ParameterDialog_StringValidatorMessage = Allowed characters are letters, numbers
 ParameterDialog_ReportNameSuffix = Report
 ParameterDialog_Error = Error running external script
 ParameterDialog_ErrorMessage = The script terminated abnormally
+
+AddAnalysisDialog_Title = Add External Analysis
+AddAnalysisDialog_Name = Name
+AddAnalysisDialog_Command = Command
+AddAnalysisDialog_NameEmptyErrorMessage = You must name the new external analysis
+AddAnalysisDialog_CommandEmptyErrorMessage = The command line cannot be empty
+AddAnalysisDialog_ErrorBoxTitle = Cannot add external analysis
+AddAnalysisDialog_ErrorBoxMessage = Cannot add external analysis
index a270bb839f4e44870da20aab9061c0fab3dfcd7b..b418146b2694fc07935a233bda0a7221319bbf90 100644 (file)
@@ -20,7 +20,7 @@ import org.eclipse.core.runtime.Status;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.tracecompass.internal.lttng2.kernel.core.event.matching.TcpEventMatching;
 import org.eclipse.tracecompass.internal.lttng2.kernel.core.event.matching.TcpLttngEventMatching;
-import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.ConfigFileLamiAnalysisFactory.ConfigFileLamiAnalysisFactoryException;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiAnalysisFactoryException;
 import org.eclipse.tracecompass.tmf.core.event.matching.TmfEventMatching;
 import org.osgi.framework.BundleContext;
 
@@ -82,7 +82,7 @@ public class Activator extends Plugin {
 
         try {
             LttngAnalysesLoader.load();
-        } catch (ConfigFileLamiAnalysisFactoryException | IOException e) {
+        } catch (LamiAnalysisFactoryException | IOException e) {
             // Not the end of the world if the analyses are not available
             logWarning("Cannot find LTTng analyses configuration files: " + e.getMessage()); //$NON-NLS-1$
         }
index af301f16e716c885f9f9fa313927744da7bc674e..65b8a069b6c54215b46e8402666332b8a0019185 100644 (file)
@@ -15,9 +15,9 @@ import java.util.Properties;
 
 import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout;
 import org.eclipse.tracecompass.internal.lttng2.kernel.core.trace.layout.Lttng27EventLayout;
-import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.ConfigFileLamiAnalysisFactory;
-import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.ConfigFileLamiAnalysisFactory.ConfigFileLamiAnalysisFactoryException;
 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiAnalysis;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiAnalysisFactoryException;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiAnalysisFactoryFromConfigFile;
 import org.eclipse.tracecompass.lttng2.kernel.core.trace.LttngKernelTrace;
 import org.eclipse.tracecompass.tmf.core.analysis.ondemand.OnDemandAnalysisManager;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
@@ -37,8 +37,8 @@ final class LttngAnalysesLoader {
     private static boolean appliesTo(ITmfTrace trace) {
         /* LTTng-Analysis is supported only on LTTng >= 2.7 kernel traces */
         if (trace instanceof LttngKernelTrace) {
-            LttngKernelTrace kernelTrace = (LttngKernelTrace) trace;
-            IKernelAnalysisEventLayout layout = kernelTrace.getKernelEventLayout();
+            final LttngKernelTrace kernelTrace = (LttngKernelTrace) trace;
+            final IKernelAnalysisEventLayout layout = kernelTrace.getKernelEventLayout();
 
             if (layout instanceof Lttng27EventLayout) {
                 return true;
@@ -49,12 +49,12 @@ final class LttngAnalysesLoader {
     }
 
     private static String[] getAnalysisNames() throws IOException {
-        ClassLoader loader = LttngAnalysesLoader.class.getClassLoader();
-        String path = "/" + CONFIG_DIR_NAME + "/index.properties"; //$NON-NLS-1$ //$NON-NLS-2$
-        String[] names = new String[0];
-        Properties indexProps = new Properties();
+        final ClassLoader loader = LttngAnalysesLoader.class.getClassLoader();
+        final String path = "/" + CONFIG_DIR_NAME + "/index.properties"; //$NON-NLS-1$ //$NON-NLS-2$
+        final String[] names = new String[0];
+        final Properties indexProps = new Properties();
 
-        try (InputStream in = loader.getResourceAsStream(path)) {
+        try (final InputStream in = loader.getResourceAsStream(path)) {
             if (in == null) {
                 return names;
             }
@@ -69,24 +69,22 @@ final class LttngAnalysesLoader {
         }
 
         analyses = analyses.trim();
-        String[] splitNames = analyses.split("\\s+"); //$NON-NLS-1$
-
-        return splitNames;
+        return analyses.split("\\s+"); //$NON-NLS-1$
     }
 
-    public static void load() throws ConfigFileLamiAnalysisFactoryException, IOException {
-        String[] names = getAnalysisNames();
-        ClassLoader loader = LttngAnalysesLoader.class.getClassLoader();
+    public static void load() throws LamiAnalysisFactoryException, IOException {
+        final String[] names = getAnalysisNames();
+        final ClassLoader loader = LttngAnalysesLoader.class.getClassLoader();
 
-        for (String name : names) {
-            String path = String.format("/%s/%s.properties", CONFIG_DIR_NAME, name); //$NON-NLS-1$
+        for (final String name : names) {
+            final String path = String.format("/%s/%s.properties", CONFIG_DIR_NAME, name); //$NON-NLS-1$
 
-            try (InputStream in = loader.getResourceAsStream(path)) {
+            try (final InputStream in = loader.getResourceAsStream(path)) {
                 if (in == null) {
                     continue;
                 }
 
-                LamiAnalysis analysis = ConfigFileLamiAnalysisFactory.buildFromInputStream(in, false, LttngAnalysesLoader::appliesTo);
+                final LamiAnalysis analysis = LamiAnalysisFactoryFromConfigFile.buildFromInputStream(in, false, LttngAnalysesLoader::appliesTo);
                 OnDemandAnalysisManager.getInstance().registerAnalysis(analysis);
             }
         }
index 3f93bb7526b1786ed387f3bea96aa62b8215b1f1..70d9ca7e6688806c64be602318f6aaec2b83d5d9 100644 (file)
@@ -71,6 +71,21 @@ public final class OnDemandAnalysisManager {
         public OndemandAnalysisWrapper(IOnDemandAnalysis analysis) {
             this.analysis = analysis;
         }
+
+        @Override
+        public int hashCode() {
+            return this.analysis.hashCode();
+        }
+
+        @Override
+        public boolean equals(@Nullable Object o) {
+            if (!(o instanceof OndemandAnalysisWrapper)) {
+                return false;
+            }
+            OndemandAnalysisWrapper other = (OndemandAnalysisWrapper) o;
+
+            return this.analysis.getName().equals(other.analysis.getName());
+        }
     }
 
     /**
@@ -123,10 +138,31 @@ public final class OnDemandAnalysisManager {
     /**
      * Registers an on-demand analysis to this manager.
      *
-     * @param analysis
-     *            On-demand analysis to register
+     * @param analysis On-demand analysis to register
      */
     public void registerAnalysis(IOnDemandAnalysis analysis) {
+        if (fAnalysisWrappers.stream().anyMatch(wrapper -> wrapper.analysis.getName().equals(analysis.getName()))) {
+            Activator.logWarning(String.format("Ignoring external analysis with existing name \"%s\"", analysis.getName())); //$NON-NLS-1$
+            return;
+        }
+
         fAnalysisWrappers.add(new OndemandAnalysisWrapper(analysis));
+        analysisCache.invalidateAll();
     }
+
+    /**
+     * Unregisters an on-demand analysis from this manager.
+     *
+     * @param analysis On-demand analysis to unregister
+     */
+    public void unregisterAnalysis(IOnDemandAnalysis analysis) {
+        if (!analysis.isUserDefined()) {
+            Activator.logWarning(String.format("Not unregistering built-in on-demand analysis \"%s\"", analysis.getName())); //$NON-NLS-1$
+            return;
+        }
+
+        fAnalysisWrappers.remove(new OndemandAnalysisWrapper(analysis));
+        analysisCache.invalidateAll();
+    }
+
 }
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/icons/ovr16/built_in_ondemand_ovr.gif b/tmf/org.eclipse.tracecompass.tmf.ui/icons/ovr16/built_in_ondemand_ovr.gif
new file mode 100644 (file)
index 0000000..cd83b96
Binary files /dev/null and b/tmf/org.eclipse.tracecompass.tmf.ui/icons/ovr16/built_in_ondemand_ovr.gif differ
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/icons/ovr16/user_defined_ondemand_ovr.gif b/tmf/org.eclipse.tracecompass.tmf.ui/icons/ovr16/user_defined_ondemand_ovr.gif
new file mode 100644 (file)
index 0000000..a9af5d5
Binary files /dev/null and b/tmf/org.eclipse.tracecompass.tmf.ui/icons/ovr16/user_defined_ondemand_ovr.gif differ
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfBuiltInOnDemandAnalysisElement.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfBuiltInOnDemandAnalysisElement.java
new file mode 100644 (file)
index 0000000..4413d64
--- /dev/null
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Philippe Proulx
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.project.model;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.tracecompass.tmf.core.analysis.ondemand.IOnDemandAnalysis;
+
+/**
+ * Project element for built-in on-demand analysis.
+ *
+ * These cannot be deleted by the user.
+ *
+ * @author Philippe Proulx
+ * @since 2.0
+ */
+public class TmfBuiltInOnDemandAnalysisElement extends TmfOnDemandAnalysisElement {
+
+    /**
+     * Constructor
+     *
+     * @param analysisName
+     *            Name of the element
+     * @param resource
+     *            Workspace resource
+     * @param parent
+     *            Parent element, should be the "on-demand analyses" one
+     * @param analysis
+     *            The actual analysis represented by this element
+     */
+    protected TmfBuiltInOnDemandAnalysisElement(@NonNull String analysisName, @NonNull IResource resource, @NonNull TmfOnDemandAnalysesElement parent, @NonNull IOnDemandAnalysis analysis) {
+        super(analysisName, resource, parent, analysis);
+    }
+
+    @Override
+    public @NonNull Image getIcon() {
+        return TmfProjectModelIcons.BUILT_IN_ONDEMAND_ICON;
+    }
+
+}
index f1f1487027ec796bd1b15a63664cca570b8daaae..49b531f6e668aad39184ae8fa83f584cd8a462db 100644 (file)
@@ -11,6 +11,8 @@ package org.eclipse.tracecompass.tmf.ui.project.model;
 
 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Set;
 
 import org.eclipse.core.resources.IFolder;
@@ -42,8 +44,6 @@ public class TmfOnDemandAnalysesElement extends TmfProjectModelElement {
 
     private static final String ELEMENT_NAME = Messages.TmfOnDemandAnalysesElement_Name;
 
-    private boolean fInitialized = false;
-
     /**
      * Constructor
      *
@@ -75,24 +75,30 @@ public class TmfOnDemandAnalysesElement extends TmfProjectModelElement {
             return;
         }
 
-        /*
-         * The criteria for which analyses can apply to a trace should never
-         * change, so initialization only needs to be done once.
-         */
-        if (!fInitialized) {
-            Set<IOnDemandAnalysis> analyses =
-                    OnDemandAnalysisManager.getInstance().getOndemandAnalyses(trace);
-
-            IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
-            IPath nodePath = getResource().getFullPath();
-
-            analyses.forEach(analysis -> {
-                IFolder analysisRes = checkNotNull(root.getFolder(nodePath.append(analysis.getName())));
-                TmfOnDemandAnalysisElement elem = new TmfOnDemandAnalysisElement(
-                        analysis.getName(), analysisRes, this, analysis);
-                addChild(elem);
-            });
-        }
+        // Remove children first
+        List<ITmfProjectModelElement> children = new ArrayList<>(getChildren());
+        children.stream().forEach(elem -> {
+            removeChild(elem);
+        });
+
+        Set<IOnDemandAnalysis> analyses =
+                OnDemandAnalysisManager.getInstance().getOndemandAnalyses(trace);
+
+        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+        IPath nodePath = getResource().getFullPath();
+
+        analyses.forEach(analysis -> {
+            IFolder analysisRes = checkNotNull(root.getFolder(nodePath.append(analysis.getName())));
+            TmfOnDemandAnalysisElement elem;
+
+            if (analysis.isUserDefined()) {
+                elem = new TmfUserDefinedOnDemandAnalysisElement(analysis.getName(), analysisRes, this, analysis);
+            } else {
+                elem = new TmfBuiltInOnDemandAnalysisElement(analysis.getName(), analysisRes, this, analysis);
+            }
+
+            addChild(elem);
+        });
 
         /* Refresh all children */
         getChildren().forEach(child -> ((TmfProjectModelElement) child).refreshChildren());
index 49aeacd50aa0d06580f92162e98067601ca13d64..30b5ecbfa6c78016a08f962c21e92b99a3ccf940 100644 (file)
@@ -31,7 +31,7 @@ import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
  * @since 2.0
  */
 @NonNullByDefault
-public class TmfOnDemandAnalysisElement extends TmfProjectModelElement
+public abstract class TmfOnDemandAnalysisElement extends TmfProjectModelElement
         implements ITmfStyledProjectModelElement {
 
     /**
@@ -103,9 +103,7 @@ public class TmfOnDemandAnalysisElement extends TmfProjectModelElement
     }
 
     @Override
-    public Image getIcon() {
-        return TmfProjectModelIcons.DEFAULT_ANALYSIS_ICON;
-    }
+    public abstract Image getIcon();
 
     @Override
     protected void refreshChildren() {
index 7e2506543285075bfc989a062e19569d415d0dbd..16c0b42ea057d162c426ba1415a46efd058a3eab 100644 (file)
@@ -42,6 +42,8 @@ final class TmfProjectModelIcons {
     public static final @NonNull Image FOLDER_ICON;
     public static final @NonNull Image VIEWS_ICON;
     public static final @NonNull Image ONDEMAND_ANALYSES_ICON;
+    public static final @NonNull Image BUILT_IN_ONDEMAND_ICON;
+    public static final @NonNull Image USER_DEFINED_ONDEMAND_ICON;
     public static final @NonNull Image REPORTS_ICON;
 
     public static final WorkbenchLabelProvider WORKSPACE_LABEL_PROVIDER = new WorkbenchLabelProvider();
@@ -49,6 +51,8 @@ final class TmfProjectModelIcons {
     private static final String TRACE_ICON_FILE = "icons/elcl16/trace.gif"; //$NON-NLS-1$
     private static final String EXPERIMENT_ICON_FILE = "icons/elcl16/experiment.gif"; //$NON-NLS-1$
     private static final String ANALYSIS_ICON_FILE = "icons/ovr16/experiment_folder_ovr.png"; //$NON-NLS-1$
+    private static final String BUILT_IN_ONDEMAND_FILE = "icons/ovr16/built_in_ondemand_ovr.gif"; //$NON-NLS-1$
+    private static final String USER_DEFINED_ONDEMAND_FILE = "icons/ovr16/user_defined_ondemand_ovr.gif"; //$NON-NLS-1$
     private static final String VIEW_ICON_FILE = "icons/obj16/node_obj.gif"; //$NON-NLS-1$
     private static final String ONDEMAND_ANALYSES_ICON_FILE = "icons/obj16/debugt_obj.gif"; //$NON-NLS-1$
     private static final String REPORTS_ICON_FILE = "icons/obj16/arraypartition_obj.gif"; //$NON-NLS-1$
@@ -66,6 +70,8 @@ final class TmfProjectModelIcons {
         FOLDER_ICON = checkNotNull(sharedImages.getImage(ISharedImages.IMG_OBJ_FOLDER));
         ONDEMAND_ANALYSES_ICON = checkNotNull(loadIcon(bundle, ONDEMAND_ANALYSES_ICON_FILE));
         REPORTS_ICON = checkNotNull(loadIcon(bundle, REPORTS_ICON_FILE));
+        BUILT_IN_ONDEMAND_ICON = checkNotNull(loadIcon(bundle, BUILT_IN_ONDEMAND_FILE));
+        USER_DEFINED_ONDEMAND_ICON = checkNotNull(loadIcon(bundle, USER_DEFINED_ONDEMAND_FILE));
 
         DEFAULT_TRACE_ICON = checkNotNull(loadIcon(bundle, TRACE_ICON_FILE));
         DEFAULT_EXPERIMENT_ICON = checkNotNull(loadIcon(bundle, EXPERIMENT_ICON_FILE));
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfUserDefinedOnDemandAnalysisElement.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfUserDefinedOnDemandAnalysisElement.java
new file mode 100644 (file)
index 0000000..681a4d3
--- /dev/null
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Philippe Proulx
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.project.model;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.tracecompass.tmf.core.analysis.ondemand.IOnDemandAnalysis;
+
+/**
+ * User-defined on-demand analysis element.
+ *
+ * @author Philippe Proulx
+ * @since 2.0
+ */
+public class TmfUserDefinedOnDemandAnalysisElement extends TmfOnDemandAnalysisElement {
+
+    /**
+     * Constructor
+     *
+     * @param analysisName
+     *            Name of the element
+     * @param resource
+     *            Workspace resource
+     * @param parent
+     *            Parent element, should be the "on-demand analyses" one
+     * @param analysis
+     *            The actual analysis represented by this element
+     */
+    protected TmfUserDefinedOnDemandAnalysisElement(@NonNull String analysisName, @NonNull IResource resource, @NonNull TmfOnDemandAnalysesElement parent, @NonNull IOnDemandAnalysis analysis) {
+        super(analysisName, resource, parent, analysis);
+    }
+
+    @Override
+    public @NonNull Image getIcon() {
+        return TmfProjectModelIcons.USER_DEFINED_ONDEMAND_ICON;
+    }
+
+}
This page took 0.047556 seconds and 5 git commands to generate.