From: Alexandre Montplaisir Date: Fri, 7 Jul 2017 20:58:45 +0000 (-0400) Subject: tmf: Add Export Time Selection action and related interface X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=c9694d5488e99ef9412951697bd6516386696b4d;p=deliverable%2Ftracecompass.git tmf: Add Export Time Selection action and related interface 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 --- diff --git a/tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF b/tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF index 223d6acd78..a2de1cc15a 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF +++ b/tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF @@ -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 index 0000000000..49e723108e --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/trim/ITmfTrimmableTrace.java @@ -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 index 0000000000..1a20db2cad --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/trim/package-info.java @@ -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 diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/plugin.properties b/tmf/org.eclipse.tracecompass.tmf.ui/plugin.properties index 87930f5ea6..13a667853d 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/plugin.properties +++ b/tmf/org.eclipse.tracecompass.tmf.ui/plugin.properties @@ -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 diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/plugin.xml b/tmf/org.eclipse.tracecompass.tmf.ui/plugin.xml index c32715d9d8..582b8686eb 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/plugin.xml +++ b/tmf/org.eclipse.tracecompass.tmf.ui/plugin.xml @@ -756,6 +756,28 @@ + + + + + + + + + + + + @@ -1228,6 +1250,11 @@ id="org.eclipse.linuxtools.tmf.ui.command.clear_offset" name="%command.clear_offset"> + + @@ -1470,6 +1497,10 @@ + + diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/Messages.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/Messages.java index 0314b68990..e4915da6f6 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/Messages.java +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/Messages.java @@ -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 index 0000000000..73d0aeb88e --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/TrimTraceHandler.java @@ -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; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/messages.properties b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/messages.properties index 95ab3da1f3..17b36ed12d 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/messages.properties +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/messages.properties @@ -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 diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfOpenTraceHelper.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfOpenTraceHelper.java index cb644509be..cc19ff3af4 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfOpenTraceHelper.java +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/project/model/TmfOpenTraceHelper.java @@ -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);