ctf: Add "Stream intersection" UI action
authorAlexandre Montplaisir <alexmonthy@efficios.com>
Fri, 7 Jul 2017 20:59:31 +0000 (16:59 -0400)
committerAlexandre Montplaisir <alexmonthy@efficios.com>
Fri, 7 Jul 2017 21:00:39 +0000 (17:00 -0400)
This action only applies to CTF traces, so it is only
visible for CTF traces.

Change-Id: Ief16a7f17bf971831b77986dfe01c8d5e88ddfb8
Signed-off-by: Alexandre Montplaisir <alexmonthy@efficios.com>
ctf/org.eclipse.tracecompass.tmf.ctf.ui/META-INF/MANIFEST.MF
ctf/org.eclipse.tracecompass.tmf.ctf.ui/build.properties
ctf/org.eclipse.tracecompass.tmf.ctf.ui/plugin.properties
ctf/org.eclipse.tracecompass.tmf.ctf.ui/plugin.xml [new file with mode: 0644]
ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/CtfTmfTracePropertyTester.java [new file with mode: 0644]
ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/Messages.java [new file with mode: 0644]
ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/StreamIntersectionHandler.java [new file with mode: 0644]
ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/messages.properties [new file with mode: 0644]
ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/package-info.java [new file with mode: 0644]

index 8daa648cbff91a72fe2dcabc067c50d2f296adcb..161cec864e32ac9d19597d19a6daf0ea0a71e33a 100644 (file)
@@ -10,7 +10,16 @@ Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Require-Bundle: org.eclipse.osgi,
  org.eclipse.core.runtime,
+ org.eclipse.ui,
  org.eclipse.ui.workbench,
- org.eclipse.tracecompass.common.core
-Export-Package: org.eclipse.tracecompass.internal.tmf.ctf.ui;x-internal:=true
+ org.eclipse.tracecompass.common.core,
+ org.eclipse.core.commands,
+ org.eclipse.jface,
+ org.eclipse.tracecompass.tmf.ui,
+ org.eclipse.tracecompass.tmf.core,
+ org.eclipse.tracecompass.tmf.ctf.core,
+ org.eclipse.core.expressions
+Export-Package: org.eclipse.tracecompass.internal.tmf.ctf.ui;x-internal:=true,
+ org.eclipse.tracecompass.internal.tmf.ctf.ui.streamintersection;x-internal:=true
+Import-Package: com.google.common.collect
 
index 990345f93ba7350497da1e000562c0868663797f..32a02e552add1efe02e38b6a24ed0a7af42098e2 100644 (file)
@@ -12,7 +12,8 @@ output.. = bin/
 bin.includes = META-INF/,\
                .,\
                about.html,\
-               plugin.properties
+               plugin.properties,\
+               plugin.xml
 src.includes = about.html
 
 additional.bundles = org.eclipse.jdt.annotation
index dbaef1a36a9be426fbd83e402a8a56f1bd79d970..1bdb483103119d7f575337177a48461fbcae38dc 100644 (file)
@@ -13,3 +13,5 @@
 Bundle-Vendor = Eclipse Trace Compass
 Bundle-Name = CTF support for TMF UI Plug-in
 
+command.stream_intersection = Perform Stream Intersection...
+command.stream_intersection.description = Trim the trace to the time range intersecting all CTF streams
diff --git a/ctf/org.eclipse.tracecompass.tmf.ctf.ui/plugin.xml b/ctf/org.eclipse.tracecompass.tmf.ctf.ui/plugin.xml
new file mode 100644 (file)
index 0000000..6ccb9a2
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension
+         point="org.eclipse.ui.menus">
+      <menuContribution
+            locationURI="popup:org.eclipse.ui.popup.any?after=additions">
+         <command
+               commandId="org.eclipse.tracecompass.tmf.ctf.ui.command.stream_intersection"
+               label="%command.stream_intersection"
+               style="push"
+               tooltip="%command.stream_intersection.description">
+            <visibleWhen
+                  checkEnabled="false">
+               <with
+                     variable="selection">
+                  <and>
+                     <iterate>
+                        <instanceof
+                              value="org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement">
+                        </instanceof>
+                     </iterate>
+                     <iterate>
+                        <test
+                              forcePluginActivation="true"
+                              property="org.eclipse.tracecompass.tmf.ctf.ui.elementIsCtfTrace">
+                        </test>
+                     </iterate>
+                  </and>
+               </with>
+            </visibleWhen>
+         </command>
+      </menuContribution>
+   </extension>
+   <extension
+         point="org.eclipse.ui.commands">
+      <command
+            description="%command.stream_intersection.description"
+            id="org.eclipse.tracecompass.tmf.ctf.ui.command.stream_intersection"
+            name="%command.stream_intersection">
+      </command>
+   </extension>
+   <extension
+         point="org.eclipse.ui.handlers">
+      <handler
+            class="org.eclipse.tracecompass.internal.tmf.ctf.ui.streamintersection.StreamIntersectionHandler"
+            commandId="org.eclipse.tracecompass.tmf.ctf.ui.command.stream_intersection">
+      </handler>
+   </extension>
+   <extension
+         point="org.eclipse.core.expressions.propertyTesters">
+      <propertyTester
+            class="org.eclipse.tracecompass.internal.tmf.ctf.ui.streamintersection.CtfTmfTracePropertyTester"
+            id="org.eclipse.tracecompass.tmf.ctf.ui.elementIsCtfTraceTester"
+            namespace="org.eclipse.tracecompass.tmf.ctf.ui"
+            properties="elementIsCtfTrace"
+            type="org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement">
+      </propertyTester>
+   </extension>
+
+</plugin>
diff --git a/ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/CtfTmfTracePropertyTester.java b/ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/CtfTmfTracePropertyTester.java
new file mode 100644 (file)
index 0000000..a964e8c
--- /dev/null
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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.tmf.ctf.ui.streamintersection;
+
+import java.util.Set;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.tmf.ctf.core.trace.CtfTmfTrace;
+import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Property tester to check if a right-clicked trace element represents a CTF
+ * trace.
+ *
+ * @author Alexandre Montplaisir
+ */
+public class CtfTmfTracePropertyTester extends PropertyTester {
+
+    private static final String ELEMENT_IS_CTF_PROPERTY = "elementIsCtfTrace"; //$NON-NLS-1$
+
+    /**
+     * Known trace IDs of CTF traces.
+     *
+     * Not great to have to define this statically, but there doesn't seem to be
+     * a way to get the trace type class without the trace being necessarily
+     * opened.
+     */
+    private static final Set<String> MATCHING_TRACE_TYPES = ImmutableSet.of(
+            "org.eclipse.linuxtools.tmf.ui.type.ctf", //$NON-NLS-1$
+            "org.eclipse.linuxtools.lttng2.kernel.tracetype", //$NON-NLS-1$
+            "org.eclipse.linuxtools.lttng2.ust.tracetype"); //$NON-NLS-1$
+
+    @Override
+    public boolean test(@Nullable Object receiver, @Nullable String property,
+            Object @Nullable [] args, @Nullable Object expectedValue) {
+
+        if (ELEMENT_IS_CTF_PROPERTY.equals(property)
+                && receiver instanceof TmfTraceElement) {
+            TmfTraceElement traceElem = (TmfTraceElement) receiver;
+
+            /*
+             * If the trace is opened, check the trace class, it should catch
+             * all CTF traces.
+             */
+            if (traceElem.getTrace() instanceof CtfTmfTrace) {
+                return true;
+            }
+
+            /* If not, defer to checking the trace type among known ones. */
+            if (MATCHING_TRACE_TYPES.contains(traceElem.getTraceType())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+}
diff --git a/ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/Messages.java b/ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/Messages.java
new file mode 100644 (file)
index 0000000..41da613
--- /dev/null
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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.tmf.ctf.ui.streamintersection;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Package messages
+ *
+ * @author Alexandre Montplaisir
+ * @noreference Messages class
+ */
+@SuppressWarnings("javadoc")
+@NonNullByDefault({})
+public class Messages extends NLS {
+
+    private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
+
+    public static String StreamIntersection_JobName;
+    public static String StreamIntersection_DirectoryChooser_DialogTitle;
+    public static String StreamIntersection_InvalidDirectory_DialogTitle;
+    public static String StreamIntersection_InvalidDirectory_DialogText;
+    public static String StreamIntersection_NoWriteAccess_DialogText;
+
+    static {
+        NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+    }
+
+    private Messages() {
+    }
+}
diff --git a/ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/StreamIntersectionHandler.java b/ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/StreamIntersectionHandler.java
new file mode 100644 (file)
index 0000000..73f4268
--- /dev/null
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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.tmf.ctf.ui.streamintersection;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.ctf.core.trace.CtfTmfTrace;
+import org.eclipse.tracecompass.tmf.ui.project.handlers.HandlerUtils;
+import org.eclipse.tracecompass.tmf.ui.project.model.TmfOpenTraceHelper;
+import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement;
+import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement;
+import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder;
+import org.eclipse.tracecompass.tmf.ui.project.model.TraceUtils;
+import org.eclipse.tracecompass.tmf.ui.project.operations.TmfWorkspaceModifyOperation;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Handler for the "Stream Intersection" action for CTF traces.
+ *
+ * @author Alexandre Montplaisir
+ */
+public class StreamIntersectionHandler extends AbstractHandler {
+
+    /**
+     * Suffix for new traces with stream intersection, added to the original
+     * trace name.
+     */
+    private static final String TRACE_NAME_SUFFIX = "-stream-intersect"; //$NON-NLS-1$
+
+    @Override
+    public boolean isEnabled() {
+        final Object element = HandlerUtils.getSelectedModelElement();
+        if (element == null) {
+            return false;
+        }
+
+        /*
+         * Only available for CTF (ctf.tmf) traces.
+         *
+         * plugin.xml should have done element type/count verification already.
+         */
+        TmfTraceElement traceElem = (TmfTraceElement) element;
+        return (traceElem.getTrace() instanceof CtfTmfTrace);
+    }
+
+    @Override
+    public @Nullable Object execute(@Nullable ExecutionEvent event) throws ExecutionException {
+        ISelection selection = HandlerUtil.getCurrentSelectionChecked(event);
+        Object element = ((IStructuredSelection) selection).getFirstElement();
+        final TmfTraceElement traceElem = (TmfTraceElement) element;
+
+        ITmfTrace trace = traceElem.getTrace();
+        if (trace == null) {
+            /* That trace is not currently opened */
+            return null;
+        }
+        /* plugin.xml should have already verified the trace type */
+        CtfTmfTrace ctfTmfTrace = (CtfTmfTrace) trace;
+
+        /*
+         * Pop a dialog asking the user to select a parent directory for the new
+         * trace.
+         */
+        final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+        DirectoryDialog dialog = new DirectoryDialog(shell);
+        dialog.setText(Messages.StreamIntersection_DirectoryChooser_DialogTitle);
+        String result = dialog.open();
+        if (result == null) {
+            /* Dialog was cancelled, take no further action. */
+            return null;
+        }
+
+        /* Verify that the selected path is valid and writeable */
+        final Path parentPath = checkNotNull(Paths.get(result));
+        if (!Files.isDirectory(parentPath)) {
+            MessageDialog.openError(shell, Messages.StreamIntersection_InvalidDirectory_DialogTitle, Messages.StreamIntersection_InvalidDirectory_DialogText);
+            return null;
+        }
+        if (!Files.isWritable(parentPath)) {
+            MessageDialog.openError(shell, Messages.StreamIntersection_InvalidDirectory_DialogTitle, Messages.StreamIntersection_NoWriteAccess_DialogText);
+            return null;
+        }
+
+        /*
+         * Create a directory for the new trace. We will pick the next available
+         * name, adding -2, -3, etc. as needed.
+         */
+        String newTraceName = trace.getName() + TRACE_NAME_SUFFIX;
+        Path potentialPath = parentPath.resolve(newTraceName);
+        for (int i = 2; Files.exists(potentialPath); i++) {
+            newTraceName = trace.getName() + TRACE_NAME_SUFFIX + '-' + String.valueOf(i);
+            potentialPath = parentPath.resolve(newTraceName);
+        }
+
+        final Path tracePath = checkNotNull(potentialPath);
+        try {
+            Files.createDirectory(tracePath);
+        } catch (IOException e) {
+            /* Should not happen since we have checked permissions, etc. */
+            throw new IllegalStateException(e);
+        }
+
+        TmfWorkspaceModifyOperation streamIntersectionOperation = new TmfWorkspaceModifyOperation() {
+            @Override
+            public void execute(@Nullable IProgressMonitor monitor) throws CoreException {
+                IProgressMonitor mon = (monitor == null ? new NullProgressMonitor() : monitor);
+
+                ctfTmfTrace.streamIntersection(tracePath, mon);
+
+                /* Import the new trace into the current project. */
+                TmfProjectElement currentProjectElement = traceElem.getProject();
+                TmfTraceFolder traceFolder = currentProjectElement.getTracesFolder();
+                TmfOpenTraceHelper.openTraceFromPath(traceFolder, tracePath.toString(), shell);
+            }
+        };
+
+        try {
+            PlatformUI.getWorkbench().getProgressService().run(true, true, streamIntersectionOperation);
+        } catch (InterruptedException e) {
+            return null;
+        } catch (InvocationTargetException e) {
+            TraceUtils.displayErrorMsg(e.toString(), e.getTargetException().toString());
+            return null;
+        }
+
+        return null;
+    }
+
+}
diff --git a/ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/messages.properties b/ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/messages.properties
new file mode 100644 (file)
index 0000000..02b6b0f
--- /dev/null
@@ -0,0 +1,14 @@
+###############################################################################
+# Copyright (c) 2016 EfficiOS Inc. and others
+#
+# 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
+###############################################################################
+
+StreamIntersection_JobName = Performing stream intersection
+StreamIntersection_DirectoryChooser_DialogTitle = Choose a parent directory for the new trace
+StreamIntersection_InvalidDirectory_DialogTitle = Invalid directory
+StreamIntersection_InvalidDirectory_DialogText = Selected directory is invalid
+StreamIntersection_NoWriteAccess_DialogText = No write access to the selected directory
diff --git a/ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/package-info.java b/ctf/org.eclipse.tracecompass.tmf.ctf.ui/src/org/eclipse/tracecompass/internal/tmf/ctf/ui/streamintersection/package-info.java
new file mode 100644 (file)
index 0000000..1d68217
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc.
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.tmf.ctf.ui.streamintersection;
\ No newline at end of file
This page took 0.031228 seconds and 5 git commands to generate.