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
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
--- /dev/null
+/*******************************************************************************
+ * 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);
+ }
+
+}
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
+++ /dev/null
-/*******************************************************************************
- * 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;
- }
-
-}
--- /dev/null
+/*******************************************************************************
+ * 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
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
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
</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">
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ };
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
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
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
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;
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;
@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;
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
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;
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$
}
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;
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;
}
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;
}
}
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);
}
}
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());
+ }
}
/**
/**
* 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();
+ }
+
}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
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;
private static final String ELEMENT_NAME = Messages.TmfOnDemandAnalysesElement_Name;
- private boolean fInitialized = false;
-
/**
* Constructor
*
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());
* @since 2.0
*/
@NonNullByDefault
-public class TmfOnDemandAnalysisElement extends TmfProjectModelElement
+public abstract class TmfOnDemandAnalysisElement extends TmfProjectModelElement
implements ITmfStyledProjectModelElement {
/**
}
@Override
- public Image getIcon() {
- return TmfProjectModelIcons.DEFAULT_ANALYSIS_ICON;
- }
+ public abstract Image getIcon();
@Override
protected void refreshChildren() {
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();
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$
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));
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}