tmf: Add Export Time Selection action and related interface
authorAlexandre Montplaisir <alexmonthy@efficios.com>
Fri, 7 Jul 2017 20:58:45 +0000 (16:58 -0400)
committerAlexandre Montplaisir <alexmonthy@efficios.com>
Fri, 7 Jul 2017 20:58:45 +0000 (16:58 -0400)
Traces implementing the new ITmfTrimmableTrace interface should provide
the "Export Time Selection" action, which will prompt the user for a
directory, and trim the trace (using the current selected time range) and
save the new cut trace in said directory.

The implementation of the trim operation itself is trace-type specific.

Change-Id: I02440b49dc7b84465f4ce02ecacc2604bbb90946
Signed-off-by: Alexandre Montplaisir <alexmonthy@efficios.com>
tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/trim/ITmfTrimmableTrace.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/trim/package-info.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/plugin.properties
tmf/org.eclipse.tracecompass.tmf.ui/plugin.xml
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/Messages.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/TrimTraceHandler.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/messages.properties
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfOpenTraceHelper.java

index 223d6acd78c504bc5656e73c15e748ba2ba6dbba..a2de1cc15a33209616043cc2507bad742127a315 100644 (file)
@@ -61,6 +61,7 @@ Export-Package: org.eclipse.tracecompass.internal.tmf.core;x-friends:="org.eclip
  org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint,
  org.eclipse.tracecompass.tmf.core.trace.location,
  org.eclipse.tracecompass.tmf.core.trace.text,
+ org.eclipse.tracecompass.tmf.core.trace.trim,
  org.eclipse.tracecompass.tmf.core.uml2sd,
  org.eclipse.tracecompass.tmf.core.util
 Import-Package: com.google.common.annotations,
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/trim/ITmfTrimmableTrace.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/trim/ITmfTrimmableTrace.java
new file mode 100644 (file)
index 0000000..49e7231
--- /dev/null
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * 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.tmf.core.trace.trim;
+
+import java.nio.file.Path;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+
+/**
+ * Interface to augment {@link org.eclipse.tracecompass.tmf.core.trace.ITmfTrace}
+ * implementations that offer trimming capabilities. This means creating a copy
+ * of the trace that contains only the events in a given time range.
+ *
+ * @author Alexandre Montplaisir
+ * @since 2.3
+ */
+public interface ITmfTrimmableTrace {
+
+    /**
+     * Perform trim operation on the current trace, keeping only the area
+     * overlapping the passed time range. The new trace will be created in the
+     * destination path.
+     *
+     * @param range
+     *            The time range outside of which to trim. Will be clamped to
+     *            the original trace's own time range.
+     * @param destinationPath
+     *            The location where the new trace will be created.
+     * @param monitor
+     *            Progress monitor for cases where the operation is ran from
+     *            inside a Job. You can use a
+     *            {@link org.eclipse.core.runtime.NullProgressMonitor} if none
+     *            is available.
+     * @throws CoreException
+     *             Optional exception indicating an error during the execution
+     *             of the operation. Will be reported to the user inside an
+     *             error dialog.
+     */
+    void trim(TmfTimeRange range, Path destinationPath, IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/trim/package-info.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/trim/package-info.java
new file mode 100644 (file)
index 0000000..1a20db2
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.tmf.core.trace.trim;
\ No newline at end of file
index 87930f5ea65fbbaf396bd2b32399c77247c831fa..13a667853dd5dd5374ada1d5cd5fcd0d19420daf 100644 (file)
@@ -169,6 +169,10 @@ command.new_experiment = New...
 command.new_experiment.mnemonic = N
 command.new_experiment.description = Create Tracing Experiment
 
+command.trim_trace = Export Time Selection as New Trace...
+command.trim_trace.mnemonic = 
+command.trim_trace.description = Create a new trace containing only the events in the currently selected time range. Only available if the trace type supports it, and if a time range is selected.
+
 command.export_trace_package = Export Trace Package...
 command.export_trace_package.mnemonic = E
 command.export_trace_package.description = Export a Trace Package
index c32715d9d88d8775f56a80fdb7653612850016aa..582b8686eb3dd61620370d60bfced9b9b9e6f672 100644 (file)
               </with>
            </visibleWhen>
         </command>
+         <command
+               commandId="org.eclipse.tracecompass.tmf.ui.command.trim_trace"
+               label="%command.trim_trace"
+               mnemonic="%command.trim_trace.mnemonic"
+               style="push"
+               tooltip="%command.trim_trace.description">
+            <visibleWhen
+                  checkEnabled="false">
+               <and>
+                  <count
+                        value="1">
+                  </count>
+                  <iterate
+                        ifEmpty="false"
+                        operator="or">
+                     <instanceof
+                           value="org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement">
+                     </instanceof>
+                  </iterate>
+               </and>
+            </visibleWhen>
+         </command>
          <separator
                name="org.eclipse.linuxtools.tmf.ui.separator3"
                visible="true">
             id="org.eclipse.linuxtools.tmf.ui.command.clear_offset"
             name="%command.clear_offset">
       </command>
+      <command
+            description="%command.trim_trace.description"
+            id="org.eclipse.tracecompass.tmf.ui.command.trim_trace"
+            name="%command.trim_trace">
+      </command>
    </extension>
    <extension
          point="org.eclipse.ui.handlers">
             </iterate>
          </activeWhen>
       </handler>
+      <handler
+            class="org.eclipse.tracecompass.internal.tmf.ui.project.handlers.TrimTraceHandler"
+            commandId="org.eclipse.tracecompass.tmf.ui.command.trim_trace">
+      </handler>
       <handler
             class="org.eclipse.tracecompass.internal.tmf.ui.project.handlers.NewFolderHandler"
             commandId="org.eclipse.linuxtools.tmf.ui.command.new_folder">
index 0314b68990bb5af213fe3f0140cd7af0d29d856d..e4915da6f6cb6c11b4bc7f7c2a58282051528b33 100644 (file)
@@ -71,6 +71,14 @@ public class Messages extends NLS {
     public static String DeleteSupplementaryFiles_DeletionTask;
     public static String DeleteSupplementaryFiles_ProjectRefreshTask;
 
+    public static String TrimTraces_JobName;
+    public static String TrimTraces_DirectoryChooser_DialogTitle;
+    public static String TrimTraces_InvalidTimeRange_DialogTitle;
+    public static String TrimTraces_InvalidTimeRange_DialogText;
+    public static String TrimTraces_InvalidDirectory_DialogTitle;
+    public static String TrimTraces_InvalidDirectory_DialogText;
+    public static String TrimTraces_NoWriteAccess_DialogText;
+
     public static String AnalysisModule_Help;
 
     public static String TmfActionProvider_OpenWith;
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/TrimTraceHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/TrimTraceHandler.java
new file mode 100644 (file)
index 0000000..73d0aeb
--- /dev/null
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * 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.ui.project.handlers;
+
+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.NonNullByDefault;
+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.internal.tmf.ui.project.operations.TmfWorkspaceModifyOperation;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.core.trace.trim.ITmfTrimmableTrace;
+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.ui.PlatformUI;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Handler for the Trace Trim operation.
+ *
+ * @author Alexandre Montplaisir
+ */
+@NonNullByDefault
+public class TrimTraceHandler extends AbstractHandler {
+
+    /** Suffix for new trimmed traces, added to the original trace name */
+    private static final String TRACE_NAME_SUFFIX = "-trimmed"; //$NON-NLS-1$
+
+    @Override
+    public boolean isEnabled() {
+        final Object element = HandlerUtils.getSelectedModelElement();
+        if (element == null) {
+            return false;
+        }
+
+        /*
+         * plugin.xml should have done type/count verification already
+         */
+        TmfTraceElement traceElem = (TmfTraceElement) element;
+        if (!(traceElem.getTrace() instanceof ITmfTrimmableTrace)) {
+            return false;
+        }
+
+        /* Only enable the action if a time range is currently selected */
+        TmfTraceManager tm = TmfTraceManager.getInstance();
+        TmfTimeRange selectionRange = tm.getCurrentTraceContext().getSelectionRange();
+        if (selectionRange.getStartTime().equals(selectionRange.getEndTime())) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @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;
+        }
+        ITmfTrimmableTrace trimmableTrace = (ITmfTrimmableTrace) trace;
+
+
+        /* Retrieve the current time range */
+        final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+        TmfTraceManager tm = TmfTraceManager.getInstance();
+        TmfTimeRange timeRange = tm.getCurrentTraceContext().getSelectionRange();
+        if (timeRange.getStartTime().equals(timeRange.getEndTime())) {
+            MessageDialog.openError(shell, Messages.TrimTraces_InvalidTimeRange_DialogTitle, Messages.TrimTraces_InvalidTimeRange_DialogText);
+            return null;
+        }
+
+        /* Ensure the time range is in the right direction */
+        final TmfTimeRange tr = ((timeRange.getStartTime().compareTo(timeRange.getEndTime()) > 0) ?
+                new TmfTimeRange(timeRange.getEndTime(), timeRange.getStartTime()) :
+                    timeRange);
+
+        /*
+         * Pop a dialog asking the user to select a parent directory for the new
+         * trace.
+         */
+        DirectoryDialog dialog = new DirectoryDialog(shell);
+        dialog.setText(Messages.TrimTraces_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.TrimTraces_InvalidDirectory_DialogTitle, Messages.TrimTraces_InvalidDirectory_DialogText);
+            return null;
+        }
+        if (!Files.isWritable(parentPath)) {
+            MessageDialog.openError(shell, Messages.TrimTraces_InvalidDirectory_DialogTitle, Messages.TrimTraces_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 trimOperation = new TmfWorkspaceModifyOperation() {
+            @Override
+            public void execute(@Nullable IProgressMonitor monitor) throws CoreException {
+                IProgressMonitor mon = (monitor == null ? new NullProgressMonitor() : monitor);
+
+                /* Perform the trace-specific trim operation. */
+                trimmableTrace.trim(tr, tracePath, mon);
+
+                /* Import the new trace into the current project, at the top-level. */
+                TmfProjectElement currentProjectElement = traceElem.getProject();
+                TmfTraceFolder traceFolder =currentProjectElement.getTracesFolder();
+                TmfOpenTraceHelper.openTraceFromPath(traceFolder, tracePath.toString(), shell);
+            }
+        };
+
+        try {
+            PlatformUI.getWorkbench().getProgressService().run(true, true, trimOperation);
+        } catch (InterruptedException e) {
+            return null;
+        } catch (InvocationTargetException e) {
+            TraceUtils.displayErrorMsg(e.toString(), e.getTargetException().toString());
+            return null;
+        }
+
+        return null;
+    }
+
+}
index 95ab3da1f38218408c548e4dac598756f9aca120..17b36ed12d584a037dcbee9dfa2579bf9fb20bd7 100644 (file)
@@ -62,6 +62,14 @@ ClearTraceOffsetHandler_ConfirmMessage=Are you sure you want to clear the time o
 DeleteSupplementaryFiles_DeletionTask=Deleting supplementary files for {0}
 DeleteSupplementaryFiles_ProjectRefreshTask=Refreshing project {0}
 
+# Trim traces
+TrimTraces_JobName = Performing trace trimming
+TrimTraces_DirectoryChooser_DialogTitle = Choose a parent directory for the new trace
+TrimTraces_InvalidTimeRange_DialogTitle = Error retrieving time range
+TrimTraces_InvalidTimeRange_DialogText = Trace trimming makes use of the current's trace active selection. Please select a valid time range.
+TrimTraces_InvalidDirectory_DialogTitle = Invalid directory
+TrimTraces_InvalidDirectory_DialogText = Selected directory is invalid
+TrimTraces_NoWriteAccess_DialogText = No write access to the selected directory
 
 # Analysis modules
 AnalysisModule_Help=Help
index cb644509be9ec93d8f5e1429cb85c87c606cdf40..cc19ff3af4419656132e1035d9d09b5dc0322c00 100644 (file)
@@ -51,6 +51,7 @@ import org.eclipse.ui.IEditorReference;
 import org.eclipse.ui.IReusableEditor;
 import org.eclipse.ui.IWorkbench;
 import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.ide.IDE;
@@ -339,7 +340,11 @@ public class TmfOpenTraceHelper {
         }
 
         final IWorkbench wb = PlatformUI.getWorkbench();
-        final IWorkbenchPage activePage = wb.getActiveWorkbenchWindow().getActivePage();
+        IWorkbenchWindow window = wb.getActiveWorkbenchWindow();
+        if (window == null) {
+            return;
+        }
+        final IWorkbenchPage activePage = window.getActivePage();
         final IEditorPart editor = findEditor(new FileEditorInput(file), true);
         if (editor != null) {
             activePage.activate(editor);
This page took 0.029922 seconds and 5 git commands to generate.