diff options
Diffstat (limited to 'tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project')
83 files changed, 16145 insertions, 0 deletions
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/Messages.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/Messages.java new file mode 100644 index 0000000000..c980279d28 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/Messages.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2011, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + * Marc-Andre Laperle - Add select/deselect all + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.dialogs; + +import org.eclipse.osgi.util.NLS; + +/** + * Message bundle for dialog messages. + */ +@SuppressWarnings("javadoc") +public class Messages extends NLS { + + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.tmf.ui.project.dialogs.messages"; //$NON-NLS-1$ + + public static String SelectSpplementaryResources_DialogTitle; + public static String SelectSpplementaryResources_ResourcesGroupTitle; + public static String Dialog_SelectAll; + public static String Dialog_DeselectAll; + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/SelectSupplementaryResourcesDialog.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/SelectSupplementaryResourcesDialog.java new file mode 100644 index 0000000000..f63145aeaa --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/SelectSupplementaryResourcesDialog.java @@ -0,0 +1,324 @@ +/******************************************************************************* + * Copyright (c) 2009, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Copied and adapted from NewFolderDialog + * Marc-Andre Laperle - Add select/deselect all + * Patrick Tasse - Add support for folder elements + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.dialogs; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map.Entry; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfCommonProjectElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; + +import com.google.common.collect.Multimap; + +/** + * SelectSupplementaryResourcesDialog + */ +public class SelectSupplementaryResourcesDialog extends Dialog { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + private static final Image EXPERIMENT_IMAGE = Activator.getDefault().getImageFromPath("icons/elcl16/experiment.gif"); //$NON-NLS-1$ + private static final Image TRACE_IMAGE = Activator.getDefault().getImageFromPath("icons/elcl16/trace.gif"); //$NON-NLS-1$ + private static final Image RESOURCE_IMAGE = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FILE); + + // ------------------------------------------------------------------------ + // Members + // ------------------------------------------------------------------------ + private CheckboxTreeViewer fTreeViewer; + private final Multimap<TmfCommonProjectElement, IResource> fResourceMap; + private IResource[] fReturnedResources; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructor. + * + * @param shell + * Parent shell of this dialog + * @param resourceMap + * Map of element to supplementary resources + */ + public SelectSupplementaryResourcesDialog(Shell shell, Multimap<TmfCommonProjectElement, IResource> resourceMap) { + super(shell); + fResourceMap = resourceMap; + setShellStyle(SWT.RESIZE | getShellStyle()); + } + + // ------------------------------------------------------------------------ + // Getters/Setters + // ------------------------------------------------------------------------ + + /** + * @return A copy of the selected resources + */ + public IResource[] getResources() { + return Arrays.copyOf(fReturnedResources, fReturnedResources.length); + } + + // ------------------------------------------------------------------------ + // Dialog + // ------------------------------------------------------------------------ + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText(Messages.SelectSpplementaryResources_DialogTitle); + newShell.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_ETOOL_DELETE)); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + composite.setLayout(new GridLayout()); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + + Group contextGroup = new Group(composite, SWT.SHADOW_NONE); + contextGroup.setText(Messages.SelectSpplementaryResources_ResourcesGroupTitle); + contextGroup.setLayout(new GridLayout(2, false)); + contextGroup.setLayoutData(new GridData(GridData.FILL_BOTH)); + + fTreeViewer = new CheckboxTreeViewer(contextGroup, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); + GridData data = new GridData(GridData.FILL_BOTH); + Tree tree = fTreeViewer.getTree(); + tree.setLayoutData(data); + fTreeViewer.setContentProvider(new ITreeContentProvider() { + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + @Override + public void dispose() { + } + + @Override + public boolean hasChildren(Object element) { + return element instanceof TmfCommonProjectElement; + } + + @Override + public Object getParent(Object element) { + if (element instanceof IResource) { + getParentElement((IResource) element); + } + return null; + } + + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof Object[]) { + return (Object[]) inputElement; + } + return null; + } + + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof TmfCommonProjectElement) { + return fResourceMap.get((TmfCommonProjectElement) parentElement).toArray(); + } + return null; + } + }); + + fTreeViewer.setLabelProvider(new LabelProvider() { + @Override + public String getText(Object element) { + if (element instanceof IResource) { + IResource resource = (IResource) element; + TmfCommonProjectElement projectElement = getParentElement(resource); + // remove .tracing/<supplementary folder> segments + IPath suppFolderPath = projectElement.getTraceSupplementaryFolder(projectElement.getElementPath()).getFullPath(); + return resource.getFullPath().removeFirstSegments(suppFolderPath.segmentCount()).toString(); + } else if (element instanceof TmfCommonProjectElement) { + TmfCommonProjectElement projectElement = (TmfCommonProjectElement) element; + return projectElement.getElementPath(); + } + return super.getText(element); + } + + @Override + public Image getImage(Object element) { + if (element instanceof IResource) { + return RESOURCE_IMAGE; + } else if (element instanceof TmfTraceElement) { + return TRACE_IMAGE; + } else if (element instanceof TmfExperimentElement) { + return EXPERIMENT_IMAGE; + } + return null; + } + + }); + + fTreeViewer.setInput(fResourceMap.keySet().toArray()); + + fTreeViewer.expandAll(); + setAllChecked(true); + + fTreeViewer.addCheckStateListener(new ICheckStateListener() { + @Override + public void checkStateChanged(CheckStateChangedEvent event) { + if (event.getElement() instanceof TmfCommonProjectElement) { + fTreeViewer.setSubtreeChecked(event.getElement(), event.getChecked()); + fTreeViewer.setGrayed(event.getElement(), false); + } else if (event.getElement() instanceof IResource) { + TmfCommonProjectElement projectElement = getParentElement((IResource) event.getElement()); + int checkedCount = 0; + Collection<IResource> resources = fResourceMap.get(projectElement); + for (IResource resource : resources) { + if (fTreeViewer.getChecked(resource)) { + checkedCount++; + } + } + if (checkedCount == resources.size()) { + fTreeViewer.setChecked(projectElement, true); + fTreeViewer.setGrayed(projectElement, false); + } else if (checkedCount > 0) { + fTreeViewer.setGrayChecked(projectElement, true); + } else { + fTreeViewer.setGrayChecked(projectElement, false); + } + } + } + }); + + fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + updateOKButtonEnablement(); + } + }); + + Composite btComp = new Composite(contextGroup, SWT.NONE); + FillLayout layout = new FillLayout(SWT.VERTICAL); + layout.spacing = 4; + btComp.setLayout(layout); + + GridData gd = new GridData(); + gd.verticalAlignment = SWT.CENTER; + btComp.setLayoutData(gd); + + final Button selectAll = new Button(btComp, SWT.PUSH); + selectAll.setText(Messages.Dialog_SelectAll); + selectAll.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setAllChecked(true); + + updateOKButtonEnablement(); + } + }); + + final Button deselectAll = new Button(btComp, SWT.PUSH); + deselectAll.setText(Messages.Dialog_DeselectAll); + deselectAll.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setAllChecked(false); + + updateOKButtonEnablement(); + } + }); + + getShell().setMinimumSize(new Point(300, 150)); + + return composite; + } + + private TmfCommonProjectElement getParentElement(IResource resource) { + for (Entry<TmfCommonProjectElement, IResource> entry : fResourceMap.entries()) { + if (entry.getValue().equals(resource)) { + return entry.getKey(); + } + } + return null; + } + + private void setAllChecked(boolean state) { + for (Object element : fResourceMap.keySet()) { + fTreeViewer.setSubtreeChecked(element, state); + fTreeViewer.setGrayed(element, false); + } + } + + private void updateOKButtonEnablement() { + Object[] checked = fTreeViewer.getCheckedElements(); + getButton(IDialogConstants.OK_ID).setEnabled(checked.length > 0); + } + + @Override + protected Control createButtonBar(Composite parent) { + Control control = super.createButtonBar(parent); + updateOKButtonEnablement(); + return control; + } + + @Override + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, true); + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + } + + @Override + protected void okPressed() { + Object[] checkedElements = fTreeViewer.getCheckedElements(); + List<IResource> checkedResources = new ArrayList<>(checkedElements.length); + for (Object checked : checkedElements) { + if (checked instanceof IResource) { + checkedResources.add((IResource) checked); + } + } + fReturnedResources = checkedResources.toArray(new IResource[0]); + super.okPressed(); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/messages.properties b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/messages.properties new file mode 100644 index 0000000000..e90050cfa8 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/messages.properties @@ -0,0 +1,16 @@ +############################################################################### +# Copyright (c) 2012, 2014 Ericsson +# +# 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 +# +# Contributors: +# Bernd Hufmann - initial API and implementation +# Marc-Andre Laperle - Add select/deselect all +############################################################################### +SelectSpplementaryResources_DialogTitle=Delete Resources +SelectSpplementaryResources_ResourcesGroupTitle=Select resources to delete +Dialog_SelectAll=Select All +Dialog_DeselectAll=Deselect All
\ No newline at end of file diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/offset/Messages.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/offset/Messages.java new file mode 100644 index 0000000000..30adffd89d --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/offset/Messages.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + * Patrick Tasse - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.dialogs.offset; + +import org.eclipse.osgi.util.NLS; + +/** + * Messages for the offset dialog + */ +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.tmf.ui.project.dialogs.offset.messages"; //$NON-NLS-1$ + + /** + * Advanced mode button + */ + public static String OffsetDialog_AdvancedButton; + /** + * Advanced mode dialog message + */ + public static String OffsetDialog_AdvancedMessage; + /** + * Basic mode button + */ + public static String OffsetDialog_BasicButton; + /** + * Basic mode dialog message + */ + public static String OffsetDialog_BasicMessage; + /** + * Offset time + */ + public static String OffsetDialog_OffsetTime; + /** + * Reference time + */ + public static String OffsetDialog_ReferenceTime; + /** + * Target time + */ + public static String OffsetDialog_TargetTime; + /** + * Dialog title + */ + public static String OffsetDialog_Title; + /** + * Trace name + */ + public static String OffsetDialog_TraceName; + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/offset/OffsetDialog.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/offset/OffsetDialog.java new file mode 100644 index 0000000000..7246c2d37c --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/offset/OffsetDialog.java @@ -0,0 +1,578 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + * Patrick Tasse - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.dialogs.offset; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.ColumnViewer; +import org.eclipse.jface.viewers.ColumnViewerEditor; +import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; +import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.jface.viewers.TreeViewerColumn; +import org.eclipse.jface.viewers.TreeViewerEditor; +import org.eclipse.jface.viewers.TreeViewerFocusCellManager; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.TreeEditor; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.tracecompass.tmf.core.signal.TmfEventSelectedSignal; +import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; +import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager; +import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal; +import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; +import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp; +import org.eclipse.tracecompass.tmf.core.timestamp.TmfNanoTimestamp; +import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfOpenTraceHelper; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.tracecompass.tmf.ui.viewers.ArrayTreeContentProvider; +import org.eclipse.ui.dialogs.FilteredTree; +import org.eclipse.ui.dialogs.PatternFilter; + +/** + * Offset wizard dialog + * + * @author Matthew Khouzam + * + */ +public class OffsetDialog extends Dialog { + + private static final int TREE_EDITOR_MIN_WIDTH = 50; + private static final String EDITOR_KEY = "$editor$"; //$NON-NLS-1$ + private static final String WIDTH_KEY = "$width$"; //$NON-NLS-1$ + + private static final TmfTimestampFormat TIME_FORMAT = new TmfTimestampFormat("yyyy-MM-dd HH:mm:ss.SSS SSS SSS"); //$NON-NLS-1$ + private static final TmfTimestampFormat OFFSET_FORMAT = new TmfTimestampFormat("T.SSS SSS SSS"); //$NON-NLS-1$ + + private final Map<TmfTraceElement, Long> fOffsetMap; + private final Map<TmfTraceElement, ITmfTimestamp> fRefTimeMap; + private final Map<TmfTraceElement, ITmfTimestamp> fTargetTimeMap; + + private Label fBasicMessageLabel; + private Group fButtonGroup; + private Label fAdvancedMessageLabel; + private FilteredTree fViewer; + + private boolean fAdvancedMode = true; + private TreeViewerColumn fButtonViewerColumn; + private TreeColumn fRefTimeColumn; + private TreeColumn fTargetTimeColumn; + + private abstract class ColumnEditingSupport extends EditingSupport { + private final TextCellEditor textCellEditor; + + private ColumnEditingSupport(ColumnViewer viewer, TextCellEditor textCellEditor) { + super(viewer); + this.textCellEditor = textCellEditor; + } + + @Override + protected CellEditor getCellEditor(Object element) { + return textCellEditor; + } + + @Override + protected boolean canEdit(Object element) { + return true; + } + } + + private class TimeEditingSupport extends ColumnEditingSupport { + private Map<TmfTraceElement, ITmfTimestamp> map; + + private TimeEditingSupport(ColumnViewer viewer, TextCellEditor textCellEditor, Map<TmfTraceElement, ITmfTimestamp> map) { + super(viewer, textCellEditor); + this.map = map; + } + + @Override + protected void setValue(Object element, Object value) { + if (value instanceof String) { + String string = (String) value; + if (string.trim().isEmpty()) { + map.remove(element); + } else { + try { + ITmfTimestamp refTime = map.get(element); + long ref = refTime == null ? 0 : refTime.normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue(); + Long newVal = TIME_FORMAT.parseValue(string, ref); + map.put((TmfTraceElement) element, new TmfNanoTimestamp(newVal)); + } catch (ParseException e) { + /* Ignore and reload previous value */ + } + } + fViewer.getViewer().update(element, null); + } + } + + @Override + protected Object getValue(Object element) { + if (map.get(element) == null) { + return ""; //$NON-NLS-1$ + } + return TIME_FORMAT.format(map.get(element).normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue()); + } + } + + private class RefTimeEditingSupport extends TimeEditingSupport { + private RefTimeEditingSupport(ColumnViewer viewer, TextCellEditor textCellEditor) { + super(viewer, textCellEditor, fRefTimeMap); + } + } + + private class TargetTimeEditingSupport extends TimeEditingSupport { + private TargetTimeEditingSupport(ColumnViewer viewer, TextCellEditor textCellEditor) { + super(viewer, textCellEditor, fTargetTimeMap); + } + } + + private class OffsetEditingSupport extends ColumnEditingSupport { + private OffsetEditingSupport(ColumnViewer viewer, TextCellEditor textCellEditor) { + super(viewer, textCellEditor); + } + + @Override + protected void setValue(Object element, Object value) { + if (value instanceof String) { + String string = (String) value; + if (string.trim().isEmpty()) { + fOffsetMap.put((TmfTraceElement) element, 0L); + } else { + try { + Long newVal = OFFSET_FORMAT.parseValue(string); + fOffsetMap.put((TmfTraceElement) element, newVal); + } catch (ParseException e) { + /* Ignore and reload previous value */ + } + } + fViewer.getViewer().update(element, null); + } + } + + @Override + protected Object getValue(Object element) { + if (fOffsetMap.get(element) == 0) { + return ""; //$NON-NLS-1$ + } + return OFFSET_FORMAT.format((long) fOffsetMap.get(element)); + } + } + + /** + * Constructor + * + * @param parent + * parent shell + * @param results + * results to put the data into + */ + public OffsetDialog(Shell parent, Map<TmfTraceElement, Long> results) { + super(parent); + setShellStyle(getShellStyle() & ~SWT.APPLICATION_MODAL); + fOffsetMap = results; + fRefTimeMap = new HashMap<>(); + fTargetTimeMap = new HashMap<>(); + } + + @Override + protected boolean isResizable() { + return true; + } + + @Override + protected Control createDialogArea(Composite parent) { + getShell().setText(Messages.OffsetDialog_Title); + Composite area = (Composite) super.createDialogArea(parent); + Composite composite = new Composite(area, SWT.NONE); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + GridLayout gl = new GridLayout(); + gl.marginHeight = 0; + gl.marginWidth = 0; + composite.setLayout(new GridLayout()); + createBasicMessage(composite); + createButtonGroup(composite); + createAdvancedMessage(composite); + createViewer(composite); + + /* set label width hint equal to tree width */ + int widthHint = fViewer.getViewer().getTree().computeSize(SWT.DEFAULT, SWT.DEFAULT).x; + GridData gd = (GridData) fBasicMessageLabel.getLayoutData(); + gd.widthHint = widthHint; + gd = (GridData) fAdvancedMessageLabel.getLayoutData(); + gd.widthHint = widthHint; + gd = (GridData) composite.getLayoutData(); + gd.heightHint = composite.computeSize(widthHint, SWT.DEFAULT).y; + setBasicMode(); + + TmfSignalManager.register(this); + composite.addDisposeListener(new DisposeListener() { + @Override + public void widgetDisposed(DisposeEvent e) { + TmfSignalManager.deregister(this); + } + }); + return area; + } + + private void createBasicMessage(final Composite parent) { + fBasicMessageLabel = new Label(parent, SWT.WRAP); + fBasicMessageLabel.setText(Messages.OffsetDialog_BasicMessage); + GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false); + gd.widthHint = 0; + gd.heightHint = SWT.DEFAULT; + fBasicMessageLabel.setLayoutData(gd); + } + + private void createButtonGroup(final Composite parent) { + fButtonGroup = new Group(parent, SWT.SHADOW_NONE); + fButtonGroup.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); + fButtonGroup.setLayout(new RowLayout(SWT.HORIZONTAL)); + + final Button basicButton = new Button(fButtonGroup, SWT.RADIO); + basicButton.setText(Messages.OffsetDialog_BasicButton); + basicButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (!basicButton.getSelection() || !fAdvancedMode) { + return; + } + setBasicMode(); + parent.layout(); + } + }); + basicButton.setSelection(true); + + final Button advancedButton = new Button(fButtonGroup, SWT.RADIO); + advancedButton.setText(Messages.OffsetDialog_AdvancedButton); + advancedButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (!advancedButton.getSelection() || fAdvancedMode) { + return; + } + setAdvancedMode(); + parent.layout(); + } + }); + } + + private void createAdvancedMessage(final Composite parent) { + fAdvancedMessageLabel = new Label(parent, SWT.WRAP); + fAdvancedMessageLabel.setText(Messages.OffsetDialog_AdvancedMessage); + GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false); + gd.widthHint = 0; + gd.heightHint = SWT.DEFAULT; + fAdvancedMessageLabel.setLayoutData(gd); + } + + private void createViewer(Composite parent) { + + // Define the TableViewer + fViewer = new FilteredTree(parent, SWT.MULTI | SWT.H_SCROLL + | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER, new PatternFilter() { + @Override + protected boolean isLeafMatch(Viewer viewer, Object element) { + return wordMatches(((TmfTraceElement) element).getElementPath()); + } + }, true); + + // Make lines and make header visible + final Tree tree = fViewer.getViewer().getTree(); + tree.setHeaderVisible(true); + tree.setLinesVisible(true); + + TreeViewerFocusCellManager focusCellManager = new TreeViewerFocusCellManager(fViewer.getViewer(), new FocusCellOwnerDrawHighlighter(fViewer.getViewer())); + ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(fViewer.getViewer()); + TreeViewerEditor.create(fViewer.getViewer(), focusCellManager, actSupport, ColumnViewerEditor.TABBING_HORIZONTAL + | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR + | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION); + + final TextCellEditor textCellEditor = new TextCellEditor(fViewer.getViewer().getTree(), SWT.RIGHT); + + fViewer.getViewer().setColumnProperties(new String[] { Messages.OffsetDialog_TraceName, Messages.OffsetDialog_ReferenceTime, Messages.OffsetDialog_OffsetTime }); + + TreeViewerColumn column = createTreeViewerColumn(Messages.OffsetDialog_TraceName, SWT.NONE); + column.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return ((TmfTraceElement) element).getElementPath(); + } + }); + + column = createTreeViewerColumn(Messages.OffsetDialog_OffsetTime, SWT.RIGHT); + column.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + if (fOffsetMap.get(element) != 0) { + return super.getText(OFFSET_FORMAT.format((long) fOffsetMap.get(element))); + } + return ""; //$NON-NLS-1$ + } + }); + column.setEditingSupport(new OffsetEditingSupport(fViewer.getViewer(), textCellEditor)); + + column = createTreeViewerColumn("", SWT.NONE); //$NON-NLS-1$ + column.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return ""; //$NON-NLS-1$ + } + }); + column.getColumn().setWidth(TREE_EDITOR_MIN_WIDTH); + column.getColumn().setResizable(false); + fButtonViewerColumn = column; + + column = createTreeViewerColumn(Messages.OffsetDialog_ReferenceTime, SWT.RIGHT); + column.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return super.getText(fRefTimeMap.get(element)); + } + }); + column.setEditingSupport(new RefTimeEditingSupport(fViewer.getViewer(), textCellEditor)); + fRefTimeColumn = column.getColumn(); + + column = createTreeViewerColumn(Messages.OffsetDialog_TargetTime, SWT.RIGHT); + column.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return super.getText(fTargetTimeMap.get(element)); + } + }); + column.setEditingSupport(new TargetTimeEditingSupport(fViewer.getViewer(), textCellEditor)); + fTargetTimeColumn = column.getColumn(); + + List<TmfTraceElement> traces = new ArrayList<>(fOffsetMap.keySet()); + Collections.sort(traces, new Comparator<TmfTraceElement>() { + @Override + public int compare(TmfTraceElement o1, TmfTraceElement o2) { + IPath folder1 = new Path(o1.getElementPath()).removeLastSegments(1); + IPath folder2 = new Path(o2.getElementPath()).removeLastSegments(1); + if (folder1.equals(folder2)) { + return o1.getName().compareToIgnoreCase(o2.getName()); + } + if (folder1.isPrefixOf(folder2)) { + return 1; + } else if (folder2.isPrefixOf(folder1)) { + return -1; + } + return folder1.toString().compareToIgnoreCase(folder2.toString()); + } + }); + + fViewer.getViewer().setContentProvider(new ArrayTreeContentProvider()); + fViewer.getViewer().setInput(traces); + + /* add button as tree editors to fourth column of every item */ + for (TreeItem treeItem : tree.getItems()) { + TreeEditor treeEditor = new TreeEditor(tree); + Button applyButton = new Button(tree, SWT.PUSH); + applyButton.setText("<<"); //$NON-NLS-1$ + applyButton.setData(treeItem.getData()); + applyButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TmfTraceElement traceElement = (TmfTraceElement) e.widget.getData(); + ITmfTimestamp targetTime = fTargetTimeMap.get(traceElement); + ITmfTimestamp refTime = fRefTimeMap.get(traceElement); + if (targetTime != null && refTime != null) { + long offset = new TmfNanoTimestamp(targetTime).getValue() - + new TmfNanoTimestamp(refTime).getValue(); + fOffsetMap.put(traceElement, offset); + fViewer.getViewer().update(traceElement, null); + } + } + }); + treeEditor.grabHorizontal = true; + treeEditor.minimumWidth = TREE_EDITOR_MIN_WIDTH; + treeEditor.setEditor(applyButton, treeItem, 2); + treeItem.setData(EDITOR_KEY, applyButton); + } + + /* put temporary values in maps to pack according to time formats */ + fRefTimeMap.put(traces.get(0), new TmfNanoTimestamp()); + fTargetTimeMap.put(traces.get(0), new TmfNanoTimestamp()); + fViewer.getViewer().update(traces.get(0), null); + for (final TreeColumn treeColumn : tree.getColumns()) { + if (treeColumn.getResizable()) { + treeColumn.pack(); + } + } + fRefTimeMap.clear(); + fTargetTimeMap.clear(); + fViewer.getViewer().update(traces.get(0), null); + + for (TmfTraceElement traceElement : fOffsetMap.keySet()) { + for (ITmfTrace parentTrace : TmfTraceManager.getInstance().getOpenedTraces()) { + for (ITmfTrace trace : TmfTraceManager.getTraceSet(parentTrace)) { + if (traceElement.getResource().equals(trace.getResource())) { + fRefTimeMap.put(traceElement, trace.getStartTime()); + fViewer.getViewer().update(traceElement, null); + break; + } + } + if (fRefTimeMap.get(traceElement) != null) { + break; + } + } + } + + /* open trace when double-clicking a tree item */ + tree.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetDefaultSelected(SelectionEvent e) { + TmfTraceElement traceElement = (TmfTraceElement) e.item.getData(); + TmfOpenTraceHelper.openTraceFromElement(traceElement); + } + }); + + tree.setFocus(); + } + + private TreeViewerColumn createTreeViewerColumn(String title, int style) { + final TreeViewerColumn viewerColumn = new TreeViewerColumn(fViewer.getViewer(), style); + final TreeColumn column = viewerColumn.getColumn(); + column.setText(title); + column.setResizable(true); + return viewerColumn; + } + + private void setBasicMode() { + fAdvancedMode = false; + fRefTimeColumn.setData(WIDTH_KEY, fRefTimeColumn.getWidth()); + fTargetTimeColumn.setData(WIDTH_KEY, fTargetTimeColumn.getWidth()); + for (TreeItem treeItem : fViewer.getViewer().getTree().getItems()) { + Control editor = (Control) treeItem.getData(EDITOR_KEY); + editor.setVisible(false); + } + fTargetTimeColumn.setWidth(0); + fTargetTimeColumn.setResizable(false); + fRefTimeColumn.setWidth(0); + fRefTimeColumn.setResizable(false); + fButtonViewerColumn.getColumn().setWidth(0); + fAdvancedMessageLabel.setText(""); //$NON-NLS-1$ + } + + private void setAdvancedMode() { + fAdvancedMode = true; + fButtonViewerColumn.getColumn().setWidth(TREE_EDITOR_MIN_WIDTH); + fRefTimeColumn.setWidth((Integer) fRefTimeColumn.getData(WIDTH_KEY)); + fRefTimeColumn.setResizable(true); + fTargetTimeColumn.setWidth((Integer) fTargetTimeColumn.getData(WIDTH_KEY)); + fTargetTimeColumn.setResizable(true); + for (TreeItem treeItem : fViewer.getViewer().getTree().getItems()) { + Control editor = (Control) treeItem.getData(EDITOR_KEY); + editor.setVisible(true); + } + fAdvancedMessageLabel.setText(Messages.OffsetDialog_AdvancedMessage); + } + + /** + * Handler for the event selected signal + * + * @param signal + * the event selected signal + */ + @TmfSignalHandler + public void eventSelected(final TmfEventSelectedSignal signal) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + for (TmfTraceElement traceElement : fOffsetMap.keySet()) { + if (traceElement.getResource().equals(signal.getEvent().getTrace().getResource())) { + fRefTimeMap.put(traceElement, signal.getEvent().getTimestamp()); + fViewer.getViewer().update(traceElement, null); + break; + } + } + } + }); + } + + /** + * Handler for the time selected signal + * + * @param signal + * the event selected signal + */ + @TmfSignalHandler + public void timeSelected(final TmfSelectionRangeUpdatedSignal signal) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + for (TmfTraceElement traceElement : fOffsetMap.keySet()) { + fTargetTimeMap.put(traceElement, signal.getBeginTime()); + fViewer.getViewer().update(traceElement, null); + } + } + }); + } + + /** + * Handler for the trace opened signal + * + * @param signal + * the trace opened signal + */ + @TmfSignalHandler + public void traceOpened(final TmfTraceOpenedSignal signal) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + for (ITmfTrace trace : TmfTraceManager.getTraceSet(signal.getTrace())) { + for (TmfTraceElement traceElement : fOffsetMap.keySet()) { + if (traceElement.getResource().equals(trace.getResource())) { + if (fRefTimeMap.get(traceElement) == null) { + fRefTimeMap.put(traceElement, trace.getStartTime()); + fViewer.getViewer().update(traceElement, null); + } + break; + } + } + } + } + }); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/offset/messages.properties b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/offset/messages.properties new file mode 100644 index 0000000000..af1de0d719 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/dialogs/offset/messages.properties @@ -0,0 +1,24 @@ +############################################################################### +# Copyright (c) 2014 Ericsson +# +# 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 +# +# Contributors: +# Matthew Khouzam - Initial API and implementation +# Patrick Tasse - Initial API and implementation +############################################################################### + +OffsetDialog_AdvancedButton=Advanced +OffsetDialog_AdvancedMessage=Double-click a trace to open it, and select an event to set a reference time. \ +If the reference time and target time are set, press the button to compute their offset automatically. \ +The reference time and target time can be entered in format 'yyyy-mm-dd hh:mm:ss.sss sss sss'. +OffsetDialog_BasicButton=Basic +OffsetDialog_BasicMessage=Set the time offset to apply to each trace. +OffsetDialog_OffsetTime=Offset in seconds +OffsetDialog_ReferenceTime=Reference Time +OffsetDialog_TargetTime=Target Time +OffsetDialog_Title=Apply time offset +OffsetDialog_TraceName=Trace name diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/BatchImportTraceHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/BatchImportTraceHandler.java new file mode 100644 index 0000000000..4bac901458 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/BatchImportTraceHandler.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + * Bernd Hufmann - Simplify selection logic + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.BatchImportTraceWizard; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Batch import handler, spawn a wizard + * + * @author Matthew Khouzam + */ +public class BatchImportTraceHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + BatchImportTraceWizard w = new BatchImportTraceWizard(); + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + + if (window == null) { + return false; + } + + ISelection currentSelection = HandlerUtil.getCurrentSelection(event); + + IStructuredSelection sec = StructuredSelection.EMPTY; + if (currentSelection instanceof IStructuredSelection) { + sec = (IStructuredSelection) currentSelection; + } + + w.init(PlatformUI.getWorkbench(), sec); + WizardDialog dialog = new WizardDialog(window.getShell(), w); + dialog.open(); + + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/ClearTraceOffsetHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/ClearTraceOffsetHandler.java new file mode 100644 index 0000000000..97968fe5f2 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/ClearTraceOffsetHandler.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2014, 2015 Ericsson + * + * 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 + * + * Contributors: + * Patrick Tasse - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import java.lang.reflect.InvocationTargetException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +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.OperationCanceledException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.internal.tmf.ui.project.operations.TmfWorkspaceModifyOperation; +import org.eclipse.tracecompass.tmf.core.synchronization.TimestampTransformFactory; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Clear Trace Offset Handler + * + * @author Patrick Tasse + */ +public class ClearTraceOffsetHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(final ExecutionEvent event) throws ExecutionException { + + ISelection selection = HandlerUtil.getCurrentSelection(event); + + // Get the set of selected trace elements + final Set<TmfTraceElement> traceElements = new HashSet<>(); + if (selection instanceof StructuredSelection) { + Iterator<Object> iterator = ((StructuredSelection) selection).iterator(); + while (iterator.hasNext()) { + Object element = iterator.next(); + if (element instanceof TmfTraceElement) { + TmfTraceElement trace = (TmfTraceElement) element; + traceElements.add(trace.getElementUnderTraceFolder()); + } else if (element instanceof TmfExperimentElement) { + TmfExperimentElement exp = (TmfExperimentElement) element; + for (TmfTraceElement trace : exp.getTraces()) { + traceElements.add(trace.getElementUnderTraceFolder()); + } + } else if (element instanceof TmfTraceFolder) { + TmfTraceFolder folder = (TmfTraceFolder) element; + traceElements.addAll(folder.getTraces()); + } + } + } + + if (traceElements.isEmpty()) { + return null; + } + + Shell shell = HandlerUtil.getActiveShellChecked(event); + MessageBox mb = new MessageBox(shell, SWT.ICON_QUESTION | SWT.CANCEL | SWT.OK); + mb.setText(Messages.ClearTraceOffsetHandler_Title); + mb.setMessage(Messages.ClearTraceOffsetHandler_ConfirmMessage); + if (mb.open() != SWT.OK) { + return null; + } + + TmfWorkspaceModifyOperation operation = new TmfWorkspaceModifyOperation() { + @Override + public void execute(IProgressMonitor monitor) throws CoreException { + for (final TmfTraceElement trace : traceElements) { + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + if (!TimestampTransformFactory.getTimestampTransform(trace.getResource()).equals(TimestampTransformFactory.getDefaultTransform())) { + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + trace.closeEditors(); + } + }); + trace.deleteSupplementaryResources(); + TimestampTransformFactory.setTimestampTransform(trace.getResource(), null); + trace.refreshSupplementaryFolder(); + } + } + } + }; + try { + PlatformUI.getWorkbench().getProgressService().run(true, true, operation); + } catch (InterruptedException e) { + return null; + } catch (InvocationTargetException e) { + MessageDialog.openError(shell, 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/CopyExperimentHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/CopyExperimentHandler.java new file mode 100644 index 0000000000..f8d3bc93d1 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/CopyExperimentHandler.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2009, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + * Patrick Tasse - Remove enable check + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.wizards.CopyExperimentDialog; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * <b><u>CopyExperimentHandler</u></b> + * <p> + */ +public class CopyExperimentHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Get selection already validated by handler in plugin.xml + ISelection selection = HandlerUtil.getCurrentSelectionChecked(event); + if (!(selection instanceof IStructuredSelection)) { + return null; + } + TmfExperimentElement experiment = (TmfExperimentElement) ((IStructuredSelection) selection).getFirstElement(); + + // Fire the Copy Experiment dialog + Shell shell = HandlerUtil.getActiveShellChecked(event); + CopyExperimentDialog dialog = new CopyExperimentDialog(shell, experiment); + dialog.open(); + + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/CopyTraceHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/CopyTraceHandler.java new file mode 100644 index 0000000000..f3c2bc7996 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/CopyTraceHandler.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2011, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + * Patrick Tasse - Remove enable check + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.tracecompass.tmf.ui.project.wizards.CopyTraceDialog; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * <b><u>CopyTraceHandler</u></b> + * <p> + */ +public class CopyTraceHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Get selection already validated by handler in plugin.xml + ISelection selection = HandlerUtil.getCurrentSelectionChecked(event); + if (!(selection instanceof IStructuredSelection)) { + return null; + } + TmfTraceElement trace = (TmfTraceElement) ((IStructuredSelection) selection).getFirstElement(); + + // Fire the Copy Trace dialog + Shell shell = HandlerUtil.getActiveShellChecked(event); + CopyTraceDialog dialog = new CopyTraceDialog(shell, trace); + dialog.open(); + + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/DeleteExperimentHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/DeleteExperimentHandler.java new file mode 100644 index 0000000000..a679e0e91b --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/DeleteExperimentHandler.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2009, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + * Patrick Tasse - Close editors to release resources + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import java.util.Iterator; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * <b><u>DeleteExperimentHandler</u></b> + * <p> + */ +public class DeleteExperimentHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + // Confirm the operation + Shell shell = window.getShell(); + MessageBox confirmOperation = new MessageBox(shell, SWT.ICON_QUESTION | SWT.CANCEL | SWT.OK); + confirmOperation.setText(Messages.DeleteDialog_Title); + confirmOperation.setMessage(Messages.DeleteExperimentHandler_Message); + if (confirmOperation.open() != SWT.OK) { + return null; + } + + // Get the selection + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IWorkbenchPart part = page.getActivePart(); + if (part == null) { + return Boolean.FALSE; + } + ISelection selection = part.getSite().getSelectionProvider().getSelection(); + + if (selection instanceof TreeSelection) { + TreeSelection sel = (TreeSelection) selection; + Iterator<Object> iterator = sel.iterator(); + while (iterator.hasNext()) { + Object element = iterator.next(); + if (element instanceof TmfExperimentElement) { + final TmfExperimentElement experiment = (TmfExperimentElement) element; + IResource resource = experiment.getResource(); + + try { + // Close the experiment if open + experiment.closeEditors(); + + IPath path = resource.getLocation(); + if (path != null) { + // Delete supplementary files + experiment.deleteSupplementaryFolder(); + } + + // Finally, delete the experiment + resource.delete(true, null); + + } catch (final CoreException e) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + final MessageBox mb = new MessageBox(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell()); + mb.setText(Messages.DeleteTraceHandler_Error + ' ' + experiment.getName()); + mb.setMessage(e.getMessage()); + mb.open(); + } + }); + Activator.getDefault().logError("Error deleting experiment: " + experiment.getName(), e); //$NON-NLS-1$ + } + } + } + } + + return null; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/DeleteTraceFolderElementHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/DeleteTraceFolderElementHandler.java new file mode 100644 index 0000000000..22a5211b1e --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/DeleteTraceFolderElementHandler.java @@ -0,0 +1,349 @@ +/******************************************************************************* + * Copyright (c) 2009, 2014 Ericsson, École Polytechnique de Montréal + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + * Patrick Tasse - Close editors to release resources + * Geneviève Bastien - Moved the delete code to element model's classes + * Marc-Andre Laperle - Merged DeleteTraceHandler and DeleteFolderHandler + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import java.lang.reflect.InvocationTargetException; +import java.util.Iterator; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceVisitor; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; +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.viewers.TreeSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.internal.tmf.ui.project.operations.TmfWorkspaceModifyOperation; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +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.TmfTracesFolder; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * An handler for deletion of both traces and trace folders. It allows mixing + * both types of elements. + */ +public class DeleteTraceFolderElementHandler extends AbstractHandler { + + private TreeSelection fSelection = null; + + private enum DeleteType { + /** + * Only trace folders are selected. + */ + DELETE_TRACE_FOLDERS, + /** + * Only traces are selected. + */ + DELETE_TRACES, + /** + * A mix of different elements are selected. + */ + DELETE_GENERIC, + /** + * Only Traces (top trace folders) are selected. + */ + CLEAR_TRACES_FOLDER, + /** + * Only Traces under experiments are selected. + */ + REMOVE_TRACES_FROM_EXPERIMENT + } + + // ------------------------------------------------------------------------ + // Validation + // ------------------------------------------------------------------------ + + @Override + public boolean isEnabled() { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return false; + } + + // Get the selection + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IWorkbenchPart part = page.getActivePart(); + if (part == null) { + return false; + } + ISelectionProvider selectionProvider = part.getSite().getSelectionProvider(); + if (selectionProvider == null) { + return false; + } + ISelection selection = selectionProvider.getSelection(); + + // Make sure selection contains only traces and trace folders + fSelection = null; + if (selection instanceof TreeSelection) { + fSelection = (TreeSelection) selection; + Iterator<Object> iterator = fSelection.iterator(); + while (iterator.hasNext()) { + Object element = iterator.next(); + if (!(element instanceof TmfTraceElement) && !(element instanceof TmfTraceFolder)) { + return false; + } + } + } + + // If we get here, either nothing is selected or everything is a trace or folder + return !selection.isEmpty(); + } + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + private static DeleteType getDeleteType(ISelection selection) { + int numTracesFolder = 0; + int numTraceFolder = 0; + int numTraces = 0; + int numTracesUnderExperiment = 0; + + @SuppressWarnings("rawtypes") + Iterator iterator = ((IStructuredSelection) selection).iterator(); + while (iterator.hasNext()) { + Object next = iterator.next(); + if ((next instanceof TmfTracesFolder)) { + numTracesFolder++; + } else if (next instanceof TmfTraceFolder) { + numTraceFolder++; + } else if (next instanceof TmfTraceElement) { + TmfTraceElement traceElement = (TmfTraceElement) next; + if (traceElement.getParent() instanceof TmfExperimentElement) { + numTracesUnderExperiment++; + } else { + numTraces++; + } + } + } + + int total = numTraceFolder + numTracesFolder + numTracesUnderExperiment + numTraces; + + if (numTracesFolder == total) { + return DeleteType.CLEAR_TRACES_FOLDER; + } + + if (numTraceFolder == total) { + return DeleteType.DELETE_TRACE_FOLDERS; + } + + if (numTraces == total) { + return DeleteType.DELETE_TRACES; + } + + if (numTracesUnderExperiment == total) { + return DeleteType.REMOVE_TRACES_FROM_EXPERIMENT; + } + + return DeleteType.DELETE_GENERIC; + } + + private static String getTitle(final DeleteType deleteType) { + switch (deleteType) + { + case DELETE_GENERIC: + case DELETE_TRACES: + case DELETE_TRACE_FOLDERS: + return Messages.DeleteDialog_Title; + case CLEAR_TRACES_FOLDER: + return Messages.ClearDialog_Title; + case REMOVE_TRACES_FROM_EXPERIMENT: + return Messages.RemoveDialog_Title; + default: + throw new IllegalArgumentException(); + } + } + + private static String getMessage(DeleteType deleteType) { + switch (deleteType) + { + case DELETE_GENERIC: + return Messages.DeleteTraceHandlerGeneric_Message; + case DELETE_TRACES: + return Messages.DeleteTraceHandler_Message; + case CLEAR_TRACES_FOLDER: + return Messages.DeleteFolderHandlerClear_Message; + case DELETE_TRACE_FOLDERS: + return Messages.DeleteFolderHandler_Message; + case REMOVE_TRACES_FROM_EXPERIMENT: + return Messages.RemoveTraceFromExperimentHandler_Message; + default: + throw new IllegalArgumentException(); + } + } + + private static String getTraceErrorMessage(DeleteType deleteType) { + return deleteType == DeleteType.REMOVE_TRACES_FROM_EXPERIMENT ? Messages.RemoveTraceFromExperimentHandler_Error : Messages.DeleteFolderHandler_Error; + } + + private static String getFolderErrorMessage(DeleteType deleteType) { + return deleteType == DeleteType.CLEAR_TRACES_FOLDER ? Messages.DeleteFolderHandlerClear_Error : Messages.DeleteFolderHandler_Error; + } + + private static String getTraceTaskName(DeleteType deleteType) { + return deleteType == DeleteType.REMOVE_TRACES_FROM_EXPERIMENT ? Messages.RemoveTraceFromExperimentHandler_TaskName : Messages.DeleteFolderHandler_TaskName; + } + + private static String getTraceFolderTaskName(DeleteType deleteType) { + return deleteType == DeleteType.CLEAR_TRACES_FOLDER ? Messages.DeleteFolderHandlerClear_TaskName : Messages.DeleteFolderHandler_TaskName; + } + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + // Get the selection + ISelection selection = HandlerUtil.getCurrentSelection(event); + if (!(selection instanceof IStructuredSelection)) { + return null; + } + final DeleteType deleteType = getDeleteType(selection); + + // Confirm the operation + Shell shell = window.getShell(); + MessageBox confirmOperation = new MessageBox(shell, SWT.ICON_QUESTION | SWT.CANCEL | SWT.OK); + confirmOperation.setText(getTitle(deleteType)); + confirmOperation.setMessage(getMessage(deleteType)); + if (confirmOperation.open() != SWT.OK) { + return null; + } + + final Iterator<Object> iterator = fSelection.iterator(); + final int nbElements = fSelection.size(); + + TmfWorkspaceModifyOperation operation = new TmfWorkspaceModifyOperation() { + @Override + public void execute(IProgressMonitor monitor) throws CoreException { + SubMonitor subMonitor = SubMonitor.convert(monitor, nbElements); + + while (iterator.hasNext()) { + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + Object element = iterator.next(); + SubProgressMonitor elementSubMonitor = new SubProgressMonitor(subMonitor, 1); + if (element instanceof TmfTraceElement) { + final TmfTraceElement trace = (TmfTraceElement) element; + if (!trace.getResource().exists()) { + continue; + } + subMonitor.setTaskName(getTraceTaskName(deleteType) + " " + trace.getElementPath()); //$NON-NLS-1$ + try { + SubMonitor deleteSubMonitor = SubMonitor.convert(elementSubMonitor, 1); + trace.delete(deleteSubMonitor); + } catch (final CoreException e) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + final MessageBox mb = new MessageBox(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell()); + mb.setText(getTraceErrorMessage(deleteType) + ' ' + trace.getName()); + mb.setMessage(e.getMessage()); + mb.open(); + } + }); + Activator.getDefault().logError(getTraceErrorMessage(deleteType) + trace.getName(), e); + } + } else if (element instanceof TmfTraceFolder) { + final TmfTraceFolder folder = (TmfTraceFolder) element; + final IResource resource = folder.getResource(); + if (!resource.exists()) { + continue; + } + + subMonitor.setTaskName(getTraceFolderTaskName(deleteType) + " " + folder.getPath()); //$NON-NLS-1$ + + try { + // delete all traces under this folder + SubMonitor childrenSubMonitor = SubMonitor.convert(elementSubMonitor, folder.getTraces().size() + 1); + for (TmfTraceElement traceElement : folder.getTraces()) { + SubProgressMonitor deleteSubMonitor = new SubProgressMonitor(childrenSubMonitor, 1); + traceElement.delete(deleteSubMonitor); + } + + // Finally, delete the folder. For the Traces + // folder, we only delete the children since the + // folder should always be there. + final SubProgressMonitor deleteSubMonitor = new SubProgressMonitor(subMonitor, 1); + if (folder instanceof TmfTracesFolder) { + resource.accept(new IResourceVisitor() { + @Override + public boolean visit(IResource visitedResource) throws CoreException { + if (visitedResource != resource) { + visitedResource.delete(true, deleteSubMonitor); + } + return true; + } + }, IResource.DEPTH_ONE, 0); + } else { + resource.delete(true, deleteSubMonitor); + } + childrenSubMonitor.done(); + } catch (final CoreException e) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + final MessageBox mb = new MessageBox(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell()); + mb.setText(getFolderErrorMessage(deleteType) + ' ' + folder.getName()); + mb.setMessage(e.getMessage()); + mb.open(); + } + }); + Activator.getDefault().logError(getFolderErrorMessage(deleteType) + folder.getName(), e); + } + } + subMonitor.setTaskName(""); //$NON-NLS-1$ + elementSubMonitor.done(); + } + } + }; + + try { + PlatformUI.getWorkbench().getProgressService().run(true, true, operation); + } catch (InterruptedException e) { + return null; + } catch (InvocationTargetException e) { + MessageDialog.openError(window.getShell(), e.toString(), e.getTargetException().toString()); + return null; + } + return null; + } + +}
\ No newline at end of file diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/DeleteTraceSupplementaryFilesHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/DeleteTraceSupplementaryFilesHandler.java new file mode 100644 index 0000000000..982849a2e8 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/DeleteTraceSupplementaryFilesHandler.java @@ -0,0 +1,192 @@ +/******************************************************************************* + * Copyright (c) 2012, 2014 Ericsson + * + * 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 + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + * Patrick Tasse - Close editors to release resources + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.window.Window; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.internal.tmf.ui.project.dialogs.SelectSupplementaryResourcesDialog; +import org.eclipse.tracecompass.internal.tmf.ui.project.operations.TmfWorkspaceModifyOperation; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfCommonProjectElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.handlers.HandlerUtil; + +import com.google.common.collect.Multimap; +import com.google.common.collect.TreeMultimap; + +/** + * Handler for Delete Supplementary Files command on trace + */ +public class DeleteTraceSupplementaryFilesHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Inner classes + // ------------------------------------------------------------------------ + + private class ElementComparator implements Comparator<TmfCommonProjectElement> { + @Override + public int compare(TmfCommonProjectElement e1, TmfCommonProjectElement e2) { + return e1.getPath().toString().compareTo(e2.getPath().toString()); + } + } + + private class ResourceComparator implements Comparator<IResource> { + @Override + public int compare(IResource r1, IResource r2) { + return r1.getFullPath().toString().compareTo(r2.getFullPath().toString()); + } + } + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + // Get the selection + ISelection selection = HandlerUtil.getCurrentSelection(event); + if (!(selection instanceof IStructuredSelection)) { + return null; + } + final Multimap<TmfCommonProjectElement, IResource> resourceMap = + TreeMultimap.create(new ElementComparator(), new ResourceComparator()); + final Iterator<Object> iterator = ((IStructuredSelection) selection).iterator(); + + while (iterator.hasNext()) { + Object element = iterator.next(); + if (element instanceof TmfTraceElement) { + TmfTraceElement trace = (TmfTraceElement) element; + // If trace is under an experiment, use the original trace from the traces folder + trace = trace.getElementUnderTraceFolder(); + for (IResource resource : trace.getSupplementaryResources()) { + resourceMap.put(trace, resource); + } + + } else if (element instanceof TmfExperimentElement) { + TmfExperimentElement experiment = (TmfExperimentElement) element; + for (IResource resource : experiment.getSupplementaryResources()) { + resourceMap.put(experiment, resource); + } + for (TmfTraceElement trace : experiment.getTraces()) { + // If trace is under an experiment, use the original trace from the traces folder + trace = trace.getElementUnderTraceFolder(); + for (IResource resource : trace.getSupplementaryResources()) { + resourceMap.put(trace, resource); + } + } + } + } + + final SelectSupplementaryResourcesDialog dialog = + new SelectSupplementaryResourcesDialog(window.getShell(), resourceMap); + if (dialog.open() != Window.OK) { + return null; + } + + TmfWorkspaceModifyOperation operation = new TmfWorkspaceModifyOperation() { + @Override + public void execute(IProgressMonitor monitor) throws CoreException { + + Set<IProject> projectsToRefresh = new HashSet<>(); + + // Delete the resources that were selected + List<IResource> allResourcesToDelete = Arrays.asList(dialog.getResources()); + + SubMonitor subMonitor = SubMonitor.convert(monitor, allResourcesToDelete.size()); + + for (final TmfCommonProjectElement element : resourceMap.keySet()) { + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + List<IResource> traceResourcesToDelete = new ArrayList<>(resourceMap.get(element)); + traceResourcesToDelete.retainAll(allResourcesToDelete); + if (!traceResourcesToDelete.isEmpty()) { + subMonitor.setTaskName(NLS.bind(Messages.DeleteSupplementaryFiles_DeletionTask, element.getElementPath())); + // Delete the selected resources + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + element.closeEditors(); + } + }); + element.deleteSupplementaryResources(traceResourcesToDelete.toArray(new IResource[0])); + projectsToRefresh.add(element.getProject().getResource()); + } + subMonitor.worked(traceResourcesToDelete.size()); + } + + subMonitor = SubMonitor.convert(monitor, projectsToRefresh.size()); + + // Refresh projects + Iterator<IProject> projectIterator = projectsToRefresh.iterator(); + while (projectIterator.hasNext()) { + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + IProject project = projectIterator.next(); + subMonitor.setTaskName(NLS.bind(Messages.DeleteSupplementaryFiles_ProjectRefreshTask, project.getName())); + try { + project.refreshLocal(IResource.DEPTH_INFINITE, null); + } catch (CoreException e) { + Activator.getDefault().logError("Error refreshing project " + project, e); //$NON-NLS-1$ + } + subMonitor.worked(1); + } + } + }; + + try { + PlatformUI.getWorkbench().getProgressService().run(true, true, operation); + } catch (InterruptedException e) { + return null; + } catch (InvocationTargetException e) { + MessageDialog.openError(window.getShell(), 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/DropAdapterAssistant.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/DropAdapterAssistant.java new file mode 100644 index 0000000000..c8089b9409 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/DropAdapterAssistant.java @@ -0,0 +1,669 @@ +/******************************************************************************* +* Copyright (c) 2012, 2014 Ericsson + * + * 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 + * + * Contributors: + * Patrick Tasse - Initial API and implementation + * Patrick Tasse - Add support for DROP_LINK and rename prompt on name clash + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.URIUtil; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.FileTransfer; +import org.eclipse.swt.dnd.TransferData; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.internal.tmf.ui.editors.ITmfEventsEditorConstants; +import org.eclipse.tracecompass.tmf.core.TmfCommonConstants; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceImportException; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType; +import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper; +import org.eclipse.tracecompass.tmf.ui.project.model.ITmfProjectModelElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry; +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.TmfTraceTypeUIUtils; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.WorkspaceModifyDelegatingOperation; +import org.eclipse.ui.dialogs.IOverwriteQuery; +import org.eclipse.ui.navigator.CommonDropAdapter; +import org.eclipse.ui.navigator.CommonDropAdapterAssistant; +import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider; +import org.eclipse.ui.wizards.datatransfer.ImportOperation; + +/** + * Drop adapter assistant for project explorer + */ +public class DropAdapterAssistant extends CommonDropAdapterAssistant { + + /** + * Default constructor + */ + public DropAdapterAssistant() { + } + + @Override + public boolean isSupportedType(TransferData aTransferType) { + return super.isSupportedType(aTransferType) || FileTransfer.getInstance().isSupportedType(aTransferType); + } + + @Override + public IStatus validateDrop(Object target, int operation, TransferData transferType) { + if (target instanceof TmfTraceFolder) { + return Status.OK_STATUS; + } + if (target instanceof TmfExperimentElement) { + return Status.OK_STATUS; + } + if (target instanceof TmfTraceElement) { + ITmfProjectModelElement parent = ((TmfTraceElement) target).getParent(); + if (parent instanceof TmfTraceFolder) { + return Status.OK_STATUS; + } + if (parent instanceof TmfExperimentElement) { + return Status.OK_STATUS; + } + } + if (target instanceof IProject) { + return Status.OK_STATUS; + } + return Status.CANCEL_STATUS; + } + + @Override + public IStatus handleDrop(CommonDropAdapter aDropAdapter, DropTargetEvent aDropTargetEvent, Object aTarget) { + boolean ok = false; + + // Use local variable to avoid parameter assignment + Object targetToUse = aTarget; + + int operation = aDropTargetEvent.detail; + if (operation != DND.DROP_LINK) { + operation = DND.DROP_COPY; + } + + // If target is a trace, use its parent (either trace folder or experiment) + if (targetToUse instanceof TmfTraceElement) { + targetToUse = ((TmfTraceElement) targetToUse).getParent(); + } + + // If target is a project, use its trace folder + if (targetToUse instanceof IProject) { + TmfProjectElement projectElement = TmfProjectRegistry.getProject((IProject) targetToUse, true); + if (projectElement != null) { + targetToUse = projectElement.getTracesFolder(); + } + } + + if (aDropTargetEvent.data instanceof IStructuredSelection) { + IStructuredSelection selection = (IStructuredSelection) aDropTargetEvent.data; + for (Object source : selection.toArray()) { + if (source instanceof IResource) { + // If source resource is a trace, use the trace element + IResource sourceResource = (IResource) source; + TmfProjectElement projectElement = TmfProjectRegistry.getProject(sourceResource.getProject()); + if (projectElement != null && projectElement.getTracesFolder() != null) { + for (TmfTraceElement trace : projectElement.getTracesFolder().getTraces()) { + if (trace.getResource().equals(sourceResource)) { + source = trace; + break; + } + } + } + } + if (source instanceof TmfTraceElement) { + TmfTraceElement sourceTrace = (TmfTraceElement) source; + // If source trace is under an experiment, use the original trace from the traces folder + sourceTrace = sourceTrace.getElementUnderTraceFolder(); + if (targetToUse instanceof TmfExperimentElement) { + TmfExperimentElement targetExperiment = (TmfExperimentElement) targetToUse; + ok |= drop(sourceTrace, targetExperiment, operation); + } else if (targetToUse instanceof TmfTraceFolder) { + TmfTraceFolder traceFolder = (TmfTraceFolder) targetToUse; + ok |= drop(sourceTrace, traceFolder, operation); + } + } else if (source instanceof IResource) { + IResource sourceResource = (IResource) source; + if (sourceResource.getType() != IResource.FILE && sourceResource.getType() != IResource.FOLDER) { + continue; + } + if (targetToUse instanceof TmfExperimentElement) { + TmfExperimentElement targetExperiment = (TmfExperimentElement) targetToUse; + ok |= (drop(sourceResource, targetExperiment, operation) != null); + } else if (targetToUse instanceof TmfTraceFolder) { + TmfTraceFolder traceFolder = (TmfTraceFolder) targetToUse; + ok |= (drop(sourceResource, traceFolder, operation) != null); + } + } + } + } else if (aDropTargetEvent.data instanceof String[]) { + String[] sources = (String[]) aDropTargetEvent.data; + for (String source : sources) { + Path path = new Path(source); + if (targetToUse instanceof TmfExperimentElement) { + TmfExperimentElement targetExperiment = (TmfExperimentElement) targetToUse; + ok |= drop(path, targetExperiment, operation); + } else if (targetToUse instanceof TmfTraceFolder) { + TmfTraceFolder traceFolder = (TmfTraceFolder) targetToUse; + ok |= drop(path, traceFolder, operation); + } + } + } + return (ok ? Status.OK_STATUS : Status.CANCEL_STATUS); + } + + + /** + * Drop a trace by copying/linking a trace element in a target experiment + * + * @param sourceTrace the source trace element to copy + * @param targetExperiment the target experiment + * @param operation the drop operation (DND.DROP_COPY | DND.DROP_LINK) + * @return true if successful + */ + private static boolean drop(TmfTraceElement sourceTrace, + TmfExperimentElement targetExperiment, + int operation) { + + IResource sourceResource = sourceTrace.getResource(); + IResource targetResource = drop(sourceResource, targetExperiment, operation); + + if (targetResource != null) { + if (! sourceTrace.getProject().equals(targetExperiment.getProject())) { + IFolder destinationSupplementaryFolder = targetExperiment.getTraceSupplementaryFolder(targetResource.getName()); + sourceTrace.copySupplementaryFolder(destinationSupplementaryFolder); + } + return true; + } + return false; + } + + /** + * Drop a trace by copying/linking a resource in a target experiment + * + * @param sourceResource the source resource + * @param targetExperiment the target experiment + * @param operation the drop operation (DND.DROP_COPY | DND.DROP_LINK) + * @return the target resource or null if unsuccessful + */ + private static IResource drop(IResource sourceResource, + TmfExperimentElement targetExperiment, + int operation) { + + IResource traceResource = sourceResource; + + IPath tracesFolderPath = targetExperiment.getProject().getTracesFolder().getPath(); + if (tracesFolderPath.isPrefixOf(sourceResource.getFullPath())) { + String elementPath = sourceResource.getFullPath().makeRelativeTo(tracesFolderPath).toString(); + for (TmfTraceElement trace : targetExperiment.getTraces()) { + if (trace.getElementPath().equals(elementPath)) { + return null; + } + } + } else { + String targetName = sourceResource.getName(); + for (ITmfProjectModelElement element : targetExperiment.getProject().getTracesFolder().getChildren()) { + if (element.getName().equals(targetName)) { + targetName = promptRename(element); + if (targetName == null) { + return null; + } + break; + } + } + try { + if (operation == DND.DROP_COPY && !sourceResource.isLinked()) { + IPath destination = targetExperiment.getProject().getTracesFolder().getResource().getFullPath().addTrailingSeparator().append(targetName); + sourceResource.copy(destination, false, null); + cleanupBookmarks(destination); + } else { + createLink(targetExperiment.getProject().getTracesFolder().getResource(), sourceResource, targetName); + } + // use the copied resource for the experiment + if (sourceResource.getType() == IResource.FILE) { + traceResource = targetExperiment.getProject().getTracesFolder().getResource().getFile(targetName); + } else if (sourceResource.getType() == IResource.FOLDER) { + traceResource = targetExperiment.getProject().getTracesFolder().getResource().getFolder(targetName); + } + String sourceLocation = sourceResource.getPersistentProperty(TmfCommonConstants.SOURCE_LOCATION); + if (sourceLocation == null) { + sourceLocation = URIUtil.toUnencodedString(new File(sourceResource.getLocationURI()).toURI()); + } + traceResource.setPersistentProperty(TmfCommonConstants.SOURCE_LOCATION, sourceLocation); + } catch (CoreException e) { + displayException(e); + return null; + } + } + if (traceResource != null && traceResource.exists()) { + setTraceType(traceResource); + for (TmfTraceElement trace : targetExperiment.getProject().getTracesFolder().getTraces()) { + if (trace.getResource().equals(traceResource)) { + targetExperiment.addTrace(trace); + targetExperiment.closeEditors(); + targetExperiment.deleteSupplementaryResources(); + break; + } + } + return traceResource; + } + return null; + } + + /** + * Drop a trace by copying/linking a trace element in a trace folder + * + * @param sourceTrace the source trace + * @param traceFolder the target trace folder + * @param operation the drop operation (DND.DROP_COPY | DND.DROP_LINK) + * @return true if successful + */ + private static boolean drop(TmfTraceElement sourceTrace, + TmfTraceFolder traceFolder, + int operation) { + + IResource sourceResource = sourceTrace.getResource(); + IResource targetResource = drop(sourceResource, traceFolder, operation); + + if (targetResource != null) { + String elementPath = targetResource.getFullPath().makeRelativeTo(traceFolder.getProject().getTracesFolder().getPath()).toString(); + IFolder destinationSupplementaryFolder = traceFolder.getTraceSupplementaryFolder(elementPath); + sourceTrace.copySupplementaryFolder(destinationSupplementaryFolder); + return true; + } + return false; + } + + /** + * Drop a trace by copying/linking a resource in a trace folder + * + * @param sourceResource the source resource + * @param traceFolder the target trace folder + * @param operation the drop operation (DND.DROP_COPY | DND.DROP_LINK) + * @return the target resource or null if unsuccessful + */ + private static IResource drop(IResource sourceResource, + TmfTraceFolder traceFolder, + int operation) { + + if (sourceResource.getParent().equals(traceFolder.getResource())) { + return null; + } + String targetName = sourceResource.getName(); + for (ITmfProjectModelElement element : traceFolder.getChildren()) { + if (element.getName().equals(targetName)) { + targetName = promptRename(element); + if (targetName == null) { + return null; + } + break; + } + } + try { + if (operation == DND.DROP_COPY && !sourceResource.isLinked()) { + IPath destination = traceFolder.getResource().getFullPath().addTrailingSeparator().append(targetName); + sourceResource.copy(destination, false, null); + cleanupBookmarks(destination); + } else { + createLink(traceFolder.getResource(), sourceResource, targetName); + } + IResource traceResource = traceFolder.getResource().findMember(targetName); + if (traceResource != null && traceResource.exists()) { + String sourceLocation = sourceResource.getPersistentProperty(TmfCommonConstants.SOURCE_LOCATION); + if (sourceLocation == null) { + sourceLocation = URIUtil.toUnencodedString(new File(sourceResource.getLocationURI()).toURI()); + } + traceResource.setPersistentProperty(TmfCommonConstants.SOURCE_LOCATION, sourceLocation); + setTraceType(traceResource); + } + return traceResource; + } catch (CoreException e) { + displayException(e); + } + return null; + } + + /** + * Drop a trace by importing/linking a path in a target experiment + * + * @param path the source path + * @param targetExperiment the target experiment + * @param operation the drop operation (DND.DROP_COPY | DND.DROP_LINK) + * @return true if successful + */ + private static boolean drop(Path path, + TmfExperimentElement targetExperiment, + int operation) { + + IPath tracesFolderPath = targetExperiment.getProject().getTracesFolder().getResource().getLocation(); + IResource traceResource = null; + if (tracesFolderPath.isPrefixOf(path)) { + String elementPath = path.makeRelativeTo(tracesFolderPath).toString(); + for (TmfTraceElement trace : targetExperiment.getTraces()) { + if (trace.getElementPath().equals(elementPath)) { + return false; + } + } + traceResource = targetExperiment.getProject().getTracesFolder().getResource().findMember(elementPath); + } else { + String targetName = path.lastSegment(); + for (ITmfProjectModelElement element : targetExperiment.getProject().getTracesFolder().getChildren()) { + if (element.getName().equals(targetName)) { + targetName = promptRename(element); + if (targetName == null) { + return false; + } + break; + } + } + if (operation == DND.DROP_COPY) { + importTrace(targetExperiment.getProject().getTracesFolder().getResource(), path, targetName); + } else { + createLink(targetExperiment.getProject().getTracesFolder().getResource(), path, targetName); + } + // use the copied resource for the experiment + File file = new File(path.toString()); + if (file.exists() && file.isFile()) { + traceResource = targetExperiment.getProject().getTracesFolder().getResource().getFile(targetName); + } else if (file.exists() && file.isDirectory()) { + traceResource = targetExperiment.getProject().getTracesFolder().getResource().getFolder(targetName); + } + } + if (traceResource != null && traceResource.exists()) { + try { + String sourceLocation = URIUtil.toUnencodedString(path.toFile().toURI()); + traceResource.setPersistentProperty(TmfCommonConstants.SOURCE_LOCATION, sourceLocation); + } catch (CoreException e) { + displayException(e); + } + setTraceType(traceResource); + for (TmfTraceElement trace : targetExperiment.getProject().getTracesFolder().getTraces()) { + if (trace.getResource().equals(traceResource)) { + targetExperiment.addTrace(trace); + targetExperiment.closeEditors(); + targetExperiment.deleteSupplementaryResources(); + break; + } + } + return true; + } + return false; + } + + /** + * Drop a trace by importing/linking a path in a trace folder + * + * @param path the source path + * @param traceFolder the target trace folder + * @param operation the drop operation (DND.DROP_COPY | DND.DROP_LINK) + * @return true if successful + */ + private static boolean drop(Path path, + TmfTraceFolder traceFolder, + int operation) { + + String targetName = path.lastSegment(); + for (ITmfProjectModelElement element : traceFolder.getChildren()) { + if (element.getName().equals(targetName)) { + targetName = promptRename(element); + if (targetName == null) { + return false; + } + break; + } + } + if (operation == DND.DROP_COPY) { + importTrace(traceFolder.getResource(), path, targetName); + } else { + createLink(traceFolder.getResource(), path, targetName); + } + IResource traceResource = traceFolder.getResource().findMember(targetName); + if (traceResource != null && traceResource.exists()) { + try { + String sourceLocation = URIUtil.toUnencodedString(path.toFile().toURI()); + traceResource.setPersistentProperty(TmfCommonConstants.SOURCE_LOCATION, sourceLocation); + } catch (CoreException e) { + displayException(e); + } + setTraceType(traceResource); + } + return true; + } + + /** + * Import a trace to the trace folder + * + * @param folder the trace folder resource + * @param path the path to the trace to import + * @param targetName the target name + */ + private static void importTrace(final IFolder folder, final Path path, final String targetName) { + final File source = new File(path.toString()); + if (source.isDirectory()) { + IPath containerPath = folder.getFullPath().addTrailingSeparator().append(targetName); + IOverwriteQuery overwriteImplementor = new IOverwriteQuery() { + @Override + public String queryOverwrite(String pathString) { + return IOverwriteQuery.NO_ALL; + } + }; + List<File> filesToImport = Arrays.asList(source.listFiles()); + ImportOperation operation = new ImportOperation( + containerPath, + source, + FileSystemStructureProvider.INSTANCE, + overwriteImplementor, + filesToImport); + operation.setCreateContainerStructure(false); + try { + operation.run(new NullProgressMonitor()); + } catch (InvocationTargetException e) { + displayException(e); + } catch (InterruptedException e) { + displayException(e); + } + } else { + IRunnableWithProgress runnable = new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + try (InputStream inputStream = new FileInputStream(source);) { + IFile targetFile = folder.getFile(targetName); + targetFile.create(inputStream, IResource.NONE, monitor); + } catch (CoreException | IOException e) { + displayException(e); + } + } + }; + WorkspaceModifyDelegatingOperation operation = new WorkspaceModifyDelegatingOperation(runnable); + try { + operation.run(new NullProgressMonitor()); + } catch (InvocationTargetException e) { + displayException(e); + } catch (InterruptedException e) { + displayException(e); + } + } + } + + /** + * Create a link to the actual trace and set the trace type + * + * @param parentFolder the parent folder + * @param resource the resource + * @param targetName the target name + */ + private static void createLink(IFolder parentFolder, IResource resource, String targetName) { + IPath location = resource.getLocation(); + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + try { + String traceType = TmfTraceType.getTraceTypeId(resource); + TraceTypeHelper traceTypeHelper = TmfTraceType.getTraceType(traceType); + + if (resource instanceof IFolder) { + IFolder folder = parentFolder.getFolder(targetName); + IStatus result = workspace.validateLinkLocation(folder, location); + if (result.isOK() || result.matches(IStatus.INFO | IStatus.WARNING)) { + folder.createLink(location, IResource.REPLACE, null); + if (traceTypeHelper != null) { + TmfTraceTypeUIUtils.setTraceType(folder, traceTypeHelper); + } + } else { + Activator.getDefault().logError("Invalid Trace Location"); //$NON-NLS-1$ + } + } else { + IFile file = parentFolder.getFile(targetName); + IStatus result = workspace.validateLinkLocation(file, location); + if (result.isOK() || result.matches(IStatus.INFO | IStatus.WARNING)) { + file.createLink(location, IResource.REPLACE, null); + if (traceTypeHelper != null) { + TmfTraceTypeUIUtils.setTraceType(file, traceTypeHelper); + } + } else { + Activator.getDefault().logError("Invalid Trace Location"); //$NON-NLS-1$ + } + } + } catch (CoreException e) { + displayException(e); + } + } + + /** + * Create a link to a file or folder + * + * @param parentFolder the parent folder + * @param source the file or folder + * @param targetName the target name + */ + private static void createLink(IFolder parentFolder, IPath location, String targetName) { + File source = new File(location.toString()); + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + try { + + if (source.isDirectory()) { + IFolder folder = parentFolder.getFolder(targetName); + IStatus result = workspace.validateLinkLocation(folder, location); + if (result.isOK() || result.matches(IStatus.INFO | IStatus.WARNING)) { + folder.createLink(location, IResource.REPLACE, null); + } else { + Activator.getDefault().logError("Invalid Trace Location"); //$NON-NLS-1$ + } + } else { + IFile file = parentFolder.getFile(targetName); + IStatus result = workspace.validateLinkLocation(file, location); + if (result.isOK() || result.matches(IStatus.INFO | IStatus.WARNING)) { + file.createLink(location, IResource.REPLACE, null); + } else { + Activator.getDefault().logError("Invalid Trace Location"); //$NON-NLS-1$ + } + } + } catch (CoreException e) { + displayException(e); + } + } + + /** + * Prompts the user to rename a trace + * + * @param element the conflicting element + * @return the new name to use or null if rename is canceled + */ + private static String promptRename(ITmfProjectModelElement element) { + MessageBox mb = new MessageBox(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), SWT.ICON_QUESTION | SWT.CANCEL | SWT.OK); + mb.setText(Messages.DropAdapterAssistant_RenameTraceTitle); + mb.setMessage(NLS.bind(Messages.DropAdapterAssistant_RenameTraceMessage, element.getName())); + if (mb.open() != SWT.OK) { + return null; + } + IContainer folder = element.getResource().getParent(); + int i = 2; + while (true) { + String name = element.getName() + '(' + Integer.toString(i++) + ')'; + IResource resource = folder.findMember(name); + if (resource == null) { + return name; + } + } + } + + /** + * Cleanup bookmarks file in copied trace + */ + private static void cleanupBookmarks(IPath path) { + IFolder folder = ResourcesPlugin.getWorkspace().getRoot().getFolder(path); + if (folder.exists()) { + try { + for (IResource member : folder.members()) { + if (ITmfEventsEditorConstants.TRACE_INPUT_TYPE_CONSTANTS.contains(TmfTraceType.getTraceTypeId(member))) { + member.delete(true, null); + } + } + } catch (CoreException e) { + displayException(e); + } + } + } + + private static void setTraceType(IResource traceResource) { + try { + String traceType = TmfTraceType.getTraceTypeId(traceResource); + TraceTypeHelper traceTypeHelper = TmfTraceType.getTraceType(traceType); + if (traceTypeHelper == null) { + traceTypeHelper = TmfTraceTypeUIUtils.selectTraceType(traceResource.getLocation().toOSString(), null, null); + } + if (traceTypeHelper != null) { + TmfTraceTypeUIUtils.setTraceType(traceResource, traceTypeHelper); + } + } catch (TmfTraceImportException e) { + } catch (CoreException e) { + displayException(e); + } + } + + /** + * Display an exception in a message box + * + * @param e the exception + */ + private static void displayException(Exception e) { + MessageBox mb = new MessageBox(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell()); + mb.setText(e.getClass().getName()); + mb.setMessage(e.getMessage()); + mb.open(); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/ImportTraceHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/ImportTraceHandler.java new file mode 100644 index 0000000000..ead339d9b3 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/ImportTraceHandler.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2009, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + * Bernd Hufmann - Update selection handling + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.ImportTraceWizard; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * <b><u>ImportTraceHandler</u></b> + * <p> + * Starts an ImportTraceWizard that will handle the lowly details. + */ +public class ImportTraceHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ImportTraceWizard w = new ImportTraceWizard(); + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + + if (window == null) { + return false; + } + + ISelection currentSelection = HandlerUtil.getCurrentSelection(event); + // Menu Selection is only not null for context-sensitive menu + ISelection menuSelection = HandlerUtil.getActiveMenuSelection(event); + + IStructuredSelection sec = StructuredSelection.EMPTY; + + // Only use the selection if handler is called from context-sensitive menu + if ((menuSelection != null) && (currentSelection instanceof IStructuredSelection)) { + sec = (IStructuredSelection) currentSelection; + } + + w.init(PlatformUI.getWorkbench(), sec); + WizardDialog dialog = new WizardDialog(window.getShell(), w); + dialog.open(); + return null; + } +} 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 new file mode 100644 index 0000000000..0314b68990 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/Messages.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2011, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + * Patrick Tasse - Added drag and drop messages + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.osgi.util.NLS; + +/** + * Messages file + * + * @author Francois Chouinard + * @version 1.0 + */ +@SuppressWarnings("javadoc") +public class Messages extends NLS { + + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.tmf.ui.project.handlers.messages"; //$NON-NLS-1$ + + public static String DeleteDialog_Title; + public static String DeleteTraceHandler_Message; + public static String DeleteTraceHandler_Error; + public static String DeleteTraceHandler_TaskName; + public static String DeleteTraceHandlerGeneric_Message; + public static String DeleteTraceHandlerGeneric_Error; + public static String DeleteExperimentHandler_Message; + public static String DeleteExperimentHandler_Error; + public static String DeleteFolderHandler_Message; + public static String DeleteFolderHandler_Error; + public static String DeleteFolderHandler_TaskName; + + public static String RemoveDialog_Title; + public static String RemoveTraceFromExperimentHandler_Message; + public static String RemoveTraceFromExperimentHandler_TaskName; + public static String RemoveTraceFromExperimentHandler_Error; + public static String ClearDialog_Title; + public static String DeleteFolderHandlerClear_Message; + public static String DeleteFolderHandlerClear_Error; + public static String DeleteFolderHandlerClear_TaskName; + + public static String SelectTraceTypeHandler_ErrorSelectingTrace; + public static String SelectTraceTypeHandler_Title; + public static String SelectTraceTypeHandler_TraceFailedValidation; + public static String SelectTraceTypeHandler_TracesFailedValidation; + public static String SelectTraceTypeHandler_InvalidTraceType; + + public static String DropAdapterAssistant_RenameTraceTitle; + public static String DropAdapterAssistant_RenameTraceMessage; + + public static String SynchronizeTracesHandler_InitError; + public static String SynchronizeTracesHandler_CopyProblem; + public static String SynchronizeTracesHandler_WrongType; + public static String SynchronizeTracesHandler_WrongTraceNumber; + public static String SynchronizeTracesHandler_Title; + public static String SynchronizeTracesHandler_Error; + public static String SynchronizeTracesHandler_ErrorSynchingExperiment; + public static String SynchronizeTracesHandler_ErrorSynchingForTrace; + + public static String ClearTraceOffsetHandler_Title; + public static String ClearTraceOffsetHandler_ConfirmMessage; + + public static String DeleteSupplementaryFiles_DeletionTask; + public static String DeleteSupplementaryFiles_ProjectRefreshTask; + + public static String AnalysisModule_Help; + + public static String TmfActionProvider_OpenWith; + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/NewExperimentHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/NewExperimentHandler.java new file mode 100644 index 0000000000..0548db66bc --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/NewExperimentHandler.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2009, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentFolder; +import org.eclipse.tracecompass.tmf.ui.project.wizards.NewExperimentDialog; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * <b><u>NewExperimentHandler</u></b> + * <p> + */ +public class NewExperimentHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + // Get the selection + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IWorkbenchPart part = page.getActivePart(); + if (part == null) { + return Boolean.FALSE; + } + ISelection selection = part.getSite().getSelectionProvider().getSelection(); + TmfExperimentFolder experimentFolder = null; + if (selection instanceof TreeSelection) { + TreeSelection sel = (TreeSelection) selection; + Object element = sel.getFirstElement(); + if (element instanceof TmfExperimentFolder) { + experimentFolder = (TmfExperimentFolder) element; + } + } + if (experimentFolder == null) { + return null; + } + + // Fire the New Experiment dialog + Shell shell = window.getShell(); + NewExperimentDialog dialog = new NewExperimentDialog(shell, experimentFolder); + dialog.open(); + + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/NewFolderHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/NewFolderHandler.java new file mode 100644 index 0000000000..c189f11b4e --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/NewFolderHandler.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson + * + * 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 + * + * Contributors: + * Patrick Tasse - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; +import org.eclipse.tracecompass.tmf.ui.project.wizards.NewFolderDialog; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Handler for the New Folder command. + */ +public class NewFolderHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + ISelection selection = HandlerUtil.getCurrentSelection(event); + if (!(selection instanceof IStructuredSelection)) { + return null; + } + final Object element = ((IStructuredSelection) selection).getFirstElement(); + if (!(element instanceof TmfTraceFolder)) { + return null; + } + TmfTraceFolder parent = (TmfTraceFolder) element; + + // Fire the New Folder dialog + Shell shell = window.getShell(); + NewFolderDialog dialog = new NewFolderDialog(shell, parent); + dialog.open(); + + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OffsetTraceHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OffsetTraceHandler.java new file mode 100644 index 0000000000..a87a2320fe --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OffsetTraceHandler.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2014, 2015 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + * Patrick Tasse - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import java.lang.reflect.InvocationTargetException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +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.OperationCanceledException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.internal.tmf.ui.project.dialogs.offset.OffsetDialog; +import org.eclipse.tracecompass.internal.tmf.ui.project.operations.TmfWorkspaceModifyOperation; +import org.eclipse.tracecompass.tmf.core.synchronization.ITmfTimestampTransform; +import org.eclipse.tracecompass.tmf.core.synchronization.TimestampTransformFactory; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Offset Handler + * + * @author Matthew Khouzam + */ +public class OffsetTraceHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(final ExecutionEvent event) throws ExecutionException { + + ISelection selection = HandlerUtil.getCurrentSelection(event); + + // Get the set of selected trace elements + final Set<TmfTraceElement> traceElements = new HashSet<>(); + if (selection instanceof StructuredSelection) { + Iterator<Object> iterator = ((StructuredSelection) selection).iterator(); + while (iterator.hasNext()) { + Object element = iterator.next(); + if (element instanceof TmfTraceElement) { + TmfTraceElement trace = (TmfTraceElement) element; + traceElements.add(trace.getElementUnderTraceFolder()); + } else if (element instanceof TmfExperimentElement) { + TmfExperimentElement exp = (TmfExperimentElement) element; + for (TmfTraceElement trace : exp.getTraces()) { + traceElements.add(trace.getElementUnderTraceFolder()); + } + } else if (element instanceof TmfTraceFolder) { + TmfTraceFolder folder = (TmfTraceFolder) element; + traceElements.addAll(folder.getTraces()); + } + } + } + + if (traceElements.isEmpty()) { + return null; + } + + final Map<TmfTraceElement, Long> offsets = new LinkedHashMap<>(traceElements.size()); + for (TmfTraceElement trace : traceElements) { + offsets.put(trace, 0L); + } + + Shell shell = HandlerUtil.getActiveShellChecked(event); + OffsetDialog dialog = new OffsetDialog(shell, offsets); + dialog.open(); + + if (dialog.getReturnCode() != Window.OK) { + return null; + } + + TmfWorkspaceModifyOperation operation = new TmfWorkspaceModifyOperation() { + @Override + public void execute(IProgressMonitor monitor) throws CoreException { + for (final TmfTraceElement trace : offsets.keySet()) { + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + Long offset = offsets.get(trace); + if (offset != 0 && trace.getResource().exists()) { + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + trace.closeEditors(); + } + }); + long previousOffset = TimestampTransformFactory.getTimestampTransform(trace.getResource()).transform(0); + ITmfTimestampTransform transform = TimestampTransformFactory.createWithOffset(previousOffset + offset); + trace.deleteSupplementaryResources(); + // make sure the supplementary folder exists + trace.refreshSupplementaryFolder(); + TimestampTransformFactory.setTimestampTransform(trace.getResource(), transform); + trace.refreshSupplementaryFolder(); + } + } + } + }; + try { + PlatformUI.getWorkbench().getProgressService().run(true, true, operation); + } catch (InterruptedException e) { + return null; + } catch (InvocationTargetException e) { + MessageDialog.openError(shell, 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/OpenAction.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenAction.java new file mode 100644 index 0000000000..f7bec56714 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenAction.java @@ -0,0 +1,94 @@ +/******************************************************************************* +* Copyright (c) 2012, 2014 Ericsson + * + * 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 + * + * Contributors: + * Patrick Tasse - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.NotEnabledException; +import org.eclipse.core.commands.NotHandledException; +import org.eclipse.core.commands.common.NotDefinedException; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfAnalysisOutputElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectModelElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.handlers.IHandlerService; + +/** + * <b><u>OpenAction</u></b> + */ +public class OpenAction extends Action { + + private static final String OPEN_COMMAND_ID = "org.eclipse.ui.navigate.openResource"; //$NON-NLS-1$ + + private final IWorkbenchPage page; + private final ISelectionProvider selectionProvider; + private TmfProjectModelElement element; + + /** + * Default constructor + * @param page the workbench page + * @param selectionProvider the selection provider + */ + public OpenAction(IWorkbenchPage page, ISelectionProvider selectionProvider) { + this.page = page; + this.selectionProvider = selectionProvider; + } + + @Override + public boolean isEnabled() { + ISelection selection = selectionProvider.getSelection(); + if (!selection.isEmpty()) { + IStructuredSelection sSelection = (IStructuredSelection) selection; + Object firstElement = sSelection.getFirstElement(); + if ((sSelection.size() == 1) && (firstElement instanceof TmfTraceElement || + firstElement instanceof TmfExperimentElement || + firstElement instanceof TmfAnalysisOutputElement)) { + element = (TmfProjectModelElement) firstElement; + return true; + } + } + return false; + } + + @Override + public void run() { + try { + Object service = page.getActivePart().getSite().getService(IHandlerService.class); + IHandlerService handlerService = (IHandlerService) service; + boolean executeCommand = ((element instanceof TmfTraceElement) || (element instanceof TmfAnalysisOutputElement)); + + if (!executeCommand && element instanceof TmfExperimentElement) { + TmfExperimentElement experiment = (TmfExperimentElement) element; + executeCommand = (experiment.getTraces().size() > 0); + } + + if (executeCommand) { + handlerService.executeCommand(OPEN_COMMAND_ID, null); + } + } catch (ExecutionException e) { + Activator.getDefault().logError("Error opening resource " + element.getName(), e); //$NON-NLS-1$ + } catch (NotDefinedException e) { + Activator.getDefault().logError("Error opening resource " + element.getName(), e); //$NON-NLS-1$ + } catch (NotEnabledException e) { + Activator.getDefault().logError("Error opening resource " + element.getName(), e); //$NON-NLS-1$ + } catch (NotHandledException e) { + Activator.getDefault().logError("Error opening resource " + element.getName(), e); //$NON-NLS-1$ + } + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenAnalysisHelpHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenAnalysisHelpHandler.java new file mode 100644 index 0000000000..ae52eb4ba6 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenAnalysisHelpHandler.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 École Polytechnique de Montréal + * + * 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 + * + * Contributors: + * Geneviève Bastien - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfAnalysisElement; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * Handler for when user wants to open the analysis help text + * + * @author Geneviève Bastien + */ +public class OpenAnalysisHelpHandler extends AbstractHandler { + + private TmfAnalysisElement fAnalysis; + + @Override + public boolean isEnabled() { + // Check if we are closing down + final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == 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(); + + // Make sure there is only one selection and that it is a trace + fAnalysis = null; + if (selection instanceof TreeSelection) { + final TreeSelection sel = (TreeSelection) selection; + // There should be only one item selected as per the plugin.xml + final Object element = sel.getFirstElement(); + if (element instanceof TmfAnalysisElement) { + fAnalysis = (TmfAnalysisElement) element; + } + } + + return (fAnalysis != null); + } + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + // Check that the trace is valid + if (fAnalysis == null) { + return null; + } + + Thread thread = new Thread() { + @Override + public void run() { + displayHelpMsg(fAnalysis.getHelpMessage()); + } + }; + + thread.start(); + + return null; + } + + private static void displayHelpMsg(final String errorMsg) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + /* + * TODO: A message box is not the best place to show help. + * Something should be done with the Eclipse help + */ + final MessageBox mb = new MessageBox(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell()); + mb.setText(Messages.AnalysisModule_Help); + mb.setMessage(errorMsg); + mb.open(); + } + }); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenAnalysisOutputHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenAnalysisOutputHandler.java new file mode 100644 index 0000000000..f4d88d2d93 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenAnalysisOutputHandler.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 École Polytechnique de Montréal + * + * 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 + * + * Contributors: + * Geneviève Bastien - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfAnalysisOutputElement; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * Handler to programatically open a view + * + * @author Geneviève Bastien + */ +public class OpenAnalysisOutputHandler extends AbstractHandler { + + private TmfAnalysisOutputElement fOutputElement; + + @Override + public boolean isEnabled() { + /* Check if we are closing down */ + final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == 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(); + + /* Make sure there is only one selection and that it is an analysis output */ + fOutputElement = null; + if (selection instanceof TreeSelection) { + final TreeSelection sel = (TreeSelection) selection; + // There should be only one item selected as per the plugin.xml + final Object element = sel.getFirstElement(); + if (element instanceof TmfAnalysisOutputElement) { + fOutputElement = (TmfAnalysisOutputElement) element; + } + } + + return (fOutputElement != null); + } + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + /* Check if we are closing down */ + final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + /* Check that the view is valid */ + if (fOutputElement == null) { + return null; + } + + fOutputElement.outputAnalysis(); + + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenExperimentHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenExperimentHandler.java new file mode 100644 index 0000000000..ba782e15a3 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenExperimentHandler.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2009, 2014 Ericsson, École Polytechnique de Montréal + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + * Geneviève Bastien - Experiment instantiates with an experiment type + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfOpenTraceHelper; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * <b><u>OpenExperimentHandler</u></b> + * <p> + */ +public class OpenExperimentHandler extends AbstractHandler { + + private TmfExperimentElement fExperiment = null; + + // ------------------------------------------------------------------------ + // Validation + // ------------------------------------------------------------------------ + + @Override + public boolean isEnabled() { + + // Check if we are closing down + final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == 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(); + + // Make sure there is only one selection and that it is an experiment + fExperiment = null; + if (selection instanceof TreeSelection) { + final TreeSelection sel = (TreeSelection) selection; + // There should be only one item selected as per the plugin.xml + final Object element = sel.getFirstElement(); + if (element instanceof TmfExperimentElement) { + fExperiment = (TmfExperimentElement) element; + } + } + + // We only enable opening from the Traces folder for now + return ((fExperiment != null) && (fExperiment.getTraces().size() > 0)); + } + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(final ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + // Check that the experiment is valid + if (fExperiment == null) { + return null; + } + + TmfOpenTraceHelper.openTraceFromElement(fExperiment); + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenTraceHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenTraceHandler.java new file mode 100644 index 0000000000..604aba59c2 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/OpenTraceHandler.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2009, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfOpenTraceHelper; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * <b><u>OpenTraceHandler</u></b> + * <p> + * TODO: Add support for multiple trace selection + */ +public class OpenTraceHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + private TmfTraceElement fTrace = null; + + // ------------------------------------------------------------------------ + // Validation + // ------------------------------------------------------------------------ + + @Override + public boolean isEnabled() { + + // Check if we are closing down + final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == 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(); + + // Make sure there is only one selection and that it is a trace + fTrace = null; + if (selection instanceof TreeSelection) { + final TreeSelection sel = (TreeSelection) selection; + // There should be only one item selected as per the plugin.xml + final Object element = sel.getFirstElement(); + if (element instanceof TmfTraceElement) { + fTrace = (TmfTraceElement) element; + } + } + + // We only enable opening from the Traces folder for now + return (fTrace != null); + } + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(final ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + // Check that the trace is valid + if (fTrace == null) { + return null; + } + + // If trace is under an experiment, use the original trace from the traces folder + TmfOpenTraceHelper.openTraceFromElement(fTrace.getElementUnderTraceFolder()); + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/RefreshHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/RefreshHandler.java new file mode 100644 index 0000000000..14edcc13b7 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/RefreshHandler.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2011, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentFolder; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * <b><u>RefreshHandler</u></b> + * <p> + * TODO: Handle multiple selections + */ +public class RefreshHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + // Get the selection + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IWorkbenchPart part = page.getActivePart(); + if (part == null) { + return false; + } + ISelection selection = part.getSite().getSelectionProvider().getSelection(); + if (selection instanceof TreeSelection) { + TreeSelection treeSelection = (TreeSelection) selection; + Object element = treeSelection.getFirstElement(); + IResource resource = null; + if (element instanceof TmfTraceFolder) { + TmfTraceFolder folder = (TmfTraceFolder) element; + resource = folder.getResource(); + } + else if (element instanceof TmfExperimentFolder) { + TmfExperimentFolder folder = (TmfExperimentFolder) element; + resource = folder.getResource(); + } + else if (element instanceof TmfExperimentElement) { + TmfExperimentElement folder = (TmfExperimentElement) element; + resource = folder.getResource(); + } + try { + if (resource != null) { + resource.refreshLocal(IResource.DEPTH_INFINITE, null); + } + } catch (CoreException e) { + Activator.getDefault().logError("Error refreshing projects", e); //$NON-NLS-1$ + } + } + + + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/RenameExperimentHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/RenameExperimentHandler.java new file mode 100644 index 0000000000..b66bb31d68 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/RenameExperimentHandler.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2011, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.wizards.RenameExperimentDialog; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * <b><u>RenameExperimentHandler</u></b> + * <p> + */ +public class RenameExperimentHandler extends AbstractHandler { + + private TmfExperimentElement fExperiment = null; + + // ------------------------------------------------------------------------ + // isEnabled + // ------------------------------------------------------------------------ + + @Override + public boolean isEnabled() { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return false; + } + + // Get the selection + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IWorkbenchPart part = page.getActivePart(); + if (part == null) { + return false; + } + ISelectionProvider selectionProvider = part.getSite().getSelectionProvider(); + if (selectionProvider == null) { + return false; + } + ISelection selection = selectionProvider.getSelection(); + + // Make sure there is only selection and that it is an experiment + fExperiment = null; + if (selection instanceof TreeSelection) { + TreeSelection sel = (TreeSelection) selection; + Object element = sel.getFirstElement(); + if (element instanceof TmfExperimentElement) { + fExperiment = (TmfExperimentElement) element; + } + } + + return (fExperiment != null); + } + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + // Fire the Rename Experiment dialog + Shell shell = window.getShell(); + RenameExperimentDialog dialog = new RenameExperimentDialog(shell, fExperiment); + dialog.open(); + + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/RenameFolderHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/RenameFolderHandler.java new file mode 100644 index 0000000000..cbbfb8546a --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/RenameFolderHandler.java @@ -0,0 +1,164 @@ +/******************************************************************************* + * Copyright (c) 2014, 2015 Ericsson + * + * 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 + * + * Contributors: + * Patrick Tasse - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +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.TmfExperimentElement; +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.wizards.RenameFolderDialog; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.WorkspaceModifyOperation; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Handler for the Rename Folder command. + */ +public class RenameFolderHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + ISelection selection = HandlerUtil.getCurrentSelection(event); + TmfTraceFolder selectedFolder = null; + if (selection instanceof IStructuredSelection) { + Object element = ((IStructuredSelection) selection).getFirstElement(); + if (element instanceof TmfTraceFolder) { + selectedFolder = (TmfTraceFolder) element; + } + } + if (selectedFolder == null) { + return null; + } + final TmfTraceFolder oldFolder = selectedFolder; + + // Fire the Rename Folder dialog + RenameFolderDialog dialog = new RenameFolderDialog(window.getShell(), oldFolder); + dialog.open(); + + if (dialog.getReturnCode() != Window.OK) { + return null; + } + + final String newName = (String) dialog.getFirstResult(); + + IContainer parentFolder = oldFolder.getResource().getParent(); + final TmfTraceFolder tracesFolder = oldFolder.getProject().getTracesFolder(); + final IPath newFolderPath = parentFolder.getFullPath().append(newName); + + WorkspaceModifyOperation operation = new WorkspaceModifyOperation() { + @Override + public void execute(IProgressMonitor monitor) throws CoreException { + try { + monitor.beginTask("", 1000); //$NON-NLS-1$ + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + + for (final TmfTraceElement traceElement : oldFolder.getTraces()) { + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + traceElement.closeEditors(); + } + }); + + IPath relativePath = traceElement.getPath().makeRelativeTo(oldFolder.getPath()); + String newElementPath = newFolderPath.makeRelativeTo(tracesFolder.getPath()).append(relativePath).toString(); + traceElement.renameSupplementaryFolder(newElementPath); + } + + oldFolder.getResource().move(newFolderPath, IResource.FORCE | IResource.SHALLOW, monitor); + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + } finally { + monitor.done(); + } + } + }; + + try { + PlatformUI.getWorkbench().getProgressService().busyCursorWhile(operation); + } catch (InterruptedException e) { + return null; + } catch (InvocationTargetException e) { + MessageDialog.openError(window.getShell(), e.toString(), e.getTargetException().toString()); + return null; + } + + /* We need to split the WorkspaceModifyOperation so that the new model + * elements get created by the resource changed event */ + operation = new WorkspaceModifyOperation() { + @Override + protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { + + IPath oldFolderElementPath = oldFolder.getPath().makeRelativeTo(tracesFolder.getPath()); + IPath newFolderElementPath = oldFolderElementPath.removeLastSegments(1).append(newName); + for (TmfExperimentElement experiment : oldFolder.getProject().getExperimentsFolder().getExperiments()) { + for (TmfTraceElement oldTrace : experiment.getTraces()) { + if (oldTrace.getElementPath().startsWith(oldFolderElementPath.toString())) { + experiment.removeTrace(oldTrace); + String relativePath = oldTrace.getElementPath().substring(oldFolderElementPath.toString().length() + 1); + String newTraceElementPath = newFolderElementPath.append(relativePath).toString(); + for (TmfTraceElement newTrace : tracesFolder.getTraces()) { + if (newTrace.getElementPath().equals(newTraceElementPath)) { + experiment.addTrace(newTrace); + break; + } + } + } + } + } + } + }; + + try { + PlatformUI.getWorkbench().getProgressService().busyCursorWhile(operation); + } catch (InterruptedException e) { + return null; + } catch (InvocationTargetException e) { + MessageDialog.openError(window.getShell(), 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/RenameTraceHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/RenameTraceHandler.java new file mode 100644 index 0000000000..a9066d3320 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/RenameTraceHandler.java @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright (c) 2009, 2015 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + * Patrick Tasse - Add support for folder elements + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +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.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentFolder; +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.wizards.RenameTraceDialog; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.WorkspaceModifyOperation; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Handler for the Rename Trace command. + */ +public class RenameTraceHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + ISelection selection = HandlerUtil.getCurrentSelection(event); + TmfTraceElement selectedTrace = null; + if (selection instanceof IStructuredSelection) { + Object element = ((IStructuredSelection) selection).getFirstElement(); + if (element instanceof TmfTraceElement) { + selectedTrace = (TmfTraceElement) element; + } + } + if (selectedTrace == null) { + return null; + } + + // If trace is under an experiment, use the original trace from the traces folder + final TmfTraceElement oldTrace = selectedTrace.getElementUnderTraceFolder(); + + RenameTraceDialog dialog = new RenameTraceDialog(window.getShell(), oldTrace); + if (dialog.open() != Window.OK) { + return null; + } + + final TmfTraceFolder traceFolder = (TmfTraceFolder) oldTrace.getParent(); + final String newName = (String) dialog.getFirstResult(); + + IFolder parentFolder = (IFolder) oldTrace.getParent().getResource(); + final TmfTraceFolder tracesFolder = oldTrace.getProject().getTracesFolder(); + final IPath newPath = parentFolder.getFullPath().append(newName); + + WorkspaceModifyOperation operation = new WorkspaceModifyOperation() { + @Override + public void execute(IProgressMonitor monitor) throws CoreException { + try { + monitor.beginTask("", 1000); //$NON-NLS-1$ + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + // Close the trace if open + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + oldTrace.closeEditors(); + } + }); + + if (oldTrace.getResource() instanceof IFolder) { + IFolder folder = (IFolder) oldTrace.getResource(); + IFile bookmarksFile = oldTrace.getBookmarksFile(); + if (bookmarksFile.exists()) { + IFile newBookmarksFile = folder.getFile(bookmarksFile.getName().replace(oldTrace.getName(), newName)); + if (!newBookmarksFile.exists()) { + IPath newBookmarksPath = newBookmarksFile.getFullPath(); + bookmarksFile.move(newBookmarksPath, IResource.FORCE | IResource.SHALLOW, monitor); + } + } + } + + String newElementPath = newPath.makeRelativeTo(tracesFolder.getPath()).toString(); + oldTrace.renameSupplementaryFolder(newElementPath); + oldTrace.getResource().move(newPath, IResource.FORCE | IResource.SHALLOW, monitor); + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + } finally { + monitor.done(); + } + } + }; + + try { + PlatformUI.getWorkbench().getProgressService().busyCursorWhile(operation); + } catch (InterruptedException e) { + return null; + } catch (InvocationTargetException e) { + MessageDialog.openError(window.getShell(), e.toString(), e.getTargetException().toString()); + return null; + } + + /* We need to split the WorkspaceModifyOperation so that the new model + * elements get created by the resource changed event */ + operation = new WorkspaceModifyOperation() { + @Override + protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { + + // Locate the new trace object + TmfTraceElement newTrace = null; + String newElementPath = oldTrace.getParent().getPath().append(newName).makeRelativeTo(tracesFolder.getPath()).toString(); + for (TmfTraceElement element : traceFolder.getTraces()) { + if (element.getElementPath().equals(newElementPath)) { + newTrace = element; + break; + } + } + if (newTrace == null) { + return; + } + + TmfExperimentFolder experimentFolder = newTrace.getProject().getExperimentsFolder(); + for (final TmfExperimentElement experiment : experimentFolder.getExperiments()) { + for (final TmfTraceElement expTrace : experiment.getTraces()) { + if (expTrace.getElementPath().equals(oldTrace.getElementPath())) { + experiment.removeTrace(expTrace); + experiment.addTrace(newTrace); + } + } + } + } + }; + + try { + PlatformUI.getWorkbench().getProgressService().busyCursorWhile(operation); + } catch (InterruptedException e) { + } catch (InvocationTargetException e) { + MessageDialog.openError(window.getShell(), e.toString(), e.getTargetException().toString()); + } + + return null; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/SelectElementTypeContributionItem.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/SelectElementTypeContributionItem.java new file mode 100644 index 0000000000..2c09e8d3d5 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/SelectElementTypeContributionItem.java @@ -0,0 +1,269 @@ +/******************************************************************************* + * Copyright (c) 2011, 2014 Ericsson, École Polytechnique de Montréal + * + * 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 + * + * Contributors: + * Patrick Tasse - Initial API and implementation + * Geneviève Bastien - Moved SelectTraceTypeContributionItem to this class + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomTxtTrace; +import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomTxtTraceDefinition; +import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlTrace; +import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlTraceDefinition; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType.TraceElementType; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceTypeUIUtils; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.CompoundContributionItem; +import org.eclipse.ui.menus.CommandContributionItem; +import org.eclipse.ui.menus.CommandContributionItemParameter; + +/** + * ContributionItem for the element type selection. + * + * @author Patrick Tassé + */ +public class SelectElementTypeContributionItem extends CompoundContributionItem { + + private static final ImageDescriptor SELECTED_ICON = Activator.getDefault().getImageDescripterFromPath("icons/elcl16/bullet.gif"); //$NON-NLS-1$ + private static final String BUNDLE_PARAMETER = "org.eclipse.linuxtools.tmf.ui.commandparameter.select_trace_type.bundle"; //$NON-NLS-1$ + private static final String TYPE_PARAMETER = "org.eclipse.linuxtools.tmf.ui.commandparameter.select_trace_type.type"; //$NON-NLS-1$ + private static final String ICON_PARAMETER = "org.eclipse.linuxtools.tmf.ui.commandparameter.select_trace_type.icon"; //$NON-NLS-1$ + private static final String SELECT_TRACE_TYPE_COMMAND_ID = "org.eclipse.linuxtools.tmf.ui.command.select_trace_type"; //$NON-NLS-1$ + private static final String DEFAULT_TRACE_ICON_PATH = "icons/elcl16/trace.gif"; //$NON-NLS-1$ + + @Override + protected IContributionItem[] getContributionItems() { + + /* + * Fill the selected trace types and verify if selection applies only to + * either traces or experiments + */ + Set<String> selectedTraceTypes = new HashSet<>(); + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + IWorkbenchPage page = window.getActivePage(); + ISelection selection = page.getSelection(); + boolean forTraces = false, forExperiments = false; + if (selection instanceof StructuredSelection) { + for (Object element : ((StructuredSelection) selection).toList()) { + if (element instanceof TmfTraceElement) { + TmfTraceElement trace = (TmfTraceElement) element; + selectedTraceTypes.add(trace.getTraceType()); + forTraces = true; + } else if (element instanceof TmfExperimentElement) { + TmfExperimentElement exp = (TmfExperimentElement) element; + selectedTraceTypes.add(exp.getTraceType()); + forExperiments = true; + } + } + } + + if (forTraces && forExperiments) { + /* This should never happen anyways */ + throw new RuntimeException("You must select only experiments or only traces to set the element type"); //$NON-NLS-1$ + } + + return getContributionItems(selectedTraceTypes, forExperiments); + } + + /** + * Get the contribution items for traces + * + * @param selectedTraceTypes + * The set of selected trace types + * @param forExperiments + * <code>true</code> if the contribution items are requested for + * experiments, <code>false</code> for traces + * + * @return The list of contribution items + */ + protected IContributionItem[] getContributionItems(Set<String> selectedTraceTypes, boolean forExperiments) { + + String ceType = forExperiments ? TmfTraceType.EXPERIMENT_ELEM : TmfTraceType.TYPE_ELEM; + TraceElementType elementType = forExperiments ? TraceElementType.EXPERIMENT : TraceElementType.TRACE; + + List<IContributionItem> list = new LinkedList<>(); + + Map<String, MenuManager> categoriesMap = new HashMap<>(); + IConfigurationElement[] config = Platform.getExtensionRegistry().getConfigurationElementsFor( + TmfTraceType.TMF_TRACE_TYPE_ID); + for (IConfigurationElement ce : config) { + if (ce.getName().equals(TmfTraceType.CATEGORY_ELEM)) { + String categoryId = ce.getAttribute(TmfTraceType.ID_ATTR); + ImageDescriptor icon = isSelectedCategory(categoryId, config, selectedTraceTypes) ? SELECTED_ICON : null; + MenuManager subMenu = new MenuManager(ce.getAttribute(TmfTraceType.NAME_ATTR), icon, null); + categoriesMap.put(categoryId, subMenu); + list.add(subMenu); + } + } + + for (IConfigurationElement ce : config) { + if (ce.getName().equals(ceType)) { + String traceBundle = ce.getContributor().getName(); + String traceTypeId = ce.getAttribute(TmfTraceType.ID_ATTR); + String label = ce.getAttribute(TmfTraceType.NAME_ATTR).replaceAll("&", "&&"); //$NON-NLS-1$ //$NON-NLS-2$ + boolean selected = selectedTraceTypes.contains(traceTypeId); + MenuManager subMenu = categoriesMap.get(ce.getAttribute(TmfTraceType.CATEGORY_ATTR)); + + /* Get the icon from the tmftracetypeui extension, if it exists */ + String traceIcon = null; + IConfigurationElement uiCE = TmfTraceTypeUIUtils.getTraceUIAttributes(traceTypeId, elementType); + if (uiCE != null) { + traceIcon = uiCE.getAttribute(TmfTraceTypeUIUtils.ICON_ATTR); + } + + addContributionItem(list, traceBundle, traceTypeId, traceIcon, label, selected, subMenu); + } + } + + Comparator<IContributionItem> comparator = new Comparator<IContributionItem>() { + @Override + public int compare(IContributionItem o1, IContributionItem o2) { + if (o1 instanceof MenuManager) { + if (o2 instanceof MenuManager) { + MenuManager m1 = (MenuManager) o1; + MenuManager m2 = (MenuManager) o2; + return m1.getMenuText().compareTo(m2.getMenuText()); + } + return -1; + } + if (o2 instanceof MenuManager) { + return 1; + } + CommandContributionItem c1 = (CommandContributionItem) o1; + CommandContributionItem c2 = (CommandContributionItem) o2; + return c1.getData().label.compareTo(c2.getData().label); + } + }; + + if (forExperiments) { + Collections.sort(list, comparator); + return list.toArray(new IContributionItem[list.size()]); + } + + /* + * Add the custom txt and xml trace type to the contribution items for + * traces + */ + for (CustomTxtTraceDefinition def : CustomTxtTraceDefinition.loadAll()) { + String traceBundle = Activator.getDefault().getBundle().getSymbolicName(); + String traceTypeId = CustomTxtTrace.buildTraceTypeId(def.categoryName, def.definitionName); + String traceIcon = DEFAULT_TRACE_ICON_PATH; + String label = def.definitionName; + boolean selected = selectedTraceTypes.contains(traceTypeId); + MenuManager subMenu = getCategorySubMenu(list, categoriesMap, def.categoryName, selected); + + addContributionItem(list, traceBundle, traceTypeId, traceIcon, label, selected, subMenu); + } + for (CustomXmlTraceDefinition def : CustomXmlTraceDefinition.loadAll()) { + String traceBundle = Activator.getDefault().getBundle().getSymbolicName(); + String traceTypeId = CustomXmlTrace.buildTraceTypeId(def.categoryName, def.definitionName); + String traceIcon = DEFAULT_TRACE_ICON_PATH; + String label = def.definitionName; + boolean selected = selectedTraceTypes.contains(traceTypeId); + MenuManager subMenu = getCategorySubMenu(list, categoriesMap, def.categoryName, selected); + + addContributionItem(list, traceBundle, traceTypeId, traceIcon, label, selected, subMenu); + } + + Collections.sort(list, comparator); + return list.toArray(new IContributionItem[list.size()]); + } + + private static MenuManager getCategorySubMenu(List<IContributionItem> list, + Map<String, MenuManager> categoriesMap, String categoryName, boolean selected) { + for (Entry<String, MenuManager> entry : categoriesMap.entrySet()) { + MenuManager subMenu = entry.getValue(); + if (subMenu.getMenuText().equals(categoryName)) { + if (selected) { + subMenu.setImageDescriptor(SELECTED_ICON); + } + return subMenu; + } + } + ImageDescriptor icon = selected ? SELECTED_ICON : null; + MenuManager subMenu = new MenuManager(categoryName, icon, null); + categoriesMap.put(categoryName, subMenu); + list.add(subMenu); + return subMenu; + } + + private static void addContributionItem(List<IContributionItem> list, + String traceBundle, String traceTypeId, String traceIcon, + String label, boolean selected, + MenuManager subMenu) { + Map<String, String> params; + + params = new HashMap<>(); + params.put(BUNDLE_PARAMETER, traceBundle); + params.put(TYPE_PARAMETER, traceTypeId); + params.put(ICON_PARAMETER, traceIcon); + + ImageDescriptor icon = null; + if (selected) { + icon = SELECTED_ICON; + } + + CommandContributionItemParameter param = new CommandContributionItemParameter( + PlatformUI.getWorkbench().getActiveWorkbenchWindow(), // serviceLocator + "my.parameterid", // id //$NON-NLS-1$ + SELECT_TRACE_TYPE_COMMAND_ID, // commandId + CommandContributionItem.STYLE_PUSH // style + ); + param.parameters = params; + param.icon = icon; + param.disabledIcon = icon; + param.hoverIcon = icon; + param.label = label; + param.visibleEnabled = true; + + if (subMenu != null) { + subMenu.add(new CommandContributionItem(param)); + } else { + list.add(new CommandContributionItem(param)); + } + } + + private static boolean isSelectedCategory(String categoryId, IConfigurationElement[] config, Set<String> selectedTraceTypes) { + for (IConfigurationElement ce : config) { + if (ce.getName().equals(TmfTraceType.TYPE_ELEM)) { + String traceTypeId = ce.getAttribute(TmfTraceType.ID_ATTR); + if (selectedTraceTypes.contains(traceTypeId)) { + if (categoryId.equals(ce.getAttribute(TmfTraceType.CATEGORY_ATTR))) { + return true; + } + } + } + } + return false; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/SelectTraceTypeHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/SelectTraceTypeHandler.java new file mode 100644 index 0000000000..ad5b264199 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/SelectTraceTypeHandler.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2011, 2014 Ericsson, École Polytechnique de Montréal + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + * Patrick Tasse - Fix propagation to experiment traces + * Geneviève Bastien - Add support of experiment types + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType; +import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfCommonProjectElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentFolder; +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.TmfTraceTypeUIUtils; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * <b><u>SetTraceTypeHandler</u></b> + * <p> + */ +public class SelectTraceTypeHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + + private static final String TYPE_PARAMETER = "org.eclipse.linuxtools.tmf.ui.commandparameter.select_trace_type.type"; //$NON-NLS-1$ + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + private TreeSelection fSelection = null; + + // ------------------------------------------------------------------------ + // Validation + // ------------------------------------------------------------------------ + + @Override + public boolean isEnabled() { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return false; + } + + // Get the selection + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IWorkbenchPart part = page.getActivePart(); + if (part == null) { + return false; + } + ISelectionProvider selectionProvider = part.getSite().getSelectionProvider(); + if (selectionProvider == null) { + return false; + } + ISelection selection = selectionProvider.getSelection(); + + // Make sure selection contains only traces + fSelection = null; + if (selection instanceof TreeSelection) { + fSelection = (TreeSelection) selection; + Iterator<Object> iterator = fSelection.iterator(); + while (iterator.hasNext()) { + Object element = iterator.next(); + if (!(element instanceof TmfCommonProjectElement)) { + return false; + } + } + } + + // If we get here, either nothing is selected or everything is a trace + return !selection.isEmpty(); + } + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + List<IStatus> statuses = new ArrayList<>(); + Set<TmfProjectElement> projects = new HashSet<>(); + boolean ok = true; + for (Object element : fSelection.toList()) { + TmfCommonProjectElement trace = (TmfCommonProjectElement) element; + if (trace instanceof TmfTraceElement) { + trace = ((TmfTraceElement) trace).getElementUnderTraceFolder(); + } + IResource resource = trace.getResource(); + if (resource != null) { + try { + // Set the trace type for this resource + String traceType = event.getParameter(TYPE_PARAMETER); + String previousTraceType = trace.getTraceType(); + IStatus status = propagateProperties(trace, traceType); + ok &= status.isOK(); + + if (status.isOK()) { + if ((previousTraceType != null) && (!traceType.equals(previousTraceType))) { + // Close the trace if open + trace.closeEditors(); + // Delete all supplementary resources + trace.deleteSupplementaryResources(); + } + } else { + statuses.add(status); + } + projects.add(trace.getProject()); + } catch (CoreException e) { + Activator.getDefault().logError(Messages.SelectTraceTypeHandler_ErrorSelectingTrace + trace.getName(), e); + } + } + trace.getProject(); + } + for (TmfProjectElement project : projects) { + project.refresh(); + } + + if (!ok) { + final Shell shell = window.getShell(); + MultiStatus info = new MultiStatus(Activator.PLUGIN_ID, 1, Messages.SelectTraceTypeHandler_TraceFailedValidation, null); + if (statuses.size() > 1) + { + info = new MultiStatus(Activator.PLUGIN_ID, 1, Messages.SelectTraceTypeHandler_TracesFailedValidation, null); + } + for (IStatus status : statuses) { + info.add(status); + } + ErrorDialog.openError(shell, Messages.SelectTraceTypeHandler_Title, Messages.SelectTraceTypeHandler_InvalidTraceType, info); + } + return null; + } + + private static IStatus propagateProperties(TmfCommonProjectElement element, String traceType) + throws CoreException { + + TraceTypeHelper traceTypeHelper = TmfTraceType.getTraceType(traceType); + if (traceTypeHelper == null) { + return Status.CANCEL_STATUS; + } + final IStatus validateTraceType = traceTypeHelper.validate(element.getResource().getLocation().toOSString()); + if (!validateTraceType.isOK()) { + return validateTraceType; + } + + IResource resource = element.getResource(); + TmfTraceTypeUIUtils.setTraceType(resource, traceTypeHelper); + + TmfExperimentFolder experimentFolder = element.getProject().getExperimentsFolder(); + for (final TmfExperimentElement experiment : experimentFolder.getExperiments()) { + for (final TmfTraceElement child : experiment.getTraces()) { + if (child.getName().equals(element.getName())) { + TmfTraceTypeUIUtils.setTraceType(child.getResource(), traceTypeHelper); + break; + } + } + } + + return Status.OK_STATUS; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/SelectTracesHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/SelectTracesHandler.java new file mode 100644 index 0000000000..1865df3bf0 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/SelectTracesHandler.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2009, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentFolder; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement; +import org.eclipse.tracecompass.tmf.ui.project.wizards.SelectTracesWizard; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * <b><u>SelectTracesHandler</u></b> + * <p> + */ +public class SelectTracesHandler extends AbstractHandler { + + private TmfExperimentElement fExperiment = null; + + // ------------------------------------------------------------------------ + // Validation + // ------------------------------------------------------------------------ + + @Override + public boolean isEnabled() { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return false; + } + + // Get the selection + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IWorkbenchPart part = page.getActivePart(); + if (part == null) { + return false; + } + ISelectionProvider selectionProvider = part.getSite().getSelectionProvider(); + if (selectionProvider == null) { + return false; + } + ISelection selection = selectionProvider.getSelection(); + + // Make sure there is only one selection and that it is an experiment + fExperiment = null; + if (selection instanceof TreeSelection) { + TreeSelection sel = (TreeSelection) selection; + // There should be only one item selected as per the plugin.xml + Object element = sel.getFirstElement(); + if (element instanceof TmfExperimentElement) { + fExperiment = (TmfExperimentElement) element; + } + } + + return (fExperiment != null); + } + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + // Fire the Select Traces Wizard + IWorkbench workbench = PlatformUI.getWorkbench(); + Shell shell = workbench.getActiveWorkbenchWindow().getShell(); + + TmfExperimentFolder experiments = (TmfExperimentFolder) fExperiment.getParent(); + TmfProjectElement project = (TmfProjectElement) experiments.getParent(); + SelectTracesWizard wizard = new SelectTracesWizard(project, fExperiment); + wizard.init(PlatformUI.getWorkbench(), null); + WizardDialog dialog = new WizardDialog(shell, wizard); + dialog.open(); + + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/SynchronizeTracesHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/SynchronizeTracesHandler.java new file mode 100644 index 0000000000..13706e7243 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/SynchronizeTracesHandler.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 École Polytechnique de Montréal + * + * 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 + * + * Contributors: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; +import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException; +import org.eclipse.tracecompass.tmf.core.synchronization.SynchronizationAlgorithm; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; +import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TraceUtils; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * Handles the synchronization of an experiment, when the user selects this + * option in the menu + */ +public class SynchronizeTracesHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + private TreeSelection fSelection = null; + private static final String CR = System.getProperty("line.separator"); //$NON-NLS-1$ + + // ------------------------------------------------------------------------ + // Validation + // ------------------------------------------------------------------------ + + @Override + public boolean isEnabled() { + return true; + } + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + // Get the selection + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IWorkbenchPart part = page.getActivePart(); + if (part == null) { + return Boolean.FALSE; + } + ISelectionProvider selectionProvider = part.getSite().getSelectionProvider(); + if (selectionProvider == null) { + return Boolean.FALSE; + } + ISelection selection = selectionProvider.getSelection(); + + // Make sure selection contains only traces + fSelection = null; + final ArrayList<TmfTraceElement> tl = new ArrayList<>(); + final ArrayList<TmfExperimentElement> uiexperiment = new ArrayList<>(); + if (selection instanceof TreeSelection) { + fSelection = (TreeSelection) selection; + Iterator<Object> iterator = fSelection.iterator(); + while (iterator.hasNext()) { + Object element = iterator.next(); + if (element instanceof TmfTraceElement) { + tl.add((TmfTraceElement) element); + } else if (element instanceof TmfExperimentElement) { + TmfExperimentElement exp = (TmfExperimentElement) element; + uiexperiment.add(exp); + for (TmfTraceElement trace : exp.getTraces()) { + tl.add(trace); + } + } + } + } + + if ((uiexperiment.size() != 1) || (tl.size() < 2)) { + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, Messages.SynchronizeTracesHandler_WrongTraceNumber); + return null; + } + + Thread thread = new Thread() { + @Override + public void run() { + + final ITmfTrace[] traces = new ITmfTrace[tl.size()]; + final TmfExperimentElement exp = uiexperiment.get(0); + + for (int i = 0; i < tl.size(); i++) { + ITmfTrace trace = tl.get(i).instantiateTrace(); + ITmfEvent traceEvent = tl.get(i).instantiateEvent(); + if (trace == null) { + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, Messages.SynchronizeTracesHandler_WrongType + tl.get(i).getName()); + for (int j = 0; j < i; j++) { + traces[j].dispose(); + } + return; + } + try { + trace.initTrace(tl.get(i).getResource(), tl.get(i).getResource().getLocation().toOSString(), traceEvent.getClass()); + TmfTraceManager.refreshSupplementaryFiles(trace); + } catch (TmfTraceException e) { + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, Messages.SynchronizeTracesHandler_InitError + CR + CR + e); + trace.dispose(); + for (int j = 0; j < i; j++) { + traces[j].dispose(); + } + return; + } + traces[i] = trace; + } + + /* + * FIXME Unlike traces, there is no instanceExperiment, so + * we call this function here alone. Maybe it would be + * better to do this on experiment's element constructor? + */ + exp.refreshSupplementaryFolder(); + final TmfExperiment experiment = new TmfExperiment(ITmfEvent.class, + exp.getName(), traces, TmfExperiment.DEFAULT_INDEX_PAGE_SIZE, exp.getResource()); + + final SynchronizationAlgorithm syncAlgo = experiment.synchronizeTraces(true); + TmfTraceManager.refreshSupplementaryFiles(experiment); + + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + List<TmfTraceElement> tracesToAdd = new ArrayList<>(); + List<TmfTraceElement> tracesToRemove = new ArrayList<>(); + /* + * For each trace in the experiment, if there is + * a transform equation, copy the original + * trace, so that a new state system will be + * generated with sync time. + */ + for (TmfTraceElement traceel : tl) { + /* + * Find the trace corresponding to this + * element in the experiment + */ + ITmfTrace expTrace = null; + for (ITmfTrace t : experiment.getTraces()) { + if (t.getResource().equals(traceel.getResource())) { + expTrace = t; + break; + } + } + if ((expTrace != null) && syncAlgo.isTraceSynced(expTrace.getHostId())) { + + /* Find the original trace */ + TmfTraceElement origtrace = traceel.getElementUnderTraceFolder(); + + /* + * Make sure a trace with the + * new name does not exist + */ + String newname = traceel.getName(); + IContainer parentFolder = origtrace.getResource().getParent(); + boolean traceexists; + do { + traceexists = false; + newname += "_"; //$NON-NLS-1$ + if (parentFolder.findMember(newname) != null) { + traceexists = true; + } + } while (traceexists); + + /* Copy the original trace */ + TmfTraceElement newtrace = origtrace.copy(newname); + if (newtrace == null) { + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, + Messages.SynchronizeTracesHandler_Error + CR + CR + String.format(Messages.SynchronizeTracesHandler_CopyProblem, origtrace.getName())); + continue; + } + + /* + * Instantiate the new trace + * and set its sync formula + */ + ITmfTrace trace = newtrace.instantiateTrace(); + ITmfEvent traceEvent = newtrace.instantiateEvent(); + + try { + trace.initTrace(newtrace.getResource(), newtrace.getResource().getLocation().toOSString(), traceEvent.getClass()); + } catch (TmfTraceException e) { + Activator.getDefault().logError(String.format(Messages.SynchronizeTracesHandler_ErrorSynchingForTrace, exp.getName(), traceel.getName()), e); + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, Messages.SynchronizeTracesHandler_Error + CR + CR + e.getMessage()); + } + trace.setTimestampTransform(syncAlgo.getTimestampTransform(trace)); + TmfTraceManager.refreshSupplementaryFiles(trace); + trace.dispose(); + + tracesToAdd.add(newtrace); + tracesToRemove.add(traceel); + } + } + experiment.dispose(); + + // Move synchronization file temporarily so that + // it doesn't get deleted by the experiment change + IFolder tmpFolder = exp.getTraceSupplementaryFolder(exp.getName() + '.' + experiment.getSynchronizationFolder(false)); + IResource syncFile = null; + for (IResource resource : exp.getSupplementaryResources()) { + if (resource.getName().equals(experiment.getSynchronizationFolder(false))) { + try { + resource.move(tmpFolder.getFullPath(), false, null); + syncFile = resource; + break; + } catch (CoreException e) { + Activator.getDefault().logError(String.format(Messages.SynchronizeTracesHandler_ErrorSynchingExperiment, exp.getName()), e); + } + } + } + + for (TmfTraceElement trace : tracesToRemove) { + try { + exp.removeTrace(trace); + } catch (CoreException e) { + Activator.getDefault().logError(String.format(Messages.SynchronizeTracesHandler_ErrorSynchingForTrace, exp.getName(), trace.getName()), e); + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, Messages.SynchronizeTracesHandler_Error + CR + CR + e.getMessage()); + } + } + for (TmfTraceElement trace : tracesToAdd) { + exp.addTrace(trace); + } + + // Move synchronization file back + if (tmpFolder.exists() && syncFile != null) { + try { + tmpFolder.move(syncFile.getFullPath(), false, null); + } catch (CoreException e) { + Activator.getDefault().logError(String.format(Messages.SynchronizeTracesHandler_ErrorSynchingExperiment, exp.getName()), e); + } + } + } + }); + } + }; + thread.start(); + + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/TmfActionProvider.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/TmfActionProvider.java new file mode 100644 index 0000000000..0ddd7eb8ae --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/TmfActionProvider.java @@ -0,0 +1,81 @@ +/******************************************************************************* +* Copyright (c) 2012, 2014 Ericsson + * + * 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 + * + * Contributors: + * Patrick Tasse - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import org.eclipse.core.resources.IFile; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.actions.OpenWithMenu; +import org.eclipse.ui.navigator.CommonActionProvider; +import org.eclipse.ui.navigator.ICommonActionConstants; +import org.eclipse.ui.navigator.ICommonActionExtensionSite; +import org.eclipse.ui.navigator.ICommonMenuConstants; +import org.eclipse.ui.navigator.ICommonViewerSite; +import org.eclipse.ui.navigator.ICommonViewerWorkbenchSite; + +/** + * Base action provider. + * + * @author Patrick Tassé + */ +public class TmfActionProvider extends CommonActionProvider { + + private OpenAction openAction; + + private IWorkbenchPage page; + + /** + * Default constructor + */ + public TmfActionProvider() { + } + + @Override + public void init(ICommonActionExtensionSite aSite) { + ICommonViewerSite viewSite = aSite.getViewSite(); + if (viewSite instanceof ICommonViewerWorkbenchSite) { + ICommonViewerWorkbenchSite workbenchSite = (ICommonViewerWorkbenchSite) viewSite; + page = workbenchSite.getPage(); + openAction = new OpenAction(page, workbenchSite.getSelectionProvider()); + } + } + + @Override + public void fillContextMenu(IMenuManager menu) { + ISelection selection = getContext().getSelection(); + if (selection instanceof IStructuredSelection) { + IStructuredSelection structuredSelection = (IStructuredSelection) selection; + if (structuredSelection.size() == 1 && structuredSelection.getFirstElement() instanceof TmfTraceElement) { + TmfTraceElement traceElement = (TmfTraceElement) structuredSelection.getFirstElement(); + if (traceElement.getResource() instanceof IFile) { + MenuManager openWithMenu = new MenuManager(Messages.TmfActionProvider_OpenWith); + openWithMenu.add(new OpenWithMenu(page, traceElement.getResource())); + menu.insertAfter(ICommonMenuConstants.GROUP_OPEN_WITH, openWithMenu); + } + } + } + } + + @Override + public void fillActionBars(IActionBars actionBars) { + if (openAction.isEnabled()) { + actionBars.setGlobalActionHandler(ICommonActionConstants.OPEN, openAction); + } + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/TracePropertyTester.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/TracePropertyTester.java new file mode 100644 index 0000000000..4da0af5cd1 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/TracePropertyTester.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2012, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.handlers; + +import java.util.Iterator; + +import org.eclipse.core.expressions.PropertyTester; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; + +/** + * <b><u>TracePropertyTester</u></b> + * <p> + */ +public class TracePropertyTester extends PropertyTester { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + + private static final String IS_IN_TRACE_FOLDER = "isInTraceFolder"; //$NON-NLS-1$ + private static final String IS_EXPERIMENT_TRACE = "isExperimentTrace"; //$NON-NLS-1$ + private static final String HAS_SUPPLEMENTARY_FILES = "hasSupplementaryFiles"; //$NON-NLS-1$ + private static final String TRACE_TYPE = "traceType"; //$NON-NLS-1$ + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Default constructor + */ + public TracePropertyTester() { + } + + // ------------------------------------------------------------------------ + // IPropertyTester + // ------------------------------------------------------------------------ + + @Override + public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { + + // Check if the selected elements are in the trace folder + if (IS_IN_TRACE_FOLDER.equals(property)) { + if (receiver instanceof IStructuredSelection) { + Iterator<?> iter = ((IStructuredSelection) receiver).iterator(); + while (iter.hasNext()) { + Object item = iter.next(); + if (item instanceof TmfTraceElement) { + TmfTraceElement trace = (TmfTraceElement) item; + if (!(trace.getParent() instanceof TmfTraceFolder)) { + return false; + } + } else { + return false; + } + } + return true; + } + } + + // Check if the parent of a trace element is an experiment + if (IS_EXPERIMENT_TRACE.equals(property)) { + if (receiver instanceof TmfTraceElement) { + TmfTraceElement trace = (TmfTraceElement) receiver; + return trace.getParent() instanceof TmfExperimentElement; + } + return false; + } + + // Check if traces has supplementary files + if (HAS_SUPPLEMENTARY_FILES.equals(property)) { + if (receiver instanceof TmfTraceElement) { + TmfTraceElement trace = (TmfTraceElement) receiver; + return trace.hasSupplementaryResources(); + } else if (receiver instanceof TmfExperimentElement) { + TmfExperimentElement trace = (TmfExperimentElement) receiver; + boolean hasHistory = false; + for (TmfTraceElement aTrace : trace.getTraces()) { + hasHistory |= aTrace.hasSupplementaryResources(); + } + hasHistory |= trace.hasSupplementaryResources(); + return hasHistory; + } + return false; + } + + // Check if the trace element is of a specific trace type + if (TRACE_TYPE.equals(property)) { + if (receiver instanceof TmfTraceElement) { + TmfTraceElement trace = (TmfTraceElement) receiver; + if (expectedValue instanceof String && expectedValue.equals(trace.getTraceType())) { + return true; + } + } + return false; + } + + return false; + } + +} 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 new file mode 100644 index 0000000000..95ab3da1f3 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/handlers/messages.properties @@ -0,0 +1,70 @@ +############################################################################### +# Copyright (c) 2013, 2014 Ericsson +# +# 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 +# +# Contributors: +# Ericsson - Initial API and implementation +############################################################################### + +# Delete message +DeleteDialog_Title = Confirm Delete +DeleteTraceHandler_Message = Are you sure you want to delete the selected trace(s)? +DeleteTraceHandler_Error = Error deleting trace +DeleteTraceHandler_TaskName = Deleting trace +RemoveDialog_Title = Confirm Remove +RemoveTraceFromExperimentHandler_Message = Are you sure you want to remove the selected trace(s)? +RemoveTraceFromExperimentHandler_TaskName = Removing trace +RemoveTraceFromExperimentHandler_Error = Error removing trace +DeleteExperimentHandler_Message = Are you sure you want to delete this experiment? +DeleteExperimentHandler_Error = Error deleting experiment +DeleteFolderHandler_Message = Are you sure you want to delete the selected folder(s)? +DeleteFolderHandler_Error = Error deleting folder +DeleteFolderHandler_TaskName = Deleting folder +DeleteTraceHandlerGeneric_Message = Are you sure you want to delete the selected elements? +DeleteTraceHandlerGeneric_Error= Error deleting elements + +# Clear message +ClearDialog_Title = Confirm Clear +DeleteFolderHandlerClear_TaskName = Clearing folder +DeleteFolderHandlerClear_Message = Are you sure you want to clear the selected folder(s)? +DeleteFolderHandlerClear_Error = Error clearing folder + +# Set Trace Type +SelectTraceTypeHandler_ErrorSelectingTrace=Error selecting trace type for trace +SelectTraceTypeHandler_Title = Validation Error +SelectTraceTypeHandler_TraceFailedValidation=A trace has failed validation +SelectTraceTypeHandler_TracesFailedValidation=Several trace files failed validation +SelectTraceTypeHandler_InvalidTraceType = Type could not be set for one or more traces + +# Drag and drop +DropAdapterAssistant_RenameTraceTitle=Confirm rename trace +DropAdapterAssistant_RenameTraceMessage=An element with the name ''{0}'' already exists in the target folder.\nRename the dropped trace? + +# Trace synchronization +SynchronizeTracesHandler_InitError=Error initializing trace +SynchronizeTracesHandler_CopyProblem=Couldn't copy the original trace %s +SynchronizeTracesHandler_WrongTraceNumber=Experiment must have more than one trace +SynchronizeTracesHandler_Title=Synchronize traces +SynchronizeTracesHandler_WrongType=Trace is not a kernel trace:\n +SynchronizeTracesHandler_Error=Error synchronizing experiment + +SynchronizeTracesHandler_ErrorSynchingExperiment=Error synchronizing experiment %s +SynchronizeTracesHandler_ErrorSynchingForTrace=Error synchronizing experiment %s for trace %s + +ClearTraceOffsetHandler_Title=Clear time offset +ClearTraceOffsetHandler_ConfirmMessage=Are you sure you want to clear the time offset for the selected trace(s)? + +# Delete Supplementary Files messages +DeleteSupplementaryFiles_DeletionTask=Deleting supplementary files for {0} +DeleteSupplementaryFiles_ProjectRefreshTask=Refreshing project {0} + + +# Analysis modules +AnalysisModule_Help=Help + +# TMF Action Provider +TmfActionProvider_OpenWith=Open With diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/model/TmfEditorLinkHelper.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/model/TmfEditorLinkHelper.java new file mode 100644 index 0000000000..d9af95a61b --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/model/TmfEditorLinkHelper.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2012, 2015 Ericsson + * + * 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 + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tracecompass.internal.tmf.ui.project.model; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.tracecompass.internal.tmf.ui.editors.ITmfEventsEditorConstants; +import org.eclipse.tracecompass.tmf.core.TmfCommonConstants; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.ide.ResourceUtil; +import org.eclipse.ui.navigator.ILinkHelper; +import org.eclipse.ui.part.FileEditorInput; + +/** + * Implementation of ILinkHelper interface for linking with editor extension for traces and + * experiments. + * + * @author Bernd Hufmann + */ +public class TmfEditorLinkHelper implements ILinkHelper { + + @Override + public IStructuredSelection findSelection(IEditorInput anInput) { + IFile file = ResourceUtil.getFile(anInput); + if (file != null) { + + try { + // Get the trace type ID + String traceTypeId = file.getPersistentProperty(TmfCommonConstants.TRACETYPE); + if (traceTypeId == null) { + return StructuredSelection.EMPTY; + } + + final TmfProjectElement project = TmfProjectRegistry.getProject(file.getProject(), true); + + // Check for experiments, traces which are folders or traces which are files + if (ITmfEventsEditorConstants.EXPERIMENT_INPUT_TYPE_CONSTANTS.contains(traceTypeId)) { + // Case 1: Experiment + for (final TmfExperimentElement experimentElement : project.getExperimentsFolder().getExperiments()) { + if (experimentElement.getResource().equals(file.getParent())) { + return new StructuredSelection(experimentElement); + } + } + } else if (ITmfEventsEditorConstants.TRACE_INPUT_TYPE_CONSTANTS.contains(traceTypeId)) { + // Case 2: Trace that is a folder + for (final TmfTraceElement traceElement : project.getTracesFolder().getTraces()) { + if (traceElement.getResource().equals(file.getParent())) { + return new StructuredSelection(traceElement); + } + } + } else { + // Case 3: Trace that is a file + for (final TmfTraceElement traceElement : project.getTracesFolder().getTraces()) { + if (traceElement.getResource().equals(file)) { + return new StructuredSelection(traceElement); + } + } + } + } catch (CoreException e) { + return StructuredSelection.EMPTY; + } + } + return StructuredSelection.EMPTY; + } + + @Override + public void activateEditor(IWorkbenchPage aPage, IStructuredSelection aSelection) { + if (aSelection == null || aSelection.isEmpty()) { + return; + } + + IFile file = null; + + if ((aSelection.getFirstElement() instanceof TmfTraceElement)) { + TmfTraceElement traceElement = ((TmfTraceElement)aSelection.getFirstElement()); + + // If trace is under an experiment, use the original trace from the traces folder + traceElement = traceElement.getElementUnderTraceFolder(); + file = traceElement.getBookmarksFile(); + } else if ((aSelection.getFirstElement() instanceof TmfExperimentElement)) { + TmfExperimentElement experimentElement = (TmfExperimentElement) aSelection.getFirstElement(); + file = experimentElement.getBookmarksFile(); + } + + if (file != null) { + IEditorInput tmpInput = new FileEditorInput(file); + IEditorPart localEditor = aPage.findEditor(tmpInput); + if (localEditor != null) { + // Editor found. + aPage.bringToTop(localEditor); + } else { + // Search in references for corresponding editor + IEditorReference[] refs = aPage.getEditorReferences(); + for (IEditorReference editorReference : refs) { + try { + if (editorReference.getEditorInput().equals(tmpInput)) { + localEditor = editorReference.getEditor(true); + if (localEditor != null) { + aPage.bringToTop(localEditor); + } + } + } catch (PartInitException e) { + // Ignore + } + } + } + } + } +} + diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/model/TmfImportHelper.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/model/TmfImportHelper.java new file mode 100644 index 0000000000..24ea161dc1 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/model/TmfImportHelper.java @@ -0,0 +1,76 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + **********************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.model; + +import java.io.File; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; + +/** + * Import helper used to import traces + * + * It has two purposes: - import files and directories into projects - set the + * resource types + * + * @author Matthew Khouzam + */ +public class TmfImportHelper { + + /** + * Create a link and replace what was already there. + * + * @param parentFolder + * the resource to import to, does not contain the element name + * @param location + * where the resource (file/directory) is located + * @param targetName + * the name to display + * @return the resource created. Should not be null + * @throws CoreException + * an exception made by createLink. + */ + public static IResource createLink(IFolder parentFolder, IPath location, String targetName) throws CoreException { + File source = new File(location.toString()); + IResource res = null; + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + if (source.isDirectory()) { + IFolder folder = parentFolder.getFolder(targetName); + IStatus result = workspace.validateLinkLocation(folder, location); + if (result.isOK() || result.matches(IStatus.INFO | IStatus.WARNING)) { + folder.createLink(location, IResource.REPLACE, new NullProgressMonitor()); + } else { + Activator.getDefault().logError(result.getMessage()); + } + } else { + IFile file = parentFolder.getFile(targetName); + IStatus result = workspace.validateLinkLocation(file, location); + if (result.isOK() || result.matches(IStatus.INFO | IStatus.WARNING)) { + file.createLink(location, IResource.REPLACE, + new NullProgressMonitor()); + } else { + Activator.getDefault().logError(result.getMessage()); + } + } + res = parentFolder.findMember(targetName); + return res; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/operations/TmfWorkspaceModifyOperation.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/operations/TmfWorkspaceModifyOperation.java new file mode 100644 index 0000000000..6fe11e1098 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/operations/TmfWorkspaceModifyOperation.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson + * + * 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 + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tracecompass.internal.tmf.ui.project.operations; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.jobs.ISchedulingRule; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.ui.actions.WorkspaceModifyOperation; + +/** + * Operation to modify the workspace that refreshes workspace at the end of the operation. + * + * For refreshing periodically use {@link WorkspaceModifyOperation} instead. + * + * @author Bernd Hufmann + * + */ +public abstract class TmfWorkspaceModifyOperation implements IRunnableWithProgress { + + private ISchedulingRule rule; + + /** + * Creates a new operation. + */ + protected TmfWorkspaceModifyOperation() { + this(ResourcesPlugin.getWorkspace().getRoot()); + } + + /** + * Creates a new operation that will run using the provided scheduling rule. + * + * @param rule + * The ISchedulingRule to use or <code>null</code>. + */ + protected TmfWorkspaceModifyOperation(ISchedulingRule rule) { + this.rule = rule; + } + + @Override + public final synchronized void run(IProgressMonitor monitor) + throws InvocationTargetException, InterruptedException { + final InvocationTargetException[] iteHolder = new InvocationTargetException[1]; + try { + IWorkspaceRunnable workspaceRunnable = new IWorkspaceRunnable() { + @Override + public void run(IProgressMonitor pm) throws CoreException { + try { + execute(pm); + } catch (InvocationTargetException e) { + // Pass it outside the workspace runnable + iteHolder[0] = e; + } catch (InterruptedException e) { + // Re-throw as OperationCanceledException, which will be + // caught and re-thrown as InterruptedException below. + throw new OperationCanceledException(e.getMessage()); + } + // CoreException and OperationCanceledException are propagated + } + }; + + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + workspace.run(workspaceRunnable, rule, IWorkspace.AVOID_UPDATE, monitor); + } catch (CoreException e) { + throw new InvocationTargetException(e); + } catch (OperationCanceledException e) { + throw new InterruptedException(e.getMessage()); + } + // Re-throw the InvocationTargetException, if any occurred + if (iteHolder[0] != null) { + throw iteHolder[0]; + } + } + + /** + * Performs the steps that are to be treated as a single logical workspace + * change. + * <p> + * Subclasses must implement this method. + * </p> + * + * @param monitor + * the progress monitor to use to display progress and field user + * requests to cancel + * @exception CoreException + * if the operation fails due to a CoreException + * @exception InvocationTargetException + * if the operation fails due to an exception other than + * CoreException + * @exception InterruptedException + * if the operation detects a request to cancel, using + * <code>IProgressMonitor.isCanceled()</code>, it should exit + * by throwing <code>InterruptedException</code>. It is also + * possible to throw <code>OperationCanceledException</code>, + * which gets mapped to <code>InterruptedException</code> by + * the <code>run</code> method. + */ + protected abstract void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException; +}
\ No newline at end of file diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/AbstractImportTraceWizardPage.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/AbstractImportTraceWizardPage.java new file mode 100644 index 0000000000..c14f1a9942 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/AbstractImportTraceWizardPage.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tracecompass.tmf.core.TmfProjectNature; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTracesFolder; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.dialogs.WizardResourceImportPage; + +/** + * The abstract import trace wizard page, the base for the import trace wizard + * pages. + * + * @author Matthew Khouzam + */ +abstract class AbstractImportTraceWizardPage extends WizardResourceImportPage { + + /** + * Import String + */ + protected static final String BATCH_IMPORT_WIZARD_PAGE = "BatchImportWizardPage"; //$NON-NLS-1$ + + /** + * The trace folder, something like "/<project name>/Traces/" + */ + protected IFolder fTargetFolder; + + /** + * The project "/<project name>" + */ + protected IProject fProject; + + /** + * The batch import trace wizard (parent) + */ + private BatchImportTraceWizard fBatchImportTraceWizard; + + /** + * @param name + * the name of the page + * @param selection + * The current selection + */ + protected AbstractImportTraceWizardPage(String name, IStructuredSelection selection) { + super(name, selection); + } + + /** + * Constructor + * + * @param workbench + * The workbench reference. + * @param selection + * The current selection + */ + public AbstractImportTraceWizardPage(IWorkbench workbench, IStructuredSelection selection) { + this(BATCH_IMPORT_WIZARD_PAGE, selection); + setTitle(null); + setDescription(null); + + // Locate the target trace folder + IFolder traceFolder = null; + Object element = selection.getFirstElement(); + + if (element instanceof TmfTraceFolder) { + TmfTraceFolder tmfTraceFolder = (TmfTraceFolder) element; + fProject = (tmfTraceFolder.getProject().getResource()); + traceFolder = tmfTraceFolder.getResource(); + } else if (element instanceof IProject) { + IProject project = (IProject) element; + try { + if (project.hasNature(TmfProjectNature.ID)) { + traceFolder = (IFolder) project.findMember(TmfTracesFolder.TRACES_FOLDER_NAME); + } + } catch (CoreException e) { + } + } + + // Set the target trace folder + if (traceFolder != null) { + fTargetFolder = (traceFolder); + String path = traceFolder.getFullPath().toOSString(); + setContainerFieldValue(path); + } + + } + + /** + * The Batch Import Wizard + * + * @return the Batch Import Wizard + */ + public BatchImportTraceWizard getBatchWizard() { + return fBatchImportTraceWizard; + } + + @Override + public void createControl(Composite parent) { + Composite composite = new Composite(parent, SWT.NULL); + composite.setLayout(new GridLayout()); + composite.setFont(parent.getFont()); + // arbitrary size + final GridData layoutData = new GridData(); + parent.getShell().setLayoutData(layoutData); + parent.getShell().redraw(); + this.setControl(composite); + + // arbitrary sizes + parent.getShell().setMinimumSize(new Point(525, 400)); + fBatchImportTraceWizard = (BatchImportTraceWizard) getWizard(); + } + + // the following methods are stubbed out on purpose. + + @Override + protected void createSourceGroup(Composite parent) { + // do nothing + } + + @Override + protected ITreeContentProvider getFileProvider() { + // do nothing + return null; + } + + @Override + protected ITreeContentProvider getFolderProvider() { + // do nothing + return null; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/BatchImportTraceWizard.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/BatchImportTraceWizard.java new file mode 100644 index 0000000000..6a3a840a8d --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/BatchImportTraceWizard.java @@ -0,0 +1,695 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + * Marc-Andre Laperle - Log some exceptions + * Patrick Tasse - Add support for source location + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.io.File; +import java.io.FileInputStream; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.BlockingQueue; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.URIUtil; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.wizard.IWizardPage; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.internal.tmf.ui.project.model.TmfImportHelper; +import org.eclipse.tracecompass.tmf.core.TmfCommonConstants; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType; +import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper; +import org.eclipse.tracecompass.tmf.core.project.model.TraceValidationHelper; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceTypeUIUtils; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.dialogs.IOverwriteQuery; +import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider; +import org.eclipse.ui.wizards.datatransfer.ImportOperation; + +/** + * Batch Import trace wizard. + * + * @author Matthew Khouzam + */ +public class BatchImportTraceWizard extends ImportTraceWizard { + + private static final int WIN_HEIGHT = 400; + private static final int WIN_WIDTH = 800; + private static final Status CANCEL_STATUS = new Status(IStatus.CANCEL, Activator.PLUGIN_ID, ""); //$NON-NLS-1$ + private static final int TOTALWORK = 65536; + // ----------------- + // Constants + // ----------------- + + private static final int MAX_FILES = TOTALWORK - 1; + private static final String BATCH_IMPORT_WIZARD = "BatchImportTraceWizard"; //$NON-NLS-1$ + + // ------------------ + // Fields + // ------------------ + + private IWizardPage fSelectDirectoriesPage; + private ImportTraceWizardScanPage fScanPage; + private IWizardPage fSelectTypePage; + private IWizardPage fOptions; + + private final List<String> fTraceTypesToScan = new ArrayList<>(); + private final Set<String> fParentFilesToScan = new HashSet<>(); + + private ImportTraceContentProvider fScannedTraces = new ImportTraceContentProvider(fTraceTypesToScan, fParentFilesToScan); + + private final Map<TraceValidationHelper, Boolean> fResults = new HashMap<>(); + private boolean fOverwrite = true; + private boolean fLinked = true; + + private BlockingQueue<TraceValidationHelper> fTracesToScan; + private final Set<FileAndName> fTraces = new TreeSet<>(); + + private Map<String, Set<String>> fParentFiles = new HashMap<>(); + + // Target import directory (trace folder) + private IFolder fTargetFolder; + + /** + * Returns the ScannedTraces model + * + * @return the ScannedTraces model + */ + public ImportTraceContentProvider getScannedTraces() { + return fScannedTraces; + } + + /** + * Constructor + */ + public BatchImportTraceWizard() { + IDialogSettings workbenchSettings = Activator.getDefault().getDialogSettings(); + IDialogSettings section = workbenchSettings.getSection(BATCH_IMPORT_WIZARD); + if (section == null) { + section = workbenchSettings.addNewSection(BATCH_IMPORT_WIZARD); + } + setDialogSettings(section); + setNeedsProgressMonitor(true); + } + + @Override + public void init(IWorkbench workbench, IStructuredSelection selection) { + + fSelectDirectoriesPage = new ImportTraceWizardSelectDirectoriesPage(workbench, selection); + fScanPage = new ImportTraceWizardScanPage(workbench, selection); + fSelectTypePage = new ImportTraceWizardSelectTraceTypePage(workbench, selection); + fOptions = new ImportTraceWizardPageOptions(workbench, selection); + // keep in case it's called later + Iterator<?> iter = selection.iterator(); + while (iter.hasNext()) { + Object selected = iter.next(); + if (selected instanceof TmfTraceFolder) { + fTargetFolder = ((TmfTraceFolder) selected).getResource(); + break; + } + } + fResults.clear(); + } + + @Override + public void addPages() { + addPage(fSelectTypePage); + addPage(fSelectDirectoriesPage); + addPage(fScanPage); + addPage(fOptions); + final WizardDialog container = (WizardDialog) getContainer(); + if (container != null) { + container.setPageSize(WIN_WIDTH, WIN_HEIGHT); + } + } + + /** + * Add a file to scan + * + * @param fileName + * the file to scan + */ + public void addFileToScan(final String fileName) { + String absolutePath = new File(fileName).getAbsolutePath(); + if (!fParentFiles.containsKey(absolutePath)) { + fParentFiles.put(absolutePath, new HashSet<String>()); + startUpdateTask(Messages.BatchImportTraceWizardAdd + ' ' + absolutePath, absolutePath); + + } + + } + + /** + * Remove files from selection + * + * @param fileName + * the name of the file to remove + */ + public void removeFile(final String fileName) { + fParentFiles.remove(fileName); + fParentFilesToScan.remove(fileName); + startUpdateTask(Messages.BatchImportTraceWizardRemove + ' ' + fileName, null); + } + + private void startUpdateTask(final String taskName, final String fileAbsolutePath) { + try { + this.getContainer().run(true, true, new IRunnableWithProgress() { + + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + synchronized (BatchImportTraceWizard.this) { // this should + // only run one + // at a time + SubMonitor sm; + sm = SubMonitor.convert(monitor); + sm.setTaskName(taskName); + sm.setWorkRemaining(TOTALWORK); + updateFiles(sm, fileAbsolutePath); + sm.done(); + } + } + }); + } catch (InvocationTargetException e) { + Activator.getDefault().logError(Messages.ImportTraceWizardImportProblem, e); + } catch (InterruptedException e) { + } + } + + /** + * The set of names of the selected files + * + * @return the set of names of the selected files + */ + public Set<String> getFileNames() { + return fParentFilesToScan; + } + + /** + * Reset the trace list to import + */ + public void clearTraces() { + fTraces.clear(); + } + + @Override + public boolean performFinish() { + if (fTraces.isEmpty()) { + return false; + } + // if this turns out to be too slow, put in a progress monitor. Does not + // appear to be slow for the moment. + boolean success = importTraces(); + return success; + } + + private boolean importTraces() { + boolean success = false; + IOverwriteQuery overwriteQuery = new IOverwriteQuery() { + @Override + public String queryOverwrite(String file) { + return fOverwrite ? IOverwriteQuery.ALL : IOverwriteQuery.NO_ALL; + } + }; + FileSystemStructureProvider fileSystemStructureProvider = FileSystemStructureProvider.INSTANCE; + + for (FileAndName traceToImport : fTraces) { + try { + if (fLinked) { + if (TmfImportHelper.createLink(fTargetFolder, Path.fromOSString(traceToImport.getFile().getAbsolutePath()), traceToImport.getName()) == null) { + success = false; + } + else { + success = setTraceTypeAndSourceLocation(traceToImport).isOK(); + } + } + else { + List<File> subList = new ArrayList<>(); + IPath path = fTargetFolder.getFullPath(); + File parentFile = traceToImport.getFile(); + final boolean isFile = parentFile.isFile(); + if (isFile) { + IFile resource = ResourcesPlugin.getWorkspace().getRoot().getFile(path.append(traceToImport.getName())); + if (fOverwrite || !resource.exists()) { + subList.add(parentFile); + parentFile = parentFile.getParentFile(); + try (final FileInputStream source = new FileInputStream(traceToImport.getFile());) { + if (resource.exists()) { + resource.delete(IResource.FORCE, new NullProgressMonitor()); + } + resource.create(source, true, new NullProgressMonitor()); + } + setTraceTypeAndSourceLocation(traceToImport); + success = true; + } + } else { + path = path.addTrailingSeparator().append(traceToImport.getName()); + // Add all files in trace directory + File[] fileList = traceToImport.getFile().listFiles(); + for (File child : fileList) { + subList.add(child); + } + + Collections.sort(subList, new Comparator<File>() { + @Override + public int compare(File o1, File o2) { + return o1.getAbsolutePath().compareTo(o2.getAbsolutePath()); + } + }); + ImportOperation operation = new ImportOperation( + path, + parentFile, + fileSystemStructureProvider, + overwriteQuery, + subList); + operation.setContext(getShell()); + operation.setCreateContainerStructure(false); + if (executeImportOperation(operation)) { + setTraceTypeAndSourceLocation(traceToImport); + success = true; + } + } + + } + } catch (Exception e) { + } + } + return success; + } + + private IStatus setTraceTypeAndSourceLocation(FileAndName traceToImport) { + IStatus status = Status.OK_STATUS; + IResource resource = fTargetFolder.findMember(traceToImport.getName()); + if (resource != null) { + try { + // Set the trace type for this resource + String traceTypeId = traceToImport.getTraceTypeId(); + TraceTypeHelper traceType = TmfTraceType.getTraceType(traceTypeId); + if (traceType != null) { + status = TmfTraceTypeUIUtils.setTraceType(resource, traceType); + } + + // Set the source location for this resource + File file = traceToImport.getFile(); + String sourceLocation = null; + IResource sourceResource; + if (file.isDirectory()) { + sourceResource = ResourcesPlugin.getWorkspace().getRoot().getContainerForLocation(Path.fromOSString(file.getAbsolutePath())); + } else { + sourceResource = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(Path.fromOSString(file.getAbsolutePath())); + } + if (sourceResource != null && sourceResource.exists()) { + sourceLocation = sourceResource.getPersistentProperty(TmfCommonConstants.SOURCE_LOCATION); + } + if (sourceLocation == null) { + sourceLocation = URIUtil.toUnencodedString(file.toURI()); + } + resource.setPersistentProperty(TmfCommonConstants.SOURCE_LOCATION, sourceLocation); + } catch (CoreException e) { + Activator.getDefault().logError(Messages.BatchImportTraceWizardErrorImportingTraceResource + + ' ' + resource.getName(), e); + } + } + return status; + } + + @Override + public boolean canFinish() { + return super.canFinish() && hasTracesToImport() && !hasConflicts() && (fTargetFolder != null); + } + + /** + * Returns if a trace to import is selected + * + * @return if there are traces to import + */ + public boolean hasTracesToImport() { + return fTraces.size() > 0; + } + + /** + * Reset the files to scan + */ + public void clearFilesToScan() { + fTracesToScan.clear(); + } + + /** + * Set the trace types to scan + * + * @param tracesToScan + * a list of trace types to scan for + */ + public void setTraceTypesToScan(List<String> tracesToScan) { + // intersection to know if there's a diff. + // if there's a diff, we need to re-enque everything + List<String> added = new ArrayList<>(); + for (String traceLoc : tracesToScan) { + if (!fTraceTypesToScan.contains(traceLoc)) { + added.add(traceLoc); + } + } + fTraceTypesToScan.clear(); + fTraceTypesToScan.addAll(tracesToScan); + updateTracesToScan(added); + } + + /** + * Get the trace types to scan + * + * @return a list of traces to Scan for + */ + public List<String> getTraceTypesToScan() { + return fTraceTypesToScan; + } + + /** + * Add files to Import + * + * @param element + * add the file and tracetype to import + */ + public void addFileToImport(FileAndName element) { + fTraces.add(element); + updateConflicts(); + } + + /** + * Remove the file to scan + * + * @param element + * the element to remove + */ + public void removeFileToImport(FileAndName element) { + fTraces.remove(element); + element.setConflictingName(false); + updateConflicts(); + } + + /** + * Updates the trace to see if there are conflicts. + */ + public void updateConflicts() { + final FileAndName[] fChildren = fTraces.toArray(new FileAndName[0]); + for (int i = 0; i < fChildren.length; i++) { + fChildren[i].setConflictingName(false); + } + for (int i = 1; i < fChildren.length; i++) { + for (int j = 0; j < i; j++) { + if (fChildren[i].getName().equals(fChildren[j].getName())) { + fChildren[i].setConflictingName(true); + fChildren[j].setConflictingName(true); + } + } + } + getContainer().updateButtons(); + } + + /** + * Is there a name conflict + */ + boolean hasConflicts() { + boolean conflict = false; + for (FileAndName child : fTraces) { + conflict |= child.isConflictingName(); + } + return conflict; + } + + private boolean executeImportOperation(ImportOperation op) { + initializeOperation(op); + + try { + getContainer().run(true, true, op); + } catch (InterruptedException e) { + return false; + } catch (InvocationTargetException e) { + Activator.getDefault().logError(Messages.ImportTraceWizardImportProblem, e); + return false; + } + + IStatus status = op.getStatus(); + if (!status.isOK()) { + ErrorDialog.openError(getContainer().getShell(), Messages.ImportTraceWizardImportProblem, null, status); + return false; + } + + return true; + } + + private static void initializeOperation(ImportOperation op) { + op.setCreateContainerStructure(false); + op.setOverwriteResources(false); + op.setVirtualFolders(false); + } + + /** + * Override existing resources + * + * @param selection + * true or false + */ + public void setOverwrite(boolean selection) { + fOverwrite = selection; + } + + /** + * Is the trace linked? + * + * @param isLink + * true or false + */ + public void setLinked(boolean isLink) { + fLinked = isLink; + } + + /** + * @param tracesToScan + * sets the common traces to scan + */ + public void setTracesToScan(BlockingQueue<TraceValidationHelper> tracesToScan) { + fTracesToScan = tracesToScan; + } + + /** + * @param traceToScan + * The trace to scan + * @return if the trace has been scanned yet or not + */ + public boolean hasScanned(TraceValidationHelper traceToScan) { + return fResults.containsKey(traceToScan); + } + + /** + * Add a result to a cache + * + * @param traceToScan + * The trace that has been scanned + * @param validate + * if the trace is valid + */ + public void addResult(TraceValidationHelper traceToScan, boolean validate) { + fResults.put(traceToScan, validate); + } + + /** + * Gets if the trace has been scanned or not + * + * @param traceToScan + * the scanned trace + * @return whether it passes or not + */ + public boolean getResult(TraceValidationHelper traceToScan) { + return fResults.get(traceToScan); + } + + /** + * Returns the amount of files scanned + * + * @return the amount of files scanned + */ + public int getNumberOfResults() { + return fResults.size(); + } + + private void updateTracesToScan(final List<String> added) { + // Treeset is used instead of a hashset since the traces should be read + // in the order they were added. + final Set<String> filesToScan = new TreeSet<>(); + for (String name : fParentFiles.keySet()) { + filesToScan.addAll(fParentFiles.get(name)); + } + IProgressMonitor pm = new NullProgressMonitor(); + try { + updateScanQueue(pm, filesToScan, added); + } catch (InterruptedException e) { + } + + } + + /* + * I am a job. Make me work + */ + private synchronized IStatus updateFiles(IProgressMonitor monitor, String traceToScanAbsPath) { + final Set<String> filesToScan = new TreeSet<>(); + + int workToDo = 1; + for (String name : fParentFiles.keySet()) { + + final File file = new File(name); + final File[] listFiles = file.listFiles(); + if (listFiles != null) { + workToDo += listFiles.length; + } + } + int step = TOTALWORK / workToDo; + try { + for (String name : fParentFiles.keySet()) { + final File fileToAdd = new File(name); + final Set<String> parentFilesToScan = fParentFiles.get(fileToAdd.getAbsolutePath()); + recurse(parentFilesToScan, fileToAdd, monitor, step); + if (monitor.isCanceled()) { + fParentFilesToScan.remove(traceToScanAbsPath); + fParentFiles.remove(traceToScanAbsPath); + return CANCEL_STATUS; + } + } + filesToScan.clear(); + for (String name : fParentFiles.keySet()) { + filesToScan.addAll(fParentFiles.get(name)); + fParentFilesToScan.add(name); + } + IStatus cancelled = updateScanQueue(monitor, filesToScan, fTraceTypesToScan); + if (cancelled.matches(IStatus.CANCEL)) { + fParentFilesToScan.remove(traceToScanAbsPath); + fParentFiles.remove(traceToScanAbsPath); + } + } catch (InterruptedException e) { + monitor.done(); + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e); + } + + monitor.done(); + return Status.OK_STATUS; + } + + private IStatus updateScanQueue(IProgressMonitor monitor, final Set<String> filesToScan, final List<String> traceTypes) throws InterruptedException { + for (String fileToScan : filesToScan) { + for (String traceCat : traceTypes) { + TraceValidationHelper tv = new TraceValidationHelper(fileToScan, traceCat); + // for thread safety, keep checks in this order. + if (!fResults.containsKey(tv)) { + if (!fTracesToScan.contains(tv)) { + fTracesToScan.put(tv); + monitor.subTask(tv.getTraceToScan()); + if (monitor.isCanceled()) { + fScanPage.refresh(); + return CANCEL_STATUS; + } + } + } + } + } + fScanPage.refresh(); + return Status.OK_STATUS; + } + + private IStatus recurse(Set<String> filesToScan, File fileToAdd, IProgressMonitor monitor, int step) { + final String absolutePath = fileToAdd.getAbsolutePath(); + if (!filesToScan.contains(absolutePath) && (filesToScan.size() < MAX_FILES)) { + filesToScan.add(absolutePath); + final File[] listFiles = fileToAdd.listFiles(); + if (null != listFiles) { + for (File child : listFiles) { + monitor.subTask(child.getName()); + if (monitor.isCanceled()) { + return CANCEL_STATUS; + } + IStatus retVal = recurse(filesToScan, child, monitor); + if (retVal.matches(IStatus.CANCEL)) { + return retVal; + } + monitor.worked(step); + } + } + } + return Status.OK_STATUS; + } + + private IStatus recurse(Set<String> filesToScan, File fileToAdd, IProgressMonitor monitor) { + final String absolutePath = fileToAdd.getAbsolutePath(); + if (!filesToScan.contains(absolutePath) && (filesToScan.size() < MAX_FILES)) { + filesToScan.add(absolutePath); + final File[] listFiles = fileToAdd.listFiles(); + if (null != listFiles) { + for (File child : listFiles) { + if (monitor.isCanceled()) { + return CANCEL_STATUS; + } + IStatus retVal = recurse(filesToScan, child, monitor); + if (retVal.matches(IStatus.CANCEL)) { + return retVal; + } + } + } + } + return Status.OK_STATUS; + } + + /** + * Gets the folder in the resource (project) + * + * @param targetFolder + * the folder to import to + */ + public void setTraceFolder(IFolder targetFolder) { + fTargetFolder = targetFolder; + if (this.getContainer() != null && this.getContainer().getCurrentPage() != null) { + this.getContainer().updateButtons(); + } + } + + /** + * Gets the target folder + * + * @return the target folder + */ + public IFolder getTargetFolder() { + return fTargetFolder; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/FileAndName.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/FileAndName.java new file mode 100644 index 0000000000..8120aa743c --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/FileAndName.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.io.File; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.equalsNullable; + +/** + * File and name internal helper class <br> + * it has the file, a name to display, whether the name is conflicting and a + * reference to the configuration element defining its trace type. + * + * @author Matthew Khouzam + */ +class FileAndName implements Comparable<FileAndName> { + + private final File fFile; + private String fTraceTypeId; + private String fName; + private boolean fConflict; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * A file and name + * + * @param f + * the file, can only be set here + * @param n + * the name, can be renamed + * + */ + public FileAndName(File f, String n) { + fFile = f; + fName = n; + fTraceTypeId = null; + } + + // ------------------------------------------------------------------------ + // Getter / Setter + // ------------------------------------------------------------------------ + + /** + * Get the name + * + * @return the name + */ + public String getName() { + return fName; + } + + /** + * Set the name + * + * @param name + * the name to set + */ + public void setName(String name) { + this.fName = name; + } + + /** + * Sets the configuration element of the + * + * @param elem + * the element + */ + public void setTraceTypeId(String elem) { + fTraceTypeId = elem; + } + + /** + * Gets the configuration element canonical name + * + * @return gets the configuration element canonical name + */ + public String getTraceTypeId() { + return fTraceTypeId; + } + + /** + * Get the file + * + * @return the file + */ + public File getFile() { + return fFile; + } + + /** + * Set that the name is conflicting or not + * + * @param conflict + * if the name is conflicting or not + */ + public void setConflictingName(boolean conflict) { + fConflict = conflict; + } + + /** + * Is the name conflicting? + * + * @return is the name conflicting? + */ + public boolean isConflictingName() { + return fConflict; + } + + /** + * Is the fileAndName renamed + * + * @return true if the name does not match the filename + */ + public boolean isRenamed() { + return !fName.equals(fFile.getName()); + } + + // ------------------------------------------------------------------------ + // Comparator & Equals + // ------------------------------------------------------------------------ + + @Override + public int compareTo(FileAndName o) { + int retVal = getFile().compareTo(o.getFile()); + if (retVal == 0 && getTraceTypeId() != null && o.getTraceTypeId() != null) { + retVal = getTraceTypeId().compareTo(o.getTraceTypeId()); + } + return retVal; + } + + @Override + public int hashCode() { + // do not take "name" into account since it can change on the fly. + final int prime = 31; + int result = 1; + result = prime * result + ((fTraceTypeId == null) ? 0 : fTraceTypeId.hashCode()); + result = prime * result + ((fFile == null) ? 0 : fFile.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + // do not take "name" into account since it can change on the fly. + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof FileAndName)) { + return false; + } + FileAndName other = (FileAndName) obj; + if (!equalsNullable(fTraceTypeId, other.fTraceTypeId)) { + return false; + } + if (!equalsNullable(fFile, other.fFile)) { + return false; + } + return true; + } +}
\ No newline at end of file diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipEntry.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipEntry.java new file mode 100644 index 0000000000..d0ffc11136 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipEntry.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2015 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation. Inspired from TarEntry. + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +/** + * GZip entry + */ +public class GzipEntry { + private static final int MILLIS_PER_SECOND = 1000; + private static final int READ_WRITE_USER_READ_GROUP = 0644; + private static final String ROOT_DIR = "/"; //$NON-NLS-1$ + private final String fName; + private final long fMode; + private final long fTime; + private final int fType; + + /** + * Entry type for normal files. This is the only valid type for Gzip + * entries. + */ + public static final int FILE = '0'; + + /** + * Entry type for directories. This doesn't really exist in a Gzip but it's + * useful to represent the root of the archive. + */ + public static final int DIRECTORY = '5'; + + /** + * Create a new Root GzipEntry + */ + public GzipEntry() { + fName = ROOT_DIR; + fMode = READ_WRITE_USER_READ_GROUP; + fType = DIRECTORY; + fTime = System.currentTimeMillis() / MILLIS_PER_SECOND; + } + + /** + * Create a new GzipEntry for a file of the given name at the given position + * in the file. + * + * @param name + * filename + */ + public GzipEntry(String name) { + fName = name; + fMode = READ_WRITE_USER_READ_GROUP; + fType = FILE; + fTime = System.currentTimeMillis() / MILLIS_PER_SECOND; + } + + /** + * Returns the type of this file, can only be FILE for a real Gzip entry. + * DIRECTORY can be specified to represent a "dummy root" in the archive. + * + * @return file type + */ + public int getFileType() { + return fType; + } + + /** + * Returns the mode of the file in UNIX permissions format. + * + * @return file mode + */ + public long getMode() { + return fMode; + } + + /** + * Returns the name of the file. + * + * @return filename + */ + public String getName() { + return fName; + } + + /** + * Returns the modification time of the file in seconds since January 1st + * 1970. + * + * @return time + */ + public long getTime() { + return fTime; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipFile.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipFile.java new file mode 100644 index 0000000000..a505ac6a99 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipFile.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2015 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation. + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.zip.GZIPInputStream; + +/** + * Wrapper for a Gzipped file + */ +public class GzipFile implements AutoCloseable { + + private static final String GZIP_EXTENSION = ".gz"; //$NON-NLS-1$ + + private final File fFile; + private final GzipEntry fEntry; + private GzipEntry fCurEntry; + private boolean fIsClosed = false; + + private final InputStream fInternalEntryStream; + + /** + * Create a new GzipFile for the given file. + * + * @param source the source file + * @throws IOException + * File not found and such + */ + public GzipFile(File source) throws IOException { + fFile = source; + + InputStream in = new FileInputStream(source); + try { + // Check if it's a GZIPInputStream. + fInternalEntryStream = new GZIPInputStream(in); + } catch (IOException e) { + in.close(); + throw e; + } + String name = source.getName(); + fEntry = new GzipEntry(name.substring(0, name.lastIndexOf(GZIP_EXTENSION))); + fCurEntry = fEntry; + } + + /** + * Close the tar file input stream. + * + * @throws IOException if the file cannot be successfully closed + */ + @Override + public void close() throws IOException { + if (fInternalEntryStream != null && !fIsClosed) { + fInternalEntryStream.close(); + fIsClosed = true; + + } + } + + /** + * Create a new GzipFile for the given path name. + * + * @param filename + * the filename of the gzip file + * @throws IOException + * if the file cannot be opened + */ + public GzipFile(String filename) throws IOException { + this(new File(filename)); + } + + /** + * Returns an enumeration cataloguing the tar archive. + * + * @return enumeration of all files in the archive + */ + public Enumeration<GzipEntry> entries() { + return new Enumeration<GzipEntry>() { + @Override + public boolean hasMoreElements() { + return (fCurEntry != null); + } + + @Override + public GzipEntry nextElement() { + GzipEntry oldEntry = fCurEntry; + fCurEntry = null; + return oldEntry; + } + }; + } + + /** + * Returns a new InputStream for the given file in the tar archive. + * + * @param entry + * the GzipEntry + * @return an input stream for the given file + */ + public InputStream getInputStream(GzipEntry entry) { + if (entry != fEntry) { + throw new IllegalArgumentException(); + } + return fInternalEntryStream; + } + + /** + * Returns the path name of the file this archive represents. + * + * @return path + */ + public String getName() { + return fFile.getPath(); + } + + @Override + protected void finalize() throws Throwable { + close(); + super.finalize(); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipLeveledStructureProvider.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipLeveledStructureProvider.java new file mode 100644 index 0000000000..47da8ea657 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/GzipLeveledStructureProvider.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2015 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation. + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.ui.internal.wizards.datatransfer.DataTransferMessages; +import org.eclipse.ui.internal.wizards.datatransfer.ILeveledImportStructureProvider; + +/** + * Leveled Structure provider for Gzip file + */ +@SuppressWarnings("restriction") +public class GzipLeveledStructureProvider implements ILeveledImportStructureProvider { + + private final GzipFile fFile; + private final GzipEntry root = new GzipEntry(); + private final GzipEntry fEntry; + + /** + * Creates a <code>GzipFileStructureProvider</code>, which will operate on + * the passed Gzip file. + * + * @param sourceFile + * the source GzipFile + */ + public GzipLeveledStructureProvider(GzipFile sourceFile) { + super(); + + fFile = sourceFile; + fEntry = sourceFile.entries().nextElement(); + } + + @Override + public List getChildren(Object element) { + ArrayList<Object> children = new ArrayList<>(); + if (element == root) { + children.add(fEntry); + } + return children; + } + + @Override + public InputStream getContents(Object element) { + return fFile.getInputStream((GzipEntry) element); + } + + @Override + public String getFullPath(Object element) { + return ((GzipEntry) element).getName(); + } + + @Override + public String getLabel(Object element) { + if (element != root && element != fEntry) { + throw new IllegalArgumentException(); + } + return ((GzipEntry) element).getName(); + } + + /** + * Returns the entry that this importer uses as the root sentinel. + * + * @return GzipEntry entry + */ + @Override + public GzipEntry getRoot() { + return root; + } + + @Override + public boolean closeArchive() { + try { + fFile.close(); + } catch (IOException e) { + Activator.getDefault().logError(DataTransferMessages.ZipImport_couldNotClose + + fFile.getName(), e); + return false; + } + return true; + } + + @Override + public boolean isFolder(Object element) { + return ((GzipEntry) element).getFileType() == GzipEntry.DIRECTORY; + } + + @Override + public void setStrip(int level) { + // Do nothing + } + + @Override + public int getStrip() { + return 0; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportConfirmation.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportConfirmation.java new file mode 100644 index 0000000000..49f4ff8729 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportConfirmation.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson. + * + * 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 + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +/** + * Enumeration for import conflict dialog + * + * @author Bernd Hufmann + */ +public enum ImportConfirmation { + + // ------------------------------------------------------------------------ + // Enum definition + // ------------------------------------------------------------------------ + /** Single rename */ + RENAME(Messages.ImportTraceWizard_ImportConfigurationRename), + /** Rename all */ + RENAME_ALL(Messages.ImportTraceWizard_ImportConfigurationRenameAll), + /** Single overwrite */ + OVERWRITE(Messages.ImportTraceWizard_ImportConfigurationOverwrite), + /** Overwrite all */ + OVERWRITE_ALL(Messages.ImportTraceWizard_ImportConfigurationOverwriteAll), + /** Single skip */ + SKIP(Messages.ImportTraceWizard_ImportConfigurationSkip), + /** Skip all*/ + SKIP_ALL(Messages.ImportTraceWizard_ImportConfigurationSkipAll), + /** Default value*/ + CONTINUE("CONTINUE"); //$NON-NLS-1$ + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + /** + * Name of enum + */ + private final String fInName; + + // ------------------------------------------------------------------------ + // Constuctor + // ------------------------------------------------------------------------ + /** + * Private constructor + * + * @param name + * the name of state + */ + private ImportConfirmation(String name) { + fInName = name; + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + /** + * @return state name + */ + public String getInName() { + return fInName; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportConflictHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportConflictHandler.java new file mode 100644 index 0000000000..1c2f783ff6 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportConflictHandler.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson. + * + * 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 + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.util.List; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; + +/** + * Handler to check for name clashes during import operations. It will allow + * users to select renaming, overwriting or skipping of a given trace as well + * as upcoming traces by keeping track of the user selection. In case of + * overwriting the original trace will be deleted. + * + * See {@link ImportConfirmation} for users selection choices. + * + * @author Bernd Hufmann + */ +public class ImportConflictHandler { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + private Shell fShell; + private TmfTraceFolder fTraceFolderElement; + private ImportConfirmation fConfirmationMode; + + // ------------------------------------------------------------------------ + // Constructor(s) + // ------------------------------------------------------------------------ + /** + * @param shell + * shell to display confirmation dialog + * @param folder + * Target folder for the traces + * @param initialMode + * Initial confirmation mode + */ + public ImportConflictHandler(Shell shell, TmfTraceFolder folder, ImportConfirmation initialMode) { + fShell = shell; + fTraceFolderElement = folder; + fConfirmationMode = initialMode; + } + + // ------------------------------------------------------------------------ + // Operation(s) + // ------------------------------------------------------------------------ + /** + * It checks for name clashes. In case of a name clash it will open a + * confirmation dialog where the use can rename, overwrite or skip + * the trace. The user has also the choice to rename, overwrite or + * skip all traces of subsequent calls to this method. This class will + * keep track about the {@link ImportConfirmation} mode selected by the + * user. + * + * In case of {@link ImportConfirmation#RENAME} or + * {@link ImportConfirmation#RENAME_ALL} a new name will be return by + * adding sequence number surrounded by (), e.g. (1) or (2). + * + * In case of {@link ImportConfirmation#OVERWRITE} or + * {@link ImportConfirmation#OVERWRITE_ALL} the original trace will be + * deleted and the original name will be returned. + * + * In case the dialog {@link ImportConfirmation#SKIP} or + * {@link ImportConfirmation#SKIP_ALL} it will return null to indicate + * the skipping. + * + * @param tracePath + * The trace to check + * @param monitor + * The progress monitor + * @return the trace name to use or null + * @throws InterruptedException + * If the dialog box was cancelled + * @throws CoreException + * If an error during deletion occurred + */ + public String checkAndHandleNameClash(IPath tracePath, IProgressMonitor monitor) throws InterruptedException, CoreException { + ImportConfirmation mode = checkForNameClash(tracePath); + switch (mode) { + case RENAME: + case RENAME_ALL: + return rename(tracePath); + case OVERWRITE: + case OVERWRITE_ALL: + delete(tracePath, monitor); + //$FALL-THROUGH$ + case CONTINUE: + return tracePath.lastSegment(); + case SKIP: + case SKIP_ALL: + default: + return null; + } + } + + // ------------------------------------------------------------------------ + // Helper methods + // ------------------------------------------------------------------------ + private ImportConfirmation checkForNameClash(IPath tracePath) throws InterruptedException { + // handle rename + if (getExistingTrace(tracePath) != null) { + if ((fConfirmationMode == ImportConfirmation.RENAME_ALL) || + (fConfirmationMode == ImportConfirmation.OVERWRITE_ALL) || + (fConfirmationMode == ImportConfirmation.SKIP_ALL)) { + return fConfirmationMode; + } + + int returnCode = promptForOverwrite(tracePath); + if (returnCode < 0) { + // Cancel + throw new InterruptedException(); + } + fConfirmationMode = ImportConfirmation.values()[returnCode]; + return fConfirmationMode; + } + return ImportConfirmation.CONTINUE; + } + + private int promptForOverwrite(IPath tracePath) { + final MessageDialog dialog = new MessageDialog(fShell, + null, null, NLS.bind(Messages.ImportTraceWizard_TraceAlreadyExists, tracePath.makeRelativeTo(fTraceFolderElement.getProject().getPath())), + MessageDialog.QUESTION, new String[] { + ImportConfirmation.RENAME.getInName(), + ImportConfirmation.RENAME_ALL.getInName(), + ImportConfirmation.OVERWRITE.getInName(), + ImportConfirmation.OVERWRITE_ALL.getInName(), + ImportConfirmation.SKIP.getInName(), + ImportConfirmation.SKIP_ALL.getInName(), + }, 4) { + @Override + protected int getShellStyle() { + return super.getShellStyle() | SWT.SHEET; + } + }; + + final int[] returnValue = new int[1]; + fShell.getDisplay().syncExec(new Runnable() { + + @Override + public void run() { + returnValue[0] = dialog.open(); + } + }); + return returnValue[0]; + } + + private String rename(IPath tracePath) { + TmfTraceElement trace = getExistingTrace(tracePath); + if (trace == null) { + return tracePath.lastSegment(); + } + + // Not using IFolder on purpose to leave the door open to import + // directly into an IProject + IContainer folder = (IContainer) trace.getParent().getResource(); + int i = 2; + while (true) { + String name = trace.getName() + '(' + Integer.toString(i++) + ')'; + IResource resource = folder.findMember(name); + if (resource == null) { + return name; + } + } + } + + private void delete(IPath tracePath, IProgressMonitor monitor) throws CoreException { + TmfTraceElement trace = getExistingTrace(tracePath); + if (trace == null) { + return; + } + + trace.delete(monitor); + } + + private TmfTraceElement getExistingTrace(IPath tracePath) { + List<TmfTraceElement> traces = fTraceFolderElement.getTraces(); + for (TmfTraceElement t : traces) { + if (t.getPath().equals(tracePath)) { + return t; + } + } + return null; + } +} + diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceContentProvider.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceContentProvider.java new file mode 100644 index 0000000000..8cf1ff99b4 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceContentProvider.java @@ -0,0 +1,182 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeSet; + +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType; +import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper; + +/** + * A helper class to show the trace types and files and names. it contains the + * model which can be defined as follows : {tracetype -> { file1, file2, ... } + * }+ + * + * @author Matthew Khouzam + */ +class ImportTraceContentProvider implements ITreeContentProvider { + + private final Map<String, String> fTraceTypes = new HashMap<>(); + private final Map<String, Set<FileAndName>> fTraceFiles = new HashMap<>(); + private final List<String> fTraceTypesToScan; + private final Set<String> fParentFilesToScan; + + public ImportTraceContentProvider(List<String> traceTypesToScan, Set<String> parentFilesToScan) { + fTraceTypesToScan = traceTypesToScan; + fParentFilesToScan = parentFilesToScan; + } + + /** + * Add a trace candidate to display + * + * @param traceTypeId + * the trace type id of the trace + * @param traceToOpen + * the trace file. + */ + public synchronized void addCandidate(String traceTypeId, File traceToOpen) { + TraceTypeHelper traceTypeHelper = TmfTraceType.getTraceType(traceTypeId); + if (traceTypeHelper == null) { + return; + } + fTraceTypes.put(traceTypeHelper.getName(), traceTypeId); + if (!fTraceFiles.containsKey(traceTypeId)) { + fTraceFiles.put(traceTypeId, new TreeSet<FileAndName>()); + } + final FileAndName traceFile = new FileAndName(traceToOpen, traceToOpen.getName()); + traceFile.setTraceTypeId(traceTypeId); + final Set<FileAndName> categorySet = fTraceFiles.get(traceTypeId); + categorySet.add(traceFile); + } + + /** + * Reset all the candidates + */ + public synchronized void clearCandidates() { + fTraceTypes.clear(); + fTraceFiles.clear(); + } + + @Override + public void dispose() { + fTraceFiles.clear(); + fTraceTypes.clear(); + + } + + @Override + public synchronized void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + if (oldInput != newInput && newInput != null) { + ImportTraceContentProvider input = (ImportTraceContentProvider) newInput; + clearCandidates(); + fTraceTypes.putAll(input.fTraceTypes); + fTraceFiles.putAll(fTraceFiles); + } + } + + @Override + public synchronized Object[] getElements(Object inputElement) { + List<String> candidates = new ArrayList<>(); + + for (String candidate : fTraceTypesToScan) { + for (Entry<String, String> entry : fTraceTypes.entrySet()) { + if (entry.getValue().equals(candidate)) { + candidates.add(entry.getKey()); + break; + } + } + + } + return candidates.toArray(new String[candidates.size()]); + } + + @Override + public synchronized Object[] getChildren(Object parentElement) { + if (parentElement instanceof String) { + final Set<FileAndName> children = fTraceFiles.get(fTraceTypes.get(parentElement)); + if (children != null) { + Set<FileAndName> candidates = new TreeSet<>(); + for (FileAndName child : children) { + for (String parent : fParentFilesToScan) { + // this is going to be slow, but less slow than UI + // display and should not be done for more than 10k + // elements. + if (child.getFile().getAbsolutePath().startsWith(parent)) { + candidates.add(child); + } + } + } + return candidates.toArray(new FileAndName[0]); + } + } + return null; + } + + /** + * Gets the brothers and systems of a file element + * + * @param element + * the child leaf + * @return the siblings of an element, including itself. Should never be + * null + */ + public synchronized FileAndName[] getSiblings(FileAndName element) { + String key = (String) getParent(element); + return (FileAndName[]) getChildren(key); + + } + + @Override + public synchronized Object getParent(Object element) { + if (element instanceof FileAndName) { + for (String key : fTraceFiles.keySet()) { + Set<FileAndName> fanSet = fTraceFiles.get(key); + if (fanSet.contains(element)) { + return key; + } + } + } + return null; + } + + @Override + public synchronized boolean hasChildren(Object element) { + if (element instanceof String) { + String key = (String) element; + return fTraceFiles.containsKey(fTraceTypes.get(key)); + } + return false; + } + + /** + * Gets the number of traces to import + * + * @return the number of traces to import + */ + public synchronized int getSize() { + int tot = 0; + for (String s : fTraceFiles.keySet()) { + tot += fTraceFiles.get(s).size(); + } + return tot; + } +}
\ No newline at end of file diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceLabelProvider.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceLabelProvider.java new file mode 100644 index 0000000000..25a34426d9 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceLabelProvider.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.io.File; + +import org.eclipse.jface.viewers.LabelProvider; + +/** + * Trace label provider for the candidate tree + * + * @author Matthew Khouzam + */ +class ImportTraceLabelProvider extends LabelProvider { + + @Override + public String getText(Object element) { + if (element instanceof String) { + return (String) element; + } + if (element instanceof FileAndName) { + final File file = ((FileAndName) element).getFile(); + if (file != null) { // should never not happen since file is final + // and always set automatically + return file.getName(); + } + } + return null; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizard.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizard.java new file mode 100644 index 0000000000..654dbb22ac --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizard.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Ericsson + * + * 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.ui.IImportWizard; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.plugin.AbstractUIPlugin; + +/** + * The import trace wizard implementation. + * <p> + * @author Francois Chouinard + */ +public class ImportTraceWizard extends Wizard implements IImportWizard { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + + private static final String PLUGIN_ID = Activator.PLUGIN_ID; + private static final String IMPORT_WIZARD = "ImportTraceWizard"; //$NON-NLS-1$ + private static final String ICON_PATH = "icons/wizban/trace_import_wiz.png"; //$NON-NLS-1$ + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + private IStructuredSelection fSelection; + private ImportTraceWizardPage fTraceImportWizardPage; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + /** + * Default constructor + */ + public ImportTraceWizard() { + IDialogSettings workbenchSettings = Activator.getDefault().getDialogSettings(); + IDialogSettings section = workbenchSettings.getSection(IMPORT_WIZARD); + if (section == null) { + section = workbenchSettings.addNewSection(IMPORT_WIZARD); + } + setDialogSettings(section); + } + + // ------------------------------------------------------------------------ + // Wizard + // ------------------------------------------------------------------------ + + @Override + public void init(IWorkbench workbench, IStructuredSelection selection) { + fSelection = selection; + + setWindowTitle(Messages.ImportTraceWizard_DialogTitle); + setDefaultPageImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, ICON_PATH)); + setNeedsProgressMonitor(true); + } + + @Override + public void addPages() { + super.addPages(); + fTraceImportWizardPage = new ImportTraceWizardPage(fSelection); + addPage(fTraceImportWizardPage); + } + + @Override + public boolean performFinish() { + return fTraceImportWizardPage.finish(); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardPage.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardPage.java new file mode 100644 index 0000000000..7377dec638 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardPage.java @@ -0,0 +1,2365 @@ +/******************************************************************************* + * Copyright (c) 2009, 2015 Ericsson 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 + * + * Contributors: + * Francois Chouinard - Initial API and implementation + * Francois Chouinard - Got rid of dependency on internal platform class + * Francois Chouinard - Complete re-design + * Anna Dushistova(Montavista) - [383047] NPE while importing a CFT trace + * Matthew Khouzam - Moved out some common functions + * Patrick Tasse - Add sorting of file system elements + * Bernd Hufmann - Re-design of trace selection and trace validation + * Marc-Andre Laperle - Preserve folder structure on import + * Marc-Andre Laperle - Extract archives during import + * Marc-Andre Laperle - Add support for Gzip (non-Tar) + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.core.runtime.URIUtil; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.layout.PixelConverter; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.operation.ModalContext; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.BusyIndicator; +import org.eclipse.swt.events.FocusAdapter; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.TraverseEvent; +import org.eclipse.swt.events.TraverseListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.tmf.core.TmfCommonConstants; +import org.eclipse.tracecompass.tmf.core.TmfProjectNature; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceImportException; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType; +import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper; +import org.eclipse.tracecompass.tmf.core.util.Pair; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceTypeUIUtils; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTracesFolder; +import org.eclipse.tracecompass.tmf.ui.project.model.TraceUtils; +import org.eclipse.ui.dialogs.FileSystemElement; +import org.eclipse.ui.dialogs.IOverwriteQuery; +import org.eclipse.ui.dialogs.WizardResourceImportPage; +import org.eclipse.ui.ide.dialogs.ResourceTreeAndListGroup; +import org.eclipse.ui.internal.ide.DialogUtil; +import org.eclipse.ui.internal.ide.dialogs.IElementFilter; +import org.eclipse.ui.internal.wizards.datatransfer.ArchiveFileManipulations; +import org.eclipse.ui.internal.wizards.datatransfer.ILeveledImportStructureProvider; +import org.eclipse.ui.internal.wizards.datatransfer.TarEntry; +import org.eclipse.ui.internal.wizards.datatransfer.TarException; +import org.eclipse.ui.internal.wizards.datatransfer.TarFile; +import org.eclipse.ui.internal.wizards.datatransfer.TarLeveledStructureProvider; +import org.eclipse.ui.internal.wizards.datatransfer.ZipLeveledStructureProvider; +import org.eclipse.ui.model.AdaptableList; +import org.eclipse.ui.model.WorkbenchContentProvider; +import org.eclipse.ui.model.WorkbenchLabelProvider; +import org.eclipse.ui.model.WorkbenchViewerComparator; +import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider; +import org.eclipse.ui.wizards.datatransfer.IImportStructureProvider; +import org.eclipse.ui.wizards.datatransfer.ImportOperation; + +/** + * A variant of the standard resource import wizard for importing traces to + * given tracing project. If no project or tracing project was selected the + * wizard imports it to the default tracing project which is created if + * necessary. + * + * In our case traces could be files or a directory structure. This wizard + * supports both cases. It imports traces for a selected trace type or, if no + * trace type is selected, it tries to detect the trace type automatically. + * However, the automatic detection is a best-effort and cannot guarantee that + * the detection is successful. The reason for this is that there might be + * multiple trace types that can be assigned to a single trace. + * + * + * @author Francois Chouinard + */ +@SuppressWarnings("restriction") +public class ImportTraceWizardPage extends WizardResourceImportPage { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + private static final String IMPORT_WIZARD_PAGE_NAME = "ImportTraceWizardPage"; //$NON-NLS-1$ + private static final String IMPORT_WIZARD_ROOT_DIRECTORY_ID = ".import_root_directory_id"; //$NON-NLS-1$; + private static final String IMPORT_WIZARD_ARCHIVE_FILE_NAME_ID = ".import_archive_file_name_id"; //$NON-NLS-1$ + private static final String IMPORT_WIZARD_IMPORT_UNRECOGNIZED_ID = ".import_unrecognized_traces_id"; //$NON-NLS-1$ + private static final String IMPORT_WIZARD_PRESERVE_FOLDERS_ID = ".import_preserve_folders_id"; //$NON-NLS-1$ + private static final String IMPORT_WIZARD_IMPORT_FROM_DIRECTORY_ID = ".import_from_directory"; //$NON-NLS-1$ + + // constant from WizardArchiveFileResourceImportPage1 + private static final String[] FILE_IMPORT_MASK = { "*.jar;*.zip;*.tar;*.tar.gz;*.tgz;*.gz", "*.*" }; //$NON-NLS-1$ //$NON-NLS-2$ + private static final String TRACE_IMPORT_TEMP_FOLDER = ".traceImport"; //$NON-NLS-1$ + + /** + * A special trace type value to communicate that automatic trace type + * detection will occur instead of setting a specific trace type when + * importing the traces. + */ + public static final String TRACE_TYPE_AUTO_DETECT = Messages.ImportTraceWizard_AutoDetection; + + /** + * Preserve the folder structure of the import traces. + */ + public static final int OPTION_PRESERVE_FOLDER_STRUCTURE = 1 << 1; + /** + * Create links to the trace files instead of copies. + */ + public static final int OPTION_CREATE_LINKS_IN_WORKSPACE = 1 << 2; + /** + * Import files that were not recognized as the selected trace type. + */ + public static final int OPTION_IMPORT_UNRECOGNIZED_TRACES = 1 << 3; + /** + * Overwrite existing resources without prompting. + */ + public static final int OPTION_OVERWRITE_EXISTING_RESOURCES = 1 << 4; + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + // Target import directory ('Traces' folder) + private IFolder fTargetFolder; + // Target Trace folder element + private TmfTraceFolder fTraceFolderElement; + // Flag to handle destination folder change event + private Boolean fIsDestinationChanged = false; + private final Object fSyncObject = new Object(); + // Combo box containing trace types + private Combo fTraceTypes; + // Button to ignore unrecognized traces or not + private Button fImportUnrecognizedButton; + // Button to overwrite existing resources or not + private Button fOverwriteExistingResourcesCheckbox; + // Button to link or copy traces to workspace + private Button fCreateLinksInWorkspaceButton; + // Button to preserve folder structure + private Button fPreserveFolderStructureButton; + private boolean entryChanged = false; + // The import from directory radio button + private Button fImportFromDirectoryRadio; + // The import from archive radio button + private Button fImportFromArchiveRadio; + // Flag to remember the "create links" checkbox when it gets disabled by + // the import from archive radio button + private Boolean fPreviousCreateLinksValue = true; + + /** The archive name field */ + protected Combo fArchiveNameField; + /** The archive browse button. */ + protected Button fArchiveBrowseButton; + /** The directory name field */ + protected Combo directoryNameField; + /** The directory browse button. */ + protected Button directoryBrowseButton; + + private ResourceTreeAndListGroup fSelectionGroup; + + // Keep trace of the selection root so that we can dispose its related + // resources + private TraceFileSystemElement fSelectionGroupRoot; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. Creates the trace wizard page. + * + * @param name + * The name of the page. + * @param selection + * The current selection + */ + protected ImportTraceWizardPage(String name, IStructuredSelection selection) { + super(name, selection); + setTitle(Messages.ImportTraceWizard_FileSystemTitle); + setDescription(Messages.ImportTraceWizard_ImportTrace); + + // Locate the target trace folder + IFolder traceFolder = null; + Object element = selection.getFirstElement(); + + if (element instanceof TmfTraceFolder) { + fTraceFolderElement = (TmfTraceFolder) element; + traceFolder = fTraceFolderElement.getResource(); + } else if (element instanceof IProject) { + IProject project = (IProject) element; + try { + if (project.hasNature(TmfProjectNature.ID)) { + TmfProjectElement projectElement = TmfProjectRegistry.getProject(project, true); + fTraceFolderElement = projectElement.getTracesFolder(); + traceFolder = project.getFolder(TmfTracesFolder.TRACES_FOLDER_NAME); + } + } catch (CoreException e) { + } + } + + // If no tracing project was selected or trace folder doesn't exist use + // default tracing project + if (traceFolder == null) { + IProject project = TmfProjectRegistry.createProject( + TmfCommonConstants.DEFAULT_TRACE_PROJECT_NAME, null, new NullProgressMonitor()); + TmfProjectElement projectElement = TmfProjectRegistry.getProject(project, true); + fTraceFolderElement = projectElement.getTracesFolder(); + traceFolder = project.getFolder(TmfTracesFolder.TRACES_FOLDER_NAME); + } + + // Set the target trace folder + if (traceFolder != null) { + fTargetFolder = traceFolder; + String path = traceFolder.getFullPath().toString(); + setContainerFieldValue(path); + } + } + + /** + * Constructor + * + * @param selection + * The current selection + */ + public ImportTraceWizardPage(IStructuredSelection selection) { + this(IMPORT_WIZARD_PAGE_NAME, selection); + } + + /** + * Create the import source selection widget. (Copied from + * WizardResourceImportPage but instead always uses the internal + * ResourceTreeAndListGroup to keep compatibility with Kepler) + */ + @Override + protected void createFileSelectionGroup(Composite parent) { + + // Just create with a dummy root. + fSelectionGroup = new ResourceTreeAndListGroup(parent, + new FileSystemElement("Dummy", null, true),//$NON-NLS-1$ + getFolderProvider(), new WorkbenchLabelProvider(), + getFileProvider(), new WorkbenchLabelProvider(), SWT.NONE, + DialogUtil.inRegularFontMode(parent)); + + ICheckStateListener listener = new ICheckStateListener() { + @Override + public void checkStateChanged(CheckStateChangedEvent event) { + updateWidgetEnablements(); + } + }; + + WorkbenchViewerComparator comparator = new WorkbenchViewerComparator(); + fSelectionGroup.setTreeComparator(comparator); + fSelectionGroup.setListComparator(comparator); + fSelectionGroup.addCheckStateListener(listener); + + } + + // ------------------------------------------------------------------------ + // WizardResourceImportPage + // ------------------------------------------------------------------------ + + @Override + protected void createSourceGroup(Composite parent) { + createSourceSelectionGroup(parent); + createFileSelectionGroup(parent); + createTraceTypeGroup(parent); + validateSourceGroup(); + } + + @Override + protected ITreeContentProvider getFileProvider() { + return new WorkbenchContentProvider() { + @Override + public Object[] getChildren(Object object) { + if (object instanceof TraceFileSystemElement) { + TraceFileSystemElement element = (TraceFileSystemElement) object; + return element.getFiles().getChildren(element); + } + return new Object[0]; + } + }; + } + + @Override + protected ITreeContentProvider getFolderProvider() { + return new WorkbenchContentProvider() { + @Override + public Object[] getChildren(Object o) { + if (o instanceof TraceFileSystemElement) { + TraceFileSystemElement element = (TraceFileSystemElement) o; + return element.getFolders().getChildren(); + } + return new Object[0]; + } + + @Override + public boolean hasChildren(Object o) { + if (o instanceof TraceFileSystemElement) { + TraceFileSystemElement element = (TraceFileSystemElement) o; + if (element.isPopulated()) { + return getChildren(element).length > 0; + } + // If we have not populated then wait until asked + return true; + } + return false; + } + }; + } + + // ------------------------------------------------------------------------ + // Directory Selection Group (forked WizardFileSystemResourceImportPage1) + // ------------------------------------------------------------------------ + + /** + * creates the source selection group. + * + * @param parent + * the parent composite + */ + protected void createSourceSelectionGroup(Composite parent) { + + Composite sourceGroup = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + layout.makeColumnsEqualWidth = false; + layout.marginWidth = 0; + sourceGroup.setLayout(layout); + sourceGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + // import from directory radio button + fImportFromDirectoryRadio = new Button(sourceGroup, SWT.RADIO); + fImportFromDirectoryRadio + .setText(Messages.ImportTraceWizard_DirectoryLocation); + + // import location entry combo + directoryNameField = createPathSelectionCombo(sourceGroup); + createDirectoryBrowseButton(sourceGroup); + + // import from archive radio button + fImportFromArchiveRadio = new Button(sourceGroup, SWT.RADIO); + fImportFromArchiveRadio + .setText(Messages.ImportTraceWizard_ArchiveLocation); + + // import location entry combo + fArchiveNameField = createPathSelectionCombo(sourceGroup); + createArchiveBrowseButton(sourceGroup); + + fImportFromDirectoryRadio.setSelection(true); + fArchiveNameField.setEnabled(false); + fArchiveBrowseButton.setEnabled(false); + + fImportFromDirectoryRadio.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + directoryRadioSelected(); + } + }); + + fImportFromArchiveRadio.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + archiveRadioSelected(); + } + }); + } + + /** + * Select or deselect all files in the file selection group + * + * @param checked + * whether or not the files should be checked + */ + protected void setFileSelectionGroupChecked(boolean checked) { + if (fSelectionGroup != null) { + fSelectionGroup.setAllSelections(checked); + } + } + + /** + * Create a combo that will be used to select a path to specify the source + * of the import. The parent is assumed to have a GridLayout. + * + * @param parent + * the parent composite + * @return the created path selection combo + */ + protected Combo createPathSelectionCombo(Composite parent) { + Combo pathSelectionCombo = new Combo(parent, SWT.BORDER); + + GridData layoutData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL); + layoutData.widthHint = new PixelConverter(pathSelectionCombo).convertWidthInCharsToPixels(25); + pathSelectionCombo.setLayoutData(layoutData); + + TraverseListener traverseListener = new TraverseListener() { + @Override + public void keyTraversed(TraverseEvent e) { + if (e.detail == SWT.TRAVERSE_RETURN) { + e.doit = false; + entryChanged = false; + updateFromSourceField(); + } + } + }; + + FocusAdapter focusAdapter = new FocusAdapter() { + @Override + public void focusLost(FocusEvent e) { + // Clear the flag to prevent constant update + if (entryChanged) { + entryChanged = false; + updateFromSourceField(); + } + } + }; + + SelectionAdapter selectionAdapter = new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + entryChanged = false; + updateFromSourceField(); + } + }; + + ModifyListener modifyListner = new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + entryChanged = true; + } + }; + + pathSelectionCombo.addModifyListener(modifyListner); + pathSelectionCombo.addTraverseListener(traverseListener); + pathSelectionCombo.addFocusListener(focusAdapter); + pathSelectionCombo.addSelectionListener(selectionAdapter); + + return pathSelectionCombo; + } + + /** + * Create the directory browse button. + * + * @param parent + * the parent composite + */ + protected void createDirectoryBrowseButton(Composite parent) { + directoryBrowseButton = createPathSelectionBrowseButton(parent); + directoryBrowseButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + handleSourceDirectoryBrowseButtonPressed(); + } + }); + } + + /** + * Create the archive browse button. + * + * @param parent + * the parent composite + */ + protected void createArchiveBrowseButton(Composite parent) { + fArchiveBrowseButton = createPathSelectionBrowseButton(parent); + fArchiveBrowseButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + handleArchiveBrowseButtonPressed(FILE_IMPORT_MASK); + } + }); + } + + /** + * Create a browse button that will be used to browse for a path to specify + * the source of the import. The parent is assumed to have a GridLayout. + * + * @param parent + * the parent composite + * @return the created path selection combo + */ + protected Button createPathSelectionBrowseButton(Composite parent) { + Button pathSelectionBrowseButton = new Button(parent, SWT.PUSH); + pathSelectionBrowseButton.setText(Messages.ImportTraceWizard_BrowseButton); + setButtonLayoutData(pathSelectionBrowseButton); + + return pathSelectionBrowseButton; + } + + private void archiveRadioSelected() { + if (!isImportFromDirectory()) { + directoryNameField.setEnabled(false); + directoryBrowseButton.setEnabled(false); + fArchiveNameField.setEnabled(true); + fArchiveBrowseButton.setEnabled(true); + updateFromSourceField(); + fArchiveNameField.setFocus(); + if (fCreateLinksInWorkspaceButton != null) { + fPreviousCreateLinksValue = fCreateLinksInWorkspaceButton.getSelection(); + fCreateLinksInWorkspaceButton.setSelection(false); + fCreateLinksInWorkspaceButton.setEnabled(false); + } + } + } + + private void directoryRadioSelected() { + if (isImportFromDirectory()) { + directoryNameField.setEnabled(true); + directoryBrowseButton.setEnabled(true); + fArchiveNameField.setEnabled(false); + fArchiveBrowseButton.setEnabled(false); + updateFromSourceField(); + directoryNameField.setFocus(); + if (fCreateLinksInWorkspaceButton != null) { + fCreateLinksInWorkspaceButton.setSelection(fPreviousCreateLinksValue); + fCreateLinksInWorkspaceButton.setEnabled(true); + } + } + } + + // ------------------------------------------------------------------------ + // Browse for the source directory + // ------------------------------------------------------------------------ + + @Override + public void handleEvent(Event event) { + if (event.widget == directoryBrowseButton) { + handleSourceDirectoryBrowseButtonPressed(); + } + + // Avoid overwriting destination path without repeatedly trigger + // call of handleEvent(); + synchronized (fSyncObject) { + if (fIsDestinationChanged == false) { + event.display.asyncExec(new Runnable() { + @Override + public void run() { + synchronized (fSyncObject) { + fIsDestinationChanged = true; + String path = fTargetFolder.getFullPath().toString(); + setContainerFieldValue(path); + } + } + }); + } else { + fIsDestinationChanged = false; + } + } + super.handleEvent(event); + } + + @Override + protected void handleContainerBrowseButtonPressed() { + // Do nothing so that destination directory cannot be changed. + } + + /** + * Handle the button pressed event + */ + protected void handleSourceDirectoryBrowseButtonPressed() { + String currentSource = directoryNameField.getText(); + DirectoryDialog dialog = new DirectoryDialog(directoryNameField.getShell(), SWT.SAVE | SWT.SHEET); + dialog.setText(Messages.ImportTraceWizard_SelectTraceDirectoryTitle); + dialog.setMessage(Messages.ImportTraceWizard_SelectTraceDirectoryMessage); + dialog.setFilterPath(getSourceDirectoryName(currentSource)); + + String selectedDirectory = dialog.open(); + if (selectedDirectory != null) { + // Just quit if the directory is not valid + if ((getSourceDirectory(selectedDirectory) == null) || selectedDirectory.equals(currentSource)) { + return; + } + // If it is valid then proceed to populate + setErrorMessage(null); + setSourcePath(selectedDirectory); + } + } + + /** + * Handle the button pressed event + * + * @param extensions + * file extensions used to filter files shown to the user + */ + protected void handleArchiveBrowseButtonPressed(String[] extensions) { + FileDialog dialog = new FileDialog(fArchiveNameField.getShell(), SWT.SHEET); + dialog.setFilterExtensions(extensions); + dialog.setText(Messages.ImportTraceWizard_SelectTraceArchiveTitle); + String fileName = fArchiveNameField.getText().trim(); + if (!fileName.isEmpty()) { + File path = new File(fileName).getParentFile(); + if (path != null && path.exists()) { + dialog.setFilterPath(path.toString()); + } + } + + String selectedArchive = dialog.open(); + if (selectedArchive != null) { + setErrorMessage(null); + setSourcePath(selectedArchive); + updateWidgetEnablements(); + } + } + + private File getSourceDirectory() { + if (directoryNameField == null) { + return null; + } + return getSourceDirectory(directoryNameField.getText()); + } + + private File getSourceArchiveFile() { + if (fArchiveNameField == null) { + return null; + } + + return getSourceArchiveFile(fArchiveNameField.getText()); + } + + private String getSourceContainerPath() { + if (isImportFromDirectory()) { + File sourceDirectory = getSourceDirectory(); + if (sourceDirectory != null) { + return sourceDirectory.getAbsolutePath(); + } + } + File sourceArchiveFile = getSourceArchiveFile(); + if (sourceArchiveFile != null) { + return sourceArchiveFile.getParent(); + } + return null; + } + + private static File getSourceDirectory(String path) { + File sourceDirectory = new File(getSourceDirectoryName(path)); + if (!sourceDirectory.exists() || !sourceDirectory.isDirectory()) { + return null; + } + + return sourceDirectory; + } + + private static File getSourceArchiveFile(String path) { + File sourceArchiveFile = new File(path); + if (!sourceArchiveFile.exists() || sourceArchiveFile.isDirectory()) { + return null; + } + + return sourceArchiveFile; + } + + private static String getSourceDirectoryName(String sourceName) { + IPath result = new Path(sourceName.trim()); + if (result.getDevice() != null && result.segmentCount() == 0) { + result = result.addTrailingSeparator(); + } else { + result = result.removeTrailingSeparator(); + } + return result.toOSString(); + } + + private void updateFromSourceField() { + setSourcePath(getSourceField().getText()); + updateWidgetEnablements(); + } + + private Combo getSourceField() { + if (directoryNameField == null) { + return fArchiveNameField; + } + + return directoryNameField.isEnabled() ? directoryNameField : fArchiveNameField; + } + + /** + * Set the source path that was selected by the user by various input + * methods (Browse button, typing, etc). + * + * Clients can also call this to set the path programmatically (hard-coded + * initial path) and this can also be overridden to be notified when the + * source path changes. + * + * @param path + * the source path + */ + protected void setSourcePath(String path) { + Combo sourceField = getSourceField(); + if (sourceField == null) { + return; + } + + if (path.length() > 0) { + String[] currentItems = sourceField.getItems(); + int selectionIndex = -1; + for (int i = 0; i < currentItems.length; i++) { + if (currentItems[i].equals(path)) { + selectionIndex = i; + } + } + if (selectionIndex < 0) { + int oldLength = currentItems.length; + String[] newItems = new String[oldLength + 1]; + System.arraycopy(currentItems, 0, newItems, 0, oldLength); + newItems[oldLength] = path; + sourceField.setItems(newItems); + selectionIndex = oldLength; + } + sourceField.select(selectionIndex); + } + resetSelection(); + } + + // ------------------------------------------------------------------------ + // File Selection Group (forked WizardFileSystemResourceImportPage1) + // ------------------------------------------------------------------------ + private void resetSelection() { + if (fSelectionGroupRoot != null) { + disposeSelectionGroupRoot(); + } + fSelectionGroupRoot = getFileSystemTree(); + fSelectionGroup.setRoot(fSelectionGroupRoot); + } + + private void disposeSelectionGroupRoot() { + if (fSelectionGroupRoot != null && fSelectionGroupRoot.getProvider() != null) { + FileSystemObjectImportStructureProvider provider = fSelectionGroupRoot.getProvider(); + provider.dispose(); + fSelectionGroupRoot = null; + } + } + + private TraceFileSystemElement getFileSystemTree() { + Pair<IFileSystemObject, FileSystemObjectImportStructureProvider> rootObjectAndProvider = getRootObjectAndProvider(getSourceFile()); + if (rootObjectAndProvider == null) { + return null; + } + return selectFiles(rootObjectAndProvider.getFirst(), rootObjectAndProvider.getSecond()); + } + + @SuppressWarnings("resource") + private Pair<IFileSystemObject, FileSystemObjectImportStructureProvider> getRootObjectAndProvider(File sourceFile) { + if (sourceFile == null) { + return null; + } + + IFileSystemObject rootElement = null; + FileSystemObjectImportStructureProvider importStructureProvider = null; + + // Import from directory + if (!isArchiveFile(sourceFile)) { + importStructureProvider = new FileSystemObjectImportStructureProvider(FileSystemStructureProvider.INSTANCE, null); + rootElement = importStructureProvider.getIFileSystemObject(sourceFile); + } else { + // Import from archive + FileSystemObjectLeveledImportStructureProvider leveledImportStructureProvider = null; + String archivePath = sourceFile.getAbsolutePath(); + if (isTarFile(archivePath)) { + if (ensureTarSourceIsValid(archivePath)) { + // We close the file when we dispose the import provider, + // see disposeSelectionGroupRoot + TarFile tarFile = getSpecifiedTarSourceFile(archivePath); + leveledImportStructureProvider = new FileSystemObjectLeveledImportStructureProvider(new TarLeveledStructureProvider(tarFile), archivePath); + } + } else if (ensureZipSourceIsValid(archivePath)) { + // We close the file when we dispose the import provider, see + // disposeSelectionGroupRoot + ZipFile zipFile = getSpecifiedZipSourceFile(archivePath); + leveledImportStructureProvider = new FileSystemObjectLeveledImportStructureProvider(new ZipLeveledStructureProvider(zipFile), archivePath); + } else if (ensureGzipSourceIsValid(archivePath)) { + // We close the file when we dispose the import provider, see + // disposeSelectionGroupRoot + GzipFile zipFile = null; + try { + zipFile = new GzipFile(archivePath); + leveledImportStructureProvider = new FileSystemObjectLeveledImportStructureProvider(new GzipLeveledStructureProvider(zipFile), archivePath); + } catch (IOException e) { + // do nothing + } + } + if (leveledImportStructureProvider == null) { + return null; + } + rootElement = leveledImportStructureProvider.getRoot(); + importStructureProvider = leveledImportStructureProvider; + } + + if (rootElement == null) { + return null; + } + + return new Pair<>(rootElement, importStructureProvider); + } + + /** + * An import provider that makes use of the IFileSystemObject abstraction + * instead of using plain file system objects (File, TarEntry, ZipEntry, etc) + */ + private static class FileSystemObjectImportStructureProvider implements IImportStructureProvider { + + private IImportStructureProvider fImportProvider; + private String fArchivePath; + + private FileSystemObjectImportStructureProvider(IImportStructureProvider importStructureProvider, String archivePath) { + fImportProvider = importStructureProvider; + fArchivePath = archivePath; + } + + @Override + public List<IFileSystemObject> getChildren(Object element) { + @SuppressWarnings("rawtypes") + List children = fImportProvider.getChildren(((IFileSystemObject) element).getRawFileSystemObject()); + List<IFileSystemObject> adapted = new ArrayList<>(children.size()); + for (Object o : children) { + adapted.add(getIFileSystemObject(o)); + } + return adapted; + } + + public IFileSystemObject getIFileSystemObject(Object o) { + if (o == null) { + return null; + } + + if (o instanceof File) { + return new FileFileSystemObject((File) o); + } else if (o instanceof TarEntry) { + return new TarFileSystemObject((TarEntry) o, fArchivePath); + } else if (o instanceof ZipEntry) { + return new ZipFileSystemObject((ZipEntry) o, fArchivePath); + } else if (o instanceof GzipEntry) { + return new GzipFileSystemObject((GzipEntry) o, fArchivePath); + } + + throw new IllegalArgumentException("Object type not handled"); //$NON-NLS-1$ + } + + @Override + public InputStream getContents(Object element) { + return fImportProvider.getContents(((IFileSystemObject) element).getRawFileSystemObject()); + } + + @Override + public String getFullPath(Object element) { + return fImportProvider.getFullPath(((IFileSystemObject) element).getRawFileSystemObject()); + } + + @Override + public String getLabel(Object element) { + return fImportProvider.getLabel(((IFileSystemObject) element).getRawFileSystemObject()); + } + + @Override + public boolean isFolder(Object element) { + return fImportProvider.isFolder(((IFileSystemObject) element).getRawFileSystemObject()); + } + + /** + * Disposes of the resources associated with the provider. + */ + public void dispose() { + } + } + + /** + * An import provider that both supports using IFileSystemObject and adds + * "archive functionality" by delegating to a leveled import provider + * (TarLeveledStructureProvider, ZipLeveledStructureProvider) + */ + private static class FileSystemObjectLeveledImportStructureProvider extends FileSystemObjectImportStructureProvider implements ILeveledImportStructureProvider { + + private ILeveledImportStructureProvider fLeveledImportProvider; + + private FileSystemObjectLeveledImportStructureProvider(ILeveledImportStructureProvider importStructureProvider, String archivePath) { + super(importStructureProvider, archivePath); + fLeveledImportProvider = importStructureProvider; + } + + @Override + public IFileSystemObject getRoot() { + return getIFileSystemObject(fLeveledImportProvider.getRoot()); + } + + @Override + public void setStrip(int level) { + fLeveledImportProvider.setStrip(level); + } + + @Override + public int getStrip() { + return fLeveledImportProvider.getStrip(); + } + + @Override + public boolean closeArchive() { + return fLeveledImportProvider.closeArchive(); + } + + @Override + public void dispose() { + super.dispose(); + closeArchive(); + } + } + + @SuppressWarnings("resource") + private boolean ensureZipSourceIsValid(String archivePath) { + ZipFile specifiedFile = getSpecifiedZipSourceFile(archivePath); + if (specifiedFile == null) { + return false; + } + return ArchiveFileManipulations.closeZipFile(specifiedFile, getShell()); + } + + private boolean ensureTarSourceIsValid(String archivePath) { + TarFile specifiedFile = getSpecifiedTarSourceFile(archivePath); + if (specifiedFile == null) { + return false; + } + return ArchiveFileManipulations.closeTarFile(specifiedFile, getShell()); + } + + private static ZipFile getSpecifiedZipSourceFile(String fileName) { + if (fileName.length() == 0) { + return null; + } + + try { + return new ZipFile(fileName); + } catch (ZipException e) { + // ignore + } catch (IOException e) { + // ignore + } + + return null; + } + + private static boolean isTarFile(String fileName) { + TarFile specifiedTarSourceFile = getSpecifiedTarSourceFile(fileName); + if (specifiedTarSourceFile != null) { + try { + specifiedTarSourceFile.close(); + return true; + } catch (IOException e) { + // ignore + } + } + return false; + } + + private static TarFile getSpecifiedTarSourceFile(String fileName) { + if (fileName.length() == 0) { + return null; + } + + // FIXME: Work around Bug 463633. Remove this block once we move to Eclipse 4.5. + if (new File(fileName).length() < 512) { + return null; + } + + try { + return new TarFile(fileName); + } catch (TarException | IOException e) { + // ignore + } + + return null; + } + + private static boolean ensureGzipSourceIsValid(String archivePath) { + return isGzipFile(archivePath); + } + + private TraceFileSystemElement selectFiles(final IFileSystemObject rootFileSystemObject, + final FileSystemObjectImportStructureProvider structureProvider) { + final TraceFileSystemElement[] results = new TraceFileSystemElement[1]; + BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() { + @Override + public void run() { + // Create the root element from the supplied file system object + results[0] = createRootTraceFileElement(rootFileSystemObject, structureProvider); + } + }); + return results[0]; + } + + private static TraceFileSystemElement createRootTraceFileElement(IFileSystemObject element, + FileSystemObjectImportStructureProvider provider) { + boolean isContainer = provider.isFolder(element); + String elementLabel = provider.getLabel(element); + + // Use an empty label so that display of the element's full name + // doesn't include a confusing label + TraceFileSystemElement dummyParent = new TraceFileSystemElement("", null, true, provider);//$NON-NLS-1$ + Object dummyParentFileSystemObject = element; + Object rawFileSystemObject = element.getRawFileSystemObject(); + if (rawFileSystemObject instanceof File) { + dummyParentFileSystemObject = provider.getIFileSystemObject(((File) rawFileSystemObject).getParentFile()); + } + dummyParent.setFileSystemObject(dummyParentFileSystemObject); + dummyParent.setPopulated(); + TraceFileSystemElement result = new TraceFileSystemElement( + elementLabel, dummyParent, isContainer, provider); + result.setFileSystemObject(element); + + // Get the files for the element so as to build the first level + result.getFiles(); + + return dummyParent; + } + + // ------------------------------------------------------------------------ + // Trace Type Group + // ------------------------------------------------------------------------ + private final void createTraceTypeGroup(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + layout.makeColumnsEqualWidth = false; + composite.setLayout(layout); + composite.setFont(parent.getFont()); + GridData buttonData = new GridData(SWT.FILL, SWT.FILL, true, false); + composite.setLayoutData(buttonData); + + // Trace type label ("Trace Type:") + Label typeLabel = new Label(composite, SWT.NONE); + typeLabel.setText(Messages.ImportTraceWizard_TraceType); + typeLabel.setFont(parent.getFont()); + + // Trace type combo + fTraceTypes = new Combo(composite, SWT.BORDER | SWT.READ_ONLY); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1); + fTraceTypes.setLayoutData(data); + fTraceTypes.setFont(parent.getFont()); + + String[] availableTraceTypes = TmfTraceType.getAvailableTraceTypes(); + String[] traceTypeList = new String[availableTraceTypes.length + 1]; + traceTypeList[0] = TRACE_TYPE_AUTO_DETECT; + for (int i = 0; i < availableTraceTypes.length; i++) { + traceTypeList[i + 1] = availableTraceTypes[i]; + } + fTraceTypes.setItems(traceTypeList); + fTraceTypes.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateWidgetEnablements(); + boolean enabled = fTraceTypes.getText().equals(TRACE_TYPE_AUTO_DETECT); + fImportUnrecognizedButton.setEnabled(enabled); + } + }); + fTraceTypes.select(0); + + // Unrecognized checkbox + fImportUnrecognizedButton = new Button(composite, SWT.CHECK); + fImportUnrecognizedButton.setSelection(true); + fImportUnrecognizedButton.setText(Messages.ImportTraceWizard_ImportUnrecognized); + } + + // ------------------------------------------------------------------------ + // Options + // ------------------------------------------------------------------------ + + @Override + protected void createOptionsGroupButtons(Group optionsGroup) { + + // Overwrite checkbox + fOverwriteExistingResourcesCheckbox = new Button(optionsGroup, SWT.CHECK); + fOverwriteExistingResourcesCheckbox.setFont(optionsGroup.getFont()); + fOverwriteExistingResourcesCheckbox.setText(Messages.ImportTraceWizard_OverwriteExistingTrace); + fOverwriteExistingResourcesCheckbox.setSelection(false); + + // Create links checkbox + fCreateLinksInWorkspaceButton = new Button(optionsGroup, SWT.CHECK); + fCreateLinksInWorkspaceButton.setFont(optionsGroup.getFont()); + fCreateLinksInWorkspaceButton.setText(Messages.ImportTraceWizard_CreateLinksInWorkspace); + fCreateLinksInWorkspaceButton.setSelection(true); + + fCreateLinksInWorkspaceButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateWidgetEnablements(); + } + }); + + fPreserveFolderStructureButton = new Button(optionsGroup, SWT.CHECK); + fPreserveFolderStructureButton.setFont(optionsGroup.getFont()); + fPreserveFolderStructureButton.setText(Messages.ImportTraceWizard_PreserveFolderStructure); + fPreserveFolderStructureButton.setSelection(true); + + updateWidgetEnablements(); + } + + // ------------------------------------------------------------------------ + // Determine if the finish button can be enabled + // ------------------------------------------------------------------------ + @Override + public boolean validateSourceGroup() { + + File source = getSourceFile(); + if (source == null) { + setMessage(Messages.ImportTraceWizard_SelectTraceSourceEmpty); + setErrorMessage(null); + return false; + } + + if (sourceConflictsWithDestination(new Path(source.getPath()))) { + setMessage(null); + setErrorMessage(getSourceConflictMessage()); + return false; + } + + if (!isImportFromDirectory() && !ensureTarSourceIsValid(source.getAbsolutePath()) && !ensureZipSourceIsValid(source.getAbsolutePath()) && !ensureGzipSourceIsValid(source.getAbsolutePath())) { + setMessage(null); + setErrorMessage(Messages.ImportTraceWizard_BadArchiveFormat); + return false; + } + + if (fSelectionGroup.getCheckedElementCount() == 0) { + setMessage(null); + setErrorMessage(Messages.ImportTraceWizard_SelectTraceNoneSelected); + return false; + } + + IContainer container = getSpecifiedContainer(); + if (container != null && container.isVirtual()) { + if (Platform.getPreferencesService().getBoolean(Activator.PLUGIN_ID, ResourcesPlugin.PREF_DISABLE_LINKING, false, null)) { + setMessage(null); + setErrorMessage(Messages.ImportTraceWizard_CannotImportFilesUnderAVirtualFolder); + return false; + } + if (fCreateLinksInWorkspaceButton == null || !fCreateLinksInWorkspaceButton.getSelection()) { + setMessage(null); + setErrorMessage(Messages.ImportTraceWizard_HaveToCreateLinksUnderAVirtualFolder); + return false; + } + } + + setErrorMessage(null); + return true; + } + + private File getSourceFile() { + return isImportFromDirectory() ? getSourceDirectory() : getSourceArchiveFile(); + } + + private boolean isImportFromDirectory() { + return fImportFromDirectoryRadio != null && fImportFromDirectoryRadio.getSelection(); + } + + private static boolean isArchiveFile(File sourceFile) { + String absolutePath = sourceFile.getAbsolutePath(); + return isTarFile(absolutePath) || ArchiveFileManipulations.isZipFile(absolutePath) || isGzipFile(absolutePath); + } + + private static boolean isGzipFile(String fileName) { + if (!fileName.isEmpty()) { + try (GzipFile specifiedTarSourceFile = new GzipFile(fileName);) { + return true; + } catch (IOException e) { + } + } + return false; + } + + @Override + protected void restoreWidgetValues() { + super.restoreWidgetValues(); + + IDialogSettings settings = getDialogSettings(); + boolean value; + if (fImportUnrecognizedButton != null) { + if (settings.get(getPageStoreKey(IMPORT_WIZARD_IMPORT_UNRECOGNIZED_ID)) == null) { + value = true; + } else { + value = settings.getBoolean(getPageStoreKey(IMPORT_WIZARD_IMPORT_UNRECOGNIZED_ID)); + } + fImportUnrecognizedButton.setSelection(value); + } + + if (fPreserveFolderStructureButton != null) { + if (settings.get(getPageStoreKey(IMPORT_WIZARD_PRESERVE_FOLDERS_ID)) == null) { + value = true; + } else { + value = settings.getBoolean(getPageStoreKey(IMPORT_WIZARD_PRESERVE_FOLDERS_ID)); + } + fPreserveFolderStructureButton.setSelection(value); + } + + if (settings.get(getPageStoreKey(IMPORT_WIZARD_IMPORT_FROM_DIRECTORY_ID)) == null) { + value = true; + } else { + value = settings.getBoolean(getPageStoreKey(IMPORT_WIZARD_IMPORT_FROM_DIRECTORY_ID)); + } + + if (directoryNameField != null) { + restoreComboValues(directoryNameField, settings, getPageStoreKey(IMPORT_WIZARD_ROOT_DIRECTORY_ID)); + } + if (fArchiveNameField != null) { + restoreComboValues(fArchiveNameField, settings, getPageStoreKey(IMPORT_WIZARD_ARCHIVE_FILE_NAME_ID)); + } + + if (fImportFromDirectoryRadio != null) { + fImportFromDirectoryRadio.setSelection(value); + if (value) { + directoryRadioSelected(); + } + } + if (fImportFromArchiveRadio != null) { + fImportFromArchiveRadio.setSelection(!value); + if (!value) { + archiveRadioSelected(); + } + } + } + + @Override + protected void saveWidgetValues() { + // Persist dialog settings + IDialogSettings settings = getDialogSettings(); + if (fImportUnrecognizedButton != null) { + settings.put(getPageStoreKey(IMPORT_WIZARD_IMPORT_UNRECOGNIZED_ID), fImportUnrecognizedButton.getSelection()); + } + if (fPreserveFolderStructureButton != null) { + settings.put(getPageStoreKey(IMPORT_WIZARD_PRESERVE_FOLDERS_ID), fPreserveFolderStructureButton.getSelection()); + } + settings.put(getPageStoreKey(IMPORT_WIZARD_IMPORT_FROM_DIRECTORY_ID), isImportFromDirectory()); + + if (directoryNameField != null) { + saveComboValues(directoryNameField, settings, getPageStoreKey(IMPORT_WIZARD_ROOT_DIRECTORY_ID)); + } + if (fArchiveNameField != null) { + saveComboValues(fArchiveNameField, settings, getPageStoreKey(IMPORT_WIZARD_ARCHIVE_FILE_NAME_ID)); + } + } + + private String getPageStoreKey(String key) { + return getName() + key; + } + + private static void restoreComboValues(Combo combo, IDialogSettings settings, String key) { + String[] directoryNames = settings.getArray(key); + if ((directoryNames != null) && (directoryNames.length != 0)) { + for (int i = 0; i < directoryNames.length; i++) { + combo.add(directoryNames[i]); + } + } + } + + private void saveComboValues(Combo combo, IDialogSettings settings, String key) { + // update names history + String[] directoryNames = settings.getArray(key); + if (directoryNames == null) { + directoryNames = new String[0]; + } + + String items[] = combo.getItems(); + for (int i = 0; i < items.length; i++) { + directoryNames = addToHistory(directoryNames, items[i]); + } + settings.put(key, directoryNames); + } + + // ------------------------------------------------------------------------ + // Import the trace(s) + // ------------------------------------------------------------------------ + + /** + * Finish the import. + * + * @return <code>true</code> if successful else <code>false</code> + */ + public boolean finish() { + String traceTypeLabel = getImportTraceTypeId(); + String traceId = null; + if (!TRACE_TYPE_AUTO_DETECT.equals(traceTypeLabel)) { + traceId = TmfTraceType.getTraceTypeId(traceTypeLabel); + } + + // Save dialog settings + saveWidgetValues(); + + IPath baseSourceContainerPath = new Path(getSourceContainerPath()); + boolean importFromArchive = getSourceArchiveFile() != null; + int importOptionFlags = getImportOptionFlags(); + + final TraceValidateAndImportOperation operation = new TraceValidateAndImportOperation(traceId, baseSourceContainerPath, getContainerFullPath(), importFromArchive, + importOptionFlags); + + IStatus status = Status.OK_STATUS; + try { + getContainer().run(true, true, new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + operation.run(monitor); + monitor.done(); + } + }); + + status = operation.getStatus(); + } catch (InvocationTargetException e) { + status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.ImportTraceWizard_ImportProblem, e); + } catch (InterruptedException e) { + status = Status.CANCEL_STATUS; + } + if (!status.isOK()) { + if (status.getSeverity() == IStatus.CANCEL) { + setMessage(Messages.ImportTraceWizard_ImportOperationCancelled); + setErrorMessage(null); + } else { + if (status.getException() != null) { + displayErrorDialog(status.getMessage() + ": " + status.getException()); //$NON-NLS-1$ + } + setMessage(null); + setErrorMessage(Messages.ImportTraceWizard_ImportProblem); + } + return false; + } + setErrorMessage(null); + return true; + } + + /** + * Get the trace type id to import as. This can also return + * {@link #TRACE_TYPE_AUTO_DETECT} to communicate that automatic trace type + * detection will occur instead of setting a specific trace type when + * importing the traces. + * + * @return the trace type id or {@link #TRACE_TYPE_AUTO_DETECT} + */ + protected String getImportTraceTypeId() { + return fTraceTypes.getText(); + } + + /** + * Get import options in the form of flags (bits). + * + * @return the import flags. + * @see #OPTION_CREATE_LINKS_IN_WORKSPACE + * @see #OPTION_IMPORT_UNRECOGNIZED_TRACES + * @see #OPTION_OVERWRITE_EXISTING_RESOURCES + * @see #OPTION_PRESERVE_FOLDER_STRUCTURE + */ + protected int getImportOptionFlags() { + int flags = 0; + if (fCreateLinksInWorkspaceButton != null && fCreateLinksInWorkspaceButton.getSelection()) { + flags |= OPTION_CREATE_LINKS_IN_WORKSPACE; + } + if (fImportUnrecognizedButton != null && fImportUnrecognizedButton.getSelection()) { + flags |= OPTION_IMPORT_UNRECOGNIZED_TRACES; + } + if (fOverwriteExistingResourcesCheckbox != null && fOverwriteExistingResourcesCheckbox.getSelection()) { + flags |= OPTION_OVERWRITE_EXISTING_RESOURCES; + } + if (fPreserveFolderStructureButton != null && fPreserveFolderStructureButton.getSelection()) { + flags |= OPTION_PRESERVE_FOLDER_STRUCTURE; + } + return flags; + } + + @Override + public void dispose() { + super.dispose(); + disposeSelectionGroupRoot(); + } + + // ------------------------------------------------------------------------ + // Classes + // ------------------------------------------------------------------------ + + private class TraceValidateAndImportOperation { + private IStatus fStatus; + private String fTraceType; + private IPath fDestinationContainerPath; + private IPath fBaseSourceContainerPath; + private boolean fImportFromArchive; + private int fImportOptionFlags; + private ImportConflictHandler fConflictHandler; + private String fCurrentPath; + + private TraceValidateAndImportOperation(String traceId, IPath baseSourceContainerPath, IPath destinationContainerPath, boolean importFromArchive, int importOptionFlags) { + fTraceType = traceId; + fBaseSourceContainerPath = baseSourceContainerPath; + fDestinationContainerPath = destinationContainerPath; + fImportOptionFlags = importOptionFlags; + fImportFromArchive = importFromArchive; + + boolean overwriteExistingResources = (importOptionFlags & OPTION_OVERWRITE_EXISTING_RESOURCES) != 0; + if (overwriteExistingResources) { + fConflictHandler = new ImportConflictHandler(getContainer().getShell(), fTraceFolderElement, ImportConfirmation.OVERWRITE_ALL); + } else { + fConflictHandler = new ImportConflictHandler(getContainer().getShell(), fTraceFolderElement, ImportConfirmation.SKIP); + } + } + + public void run(IProgressMonitor progressMonitor) { + try { + + final List<TraceFileSystemElement> selectedFileSystemElements = new LinkedList<>(); + IElementFilter passThroughFilter = new IElementFilter() { + + @Override + public void filterElements(Collection elements, IProgressMonitor monitor) { + selectedFileSystemElements.addAll(elements); + } + + @Override + public void filterElements(Object[] elements, IProgressMonitor monitor) { + for (int i = 0; i < elements.length; i++) { + selectedFileSystemElements.add((TraceFileSystemElement) elements[i]); + } + } + }; + + // List fileSystemElements will be filled using the + // passThroughFilter + SubMonitor subMonitor = SubMonitor.convert(progressMonitor, 1); + fSelectionGroup.getAllCheckedListItems(passThroughFilter, subMonitor); + + // Check if operation was cancelled. + ModalContext.checkCanceled(subMonitor); + + // Temporary directory to contain any extracted files + IFolder destTempFolder = fTargetFolder.getProject().getFolder(TRACE_IMPORT_TEMP_FOLDER); + if (destTempFolder.exists()) { + SubProgressMonitor monitor = new SubProgressMonitor(subMonitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); + destTempFolder.delete(true, monitor); + } + SubProgressMonitor monitor = new SubProgressMonitor(subMonitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); + destTempFolder.create(IResource.HIDDEN, true, monitor); + + subMonitor = SubMonitor.convert(progressMonitor, 2); + String baseSourceLocation; + if (fImportFromArchive) { + // When importing from archive, we first extract the + // *selected* files to a temporary folder then create new + // TraceFileSystemElements + + SubMonitor archiveMonitor = SubMonitor.convert(subMonitor.newChild(1), 2); + + // Extract selected files from source archive to temporary folder + extractArchiveContent(selectedFileSystemElements.iterator(), destTempFolder, archiveMonitor.newChild(1)); + + // Even if the files were extracted to temporary folder, they have to look like they originate from the source archive + baseSourceLocation = getRootElement(selectedFileSystemElements.get(0)).getSourceLocation(); + // Extract additional archives contained in the extracted files (archives in archives) + List<TraceFileSystemElement> tempFolderFileSystemElements = createElementsForFolder(destTempFolder); + extractAllArchiveFiles(tempFolderFileSystemElements, destTempFolder, destTempFolder.getLocation(), archiveMonitor.newChild(1)); + } else { + SubMonitor directoryMonitor = SubMonitor.convert(subMonitor.newChild(1), 2); + // Import selected files, excluding archives (done in a later step) + importFileSystemElements(directoryMonitor.newChild(1), selectedFileSystemElements); + + // Extract archives in selected files (if any) to temporary folder + extractAllArchiveFiles(selectedFileSystemElements, destTempFolder, fBaseSourceContainerPath, directoryMonitor.newChild(1)); + // Even if the files were extracted to temporary folder, they have to look like they originate from the source folder + baseSourceLocation = URIUtil.toUnencodedString(fBaseSourceContainerPath.toFile().getCanonicalFile().toURI()); + } + + /* Import extracted files that are now in the temporary folder, if any */ + + // We need to update the source container path because the + // "preserve folder structure" option would create the + // wrong trace folders otherwise. + fBaseSourceContainerPath = destTempFolder.getLocation(); + List<TraceFileSystemElement> tempFolderFileSystemElements = createElementsForFolder(destTempFolder); + calculateSourceLocations(tempFolderFileSystemElements, baseSourceLocation); + // Never import extracted files as links, they would link to the + // temporary directory that will be deleted + fImportOptionFlags = fImportOptionFlags & ~OPTION_CREATE_LINKS_IN_WORKSPACE; + SubMonitor importTempMonitor = subMonitor.newChild(1); + importFileSystemElements(importTempMonitor, tempFolderFileSystemElements); + + if (destTempFolder.exists()) { + destTempFolder.delete(true, progressMonitor); + } + + setStatus(Status.OK_STATUS); + } catch (InterruptedException e) { + setStatus(Status.CANCEL_STATUS); + } catch (Exception e) { + String errorMessage = Messages.ImportTraceWizard_ImportProblem + ": " + //$NON-NLS-1$ + (fCurrentPath != null ? fCurrentPath : ""); //$NON-NLS-1$ + Activator.getDefault().logError(errorMessage, e); + setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, errorMessage, e)); + } + } + + /** + * Import a collection of file system elements into the workspace. + */ + private void importFileSystemElements(IProgressMonitor monitor, List<TraceFileSystemElement> fileSystemElements) + throws InterruptedException, TmfTraceImportException, CoreException, InvocationTargetException { + SubMonitor subMonitor = SubMonitor.convert(monitor, fileSystemElements.size()); + + ListIterator<TraceFileSystemElement> fileSystemElementsIter = fileSystemElements.listIterator(); + + // Map to remember already imported directory traces + final Map<String, TraceFileSystemElement> directoryTraces = new HashMap<>(); + while (fileSystemElementsIter.hasNext()) { + ModalContext.checkCanceled(monitor); + fCurrentPath = null; + TraceFileSystemElement element = fileSystemElementsIter.next(); + IFileSystemObject fileSystemObject = element.getFileSystemObject(); + String resourcePath = element.getFileSystemObject().getAbsolutePath(fBaseSourceContainerPath.toOSString()); + element.setDestinationContainerPath(computeDestinationContainerPath(new Path(resourcePath))); + + fCurrentPath = resourcePath; + SubMonitor sub = subMonitor.newChild(1); + if (element.isDirectory()) { + if (!directoryTraces.containsKey(resourcePath) && isDirectoryTrace(element)) { + directoryTraces.put(resourcePath, element); + validateAndImportTrace(element, sub); + } + } else { + TraceFileSystemElement parentElement = (TraceFileSystemElement) element.getParent(); + String parentPath = parentElement.getFileSystemObject().getAbsolutePath(fBaseSourceContainerPath.toOSString()); + parentElement.setDestinationContainerPath(computeDestinationContainerPath(new Path(parentPath))); + fCurrentPath = parentPath; + if (!directoryTraces.containsKey(parentPath)) { + if (isDirectoryTrace(parentElement)) { + directoryTraces.put(parentPath, parentElement); + validateAndImportTrace(parentElement, sub); + } else { + boolean validateFile = true; + TraceFileSystemElement grandParentElement = (TraceFileSystemElement) parentElement.getParent(); + // Special case for LTTng trace that may contain index directory and files + if (grandParentElement != null) { + String grandParentPath = grandParentElement.getFileSystemObject().getAbsolutePath(fBaseSourceContainerPath.toOSString()); + grandParentElement.setDestinationContainerPath(computeDestinationContainerPath(new Path(parentPath))); + fCurrentPath = grandParentPath; + if (directoryTraces.containsKey(grandParentPath)) { + validateFile = false; + } else if (isDirectoryTrace(grandParentElement)) { + directoryTraces.put(grandParentPath, grandParentElement); + validateAndImportTrace(grandParentElement, sub); + validateFile = false; + } + } + if (validateFile && (fileSystemObject.exists())) { + validateAndImportTrace(element, sub); + } + } + } + } + } + } + + /** + * Generate a new list of file system elements for the specified folder. + */ + private List<TraceFileSystemElement> createElementsForFolder(IFolder folder) { + // Create the new import provider and root element based on the specified folder + FileSystemObjectImportStructureProvider importStructureProvider = new FileSystemObjectImportStructureProvider(FileSystemStructureProvider.INSTANCE, null); + IFileSystemObject rootElement = importStructureProvider.getIFileSystemObject(new File(folder.getLocation().toOSString())); + TraceFileSystemElement createRootElement = createRootTraceFileElement(rootElement, importStructureProvider); + List<TraceFileSystemElement> list = new LinkedList<>(); + getAllChildren(list, createRootElement); + return list; + } + + /** + * Extract all file system elements (File) to destination folder (typically workspace/TraceProject/.traceImport) + */ + private void extractAllArchiveFiles(List<TraceFileSystemElement> fileSystemElements, IFolder destFolder, IPath baseSourceContainerPath, IProgressMonitor progressMonitor) throws InterruptedException, CoreException, InvocationTargetException { + SubMonitor subMonitor = SubMonitor.convert(progressMonitor, fileSystemElements.size()); + ListIterator<TraceFileSystemElement> fileSystemElementsIter = fileSystemElements.listIterator(); + while (fileSystemElementsIter.hasNext()) { + ModalContext.checkCanceled(subMonitor); + + SubMonitor elementProgress = subMonitor.newChild(1); + TraceFileSystemElement element = fileSystemElementsIter.next(); + File archiveFile = (File) element.getFileSystemObject().getRawFileSystemObject(); + boolean isArchiveFileElement = element.getFileSystemObject() instanceof FileFileSystemObject && isArchiveFile(archiveFile); + if (isArchiveFileElement) { + elementProgress = SubMonitor.convert(elementProgress, 4); + IPath relativeToSourceContainer = new Path(element.getFileSystemObject().getAbsolutePath(null)).makeRelativeTo(baseSourceContainerPath); + IFolder folder = safeCreateExtractedFolder(destFolder, relativeToSourceContainer, elementProgress.newChild(1)); + extractArchiveToFolder(archiveFile, folder, elementProgress.newChild(1)); + + // Delete original archive, we don't want to import this, just the extracted content + IFile fileRes = destFolder.getFile(relativeToSourceContainer); + fileRes.delete(true, elementProgress.newChild(1)); + IPath newPath = destFolder.getFullPath().append(relativeToSourceContainer); + // Rename extracted folder (.extract) to original archive name + folder.move(newPath, true, elementProgress.newChild(1)); + folder = ResourcesPlugin.getWorkspace().getRoot().getFolder(newPath); + + // Create the new import provider and root element based on + // the newly extracted temporary folder + FileSystemObjectImportStructureProvider importStructureProvider = new FileSystemObjectImportStructureProvider(FileSystemStructureProvider.INSTANCE, null); + IFileSystemObject rootElement = importStructureProvider.getIFileSystemObject(new File(folder.getLocation().toOSString())); + TraceFileSystemElement newElement = createRootTraceFileElement(rootElement, importStructureProvider); + List<TraceFileSystemElement> extractedChildren = new ArrayList<>(); + getAllChildren(extractedChildren, newElement); + extractAllArchiveFiles(extractedChildren, folder, folder.getLocation(), progressMonitor); + } + } + } + + /** + * Extract a file (File) to a destination folder + */ + private void extractArchiveToFolder(File sourceFile, IFolder destinationFolder, IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException { + Pair<IFileSystemObject, FileSystemObjectImportStructureProvider> rootObjectAndProvider = getRootObjectAndProvider(sourceFile); + TraceFileSystemElement rootElement = createRootTraceFileElement(rootObjectAndProvider.getFirst(), rootObjectAndProvider.getSecond()); + List<TraceFileSystemElement> fileSystemElements = new ArrayList<>(); + getAllChildren(fileSystemElements, rootElement); + extractArchiveContent(fileSystemElements.listIterator(), destinationFolder, progressMonitor); + rootObjectAndProvider.getSecond().dispose(); + } + + /** + * Safely create a folder meant to receive extracted content by making sure there is no name clash. + */ + private IFolder safeCreateExtractedFolder(IFolder destinationFolder, IPath relativeContainerRelativePath, IProgressMonitor monitor) throws CoreException { + SubMonitor subMonitor = SubMonitor.convert(monitor, 2); + IFolder extractedFolder; + String suffix = ""; //$NON-NLS-1$ + int i = 2; + while (true) { + IPath fullPath = destinationFolder.getFullPath().append(relativeContainerRelativePath + ".extract" + suffix); //$NON-NLS-1$ + IFolder folder = ResourcesPlugin.getWorkspace().getRoot().getFolder(fullPath); + if (!folder.exists()) { + extractedFolder = folder; + break; + } + suffix = "(" + i + ")"; //$NON-NLS-1$//$NON-NLS-2$ + i++; + } + subMonitor.worked(1); + + TraceUtils.createFolder(extractedFolder, subMonitor.newChild(1)); + return extractedFolder; + } + + private void calculateSourceLocations(List<TraceFileSystemElement> fileSystemElements, String baseSourceLocation) { + for (TraceFileSystemElement element : fileSystemElements) { + IPath tempRelative = new Path(element.getFileSystemObject().getAbsolutePath(null)).makeRelativeTo(fBaseSourceContainerPath); + String sourceLocation = baseSourceLocation + tempRelative; + element.setSourceLocation(sourceLocation); + + TraceFileSystemElement parentElement = (TraceFileSystemElement) element.getParent(); + tempRelative = new Path(parentElement.getFileSystemObject().getAbsolutePath(null)).makeRelativeTo(fBaseSourceContainerPath); + sourceLocation = baseSourceLocation + tempRelative + '/'; + parentElement.setSourceLocation(sourceLocation); + } + } + + /** + * Extract all file system elements (Tar, Zip elements) to destination folder (typically workspace/TraceProject/.traceImport or a subfolder of it) + */ + private void extractArchiveContent(Iterator<TraceFileSystemElement> fileSystemElementsIter, IFolder tempFolder, IProgressMonitor progressMonitor) throws InterruptedException, + InvocationTargetException { + List<TraceFileSystemElement> subList = new ArrayList<>(); + // Collect all the elements + while (fileSystemElementsIter.hasNext()) { + ModalContext.checkCanceled(progressMonitor); + TraceFileSystemElement element = fileSystemElementsIter.next(); + if (element.isDirectory()) { + Object[] array = element.getFiles().getChildren(); + for (int i = 0; i < array.length; i++) { + subList.add((TraceFileSystemElement) array[i]); + } + } + subList.add(element); + } + + TraceFileSystemElement root = getRootElement(subList.get(0)); + + ImportProvider fileSystemStructureProvider = new ImportProvider(); + + IOverwriteQuery myQueryImpl = new IOverwriteQuery() { + @Override + public String queryOverwrite(String file) { + return IOverwriteQuery.NO_ALL; + } + }; + + progressMonitor.setTaskName(Messages.ImportTraceWizard_ExtractImportOperationTaskName); + IPath containerPath = tempFolder.getFullPath(); + ImportOperation operation = new ImportOperation(containerPath, root, fileSystemStructureProvider, myQueryImpl, subList); + operation.setContext(getShell()); + + operation.setCreateContainerStructure(true); + operation.setOverwriteResources(false); + operation.setVirtualFolders(false); + + operation.run(new SubProgressMonitor(progressMonitor, subList.size(), SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + } + + private TraceFileSystemElement getRootElement(TraceFileSystemElement element) { + TraceFileSystemElement root = element; + while (root.getParent() != null) { + root = (TraceFileSystemElement) root.getParent(); + } + return root; + } + + /** + * Get all the TraceFileSystemElements recursively. + * + * @param result + * the list accumulating the result + * @param rootElement + * the root element of the file system to be imported + */ + private void getAllChildren(List<TraceFileSystemElement> result, TraceFileSystemElement rootElement) { + AdaptableList files = rootElement.getFiles(); + for (Object file : files.getChildren()) { + result.add((TraceFileSystemElement) file); + } + + AdaptableList folders = rootElement.getFolders(); + for (Object folder : folders.getChildren()) { + getAllChildren(result, (TraceFileSystemElement) folder); + } + } + + private IPath computeDestinationContainerPath(Path resourcePath) { + IPath destinationContainerPath = fDestinationContainerPath; + + // We need to figure out the new destination path relative to the + // selected "base" source directory. + // Here for example, the selected source directory is /home/user + if ((fImportOptionFlags & OPTION_PRESERVE_FOLDER_STRUCTURE) != 0) { + // /home/user/bar/foo/trace -> /home/user/bar/foo + IPath sourceContainerPath = resourcePath.removeLastSegments(1); + if (fBaseSourceContainerPath.equals(resourcePath)) { + // Use resourcePath directory if fBaseSourceContainerPath + // points to a directory trace + sourceContainerPath = resourcePath; + } + // /home/user/bar/foo, /home/user -> bar/foo + IPath relativeContainerPath = sourceContainerPath.makeRelativeTo(fBaseSourceContainerPath); + // project/Traces + bar/foo -> project/Traces/bar/foo + destinationContainerPath = fDestinationContainerPath.append(relativeContainerPath); + } + return destinationContainerPath; + } + + /** + * Import a single file system element into the workspace. + */ + private void validateAndImportTrace(TraceFileSystemElement fileSystemElement, IProgressMonitor monitor) + throws TmfTraceImportException, CoreException, InvocationTargetException, InterruptedException { + String parentContainerPath = fBaseSourceContainerPath.toOSString(); + String path = fileSystemElement.getFileSystemObject().getAbsolutePath(parentContainerPath); + TraceTypeHelper traceTypeHelper = null; + + File file = (File) fileSystemElement.getFileSystemObject().getRawFileSystemObject(); + boolean isArchiveFileElement = fileSystemElement.getFileSystemObject() instanceof FileFileSystemObject && isArchiveFile(file); + if (isArchiveFileElement) { + // We'll be extracting this later, do not import as a trace + return; + } + + if (fTraceType == null) { + // Auto Detection + try { + traceTypeHelper = TmfTraceTypeUIUtils.selectTraceType(path, null, null); + } catch (TmfTraceImportException e) { + // the trace did not match any trace type + } + if (traceTypeHelper == null) { + if ((fImportOptionFlags & OPTION_IMPORT_UNRECOGNIZED_TRACES) != 0) { + importResource(fileSystemElement, monitor); + } + return; + } + } else { + boolean isDirectoryTraceType = TmfTraceType.isDirectoryTraceType(fTraceType); + if (fileSystemElement.isDirectory() != isDirectoryTraceType) { + return; + } + traceTypeHelper = TmfTraceType.getTraceType(fTraceType); + + if (traceTypeHelper == null) { + // Trace type not found + throw new TmfTraceImportException(Messages.ImportTraceWizard_TraceTypeNotFound); + } + + if (!traceTypeHelper.validate(path).isOK()) { + // Trace type exist but doesn't validate for given trace. + return; + } + } + + // Finally import trace + IResource importedResource = importResource(fileSystemElement, monitor); + if (importedResource != null) { + TmfTraceTypeUIUtils.setTraceType(importedResource, traceTypeHelper); + } + + } + + /** + * Imports a trace resource to project. In case of name collision the + * user will be asked to confirm overwriting the existing trace, + * overwriting or skipping the trace to be imported. + * + * @param fileSystemElement + * trace file system object to import + * @param monitor + * a progress monitor + * @return the imported resource or null if no resource was imported + * + * @throws InvocationTargetException + * if problems during import operation + * @throws InterruptedException + * if cancelled + * @throws CoreException + * if problems with workspace + */ + private IResource importResource(TraceFileSystemElement fileSystemElement, IProgressMonitor monitor) + throws InvocationTargetException, InterruptedException, CoreException { + + IPath tracePath = getInitialDestinationPath(fileSystemElement); + String newName = fConflictHandler.checkAndHandleNameClash(tracePath, monitor); + if (newName == null) { + return null; + } + fileSystemElement.setLabel(newName); + + List<TraceFileSystemElement> subList = new ArrayList<>(); + + FileSystemElement parentFolder = fileSystemElement.getParent(); + + IPath containerPath = fileSystemElement.getDestinationContainerPath(); + tracePath = containerPath.addTrailingSeparator().append(fileSystemElement.getLabel()); + boolean createLinksInWorkspace = (fImportOptionFlags & OPTION_CREATE_LINKS_IN_WORKSPACE) != 0; + if (fileSystemElement.isDirectory() && !createLinksInWorkspace) { + containerPath = tracePath; + + Object[] array = fileSystemElement.getFiles().getChildren(); + for (int i = 0; i < array.length; i++) { + subList.add((TraceFileSystemElement) array[i]); + } + parentFolder = fileSystemElement; + + } else { + subList.add(fileSystemElement); + } + + ImportProvider fileSystemStructureProvider = new ImportProvider(); + + IOverwriteQuery myQueryImpl = new IOverwriteQuery() { + @Override + public String queryOverwrite(String file) { + return IOverwriteQuery.NO_ALL; + } + }; + + monitor.setTaskName(Messages.ImportTraceWizard_ImportOperationTaskName + " " + fileSystemElement.getFileSystemObject().getAbsolutePath(fBaseSourceContainerPath.toOSString())); //$NON-NLS-1$ + ImportOperation operation = new ImportOperation(containerPath, parentFolder, fileSystemStructureProvider, myQueryImpl, subList); + operation.setContext(getShell()); + + operation.setCreateContainerStructure(false); + operation.setOverwriteResources(false); + operation.setCreateLinks(createLinksInWorkspace); + operation.setVirtualFolders(false); + + operation.run(new SubProgressMonitor(monitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + String sourceLocation = fileSystemElement.getSourceLocation(); + IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(tracePath); + if (sourceLocation != null) { + resource.setPersistentProperty(TmfCommonConstants.SOURCE_LOCATION, sourceLocation); + } + + return resource; + } + + private boolean isDirectoryTrace(TraceFileSystemElement fileSystemElement) { + String path = fileSystemElement.getFileSystemObject().getAbsolutePath(fBaseSourceContainerPath.toOSString()); + if (TmfTraceType.isDirectoryTrace(path)) { + return true; + } + return false; + } + + /** + * @return the initial destination path, before rename, if any + */ + private IPath getInitialDestinationPath(TraceFileSystemElement fileSystemElement) { + IPath traceFolderPath = fileSystemElement.getDestinationContainerPath(); + return traceFolderPath.append(fileSystemElement.getFileSystemObject().getLabel()); + } + + /** + * Set the status for this operation + * + * @param status + * the status + */ + protected void setStatus(IStatus status) { + fStatus = status; + } + + public IStatus getStatus() { + return fStatus; + } + } + + /** + * The <code>TraceFileSystemElement</code> is a + * <code>FileSystemElement</code> that knows if it has been populated or + * not. + */ + private static class TraceFileSystemElement extends FileSystemElement { + + private boolean fIsPopulated = false; + private String fLabel = null; + private IPath fDestinationContainerPath; + private FileSystemObjectImportStructureProvider fProvider; + private String fSourceLocation; + + public TraceFileSystemElement(String name, FileSystemElement parent, boolean isDirectory, FileSystemObjectImportStructureProvider provider) { + super(name, parent, isDirectory); + fProvider = provider; + } + + public void setDestinationContainerPath(IPath destinationContainerPath) { + fDestinationContainerPath = destinationContainerPath; + } + + public void setPopulated() { + fIsPopulated = true; + } + + public boolean isPopulated() { + return fIsPopulated; + } + + @Override + public AdaptableList getFiles() { + if (!fIsPopulated) { + populateElementChildren(); + } + return super.getFiles(); + } + + @Override + public AdaptableList getFolders() { + if (!fIsPopulated) { + populateElementChildren(); + } + return super.getFolders(); + } + + /** + * Sets the label for the trace to be used when importing at trace. + * + * @param name + * the label for the trace + */ + public void setLabel(String name) { + fLabel = name; + } + + /** + * Returns the label for the trace to be used when importing at trace. + * + * @return the label of trace resource + */ + public String getLabel() { + if (fLabel == null) { + return getFileSystemObject().getLabel(); + } + return fLabel; + } + + /** + * The full path to the container that will contain the trace + * + * @return the destination container path + */ + public IPath getDestinationContainerPath() { + return fDestinationContainerPath; + } + + /** + * Populates the children of the specified parent + * <code>FileSystemElement</code> + */ + private void populateElementChildren() { + List<IFileSystemObject> allchildren = fProvider.getChildren(this.getFileSystemObject()); + Object child = null; + TraceFileSystemElement newelement = null; + Iterator<IFileSystemObject> iter = allchildren.iterator(); + while (iter.hasNext()) { + child = iter.next(); + newelement = new TraceFileSystemElement(fProvider.getLabel(child), this, fProvider.isFolder(child), fProvider); + newelement.setFileSystemObject(child); + } + setPopulated(); + } + + public FileSystemObjectImportStructureProvider getProvider() { + return fProvider; + } + + @Override + public IFileSystemObject getFileSystemObject() { + Object fileSystemObject = super.getFileSystemObject(); + return (IFileSystemObject) fileSystemObject; + } + + public String getSourceLocation() { + if (fSourceLocation == null) { + fSourceLocation = getFileSystemObject().getSourceLocation(); + } + return fSourceLocation; + } + + public void setSourceLocation(String sourceLocation) { + fSourceLocation = sourceLocation; + } + } + + /** + * This interface abstracts the differences between different kinds of + * FileSystemObjects such as File, TarEntry, ZipEntry, etc. This allows + * clients (TraceFileSystemElement, TraceValidateAndImportOperation) to + * handle all the types transparently. + */ + private interface IFileSystemObject { + String getLabel(); + + String getName(); + + String getAbsolutePath(String parentContainerPath); + + String getSourceLocation(); + + Object getRawFileSystemObject(); + + boolean exists(); + } + + /** + * The "File" implementation of an IFileSystemObject + */ + private static class FileFileSystemObject implements IFileSystemObject { + + private File fFileSystemObject; + + private FileFileSystemObject(File fileSystemObject) { + fFileSystemObject = fileSystemObject; + } + + @Override + public String getLabel() { + String name = fFileSystemObject.getName(); + if (name.length() == 0) { + return fFileSystemObject.getPath(); + } + return name; + } + + @Override + public String getName() { + return fFileSystemObject.getName(); + } + + @Override + public String getAbsolutePath(String parentContainerPath) { + return fFileSystemObject.getAbsolutePath(); + } + + @Override + public boolean exists() { + return fFileSystemObject.exists(); + } + + @Override + public String getSourceLocation() { + IResource sourceResource; + String sourceLocation = null; + if (fFileSystemObject.isDirectory()) { + sourceResource = ResourcesPlugin.getWorkspace().getRoot().getContainerForLocation(Path.fromOSString(fFileSystemObject.getAbsolutePath())); + } else { + sourceResource = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(Path.fromOSString(fFileSystemObject.getAbsolutePath())); + } + if (sourceResource != null && sourceResource.exists()) { + try { + sourceLocation = sourceResource.getPersistentProperty(TmfCommonConstants.SOURCE_LOCATION); + } catch (CoreException e) { + // Something went wrong with the already existing resource. + // This is not a problem, we'll assign a new location below. + } + } + if (sourceLocation == null) { + try { + sourceLocation = URIUtil.toUnencodedString(fFileSystemObject.getCanonicalFile().toURI()); + } catch (IOException e) { + // Something went wrong canonicalizing the file. We can still use the URI but there might be extra ../ in it. + sourceLocation = URIUtil.toUnencodedString(fFileSystemObject.toURI()); + } + } + return sourceLocation; + } + + @Override + public Object getRawFileSystemObject() { + return fFileSystemObject; + } + } + + /** + * The "Tar" implementation of an IFileSystemObject, entries can also be Gzipped and are uncompressed transparently. + */ + private static class TarFileSystemObject implements IFileSystemObject { + + private TarEntry fFileSystemObject; + private String fArchivePath; + + private TarFileSystemObject(TarEntry fileSystemObject, String archivePath) { + fFileSystemObject = fileSystemObject; + fArchivePath = archivePath; + } + + @Override + public String getLabel() { + return new Path(fFileSystemObject.getName()).lastSegment(); + } + + @Override + public String getName() { + return fFileSystemObject.getName(); + } + + @Override + public String getAbsolutePath(String parentContainerPath) { + return new Path(parentContainerPath).append(fFileSystemObject.getName()).toOSString(); + } + + @Override + public boolean exists() { + return true; + } + + @Override + public String getSourceLocation() { + File file = new File(fArchivePath); + try { + file = file.getCanonicalFile(); + } catch (IOException e) { + // Will still work but might have extra ../ in the path + } + URI uri = file.toURI(); + IPath entryPath = new Path(fFileSystemObject.getName()); + + URI jarURI = entryPath.isRoot() ? URIUtil.toJarURI(uri, Path.EMPTY) : URIUtil.toJarURI(uri, entryPath); + return URIUtil.toUnencodedString(jarURI); + } + + @Override + public Object getRawFileSystemObject() { + return fFileSystemObject; + } + } + + /** + * The "GZIP" implementation of an IFileSystemObject. For a GZIP file that is not in a tar. + */ + private static class GzipFileSystemObject implements IFileSystemObject { + + private GzipEntry fFileSystemObject; + private String fArchivePath; + + private GzipFileSystemObject(GzipEntry fileSystemObject, String archivePath) { + fFileSystemObject = fileSystemObject; + fArchivePath = archivePath; + } + + @Override + public String getLabel() { + return new Path(fFileSystemObject.getName()).lastSegment(); + } + + @Override + public String getName() { + return fFileSystemObject.getName(); + } + + @Override + public String getAbsolutePath(String parentContainerPath) { + return new Path(parentContainerPath).append(fFileSystemObject.getName()).toOSString(); + } + + @Override + public boolean exists() { + return true; + } + + @Override + public String getSourceLocation() { + File file = new File(fArchivePath); + try { + file = file.getCanonicalFile(); + } catch (IOException e) { + // Will still work but might have extra ../ in the path + } + URI uri = file.toURI(); + IPath entryPath = new Path(fFileSystemObject.getName()); + + URI jarURI = entryPath.isRoot() ? URIUtil.toJarURI(uri, Path.EMPTY) : URIUtil.toJarURI(uri, entryPath); + return URIUtil.toUnencodedString(jarURI); + } + + @Override + public Object getRawFileSystemObject() { + return fFileSystemObject; + } + } + + /** + * The "Zip" implementation of an IFileSystemObject + */ + private static class ZipFileSystemObject implements IFileSystemObject { + + private ZipEntry fFileSystemObject; + private String fArchivePath; + + private ZipFileSystemObject(ZipEntry fileSystemObject, String archivePath) { + fFileSystemObject = fileSystemObject; + fArchivePath = archivePath; + } + + @Override + public String getLabel() { + return new Path(fFileSystemObject.getName()).lastSegment(); + } + + @Override + public String getName() { + return fFileSystemObject.getName(); + } + + @Override + public String getAbsolutePath(String parentContainerPath) { + return new Path(parentContainerPath).append(fFileSystemObject.getName()).toOSString(); + } + + @Override + public boolean exists() { + return true; + } + + @Override + public String getSourceLocation() { + File file = new File(fArchivePath); + try { + file = file.getCanonicalFile(); + } catch (IOException e) { + // Will still work but might have extra ../ in the path + } + URI uri = file.toURI(); + IPath entryPath = new Path(fFileSystemObject.getName()); + + URI jarURI = entryPath.isRoot() ? URIUtil.toJarURI(uri, Path.EMPTY) : URIUtil.toJarURI(uri, entryPath); + return URIUtil.toUnencodedString(jarURI); + } + + @Override + public Object getRawFileSystemObject() { + return fFileSystemObject; + } + } + + private class ImportProvider implements IImportStructureProvider { + + ImportProvider() { + } + + @Override + public String getLabel(Object element) { + TraceFileSystemElement resource = (TraceFileSystemElement) element; + return resource.getLabel(); + } + + @Override + public List getChildren(Object element) { + TraceFileSystemElement resource = (TraceFileSystemElement) element; + Object[] array = resource.getFiles().getChildren(); + List<Object> list = new ArrayList<>(); + for (int i = 0; i < array.length; i++) { + list.add(array[i]); + } + return list; + } + + @Override + public InputStream getContents(Object element) { + TraceFileSystemElement resource = (TraceFileSystemElement) element; + return resource.getProvider().getContents(resource.getFileSystemObject()); + } + + @Override + public String getFullPath(Object element) { + TraceFileSystemElement resource = (TraceFileSystemElement) element; + return resource.getProvider().getFullPath(resource.getFileSystemObject()); + } + + @Override + public boolean isFolder(Object element) { + TraceFileSystemElement resource = (TraceFileSystemElement) element; + return resource.isDirectory(); + } + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardPageOptions.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardPageOptions.java new file mode 100644 index 0000000000..056169c1ac --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardPageOptions.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + * Marc-Andre Laperle - Use common method to get opened tmf projects + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.List; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTracesFolder; +import org.eclipse.tracecompass.tmf.ui.project.model.TraceUtils; +import org.eclipse.ui.IWorkbench; + +/** + * This page selects the project to import to. + * + * @author Matthew Khouzam + */ +public class ImportTraceWizardPageOptions extends AbstractImportTraceWizardPage { + + private List fProjects; + private final Map<String, IProject> fProjectsMap = new LinkedHashMap<>(); + + /** + * Import page that tells where the trace will go + * + * @param workbench + * The workbench reference. + * @param selection + * The current selection + */ + public ImportTraceWizardPageOptions(IWorkbench workbench, IStructuredSelection selection) { + super(workbench, selection); + } + + @Override + public void createControl(Composite parent) { + super.createControl(parent); + IFolder originalFolder = getBatchWizard().getTargetFolder(); + IProject proj = null; + if (originalFolder != null) { + proj = originalFolder.getProject(); + } + + Composite optionPane = (Composite) this.getControl(); + optionPane.setLayout(new GridLayout()); + optionPane.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true)); + + fProjects = new List(optionPane, SWT.V_SCROLL); + fProjects.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + for (IProject project : TraceUtils.getOpenedTmfProjects()) { + final String name = project.getName(); + fProjectsMap.put(name, project); + fProjects.add(name); + } + + fProjects.getSelection(); + fProjects.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + updateWithSelection(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + updateWithSelection(); + } + }); + if (proj != null) { + fProjects.setSelection(fProjects.indexOf(proj.getName())); + } else if (fProjects.getItemCount() > 0) { + fProjects.setSelection(0); + updateWithSelection(); + } + setMessage(Messages.SharedSelectProject); + this.setTitle(Messages.ImportTraceWizardPageOptionsTitle); + } + + private void updateWithSelection() { + String[] selection = fProjects.getSelection(); + if (selection.length > 0) { + final String listItem = selection[0]; + IFolder folder = fProjectsMap.get(listItem).getFolder(TmfTracesFolder.TRACES_FOLDER_NAME); + getBatchWizard().setTraceFolder(folder); + ImportTraceWizardPageOptions.this.setErrorMessage(null); + } else { + ImportTraceWizardPageOptions.this.setErrorMessage(Messages.SharedSelectProject); + } + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardScanPage.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardScanPage.java new file mode 100644 index 0000000000..cdbd4fd816 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardScanPage.java @@ -0,0 +1,565 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.io.File; +import java.text.DecimalFormat; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.ColumnViewer; +import org.eclipse.jface.viewers.ColumnViewerEditor; +import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; +import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.jface.viewers.TreeViewerColumn; +import org.eclipse.jface.viewers.TreeViewerEditor; +import org.eclipse.jface.viewers.TreeViewerFocusCellManager; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType; +import org.eclipse.tracecompass.tmf.core.project.model.TraceValidationHelper; +import org.eclipse.ui.IWorkbench; + +/** + * <b>Import page that scans files, can be cancelled</b> this page is the third + * of three pages shown. This one selects the traces to be imported that are to + * be scanned. + * + * @author Matthew Khouzam + */ +public class ImportTraceWizardScanPage extends AbstractImportTraceWizardPage { + + private static final int COL_WIDTH = 200; + private static final int MAX_TRACES = 65536; + private CheckboxTreeViewer traceTypeViewer; + + final ScanRunnable fRunnable = new ScanRunnable("Scan job"); //$NON-NLS-1$ + private final BlockingQueue<TraceValidationHelper> fTracesToScan = new ArrayBlockingQueue<>(MAX_TRACES); + private volatile boolean fCanRun = true; + + // -------------------------------------------------------------------------------- + // Constructor and destructor + // -------------------------------------------------------------------------------- + + /** + * Import page that scans files, can be cancelled. + * + * @param name + * The name of the page. + * @param selection + * The current selection + */ + protected ImportTraceWizardScanPage(String name, IStructuredSelection selection) { + super(name, selection); + } + + /** + * Import page that scans files, can be cancelled + * + * @param workbench + * The workbench reference. + * @param selection + * The current selection + */ + public ImportTraceWizardScanPage(IWorkbench workbench, IStructuredSelection selection) { + super(workbench, selection); + } + + @Override + public void dispose() { + fCanRun = false; + fRunnable.done(Status.OK_STATUS); + super.dispose(); + } + + /* + * Init + */ + + @Override + public void createControl(Composite parent) { + super.createControl(parent); + final Composite control = (Composite) this.getControl(); + setTitle(Messages.ImportTraceWizardScanPageTitle); + traceTypeViewer = new CheckboxTreeViewer(control, SWT.CHECK); + traceTypeViewer.setContentProvider(getBatchWizard().getScannedTraces()); + traceTypeViewer.getTree().setHeaderVisible(true); + traceTypeViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + traceTypeViewer.setInput(getBatchWizard().getScannedTraces()); + traceTypeViewer.addCheckStateListener(new ImportTraceCheckStateListener()); + + TreeViewerFocusCellManager focusCellManager = new TreeViewerFocusCellManager(traceTypeViewer, new FocusCellOwnerDrawHighlighter(traceTypeViewer)); + ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(traceTypeViewer) { + }; + TreeViewerEditor.create(traceTypeViewer, focusCellManager, actSupport, ColumnViewerEditor.TABBING_HORIZONTAL + | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR + | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION); + + final TextCellEditor textCellEditor = new TextCellEditor(traceTypeViewer.getTree()); + // -------------------- + // Column 1 + // -------------------- + TreeViewerColumn column = new TreeViewerColumn(traceTypeViewer, SWT.NONE); + column.getColumn().setWidth(COL_WIDTH); + column.getColumn().setText(Messages.ImportTraceWizardTraceDisplayName); + column.setLabelProvider(new FirstColumnLabelProvider()); + column.setEditingSupport(new ColumnEditorSupport(traceTypeViewer, textCellEditor)); + + // -------------------- + // Column 2 + // -------------------- + + column = new TreeViewerColumn(traceTypeViewer, SWT.NONE); + column.getColumn().setWidth(500); + column.getColumn().setText(Messages.ImportTraceWizardImportCaption); + column.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + if (element instanceof FileAndName) { + FileAndName elem = (FileAndName) element; + return elem.getFile().getPath(); + } + return null; + } + }); + // -------------------- + // Column 3 + // -------------------- + + column = new TreeViewerColumn(traceTypeViewer, SWT.NONE); + + column.getColumn().setWidth(80); + column.getColumn().setText(Messages.ImportTraceWizardScanPageSize); + column.getColumn().setAlignment(SWT.RIGHT); + column.setLabelProvider(new ColumnLabelProvider() { + + @Override + public String getText(Object element) { + if (element instanceof FileAndName) { + + FileAndName elem = (FileAndName) element; + long len = recurseSize(elem.getFile()); + if (len > 0) { + double sizeb10 = Math.log10(len); + DecimalFormat df = new DecimalFormat(); + df.setMaximumFractionDigits(2); + df.setMinimumFractionDigits(0); + if (sizeb10 > 12) { + final double tbSize = len / 1024.0 / 1024 / 1024 / 1024; + return df.format(tbSize) + Messages.ImportTraceWizardScanPageTerabyte; + } + if (sizeb10 > 9) { + final double gbSize = len / 1024.0 / 1024 / 1024; + return df.format(gbSize) + Messages.ImportTraceWizardScanPageGigabyte; + } + if (sizeb10 > 6) { + final double mbSize = len / 1024.0 / 1024; + return df.format(mbSize) + Messages.ImportTraceWizardScanPageMegabyte; + } + if (sizeb10 > 3) { + final double kbSize = len / 1024.0; + return df.format(kbSize) + Messages.ImportTraceWizardScanPageKilobyte; + } + } + return Long.toString(len) + Messages.ImportTraceWizardScanPagebyte; + + } + return null; + } + + private long recurseSize(File file) { + if (file.isFile() && file.canRead()) { + return file.length(); + } + long size = 0; + if (file.exists() && file.isDirectory() && file.canRead()) { + final File[] listFiles = file.listFiles(); + if (listFiles != null) { + for (File child : listFiles) { + if (child.isFile() && child.canRead()) { + size += child.length(); + } else if (child.isDirectory()) { + size += recurseSize(child); + } else { + Activator.getDefault().logError("Unknown \"file\" type for " + child + ' ' + child.toString()); //$NON-NLS-1$ + } + } + } + } + return size; + } + }); + + init(); + getBatchWizard().setTracesToScan(fTracesToScan); + getBatchWizard().setTraceFolder(fTargetFolder); + + fRunnable.schedule(); + setErrorMessage(Messages.ImportTraceWizardScanPageSelectAtleastOne); + } + + private void init() { + Composite optionPane = (Composite) this.getControl(); + + optionPane.setLayout(new GridLayout()); + optionPane.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true)); + + final Button fLink = new Button(optionPane, SWT.RADIO); + fLink.setText(Messages.ImportTraceWizardLinkTraces); + fLink.setSelection(true); + fLink.setLayoutData(new GridData()); + + final Button fCopy = new Button(optionPane, SWT.RADIO); + fCopy.setText(Messages.ImportTraceWizardCopyTraces); + fCopy.setLayoutData(new GridData()); + + final SelectionListener linkedListener = new RadioChooser(fLink); + + fLink.addSelectionListener(linkedListener); + fCopy.addSelectionListener(linkedListener); + + Button fOverwrite = new Button(optionPane, SWT.CHECK); + fOverwrite.setText(Messages.ImportTraceWizardOverwriteTraces); + fOverwrite.setLayoutData(new GridData()); + fOverwrite.setSelection(true); + fOverwrite.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + getBatchWizard().setOverwrite(((Button) e.widget).getSelection()); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + } + + /* + * Helper classes + */ + + private final class RadioChooser implements SelectionListener { + private final Button isLinked; + + public RadioChooser(Button desiredButton) { + isLinked = desiredButton; + } + + @Override + public void widgetSelected(SelectionEvent e) { + + final Button widget = (Button) e.widget; + getBatchWizard().setLinked(widget.equals(isLinked)); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + + } + } + + private final class ColumnEditorSupport extends EditingSupport { + private final TextCellEditor textCellEditor; + + private ColumnEditorSupport(ColumnViewer viewer, TextCellEditor textCellEditor) { + super(viewer); + this.textCellEditor = textCellEditor; + } + + @Override + protected boolean canEdit(Object element) { + return element instanceof FileAndName; + } + + @Override + protected CellEditor getCellEditor(Object element) { + return textCellEditor; + } + + @Override + protected Object getValue(Object element) { + if (element instanceof FileAndName) { + return ((FileAndName) element).getName(); + } + return null; + } + + @Override + protected void setValue(Object element, Object value) { + FileAndName fan = (FileAndName) element; + fan.setName((String) value); + getBatchWizard().updateConflicts(); + traceTypeViewer.update(element, null); + traceTypeViewer.refresh(); + } + } + + private final class FirstColumnLabelProvider extends ColumnLabelProvider { + Image fConflict; + + @Override + public Image getImage(Object element) { + if (element instanceof FileAndName) { + final FileAndName fan = (FileAndName) element; + if (fan.isConflictingName()) { + if (fConflict == null) { + fConflict = Activator.getDefault().getImageFromImageRegistry(ITmfImageConstants.IMG_UI_CONFLICT); + } + return fConflict; + } + } + return null; + } + + @Override + public String getText(Object element) { + if (element instanceof FileAndName) { + FileAndName elem = (FileAndName) element; + return elem.getName(); + } + if (element instanceof String) { + return (String) element; + } + return null; + } + } + + private final class ImportTraceCheckStateListener implements ICheckStateListener { + @Override + public void checkStateChanged(CheckStateChangedEvent event) { + final CheckboxTreeViewer tv = (CheckboxTreeViewer) + event.getSource(); + if (event.getElement() instanceof FileAndName) { + final FileAndName element = (FileAndName) event.getElement(); + if (event.getChecked()) { + getBatchWizard().addFileToImport(element); + traceTypeViewer.update(element, null); + } + else { + getBatchWizard().removeFileToImport(element); + traceTypeViewer.update(element, null); + } + maintainCheckIntegrity(tv, element); + } + if (event.getElement() instanceof String) { + + tv.setSubtreeChecked(event.getElement(), event.getChecked()); + final Object[] children = + getBatchWizard().getScannedTraces().getChildren(event.getElement()); + if (event.getChecked()) { + for (int i = 0; i < children.length; i++) { + final FileAndName element = (FileAndName) children[i]; + getBatchWizard().addFileToImport(element); + traceTypeViewer.update(children[i], null); + } + } + else { + for (int i = 0; i < children.length; i++) { + getBatchWizard().removeFileToImport((FileAndName) children[i]); + + } + } + + } + getBatchWizard().updateConflicts(); + if (getBatchWizard().hasConflicts()) { + setErrorMessage(Messages.ImportTraceWizardScanPageRenameError); + } else if (!getBatchWizard().hasTracesToImport()) { + setErrorMessage(Messages.ImportTraceWizardScanPageSelectAtleastOne); + } else { + setErrorMessage(null); + } + getWizard().getContainer().updateButtons(); + traceTypeViewer.update(event.getElement(), null); + } + + private void maintainCheckIntegrity(final CheckboxTreeViewer viewer, final FileAndName element) { + final ImportTraceContentProvider scannedTraces = getBatchWizard().getScannedTraces(); + String parentElement = (String) scannedTraces.getParent(element); + boolean allChecked = true; + final FileAndName[] siblings = scannedTraces.getSiblings(element); + if (siblings != null) { + for (FileAndName child : siblings) { + allChecked &= viewer.getChecked(child); + } + } + viewer.setChecked(parentElement, allChecked); + } + } + + private final class ScanRunnable extends Job { + + // monitor is stored here, starts as the main monitor but becomes a + // submonitor + private IProgressMonitor fMonitor; + + public ScanRunnable(String name) { + super(name); + this.setSystem(true); + } + + private synchronized IProgressMonitor getMonitor() { + return fMonitor; + } + + @Override + public IStatus run(IProgressMonitor monitor) { + /* + * Set up phase, it is synchronous + */ + fMonitor = monitor; + final Control control = traceTypeViewer.getControl(); + // please note the sync exec here is to allow us to set + control.getDisplay().syncExec(new Runnable() { + @Override + public void run() { + // monitor gets overwritten here so it's necessary to save + // it in a field. + fMonitor = SubMonitor.convert(getMonitor()); + getMonitor().setTaskName(Messages.ImportTraceWizardPageScanScanning + ' '); + ((SubMonitor) getMonitor()).setWorkRemaining(IProgressMonitor.UNKNOWN); + } + }); + /* + * At this point we start calling async execs and updating the view. + * This is a good candidate to parallelise. + */ + while (fCanRun == true) { + boolean updated = false; + boolean validCombo; + if (fTracesToScan.isEmpty() && !control.isDisposed()) { + control.getDisplay().asyncExec(new Runnable() { + + @Override + public void run() { + if (!control.isDisposed()) { + getMonitor().setTaskName(Messages.ImportTraceWizardPageScanScanning + ' '); + getMonitor().subTask(Messages.ImportTraceWizardPageScanDone); + ImportTraceWizardScanPage.this.setMessage(Messages.ImportTraceWizardPageScanScanning + ' ' + Messages.ImportTraceWizardPageScanDone); + } + } + }); + } + try { + final TraceValidationHelper traceToScan = fTracesToScan.take(); + + if (!getBatchWizard().hasScanned(traceToScan)) { + getBatchWizard().addResult(traceToScan, TmfTraceType.validate(traceToScan)); + } + + /* + * The following is to update the UI + */ + validCombo = getBatchWizard().getResult(traceToScan); + if (validCombo) { + // Synched on it's parent + + getBatchWizard().getScannedTraces().addCandidate(traceToScan.getTraceType(), new File(traceToScan.getTraceToScan())); + updated = true; + } + final int scanned = getBatchWizard().getNumberOfResults(); + final int total = scanned + fTracesToScan.size(); + final int prevVal = (int) ((scanned - 1) * 100.0 / total); + final int curVal = (int) ((scanned) * 100.0 / total); + if (curVal != prevVal) { + updated = true; + } + /* + * update the progress + */ + if (updated) { + if (!control.isDisposed()) { + control.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + if (!control.isDisposed()) { + getMonitor().setTaskName(Messages.ImportTraceWizardPageScanScanning + ' '); + getMonitor().subTask(traceToScan.getTraceToScan()); + getMonitor().worked(1); + ImportTraceWizardScanPage.this.setMessage(Messages.ImportTraceWizardPageScanScanning + ' ' + + Integer.toString(curVal) + + '%'); + } + } + } + ); + } + } + + /* + * here we update the table + */ + final boolean editing = traceTypeViewer.isCellEditorActive(); + if (updated && !editing) { + if (!control.isDisposed()) { + control.getDisplay().asyncExec(new Runnable() { + + @Override + public void run() { + if (!control.isDisposed()) { + if (!traceTypeViewer.isCellEditorActive()) { + traceTypeViewer.refresh(); + } + } + } + }); + } + } + } catch (InterruptedException e) { + return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, new String()); + } + } + return Status.OK_STATUS; + } + } + + /** + * Refresh the view and the corresponding model. + */ + public void refresh() { + final Control control = traceTypeViewer.getControl(); + if (!control.isDisposed()) { + control.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + if (!control.isDisposed()) { + traceTypeViewer.refresh(); + } + } + }); + } + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardSelectDirectoriesPage.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardSelectDirectoriesPage.java new file mode 100644 index 0000000000..c2d61c9387 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardSelectDirectoriesPage.java @@ -0,0 +1,260 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + * Marc-Andre Laperle - Remember last selected directory + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.io.File; + +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.ui.IWorkbench; + +/** + * <b>Select the directories to scan for traces</b> this page is the second of + * three pages shown. This one selects the files to be scanned. + * + * @author Matthew Khouzam + */ +public class ImportTraceWizardSelectDirectoriesPage extends AbstractImportTraceWizardPage { + + /** + * ID + */ + public static String ID = "org.eclipse.linuxtools.tmf.ui.project.wizards.importtrace.ImportTraceWizardPagePopulate"; //$NON-NLS-1$ + + private static final String STORE_DIRECTORY_ID = ID + ".STORE_DIRECTORY_ID"; //$NON-NLS-1$ + + /** + * Constructor. Creates the trace wizard page. + * + * @param name + * The name of the page. + * @param selection + * The current selection + */ + protected ImportTraceWizardSelectDirectoriesPage(String name, IStructuredSelection selection) { + super(name, selection); + } + + /** + * Constructor + * + * @param workbench + * The workbench reference. + * @param selection + * The current selection + */ + public ImportTraceWizardSelectDirectoriesPage(IWorkbench workbench, IStructuredSelection selection) { + super(workbench, selection); + } + + @Override + public void createControl(Composite parent) { + super.createControl(parent); + final Composite control = (Composite) this.getControl(); + control.setLayout(new GridLayout(2, false)); + control.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + final Table selectedFiles = new Table(control, SWT.H_SCROLL | SWT.V_SCROLL); + selectedFiles.clearAll(); + selectedFiles.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + selectedFiles.setLinesVisible(true); + + Composite buttonArea = new Composite(control, SWT.None); + buttonArea.setLayout(new GridLayout()); + buttonArea.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false)); + + Button addFile = new Button(buttonArea, SWT.PUSH); + addFile.setText(Messages.ImportTraceWizardAddFile); + addFile.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + addFile.addSelectionListener(new AddFileHandler()); + addFile.setAlignment(SWT.CENTER); + + Button addDirectory = new Button(buttonArea, SWT.PUSH); + addDirectory.setText(Messages.ImportTraceWizardAddDirectory); + addDirectory.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + addDirectory.addSelectionListener(new AddDirectoryHandler()); + addDirectory.setAlignment(SWT.CENTER); + + Button removeFile = new Button(buttonArea, SWT.PUSH); + removeFile.setText(Messages.ImportTraceWizardRemove); + removeFile.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + removeFile.addSelectionListener(new RemoveFileHandler(selectedFiles)); + removeFile.setAlignment(SWT.CENTER); + +// int maxSize = Math.max(addFile.getSize().x, Math.max(addDirectory.getSize().x, removeFile.getSize().x)); +// int maxHeight = Math.max(addFile.getSize().y, Math.max(addDirectory.getSize().y, removeFile.getSize().y)); +// addFile.setSize(maxSize, maxHeight); +// addDirectory.setSize(maxSize, maxHeight); +// removeFile.setSize(maxSize, maxHeight); + + this.setTitle(Messages.ImportTraceWizardDirectoryTitle); + } + + private void updateButtons() { + BatchImportTraceWizard wiz = getBatchWizard(); + updateTable(); + wiz.getContainer().updateButtons(); + } + + private void updateTable() { + final Table selectedFiles = (Table) ((Composite) getControl()).getChildren()[0]; + selectedFiles.clearAll(); + selectedFiles.setItemCount(0); + for (String s : ((BatchImportTraceWizard) getWizard()).getFileNames()) { + TableItem ti = new TableItem(selectedFiles, SWT.None); + ti.setText(s); + } + } + + @Override + public boolean canFlipToNextPage() { + final Table selectedFiles = (Table) ((Composite) getControl()).getChildren()[0]; + boolean canLoad = selectedFiles.getItemCount() > 0; + if (canLoad) { + setErrorMessage(null); + } else { + setErrorMessage(Messages.ImportTraceWizardDirectoryHint); + } + return canLoad; + } + + private final class AddFileHandler implements SelectionListener { + @Override + public void widgetSelected(SelectionEvent e) { + + FileDialog dialog = new + FileDialog(Display.getCurrent().getActiveShell(), SWT.NONE); + + String lastDirectory = getLastSelectedDirectory(); + if (lastDirectory != null) { + dialog.setFilterPath(lastDirectory); + } + + String fn = dialog.open(); + if (null != fn) { + File f = new File(fn); + if (f.exists()) { + getBatchWizard().addFileToScan(fn); + saveSelectedDirectory(f.getParentFile()); + } + } + updateButtons(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + } + + private final class AddDirectoryHandler implements SelectionListener { + @Override + public void widgetSelected(SelectionEvent e) { + + // BUG BUG BUG BUG BUG IN SWT. Cannot read multiple files in a + // fake directory. + +// FileDialog dialog = new +// FileDialog(Display.getCurrent().getActiveShell(), SWT.OPEN | +// SWT.MULTI); +// dialog.setFilterPath("."); +// if (null != dialog.open()) { +// for (String fn : dialog.getFileNames()) { +// final String pathname = dialog.getFilterPath() + +// File.separator + fn; +// File f = new File(pathname); +// if (f.exists()) { +// ((BatchImportTraceWizard) getWizard()).addFile(fn, f); +// } +// } +// } + + DirectoryDialog dialog = new + DirectoryDialog(Display.getCurrent().getActiveShell(), SWT.NONE); + String lastDirectory = getLastSelectedDirectory(); + if (lastDirectory != null) { + dialog.setFilterPath(lastDirectory); + } + + String fn = dialog.open(); + if (null != fn) { + File f = new File(fn); + if (f.exists()) { + getBatchWizard().addFileToScan(fn); + saveSelectedDirectory(f); + } + } + updateButtons(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + } + + private String getLastSelectedDirectory() { + final IDialogSettings settings = getDialogSettings(); + if (settings != null) { + final String directory = settings.get(STORE_DIRECTORY_ID); + if (directory != null && !directory.isEmpty()) { + final File file = new File(directory); + if (file.exists()) { + return directory.toString(); + } + } + } + + return null; + } + + private void saveSelectedDirectory(File directory) { + final IDialogSettings settings = getDialogSettings(); + if (settings != null && directory != null && directory.exists()) { + settings.put(STORE_DIRECTORY_ID, directory.toString()); + } + } + + private final class RemoveFileHandler implements SelectionListener { + private final Table selectedFiles; + + private RemoveFileHandler(Table selectedFiles) { + this.selectedFiles = selectedFiles; + } + + @Override + public void widgetSelected(SelectionEvent e) { + TableItem selectedToRemove[] = selectedFiles.getSelection(); + for (TableItem victim : selectedToRemove) { + String victimName = victim.getText(); + ((BatchImportTraceWizard) getWizard()).removeFile(victimName); + } + updateButtons(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardSelectTraceTypePage.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardSelectTraceTypePage.java new file mode 100644 index 0000000000..dc403d5488 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/ImportTraceWizardSelectTraceTypePage.java @@ -0,0 +1,183 @@ +/******************************************************************************* + * Copyright (c) 2013, 2015 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper; +import org.eclipse.ui.IWorkbench; + +/** + * <b>Select trace types to import</b>, this page is the first of three pages + * shown. This one selects the type of traces that are to be scanned. + * + * @author Matthew Khouzam + */ +public class ImportTraceWizardSelectTraceTypePage extends AbstractImportTraceWizardPage { + + private CheckboxTreeViewer fTreeView; + private final TraceTypeContentProvider fProvider = new TraceTypeContentProvider(); + + /** + * Select trace types to import + * + * @param name + * The name of the page. + * @param selection + * The current selection + */ + protected ImportTraceWizardSelectTraceTypePage(String name, IStructuredSelection selection) { + super(name, selection); + } + + /** + * Select trace types to import + * + * @param workbench + * The workbench reference. + * @param selection + * The current selection + */ + public ImportTraceWizardSelectTraceTypePage(IWorkbench workbench, IStructuredSelection selection) { + super(workbench, selection); + } + + @Override + public void createControl(Composite parent) { + super.createControl(parent); + Composite control = (Composite) this.getControl(); + + final ICheckStateListener listener = new TraceTypeCheckListener(); + + setTitle(Messages.ImportTraceWizardSelectTraceTypePageTitle); + + fTreeView = new CheckboxTreeViewer(control, SWT.BORDER); + fTreeView.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + fTreeView.setContentProvider(fProvider); + fTreeView.setInput(fProvider); + fTreeView.setLabelProvider(new LabelProvider() { + @Override + public String getText(Object element) { + return element.toString(); + } + }); + fTreeView.addCheckStateListener(listener); + + // populateTree(treeView); + + Composite buttonArea = new Composite(control, SWT.NONE); + buttonArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + buttonArea.setLayout(new GridLayout(2, false)); + + Button selectAll = new Button(buttonArea, SWT.NONE); + selectAll.setText(Messages.ImportTraceWizardSelectAll); + selectAll.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false)); + selectAll.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + String elements[] = (String[]) ((ITreeContentProvider) fTreeView.getContentProvider()).getElements(null); + for (String key : elements) { + fTreeView.setSubtreeChecked(key, true); + } + getWizard().getContainer().updateButtons(); + } + }); + + Button selectNone = new Button(buttonArea, SWT.NONE); + selectNone.setText(Messages.ImportTraceWizardPageSelectNone); + selectNone.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); + selectNone.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + String elements[] = (String[]) ((ITreeContentProvider) fTreeView.getContentProvider()).getElements(null); + for (String key : elements) { + fTreeView.setSubtreeChecked(key, false); + } + getWizard().getContainer().updateButtons(); + } + }); + fTreeView.expandAll(); + } + + @Override + public boolean canFlipToNextPage() { + List<String> tracesToScan = new ArrayList<>(); + String elements[] = (String[]) fProvider.getElements(null); + for (String traceFamily : elements) { + final TraceTypeHelper[] children = (TraceTypeHelper[]) fProvider.getChildren(traceFamily); + if (children != null) { + for (TraceTypeHelper traceType : children) { + if (fTreeView.getChecked(traceType)) { + tracesToScan.add(traceType.getTraceTypeId()); + } + } + } + } + ((BatchImportTraceWizard) getWizard()).setTraceTypesToScan(tracesToScan); + if (tracesToScan.isEmpty()) { + setErrorMessage(Messages.ImportTraceWizardPageSelectHint); + } else { + setErrorMessage(null); + } + return super.canFlipToNextPage() && !tracesToScan.isEmpty(); + } + + private final class TraceTypeCheckListener implements ICheckStateListener { + @Override + public void checkStateChanged(CheckStateChangedEvent event) { + + boolean checkStatus = event.getChecked(); + Object element = event.getElement(); + + fTreeView.setGrayed(element, false); + fTreeView.setSubtreeChecked(element, checkStatus); + ITreeContentProvider tcp = (ITreeContentProvider) fTreeView.getContentProvider(); + String parentElement = (String) tcp.getParent(element); + if (parentElement != null) { + TraceTypeHelper[] siblings = (TraceTypeHelper[]) tcp.getChildren(parentElement); + final TraceTypeHelper first = siblings[0]; + final boolean isFirstChecked = fTreeView.getChecked(first); + boolean allSame = true; + for (TraceTypeHelper peer : siblings) { + final boolean peerChecked = fTreeView.getChecked(peer); + if (peerChecked != isFirstChecked) { + allSame = false; + } + } + if (allSame) { + fTreeView.setGrayed(parentElement, false); + fTreeView.setChecked(parentElement, checkStatus); + } else { + fTreeView.setChecked(parentElement, false); + fTreeView.setGrayed(parentElement, true); + } + } + getWizard().getContainer().updateButtons(); + + } + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/Messages.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/Messages.java new file mode 100644 index 0000000000..db2cbb4e4c --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/Messages.java @@ -0,0 +1,216 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + * Bernd Hufmann - Add ImportTraceWizard messages + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import org.eclipse.osgi.util.NLS; + +/** + * The messages for import trace wizards. + * @author Matthew Khouzam + */ +@SuppressWarnings("javadoc") +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace.messages"; //$NON-NLS-1$ + + // Import Trace Wizard + /** + * The dialog title of the import trace wizard + */ + public static String ImportTraceWizard_DialogTitle; + /** + * The title of the file system within the import trace wizard + */ + public static String ImportTraceWizard_FileSystemTitle; + /** + * The title of the the import trace wizard page. + */ + public static String ImportTraceWizard_ImportTrace; + /** + * The label of the directory location (import trace wizard) + */ + public static String ImportTraceWizard_DirectoryLocation; + /** + * The label of the archive location (import trace wizard) + */ + public static String ImportTraceWizard_ArchiveLocation; + /** + * The title of the select trace directory dialog (import trace wizard) + */ + public static String ImportTraceWizard_SelectTraceDirectoryTitle; + /** + * The title of the select trace archive dialog (import trace wizard) + */ + public static String ImportTraceWizard_SelectTraceArchiveTitle; + /** + * The message of the select trace directory dialog (import trace wizard) + */ + public static String ImportTraceWizard_SelectTraceDirectoryMessage; + /** + * The title of the trace type label (import trace wizard) + */ + public static String ImportTraceWizard_TraceType; + /** + * The label of the overwrite checkbox (import trace wizard) + */ + public static String ImportTraceWizard_OverwriteExistingTrace; + /** + * The label of the checkbox to create a link to the trace in workspace (import trace wizard) + */ + public static String ImportTraceWizard_CreateLinksInWorkspace; + /** + * The label of the checkbox to preserve the folder structure of selected the traces in workspace (import trace wizard) + */ + public static String ImportTraceWizard_PreserveFolderStructure; + /** + * The error message for invalid trace directory (import trace wizard) + */ + public static String ImportTraceWizard_InvalidTraceDirectory; + /** + * The error message when a trace validation failed (import trace wizard). + */ + public static String ImportTraceWizard_TraceValidationFailed; + /** + * The error message when a trace already exists in project (import trace wizard). + */ + public static String ImportTraceWizard_TraceAlreadyExists; + /** + * The title of rename button for import configuration dialog. + */ + public static String ImportTraceWizard_ImportConfigurationRename; + /** + * The title of rename all button for import configuration dialog. + */ + public static String ImportTraceWizard_ImportConfigurationRenameAll; + /** + * The title of overwrite button for import configuration dialog. + */ + public static String ImportTraceWizard_ImportConfigurationOverwrite; + /** + * The title of overwrite all button for import configuration dialog. + */ + public static String ImportTraceWizard_ImportConfigurationOverwriteAll; + /** + * The title of skip button for import configuration dialog. + */ + public static String ImportTraceWizard_ImportConfigurationSkip; + /** + * The title of skip all button for import configuration dialog. + */ + public static String ImportTraceWizard_ImportConfigurationSkipAll; + /** + * The error message when trace source is empty (import trace wizard). + */ + public static String ImportTraceWizard_SelectTraceSourceEmpty; + /** + * The error message when the specified archive file is not valid. + */ + public static String ImportTraceWizard_BadArchiveFormat; + /** + * The error message when no trace is selected (import trace wizard). + */ + public static String ImportTraceWizard_SelectTraceNoneSelected; + /** + * The error message when an error occurred during import operation. + */ + public static String ImportTraceWizard_ImportProblem; + /** + * The error message if destination directory is a virtual folder. + */ + public static String ImportTraceWizard_CannotImportFilesUnderAVirtualFolder; + /** + * The error message if destination directory is a virtual folder (for a link). + */ + public static String ImportTraceWizard_HaveToCreateLinksUnderAVirtualFolder; + /** + * The label string of the browse button. + */ + public static String ImportTraceWizard_BrowseButton; + /** + * The information label string. + */ + public static String ImportTraceWizard_Information; + /** + * The label of the checkbox to import unrecognized trace files + */ + public static String ImportTraceWizard_ImportUnrecognized; + /** + * The message when the import operation was cancelled. + */ + public static String ImportTraceWizard_ImportOperationCancelled; + /** + * The message when the trace type is not found. + */ + public static String ImportTraceWizard_TraceTypeNotFound; + /** + * The import operation task name. + */ + public static String ImportTraceWizard_ImportOperationTaskName; + /** + * The extract import operation task name + */ + public static String ImportTraceWizard_ExtractImportOperationTaskName; + /** + * The label to indicate that trace type auto detection shall be used. + */ + public static String ImportTraceWizard_AutoDetection; + + + // Batch Import Wizard + public static String ImportTraceWizardImportProblem ; + public static String ImportTraceWizardImportCaption; + public static String ImportTraceWizardTraceDisplayName; + public static String ImportTraceWizardLinkTraces; + public static String ImportTraceWizardCopyTraces; + public static String ImportTraceWizardOverwriteTraces; + public static String ImportTraceWizardAddFile; + public static String ImportTraceWizardAddDirectory; + public static String ImportTraceWizardRemove; + public static String ImportTraceWizardDirectoryTitle; + public static String ImportTraceWizardDirectoryHint; + public static String ImportTraceWizardScanPagebyte; + + public static String ImportTraceWizardScanPageGigabyte; + + public static String ImportTraceWizardScanPageKilobyte; + + public static String ImportTraceWizardScanPageMegabyte; + + public static String ImportTraceWizardScanPageRenameError; + public static String ImportTraceWizardScanPageSelectAtleastOne; + + public static String ImportTraceWizardScanPageSize; + public static String ImportTraceWizardSelectAll; + public static String ImportTraceWizardScanPageTerabyte; + + public static String ImportTraceWizardScanPageTitle; + public static String ImportTraceWizardSelectTraceTypePageTitle; + public static String ImportTraceWizardPageOptionsTitle; + public static String ImportTraceWizardPageScanDone; + public static String ImportTraceWizardPageScanScanning; + public static String ImportTraceWizardPageSelectNone; + public static String ImportTraceWizardPageSelectHint; + public static String BatchImportTraceWizardRemove; + public static String BatchImportTraceWizardAdd; + public static String BatchImportTraceWizardErrorImportingTraceResource; + + public static String SharedSelectProject; + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/TraceTypeContentProvider.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/TraceTypeContentProvider.java new file mode 100644 index 0000000000..a79c1cbce8 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/TraceTypeContentProvider.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Matthew Khouzam - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType; +import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper; + +/** + * Trace type content provider, a helper for showing trace types + * + * @author Matthew Khouzam + */ +public class TraceTypeContentProvider implements ITreeContentProvider { + + private final List<String> fTraceCategory = new ArrayList<>(); + private final Map<String, List<TraceTypeHelper>> fTraceType = new HashMap<>(); + + /** + * Default Constructor + */ + public TraceTypeContentProvider() { + fTraceType.clear(); + fTraceCategory.clear(); + + for (String category : TmfTraceType.getTraceCategories()) { + List<TraceTypeHelper> value = TmfTraceType.getTraceTypes(category); + if (!value.isEmpty()) { + fTraceCategory.add(category); + fTraceType.put(category, value); + } + } + } + + @Override + public void dispose() { + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // Do nothing + } + + @Override + public Object[] getElements(Object inputElement) { + return fTraceCategory.toArray(new String[0]); + } + + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof String) { + final List<TraceTypeHelper> children = fTraceType.get(parentElement); + if (children != null) { + return children.toArray(new TraceTypeHelper[0]); + } + } + return null; + } + + @Override + public Object getParent(Object element) { + if (element instanceof TraceTypeHelper) { + for (String key : fTraceCategory) { + List<TraceTypeHelper> traceSet = fTraceType.get(key); + if (traceSet != null) { + if (traceSet.contains(element)) { + return key; + } + } + } + } + return null; + } + + @Override + public boolean hasChildren(Object element) { + if (element instanceof String) { + String key = (String) element; + return fTraceType.containsKey(key); + } + return false; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/messages.properties b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/messages.properties new file mode 100644 index 0000000000..f3fdaf8e0c --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/importtrace/messages.properties @@ -0,0 +1,81 @@ +############################################################################### +# Copyright (c) 2013, 2014 Ericsson +# +# 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 +# +# Contributors: +# Ericsson - Initial API and implementation +############################################################################### + +# ImportTraceWizard +ImportTraceWizard_DialogTitle=Trace Import +ImportTraceWizard_FileSystemTitle=File system +ImportTraceWizard_ImportTrace=Import a trace from the local file system +ImportTraceWizard_DirectoryLocation=Select roo&t directory: +ImportTraceWizard_ArchiveLocation=Select &archive file: +ImportTraceWizard_BrowseButton=B&rowse... +ImportTraceWizard_TraceType=Trace Type: +ImportTraceWizard_SelectTraceDirectoryTitle=Select trace directory +ImportTraceWizard_SelectTraceArchiveTitle=Select trace archive file +ImportTraceWizard_SelectTraceDirectoryMessage=Select directory to import trace from +ImportTraceWizard_OverwriteExistingTrace=Overwrite existing trace without warning +ImportTraceWizard_CreateLinksInWorkspace=Create lin&ks in workspace +ImportTraceWizard_PreserveFolderStructure=Preserve &folder structure +ImportTraceWizard_TraceValidationFailed=Validation failed for trace resource {0} +ImportTraceWizard_TraceAlreadyExists=Trace with name "{0}" already exists in project. Do you want to rename, overwrite or skip? +ImportTraceWizard_ImportConfigurationRename=Rename +ImportTraceWizard_ImportConfigurationRenameAll=Rename All +ImportTraceWizard_ImportConfigurationOverwrite=Overwrite +ImportTraceWizard_ImportConfigurationOverwriteAll=Overwrite All +ImportTraceWizard_ImportConfigurationSkip=Skip +ImportTraceWizard_ImportConfigurationSkipAll=Skip All +ImportTraceWizard_InvalidTraceDirectory=Invalid trace directory +ImportTraceWizard_SelectTraceSourceEmpty=Source must not be empty +ImportTraceWizard_BadArchiveFormat=Source file is not a valid tar or zip file. +ImportTraceWizard_SelectTraceNoneSelected=No trace selected +ImportTraceWizard_ImportProblem=Import problem +ImportTraceWizard_CannotImportFilesUnderAVirtualFolder=Can not import trace under a virtual folder +ImportTraceWizard_HaveToCreateLinksUnderAVirtualFolder=Have to create link under a virtual folder +ImportTraceWizard_Information=Information +ImportTraceWizard_ImportUnrecognized=Import unrecognized traces +ImportTraceWizard_ImportOperationCancelled=Import operation cancelled +ImportTraceWizard_TraceTypeNotFound=No trace type helper found +ImportTraceWizard_ImportOperationTaskName=Importing +ImportTraceWizard_ExtractImportOperationTaskName=Extracting files +ImportTraceWizard_AutoDetection=<Automatic Detection> + +# BatchImportTraceWizard +ImportTraceWizardImportCaption=Trace to import +ImportTraceWizardTraceDisplayName=Trace display name +ImportTraceWizardLinkTraces=Link traces (Recommended) +ImportTraceWizardCopyTraces=Copy traces +ImportTraceWizardOverwriteTraces=Overwrite existing traces (recommended) +ImportTraceWizardAddFile=Add File... +ImportTraceWizardAddDirectory=Add Directory... +ImportTraceWizardRemove=Remove +ImportTraceWizardDirectoryTitle=Pick directories and files to scan +ImportTraceWizardDirectoryHint=Select at least one file or directory to scan +ImportTraceWizardScanPagebyte=\ B +ImportTraceWizardScanPageGigabyte=\ GB +ImportTraceWizardScanPageKilobyte=\ KB +ImportTraceWizardScanPageMegabyte=\ MB +ImportTraceWizardScanPageRenameError=Each selected trace must have a unique name, please rename. +ImportTraceWizardScanPageSelectAtleastOne=Select at least one trace to import +ImportTraceWizardScanPageSize=Size +ImportTraceWizardSelectAll=Select All +ImportTraceWizardScanPageTerabyte=\ TB +ImportTraceWizardScanPageTitle=Valid traces +ImportTraceWizardSelectTraceTypePageTitle=Available trace types +ImportTraceWizardPageOptionsTitle=Select Target Project +ImportTraceWizardPageScanDone=Done\! +ImportTraceWizardPageScanScanning=Scanning: +ImportTraceWizardPageSelectNone=Deselect All +ImportTraceWizardPageSelectHint=Select at least one trace type +BatchImportTraceWizardRemove=Removing +BatchImportTraceWizardAdd=Adding +BatchImportTraceWizardErrorImportingTraceResource=Error importing trace resource +ImportTraceWizardImportProblem=Error +SharedSelectProject=Select a project to import to diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/AbstractTracePackageOperation.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/AbstractTracePackageOperation.java new file mode 100644 index 0000000000..c3585f31ff --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/AbstractTracePackageOperation.java @@ -0,0 +1,369 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.Vector; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ui.internal.wizards.datatransfer.TarEntry; +import org.eclipse.ui.internal.wizards.datatransfer.TarException; +import org.eclipse.ui.internal.wizards.datatransfer.TarFile; + +/** + * An abstract operation containing common code useful for other trace package + * operations + * + * @author Marc-Andre Laperle + */ +@SuppressWarnings("restriction") +public abstract class AbstractTracePackageOperation { + private IStatus fStatus; + // Result of this operation, if any + private TracePackageElement[] fResultElements; + + private final String fFileName; + + /** + * Constructs a new trace package operation + * + * @param fileName + * the output file name + */ + public AbstractTracePackageOperation(String fileName) { + fFileName = fileName; + } + + /** + * Run the operation. The status (result) of the operation can be obtained + * with {@link #getStatus} + * + * @param progressMonitor + * the progress monitor to use to display progress and receive + * requests for cancellation + */ + public abstract void run(IProgressMonitor progressMonitor); + + /** + * Returns the status of the operation (result) + * + * @return the status of the operation + */ + public IStatus getStatus() { + return fStatus; + } + + /** + * Get the resulting elements for this operation, if any + * + * @return the resulting elements or null if no result is produced by this + * operation + */ + public TracePackageElement[] getResultElements() { + return fResultElements; + } + + /** + * Set the resulting elements for this operation, if any + * + * @param elements + * the resulting elements produced by this operation, can be set + * to null + */ + public void setResultElements(TracePackageElement[] elements) { + fResultElements = elements; + } + + /** + * Set the status for this operation + * + * @param status + * the status + */ + protected void setStatus(IStatus status) { + fStatus = status; + } + + /** + * Get the file name of the package + * + * @return the file name + */ + protected String getFileName() { + return fFileName; + } + + /** + * Answer a handle to the archive file currently specified as being the + * source. Return null if this file does not exist or is not of valid + * format. + * + * @return the archive file + */ + public ArchiveFile getSpecifiedArchiveFile() { + if (fFileName.length() == 0) { + return null; + } + + try { + return new ZipArchiveFile(new ZipFile(fFileName)); + } catch (IOException e) { + // ignore + } + + try { + return new TarArchiveFile(new TarFile(fFileName)); + } catch (TarException | IOException e) { + // ignore + } + + return null; + } + + /** + * Get the number of checked elements in the array and the children + * + * @param elements + * the elements to check for checked + * @return the number of checked elements + */ + protected int getNbCheckedElements(TracePackageElement[] elements) { + int totalWork = 0; + for (TracePackageElement tracePackageElement : elements) { + TracePackageElement[] children = tracePackageElement.getChildren(); + if (children != null && children.length > 0) { + totalWork += getNbCheckedElements(children); + } else if (tracePackageElement.isChecked()) { + ++totalWork; + } + } + + return totalWork; + } + + /** + * Returns whether or not the Files element is checked under the given trace + * package element + * + * @param tracePackageElement + * the trace package element + * @return whether or not the Files element is checked under the given trace + * package element + */ + public static boolean isFilesChecked(TracePackageElement tracePackageElement) { + for (TracePackageElement element : tracePackageElement.getChildren()) { + if (element instanceof TracePackageFilesElement) { + return element.isChecked(); + } + } + + return false; + } + + /** + * Common interface between ZipEntry and TarEntry + */ + protected interface ArchiveEntry { + /** + * The name of the entry + * + * @return The name of the entry + */ + String getName(); + } + + /** + * Common interface between ZipFile and TarFile + */ + protected interface ArchiveFile { + /** + * Returns an enumeration cataloging the archive. + * + * @return enumeration of all files in the archive + */ + Enumeration<? extends ArchiveEntry> entries(); + + /** + * Close the file input stream. + * + * @throws IOException + */ + void close() throws IOException; + + /** + * Returns a new InputStream for the given file in the archive. + * + * @param entry + * the given file + * @return an input stream for the given file + * @throws TarException + * @throws IOException + */ + InputStream getInputStream(ArchiveEntry entry) throws TarException, IOException; + } + + /** + * Adapter for TarFile to ArchiveFile + */ + protected class TarArchiveFile implements ArchiveFile { + + private TarFile fTarFile; + + /** + * Constructs a TarAchiveFile for a TarFile + * + * @param tarFile + * the TarFile + */ + public TarArchiveFile(TarFile tarFile) { + this.fTarFile = tarFile; + } + + @Override + public Enumeration<? extends ArchiveEntry> entries() { + Vector<ArchiveEntry> v = new Vector<>(); + for (Enumeration<?> e = fTarFile.entries(); e.hasMoreElements();) { + v.add(new TarArchiveEntry((TarEntry) e.nextElement())); + } + + return v.elements(); + } + + @Override + public void close() throws IOException { + fTarFile.close(); + } + + @Override + public InputStream getInputStream(ArchiveEntry entry) throws TarException, IOException { + return fTarFile.getInputStream(((TarArchiveEntry) entry).getTarEntry()); + } + } + + /** + * Adapter for TarEntry to ArchiveEntry + */ + protected class TarArchiveEntry implements ArchiveEntry { + private TarEntry fTarEntry; + + /** + * Constructs a TarArchiveEntry for a TarEntry + * + * @param tarEntry + * the TarEntry + */ + public TarArchiveEntry(TarEntry tarEntry) { + this.fTarEntry = tarEntry; + } + + @Override + public String getName() { + return fTarEntry.getName(); + } + + /** + * Get the corresponding TarEntry + * + * @return the corresponding TarEntry + */ + public TarEntry getTarEntry() { + return fTarEntry; + } + + @Override + public String toString() { + return getName(); + } + } + + /** + * Adapter for ArchiveEntry to ArchiveEntry + */ + protected class ZipAchiveEntry implements ArchiveEntry { + + private ZipEntry fZipEntry; + + /** + * Constructs a ZipAchiveEntry for a ZipEntry + * + * @param zipEntry + * the ZipEntry + */ + public ZipAchiveEntry(ZipEntry zipEntry) { + this.fZipEntry = zipEntry; + } + + @Override + public String getName() { + return fZipEntry.getName(); + } + + /** + * Get the corresponding ZipEntry + * + * @return the corresponding ZipEntry + */ + public ZipEntry getZipEntry() { + return fZipEntry; + } + + @Override + public String toString() { + return getName(); + } + } + + /** + * Adapter for ZipFile to ArchiveFile + */ + protected class ZipArchiveFile implements ArchiveFile { + + private ZipFile fZipFile; + + /** + * Constructs a ZipArchiveFile for a ZipFile + * + * @param zipFile + * the ZipFile + */ + public ZipArchiveFile(ZipFile zipFile) { + this.fZipFile = zipFile; + } + + @Override + public Enumeration<? extends ArchiveEntry> entries() { + Vector<ArchiveEntry> v = new Vector<>(); + for (Enumeration<?> e = fZipFile.entries(); e.hasMoreElements();) { + v.add(new ZipAchiveEntry((ZipEntry) e.nextElement())); + } + + return v.elements(); + } + + @Override + public void close() throws IOException { + fZipFile.close(); + } + + @Override + public InputStream getInputStream(ArchiveEntry entry) throws TarException, IOException { + return fZipFile.getInputStream(((ZipAchiveEntry) entry).getZipEntry()); + } + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/AbstractTracePackageWizardPage.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/AbstractTracePackageWizardPage.java new file mode 100644 index 0000000000..b8aa56bc3c --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/AbstractTracePackageWizardPage.java @@ -0,0 +1,570 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; + +/** + * An abstract wizard page containing common code useful for both import and + * export trace package wizard pages + * + * @author Marc-Andre Laperle + */ +public abstract class AbstractTracePackageWizardPage extends WizardPage { + + private static final int COMBO_HISTORY_LENGTH = 5; + private static final String STORE_FILE_PATHS_ID = ".STORE_FILEPATHS_ID"; //$NON-NLS-1$ + + private final String fStoreFilePathId; + private final IStructuredSelection fSelection; + + private CheckboxTreeViewer fElementViewer; + private Button fSelectAllButton; + private Button fDeselectAllButton; + private Combo fFilePathCombo; + private Button fBrowseButton; + + /** + * Create the trace package wizard page + * + * @param pageName + * the name of the page + * @param title + * the title for this wizard page, or null if none + * @param titleImage + * the image descriptor for the title of this wizard page, or + * null if none + * @param selection + * the current object selection + */ + protected AbstractTracePackageWizardPage(String pageName, String title, ImageDescriptor titleImage, IStructuredSelection selection) { + super(pageName, title, titleImage); + fStoreFilePathId = getName() + STORE_FILE_PATHS_ID; + fSelection = selection; + } + + /** + * Create the element viewer + * + * @param compositeParent + * the parent composite + */ + protected void createElementViewer(Composite compositeParent) { + fElementViewer = new CheckboxTreeViewer(compositeParent, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.CHECK); + + fElementViewer.addCheckStateListener(new ICheckStateListener() { + @Override + public void checkStateChanged(CheckStateChangedEvent event) { + TracePackageElement element = (TracePackageElement) event.getElement(); + if (!element.isEnabled()) { + fElementViewer.setChecked(element, element.isChecked()); + } else { + setSubtreeChecked(fElementViewer, element, true, event.getChecked()); + } + maintainCheckIntegrity(element); + + if (element.getParent() != null) { + // Uncheck everything in this trace if Trace files are unchecked + if (element instanceof TracePackageFilesElement) { + if (!element.isChecked()) { + setSubtreeChecked(fElementViewer, element.getParent(), false, false); + } + // Check Trace files if anything else is selected + } else if (element.isChecked()) { + TracePackageElement parent = element.getParent(); + while (parent != null) { + for (TracePackageElement e : parent.getChildren()) { + if (e instanceof TracePackageFilesElement) { + setSubtreeChecked(fElementViewer, e, false, true); + break; + } + } + parent = parent.getParent(); + } + } + } + + + updateApproximateSelectedSize(); + updatePageCompletion(); + } + + private void maintainCheckIntegrity(final TracePackageElement element) { + TracePackageElement parentElement = element.getParent(); + boolean allChecked = true; + boolean oneChecked = false; + if (parentElement != null) { + if (parentElement.getChildren() != null) { + for (TracePackageElement child : parentElement.getChildren()) { + if (fElementViewer.getGrayed(child)) { + oneChecked = true; + allChecked = false; + break; + } + boolean checked = fElementViewer.getChecked(child); + oneChecked |= checked; + allChecked &= checked; + } + } + if (oneChecked && !allChecked) { + fElementViewer.setGrayChecked(parentElement, true); + } else { + fElementViewer.setGrayed(parentElement, false); + fElementViewer.setChecked(parentElement, allChecked); + } + maintainCheckIntegrity(parentElement); + } + } + }); + GridData layoutData = new GridData(GridData.FILL_BOTH); + fElementViewer.getTree().setLayoutData(layoutData); + fElementViewer.setContentProvider(new TracePackageContentProvider()); + fElementViewer.setLabelProvider(new TracePackageLabelProvider()); + } + + /** + * Create the input for the element viewer + * + * @return the input for the element viewer + */ + protected abstract Object createElementViewerInput(); + + /** + * Create the file path group that allows the user to type or browse for a + * file path + * + * @param parent + * the parent composite + * @param label + * the label to describe the file path (i.e. import/export) + * @param fileDialogStyle + * SWT.OPEN or SWT.SAVE + */ + protected void createFilePathGroup(Composite parent, String label, final int fileDialogStyle) { + + Composite filePathSelectionGroup = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + filePathSelectionGroup.setLayout(layout); + filePathSelectionGroup.setLayoutData(new GridData( + GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL)); + + Label destinationLabel = new Label(filePathSelectionGroup, SWT.NONE); + destinationLabel.setText(label); + + fFilePathCombo = new Combo(filePathSelectionGroup, SWT.SINGLE + | SWT.BORDER); + GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL + | GridData.GRAB_HORIZONTAL); + data.grabExcessHorizontalSpace = true; + fFilePathCombo.setLayoutData(data); + + fBrowseButton = new Button(filePathSelectionGroup, + SWT.PUSH); + fBrowseButton.setText(org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_Browse); + fBrowseButton.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + handleFilePathBrowseButtonPressed(fileDialogStyle); + } + }); + setButtonLayoutData(fBrowseButton); + } + + /** + * Update the page with the file path the current file path selection + */ + protected abstract void updateWithFilePathSelection(); + + /** + * Creates the buttons for selecting all or none of the elements. + * + * @param parent + * the parent control + * @return the button group + */ + protected Composite createButtonsGroup(Composite parent) { + + // top level group + Composite buttonComposite = new Composite(parent, SWT.NONE); + + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + buttonComposite.setLayout(layout); + buttonComposite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL + | GridData.HORIZONTAL_ALIGN_FILL)); + + fSelectAllButton = new Button(buttonComposite, SWT.PUSH); + fSelectAllButton.setText(org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_SelectAll); + + SelectionListener listener = new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setAllChecked(fElementViewer, true, true); + updateApproximateSelectedSize(); + updatePageCompletion(); + } + }; + fSelectAllButton.addSelectionListener(listener); + + fDeselectAllButton = new Button(buttonComposite, SWT.PUSH); + fDeselectAllButton.setText(org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_DeselectAll); + + listener = new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setAllChecked(fElementViewer, true, false); + updateApproximateSelectedSize(); + updatePageCompletion(); + } + }; + fDeselectAllButton.addSelectionListener(listener); + + return buttonComposite; + } + + /** + * Restore widget values to the values that they held last time this wizard + * was used to completion. + */ + protected void restoreWidgetValues() { + IDialogSettings settings = getDialogSettings(); + if (settings != null) { + String[] directoryNames = settings.getArray(fStoreFilePathId); + if (directoryNames == null || directoryNames.length == 0) { + return; + } + + for (int i = 0; i < directoryNames.length; i++) { + fFilePathCombo.add(directoryNames[i]); + } + } + } + + /** + * Save widget values to Dialog settings + */ + protected void saveWidgetValues() { + IDialogSettings settings = getDialogSettings(); + if (settings != null) { + // update directory names history + String[] directoryNames = settings.getArray(fStoreFilePathId); + if (directoryNames == null) { + directoryNames = new String[0]; + } + + directoryNames = addToHistory(directoryNames, getFilePathValue()); + settings.put(fStoreFilePathId, directoryNames); + } + } + + /** + * Determine if the page is complete and update the page appropriately. + */ + protected void updatePageCompletion() { + boolean pageComplete = determinePageCompletion(); + setPageComplete(pageComplete); + if (pageComplete) { + setErrorMessage(null); + } + } + + /** + * Determine if the page is completed or not + * + * @return true if the page is completed, false otherwise + */ + protected boolean determinePageCompletion() { + return fElementViewer.getCheckedElements().length > 0 && !getFilePathValue().isEmpty(); + } + + /** + * Handle error status + * + * @param status + * the error status + */ + protected void handleErrorStatus(IStatus status) { + + Throwable exception = status.getException(); + String message = status.getMessage().length() > 0 ? status.getMessage() : org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorOperation; + + if (!status.isMultiStatus()) { + handleError(message, exception); + return; + } + + // Build a string with all the children status messages, exception + // messages and stack traces + StringBuilder sb = new StringBuilder(); + for (IStatus childStatus : status.getChildren()) { + StringBuilder childSb = new StringBuilder(); + if (!childStatus.getMessage().isEmpty()) { + childSb.append(childStatus.getMessage() + '\n'); + } + + Throwable childException = childStatus.getException(); + if (childException != null) { + String reason = childException.getMessage(); + // Some system exceptions have no message + if (reason == null) { + reason = childException.toString(); + } + + String stackMessage = getExceptionStackMessage(childException); + if (stackMessage == null) { + stackMessage = reason; + } + + childSb.append(stackMessage); + } + + if (childSb.length() > 0) { + childSb.insert(0, '\n'); + sb.append(childSb.toString()); + } + } + + // ErrorDialog only prints the call stack for a CoreException + exception = new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, sb.toString(), null)); + final Status statusWithException = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorMultipleProblems, exception); + + Activator.getDefault().logError(message, exception); + ErrorDialog.openError(getContainer().getShell(), org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_InternalErrorTitle, message, statusWithException); + } + + /** + * Handle errors occurring in the wizard operations + * + * @param message + * the error message + * @param exception + * the exception attached to the message + */ + protected void handleError(String message, Throwable exception) { + Activator.getDefault().logError(message, exception); + displayErrorDialog(message, exception); + } + + private static String getExceptionStackMessage(Throwable exception) { + String stackMessage = null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos); + exception.printStackTrace(ps); + ps.flush(); + try { + baos.flush(); + stackMessage = baos.toString(); + } catch (IOException e) { + } + + return stackMessage; + } + + private void displayErrorDialog(String message, Throwable exception) { + if (exception == null) { + final Status s = new Status(IStatus.ERROR, Activator.PLUGIN_ID, message); + ErrorDialog.openError(getContainer().getShell(), org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_InternalErrorTitle, null, s); + return; + } + + String reason = exception.getMessage(); + // Some system exceptions have no message + if (reason == null) { + reason = exception.toString(); + } + + String stackMessage = getExceptionStackMessage(exception); + if (stackMessage == null || stackMessage.isEmpty()) { + stackMessage = reason; + } + + // ErrorDialog only prints the call stack for a CoreException + CoreException coreException = new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, stackMessage, exception)); + final Status s = new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, reason, coreException); + ErrorDialog.openError(getContainer().getShell(), org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_InternalErrorTitle, message, s); + } + + /** + * A version of setSubtreeChecked that is aware of isEnabled + * + * @param viewer + * the viewer + * @param element + * the element + * @param enabledOnly + * if only enabled elements should be considered + * @param checked + * true if the item should be checked, and false if it should be + * unchecked + */ + protected static void setSubtreeChecked(CheckboxTreeViewer viewer, TracePackageElement element, boolean enabledOnly, boolean checked) { + if (!enabledOnly || element.isEnabled()) { + viewer.setChecked(element, checked); + if (checked) { + viewer.setGrayed(element, false); + } + element.setChecked(checked); + if (element.getChildren() != null) { + for (TracePackageElement child : element.getChildren()) { + setSubtreeChecked(viewer, child, enabledOnly, checked); + } + } + } + } + + /** + * Sets all items in the element viewer to be checked or unchecked + * + * @param viewer + * the viewer + * @param enabledOnly + * if only enabled elements should be considered + * @param checked + * whether or not items should be checked + */ + protected static void setAllChecked(CheckboxTreeViewer viewer, boolean enabledOnly, boolean checked) { + TreeItem[] items = viewer.getTree().getItems(); + for (int i = 0; i < items.length; i++) { + Object element = items[i].getData(); + setSubtreeChecked(viewer, (TracePackageElement) element, enabledOnly, checked); + } + } + + private static void addToHistory(List<String> history, String newEntry) { + history.remove(newEntry); + history.add(0, newEntry); + + // since only one new item was added, we can be over the limit + // by at most one item + if (history.size() > COMBO_HISTORY_LENGTH) { + history.remove(COMBO_HISTORY_LENGTH); + } + } + + private static String[] addToHistory(String[] history, String newEntry) { + ArrayList<String> l = new ArrayList<>(Arrays.asList(history)); + addToHistory(l, newEntry); + String[] r = new String[l.size()]; + l.toArray(r); + return r; + } + + /** + * Open an appropriate file dialog so that the user can specify a file to + * import/export + * @param fileDialogStyle + */ + private void handleFilePathBrowseButtonPressed(int fileDialogStyle) { + FileDialog dialog = new FileDialog(getContainer().getShell(), fileDialogStyle | SWT.SHEET); + dialog.setFilterExtensions(new String[] { "*.zip;*.tar.gz;*.tar;*.tgz", "*.*" }); //$NON-NLS-1$ //$NON-NLS-2$ + dialog.setText(Messages.TracePackage_FileDialogTitle); + String currentSourceString = getFilePathValue(); + int lastSeparatorIndex = currentSourceString.lastIndexOf(File.separator); + if (lastSeparatorIndex != -1) { + dialog.setFilterPath(currentSourceString.substring(0, lastSeparatorIndex)); + } + String selectedFileName = dialog.open(); + + if (selectedFileName != null) { + setFilePathValue(selectedFileName); + updateWithFilePathSelection(); + } + } + + /** + * Get the current file path value + * + * @return the current file path value + */ + protected String getFilePathValue() { + return fFilePathCombo.getText().trim(); + } + + /** + * Set the file path value + * + * @param value + * file path value + */ + protected void setFilePathValue(String value) { + fFilePathCombo.setText(value); + updatePageCompletion(); + } + + /** + * Update the approximate size of the selected elements + */ + protected void updateApproximateSelectedSize() { + } + + /** + * Get the element tree viewer + * + * @return the element tree viewer + */ + protected CheckboxTreeViewer getElementViewer() { + return fElementViewer; + } + + /** + * Get the file path combo box + * + * @return the file path combo box + */ + protected Combo getFilePathCombo() { + return fFilePathCombo; + } + + /** + * Get the object selection when the wizard was created + * + * @return the object selection + */ + protected IStructuredSelection getSelection() { + return fSelection; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/ITracePackageConstants.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/ITracePackageConstants.java new file mode 100644 index 0000000000..f7458455fe --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/ITracePackageConstants.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg; + +/** + * Constants used in the trace package (XML attribute and element names, etc). + * + * @author Marc-Andre Laperle + */ +public interface ITracePackageConstants { + + /** + * The file name for the package manifest file + */ + public static final String MANIFEST_FILENAME = "export-manifest.xml"; //$NON-NLS-1$ + + /** + * The root element of an export + */ + public static final String TMF_EXPORT_ELEMENT = "tmf-export"; //$NON-NLS-1$ + + /** + * Element representing a single trace + */ + public static final String TRACE_ELEMENT = "trace"; //$NON-NLS-1$ + + /** + * Attribute for the name of a trace + */ + public static final String TRACE_NAME_ATTRIB = "name"; //$NON-NLS-1$ + + /** + * Attribute for the type of a trace + */ + public static final String TRACE_TYPE_ATTRIB = "type"; //$NON-NLS-1$ + + /** + * Element representing a single supplementary file + */ + public static final String SUPPLEMENTARY_FILE_ELEMENT = "supplementary-file"; //$NON-NLS-1$ + + /** + * Attribute for the name of a supplementary file + */ + public static final String SUPPLEMENTARY_FILE_NAME_ATTRIB = "name"; //$NON-NLS-1$ + + /** + * Element representing a trace file or folder + */ + public static final String TRACE_FILE_ELEMENT = "file"; //$NON-NLS-1$ + + /** + * Attribute for the name of the file + */ + public static final String TRACE_FILE_NAME_ATTRIB = "name"; //$NON-NLS-1$ + + /** + * Element representing the bookmarks of a trace + */ + public static final String BOOKMARKS_ELEMENT = "bookmarks"; //$NON-NLS-1$ + + /** + * Element representing a single bookmark of a trace + */ + public static final String BOOKMARK_ELEMENT = "bookmark"; //$NON-NLS-1$ +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/Messages.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/Messages.java new file mode 100644 index 0000000000..06f49daaf5 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/Messages.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg; + +import org.eclipse.osgi.util.NLS; + +/** + * Messages common to trace package operations + * + * @author Marc-Andre Laperle + */ +public class Messages extends NLS { + + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.messages"; //$NON-NLS-1$ + + /** + * Text for supplementary files in the element viewer + */ + public static String TracePackage_SupplementaryFiles; + + /** + * Text for trace in the element viewer + */ + public static String TracePackage_TraceElement; + + /** + * Text for bookmarks in the element viewer + */ + public static String TracePackage_Bookmarks; + + /** + * Text for browse button in the wizard pages + */ + public static String TracePackage_Browse; + + /** + * Title for the file dialog + */ + public static String TracePackage_FileDialogTitle; + + /** + * Text for browse select all button in the wizard pages + */ + public static String TracePackage_SelectAll; + + /** + * Text for browse deselect all button in the wizard pages + */ + public static String TracePackage_DeselectAll; + + /** + * Generic error message for wizard operations + */ + public static String TracePackage_ErrorOperation; + + /** + * Generic error when multiple problems occur (MultiStatus) + */ + public static String TracePackage_ErrorMultipleProblems; + + /** + * Generic dialog message for error in wizard operations + */ + public static String TracePackage_InternalErrorTitle; + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageBookmarkElement.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageBookmarkElement.java new file mode 100644 index 0000000000..06d6651604 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageBookmarkElement.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg; + +import java.util.List; +import java.util.Map; + +import org.eclipse.swt.graphics.Image; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; + +/** + * A trace package element representing the bookmarks of a trace + * + * @author Marc-Andre Laperle + */ +public class TracePackageBookmarkElement extends TracePackageElement { + private static final String BOOKMARK_IMAGE_PATH = "icons/elcl16/bookmark_obj.gif"; //$NON-NLS-1$ + private final List<Map<String, String>> bookmarkAttribs; + + /** + * Construct a bookmark element containing all the bookmarks + * + * @param parent + * the parent node + * @param bookmarkAttribs + * the bookmarks for the trace + */ + public TracePackageBookmarkElement(TracePackageElement parent, List<Map<String, String>> bookmarkAttribs) { + super(parent); + this.bookmarkAttribs = bookmarkAttribs; + } + + @Override + public long getSize(boolean checkedOnly) { + return 0; + } + + @Override + public String getText() { + return Messages.TracePackage_Bookmarks; + } + + @Override + public Image getImage() { + return Activator.getDefault().getImageFromImageRegistry(BOOKMARK_IMAGE_PATH); + } + + /** + * Get all the bookmarks + * + * @return the bookmarks + */ + public List<Map<String, String>> getBookmarks() { + return bookmarkAttribs; + } +}
\ No newline at end of file diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageContentProvider.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageContentProvider.java new file mode 100644 index 0000000000..278b29b854 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageContentProvider.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg; + +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; + +/** + * A content provider to display the content of a trace package in a tree + * + * @author Marc-Andre Laperle + */ +public class TracePackageContentProvider implements ITreeContentProvider { + + @Override + public void dispose() { + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof TracePackageElement[]) { + return (TracePackageElement[]) inputElement; + } + return null; + } + + @Override + public Object[] getChildren(Object parentElement) { + return ((TracePackageElement) parentElement).getVisibleChildren(); + } + + @Override + public Object getParent(Object element) { + return ((TracePackageElement) element).getParent(); + } + + @Override + public boolean hasChildren(Object element) { + TracePackageElement traceTransferElement = (TracePackageElement) element; + TracePackageElement[] visibleChildren = traceTransferElement.getVisibleChildren(); + return visibleChildren != null && visibleChildren.length > 0; + } + +}
\ No newline at end of file diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageElement.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageElement.java new file mode 100644 index 0000000000..60fec72e7c --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageElement.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2013, 2015 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + * Patrick Tasse - Add list methods + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.model.WorkbenchAdapter; + +/** + * An ExportTraceElement represents an item in the ExportTraceWizard tree. + * + * @author Marc-Andre Laperle + */ +public abstract class TracePackageElement extends WorkbenchAdapter { + private final List<TracePackageElement> fChildren; + private TracePackageElement fParent; + private boolean fEnabled; + private boolean fChecked; + private boolean fVisible; + + /** + * + * @param parent + * the parent of this element, can be set to null + */ + public TracePackageElement(TracePackageElement parent) { + fParent = parent; + fEnabled = true; + fVisible = true; + fChildren = new ArrayList<>(); + if (parent != null) { + parent.addChild(this); + } + } + + /** + * Add a child at the end of the element's children list. + * + * @param child + * the element to add as a child + */ + public void addChild(TracePackageElement child) { + child.setParent(this); + fChildren.add(child); + } + + /** + * Insert a child at the specified position in the element's children list. + * + * @param index + * the index at which the element is to be inserted + * @param child + * the element to insert as a child + */ + public void addChild(int index, TracePackageElement child) { + fChildren.add(index, child); + child.setParent(this); + } + + /** + * Remove a child from the element's children list. + * + * @param child + * the child to remove + */ + public void removeChild(TracePackageElement child) { + fChildren.remove(child); + child.setParent(null); + } + + /** + * Returns the index of the specified child in the element's children list. + * + * @param child + * the child to search for + * @return the index of the child in the list, or -1 if not found + */ + public int indexOf(TracePackageElement child) { + return fChildren.indexOf(child); + } + + /** + * @return the parent of this element or null if there is no parent + */ + public TracePackageElement getParent() { + return fParent; + } + + private void setParent(TracePackageElement parent) { + fParent = parent; + } + + /** + * Get the text representation of this element to be displayed in the tree. + * + * @return the text representation + */ + public abstract String getText(); + + /** + * Get the children of this element + * + * @return the children of this element + */ + public TracePackageElement[] getChildren() { + return fChildren.toArray(new TracePackageElement[fChildren.size()]); + } + + /** + * Get the visible children of this element + * + * @return the visible children of this element + */ + public TracePackageElement[] getVisibleChildren() { + List<TracePackageElement> visibleChildren = new ArrayList<>(); + for (TracePackageElement child : fChildren) { + if (child.isVisible()) { + visibleChildren.add(child); + } + } + return visibleChildren.toArray(new TracePackageElement[0]); + } + + /** + * Get the total size of the element including its children + * + * @param checkedOnly + * only count checked elements + * + * @return the total size of the element + */ + public long getSize(boolean checkedOnly) { + long size = 0; + if (fChildren != null) { + for (TracePackageElement child : fChildren) { + size += child.getSize(checkedOnly); + } + } + + return size; + } + + /** + * Get the image representation of this element to be displayed in the tree. + * + * @return the image representation + */ + public Image getImage() { + return null; + } + + /** + * Returns whether or not the element is enabled (grayed and not + * modifiable). + * + * @return whether or not the element is enabled + */ + public boolean isEnabled() { + return fEnabled; + } + + /** + * Returns whether or not the element is checked. + * + * @return whether or not the element is checked + */ + public boolean isChecked() { + return fChecked; + } + + /** + * Returns whether or not the element is visible. + * + * @return whether or not the element is visible + */ + public boolean isVisible() { + return fVisible; + } + + /** + * Sets whether or not the element should be enabled (grayed and not + * modifiable). + * + * @param enabled + * if the element should be enabled + */ + public void setEnabled(boolean enabled) { + fEnabled = enabled; + } + + /** + * Sets whether or not the element should be checked. + * + * @param checked + * if the element should be checked + */ + public void setChecked(boolean checked) { + fChecked = checked; + } + + /** + * Sets whether or not the element is visible. + * + * @param visible + * if the element should be visible + */ + public void setVisible(boolean visible) { + fVisible = visible; + } +}
\ No newline at end of file diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageFilesElement.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageFilesElement.java new file mode 100644 index 0000000000..fccbadfcdf --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageFilesElement.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg; + +import java.io.File; + +import org.eclipse.core.resources.IResource; +import org.eclipse.swt.graphics.Image; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; + +/** + * An ExportTraceElement representing the trace files of a trace. + * + * @author Marc-Andre Laperle + */ +public class TracePackageFilesElement extends TracePackageElement { + + private static final String TRACE_ICON_PATH = "icons/elcl16/trace.gif"; //$NON-NLS-1$ + private String fFileName; + private final IResource fResource; + private long fSize = -1; + + /** + * Constructs an instance of ExportTraceFilesElement when exporting + * + * @param parent + * the parent of this element, can be set to null + * @param resource + * the resource representing the trace file or folder in the + * workspace + */ + public TracePackageFilesElement(TracePackageElement parent, IResource resource) { + super(parent); + fFileName = null; + fResource = resource; + } + + /** + * Constructs an instance of ExportTraceFilesElement when importing + * + * @param parent + * the parent of this element, can be set to null + * @param fileName + * the name of the file to be imported + */ + public TracePackageFilesElement(TracePackageElement parent, String fileName) { + super(parent); + fFileName = fileName; + fResource = null; + } + + private long getSize(File file) { + if (file.isDirectory()) { + long size = 0; + for (File f : file.listFiles()) { + size += getSize(f); + } + return size; + } + + return file.length(); + } + + @Override + public long getSize(boolean checkedOnly) { + if (checkedOnly && !isChecked()) { + return 0; + } + + if (fSize == -1 && fResource.exists()) { + File file = fResource.getLocation().toFile(); + fSize = getSize(file); + } + + return fSize; + } + + @Override + public String getText() { + return Messages.TracePackage_TraceElement; + } + + @Override + public Image getImage() { + return Activator.getDefault().getImageFromImageRegistry(TRACE_ICON_PATH); + } + + /** + * Get the file name for this trace file or folder + * + * @return the file name for this trace file or folder + */ + public String getFileName() { + return fFileName; + } + + /** + * Set the file name for this trace file or folder + * + * @param fileName the file name for this trace file or folder + */ + public void setFileName(String fileName) { + fFileName = fileName; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageLabelProvider.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageLabelProvider.java new file mode 100644 index 0000000000..52687608df --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageLabelProvider.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg; + +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; + +/** + * A label provider for the export trace tree. + * + * @author Marc-Andre Laperle + */ +public class TracePackageLabelProvider extends ColumnLabelProvider { + + @Override + public void addListener(ILabelProviderListener listener) { + } + + @Override + public void dispose() { + } + + @Override + public boolean isLabelProperty(Object element, String property) { + return false; + } + + @Override + public void removeListener(ILabelProviderListener listener) { + } + + @Override + public Image getImage(Object element) { + return ((TracePackageElement) element).getImage(); + } + + @Override + public String getText(Object element) { + return ((TracePackageElement) element).getText(); + } + + @Override + public Color getForeground(Object element) { + if (!((TracePackageElement) element).isEnabled()) { + return Display.getDefault().getSystemColor(SWT.COLOR_GRAY); + } + return null; + } + + @Override + public Color getBackground(Object element) { + return null; + } + +}
\ No newline at end of file diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageSupplFileElement.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageSupplFileElement.java new file mode 100644 index 0000000000..1c501ed310 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageSupplFileElement.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg; + +import org.eclipse.core.resources.IResource; +import org.eclipse.swt.graphics.Image; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; + +/** + * A trace package element representing a single supplementary file + * + * @author Marc-Andre Laperle + */ +public class TracePackageSupplFileElement extends TracePackageElement { + + private static final String SUPPL_FILE_ICON_PATH = "icons/obj16/thread_obj.gif"; //$NON-NLS-1$ + + private final IResource fResource; + private final String fSuppFileName; + + /** + * Constructor used when exporting + * + * @param resource + * the resource representing this supplementary file in the + * workspace + * @param parent + * the parent element + */ + public TracePackageSupplFileElement(IResource resource, TracePackageElement parent) { + super(parent); + fResource = resource; + fSuppFileName = null; + } + + /** + * Constructor used when importing + * + * @param suppFileName + * the name to be used for the supplementary file in the + * workspace + * @param parent + * the parent element + */ + public TracePackageSupplFileElement(String suppFileName, TracePackageElement parent) { + super(parent); + this.fSuppFileName = suppFileName; + fResource = null; + } + + /** + * Get the resource corresponding to this supplementary file + * + * @return the resource corresponding to this supplementary file + */ + public IResource getResource() { + return fResource; + } + + @Override + public String getText() { + return fResource != null ? fResource.getName() : fSuppFileName; + } + + @Override + public long getSize(boolean checkedOnly) { + if (checkedOnly && !isChecked()) { + return 0; + } + + return fResource.getLocation().toFile().length(); + } + + @Override + public Image getImage() { + return Activator.getDefault().getImageFromImageRegistry(SUPPL_FILE_ICON_PATH); + } + +}
\ No newline at end of file diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageSupplFilesElement.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageSupplFilesElement.java new file mode 100644 index 0000000000..76c427b9a7 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageSupplFilesElement.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg; + +import org.eclipse.swt.graphics.Image; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; + +/** + * A trace package element used for grouping supplementary file under a single + * subtree + * + * @author Marc-Andre Laperle + */ +public class TracePackageSupplFilesElement extends TracePackageElement { + + private static final String SUPPL_FILE_ICON_PATH = "icons/obj16/thread_obj.gif"; //$NON-NLS-1$ + + /** + * Construct a new TracePackageSupplFilesElement instance + * + * @param parent + * the parent of this element, can be set to null + */ + public TracePackageSupplFilesElement(TracePackageElement parent) { + super(parent); + } + + @Override + public String getText() { + return Messages.TracePackage_SupplementaryFiles; + } + + @Override + public Image getImage() { + return Activator.getDefault().getImageFromImageRegistry(SUPPL_FILE_ICON_PATH); + } +}
\ No newline at end of file diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageTraceElement.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageTraceElement.java new file mode 100644 index 0000000000..53fe427bb4 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/TracePackageTraceElement.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.swt.graphics.Image; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfCommonProjectElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfNavigatorLabelProvider; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; + +/** + * An ExportTraceElement associated to a TmfTraceElement. This will be the + * parent of other elements (events, supplementary files, bookmarks, etc). + * + * @author Marc-Andre Laperle + */ +public class TracePackageTraceElement extends TracePackageElement { + + private final TmfTraceElement fTraceElement; + private String fImportName; + private String fTraceType; + + /** + * Construct an instance associated to a TmfTraceElement. For exporting. + * + * @param parent + * the parent of this element, can be set to null + * @param traceElement + * the associated TmfTraceElement + */ + public TracePackageTraceElement(TracePackageElement parent, TmfTraceElement traceElement) { + super(parent); + fTraceElement = traceElement; + fImportName = null; + fTraceType = null; + } + + /** + * Construct an instance associated to a TmfTraceElement. For importing. + * + * @param parent + * the parent of this element, can be set to null + * @param importName + * the name to use to identify this trace + * @param traceType + * the trace type to set for this trace + */ + public TracePackageTraceElement(TracePackageElement parent, String importName, String traceType) { + super(parent); + fImportName = importName; + fTraceElement = null; + fTraceType = traceType; + } + + @Override + public String getText() { + return fTraceElement != null ? fTraceElement.getElementPath() : getDestinationElementPath(); + } + + /** + * Return the target TmfCommonProjectElement element path for a given trace + * package element. {@link TmfCommonProjectElement#getElementPath()} + * + * @return the element path + */ + public String getDestinationElementPath() { + String traceName = getImportName(); + for (TracePackageElement element : getChildren()) { + if (element instanceof TracePackageFilesElement) { + TracePackageFilesElement tracePackageFilesElement = (TracePackageFilesElement) element; + String fileName = tracePackageFilesElement.getFileName(); + String parentDir = removeLastSegment(fileName); + return append(parentDir, traceName); + } + } + + return traceName; + } + + /** + * We do this outside of the Path class because we don't want it to convert + * \ to / on Windows in the presence of regular expressions + */ + private static String removeLastSegment(String str) { + String ret = removeAllTrailing(str, IPath.SEPARATOR); + int lastIndexOf = ret.lastIndexOf(IPath.SEPARATOR); + if (lastIndexOf != -1) { + ret = ret.substring(0, lastIndexOf); + ret = removeAllTrailing(ret, IPath.SEPARATOR); + } else { + ret = ""; //$NON-NLS-1$ + } + + return ret; + } + + private static String removeAllTrailing(String str, char toRemove) { + String ret = str; + while (ret.endsWith(Character.toString(toRemove))) { + ret = ret.substring(0, ret.length() - 1); + } + return ret; + } + + private static String append(String path, String str) { + if (!path.isEmpty()) { + return path + IPath.SEPARATOR + str; + } + + return str; + } + + /** + * @return the associated TmfTraceElement + */ + public TmfTraceElement getTraceElement() { + return fTraceElement; + } + + /** + * Set the import name. + * + * @param importName the import name. + */ + public void setImportName(String importName) { + fImportName = importName; + } + + /** + * @return the import name + */ + public String getImportName() { + return fImportName; + } + + /** + * @return the trace type of this trace + */ + public String getTraceType() { + return fTraceType; + } + + /** + * Set the trace type of this trace. + * + * @param traceType the trace type of this trace + */ + public void setTraceType(String traceType) { + fTraceType = traceType; + } + + @Override + public Image getImage() { + TmfNavigatorLabelProvider tmfNavigatorLabelProvider = new TmfNavigatorLabelProvider(); + return tmfNavigatorLabelProvider.getImage(fTraceElement); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ExportTracePackageHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ExportTracePackageHandler.java new file mode 100644 index 0000000000..4d800f19d2 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ExportTracePackageHandler.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.wizard.WizardDialog; +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.ui.ISources; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Handler for exporting a trace package + * + * @author Marc-Andre Laperle + */ +public class ExportTracePackageHandler extends AbstractHandler { + + private boolean fEnabled = false; + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return Boolean.FALSE; + } + + ISelection currentSelection = HandlerUtil.getCurrentSelection(event); + IStructuredSelection sec = StructuredSelection.EMPTY; + List<TmfTraceElement> selectedTraces = new ArrayList<>(); + if (currentSelection instanceof IStructuredSelection) { + sec = (IStructuredSelection) currentSelection; + Object[] selectedElements = sec.toArray(); + for (Object selectedElement : selectedElements) { + if (selectedElement instanceof TmfTraceElement) { + TmfTraceElement tmfTraceElement = (TmfTraceElement) selectedElement; + selectedTraces.add(tmfTraceElement.getElementUnderTraceFolder()); + } else if (selectedElement instanceof TmfTraceFolder) { + TmfTraceFolder tmfTraceFolder = (TmfTraceFolder) selectedElement; + selectedTraces = tmfTraceFolder.getTraces(); + } + } + } + + ExportTracePackageWizard w = new ExportTracePackageWizard(selectedTraces); + + w.init(PlatformUI.getWorkbench(), sec); + WizardDialog dialog = new WizardDialog(window.getShell(), w); + dialog.open(); + return null; + } + + @Override + public boolean isEnabled() { + return super.isEnabled() && fEnabled; + } + + @Override + public void setEnabled(Object evaluationContext) { + super.setEnabled(evaluationContext); + + fEnabled = true; + + Object s = HandlerUtil.getVariable(evaluationContext, ISources.ACTIVE_MENU_SELECTION_NAME); + if (s instanceof IStructuredSelection) { + IStructuredSelection selection = (IStructuredSelection) s; + // If we have traces selected, make sure they are all from the same + // project, disable handler otherwise + Object[] selectedElements = selection.toArray(); + TmfProjectElement firstProject = null; + for (Object selectedElement : selectedElements) { + if (selectedElement instanceof TmfTraceElement) { + TmfTraceElement tmfTraceElement = (TmfTraceElement) selectedElement; + TmfProjectElement project = tmfTraceElement.getProject(); + if (firstProject != null && !project.equals(firstProject)) { + fEnabled = false; + } + + firstProject = project; + } + } + } + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ExportTracePackageSelectTraceWizardPage.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ExportTracePackageSelectTraceWizardPage.java new file mode 100644 index 0000000000..5d6b77d091 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ExportTracePackageSelectTraceWizardPage.java @@ -0,0 +1,218 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IProject; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfNavigatorContentProvider; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfNavigatorLabelProvider; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry; +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.model.WorkbenchLabelProvider; + +/** + * A wizard page for selecting the trace to export when no trace was previously + * selected. + * + * @author Marc-Andre Laperle + */ +public class ExportTracePackageSelectTraceWizardPage extends WizardPage { + + private static final String PAGE_NAME = "ExportTracePackageSelectTraceWizardPage"; //$NON-NLS-1$ + + /** + * Construct the select trace page + */ + public ExportTracePackageSelectTraceWizardPage() { + super(PAGE_NAME); + } + + private IProject fSelectedProject; + private Table fTraceTable; + + @Override + public void createControl(Composite parent) { + Composite projectSelectionGroup = new Composite(parent, SWT.NONE); + projectSelectionGroup.setLayout(new GridLayout(2, true)); + projectSelectionGroup.setLayoutData(new GridData(GridData.FILL_BOTH)); + projectSelectionGroup.setFont(parent.getFont()); + + Label projectLabel = new Label(projectSelectionGroup, SWT.NONE); + projectLabel.setText(Messages.ExportTracePackageSelectTraceWizardPage_ProjectSelection); + projectLabel.setLayoutData(new GridData()); + + Label configLabel = new Label(projectSelectionGroup, SWT.NONE); + configLabel.setText(Messages.ExportTracePackageSelectTraceWizardPage_TraceSelection); + configLabel.setLayoutData(new GridData()); + + final Table projectTable = new Table(projectSelectionGroup, SWT.SINGLE | SWT.BORDER); + projectTable.setLayoutData(new GridData(GridData.FILL_BOTH)); + + TableViewer projectViewer = new TableViewer(projectTable); + projectViewer.setContentProvider(new TmfNavigatorContentProvider() { + + @Override + public Object[] getElements(Object inputElement) { + return (IProject[]) inputElement; + } + }); + projectViewer.setLabelProvider(new WorkbenchLabelProvider()); + projectViewer.setInput(TraceUtils.getOpenedTmfProjects().toArray(new IProject[] {})); + + fTraceTable = new Table(projectSelectionGroup, SWT.BORDER | SWT.CHECK); + fTraceTable.setLayoutData(new GridData(GridData.FILL_BOTH)); + + final TableViewer traceViewer = new TableViewer(fTraceTable); + traceViewer.setContentProvider(new IStructuredContentProvider() { + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + @Override + public void dispose() { + } + + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof TmfTraceElement[]) { + return (TmfTraceElement[]) inputElement; + } + return null; + } + }); + traceViewer.setLabelProvider(new ExportLabelProvider()); + fTraceTable.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + getWizard().getContainer().updateButtons(); + updateNextPageData(); + } + }); + + projectTable.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TableItem[] items = projectTable.getSelection(); + fSelectedProject = (IProject) items[0].getData(); + + TmfProjectElement project = TmfProjectRegistry.getProject(fSelectedProject, true); + + TmfTraceFolder tracesFolder = project.getTracesFolder(); + List<TmfTraceElement> traces = tracesFolder.getTraces(); + TmfTraceElement[] array = traces.toArray(new TmfTraceElement[] {}); + traceViewer.setInput(array); + traceViewer.refresh(); + fTraceTable.select(0); + fTraceTable.notifyListeners(SWT.Selection, new Event()); + getWizard().getContainer().updateButtons(); + } + }); + + Composite btComp = new Composite(projectSelectionGroup, SWT.NONE); + btComp.setLayout(new GridLayout(2, true)); + GridData gd = new GridData(); + gd.horizontalSpan = 2; + gd.horizontalAlignment = SWT.RIGHT; + btComp.setLayoutData(gd); + + final Button selectAll = new Button(btComp, SWT.PUSH); + selectAll.setText(org.eclipse.tracecompass.internal.tmf.ui.project.dialogs.Messages.Dialog_SelectAll); + selectAll.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TableItem[] items = fTraceTable.getItems(); + for (TableItem item : items) { + item.setChecked(true); + } + + getWizard().getContainer().updateButtons(); + updateNextPageData(); + } + }); + + final Button deselectAll = new Button(btComp, SWT.PUSH); + deselectAll.setText(org.eclipse.tracecompass.internal.tmf.ui.project.dialogs.Messages.Dialog_DeselectAll); + deselectAll.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + TableItem[] items = fTraceTable.getItems(); + for (TableItem item : items) { + item.setChecked(false); + } + + getWizard().getContainer().updateButtons(); + updateNextPageData(); + } + }); + + setControl(projectSelectionGroup); + setTitle(Messages.ExportTracePackageWizardPage_Title); + setMessage(Messages.ExportTracePackageSelectTraceWizardPage_ChooseTrace); + } + + private ArrayList<TmfTraceElement> getCheckedTraces() { + TableItem[] items = fTraceTable.getItems(); + ArrayList<TmfTraceElement> traces = new ArrayList<>(); + for (TableItem item : items) { + if (item.getChecked()) { + TmfTraceElement trace = (TmfTraceElement) item.getData(); + traces.add(trace); + } + } + return traces; + } + + private void updateNextPageData() { + ExportTracePackageWizardPage page = (ExportTracePackageWizardPage) getWizard().getPage(ExportTracePackageWizardPage.PAGE_NAME); + page.setSelectedTraces(getCheckedTraces()); + } + + @Override + public boolean canFlipToNextPage() { + return getCheckedTraces().size() > 0; + } + + private class ExportLabelProvider extends TmfNavigatorLabelProvider { + @Override + public String getText(Object element) { + + if (element instanceof TmfTraceElement) { + TmfTraceElement folder = (TmfTraceElement) element; + return folder.getElementPath(); + } + return super.getText(element); + } + } + + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ExportTracePackageWizard.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ExportTracePackageWizard.java new file mode 100644 index 0000000000..512ac49e6c --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ExportTracePackageWizard.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.ui.IExportWizard; +import org.eclipse.ui.IWorkbench; + +/** + * Wizard for exporting a trace package + * + * @author Marc-Andre Laperle + */ +public class ExportTracePackageWizard extends Wizard implements IExportWizard { + + private static final String STORE_EXPORT_TRACE_WIZARD = "ExportTraceWizard"; //$NON-NLS-1$ + private IStructuredSelection fSelection; + private List<TmfTraceElement> fSelectedTraces; + private ExportTracePackageWizardPage fPage; + + /** + * Constructor for the export trace wizard + */ + public ExportTracePackageWizard() { + IDialogSettings workbenchSettings = Activator.getDefault().getDialogSettings(); + IDialogSettings section = workbenchSettings + .getSection(STORE_EXPORT_TRACE_WIZARD); + if (section == null) { + section = workbenchSettings.addNewSection(STORE_EXPORT_TRACE_WIZARD); + } + setDialogSettings(section); + fSelectedTraces = new ArrayList<>(); + } + + /** + * Constructor for the export trace wizard with known selected traces + * + * @param selectedTraces + * the selected traces + */ + public ExportTracePackageWizard(List<TmfTraceElement> selectedTraces) { + this(); + fSelectedTraces = selectedTraces; + } + + @Override + public void init(IWorkbench workbench, IStructuredSelection selection) { + fSelection = selection; + + setNeedsProgressMonitor(true); + } + + @Override + public boolean performFinish() { + return fPage.finish(); + } + + @Override + public void addPages() { + super.addPages(); + fPage = new ExportTracePackageWizardPage(fSelection, fSelectedTraces); + if (fSelectedTraces.isEmpty()) { + addPage(new ExportTracePackageSelectTraceWizardPage()); + } + addPage(fPage); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ExportTracePackageWizardPage.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ExportTracePackageWizardPage.java new file mode 100644 index 0000000000..e39508b42b --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ExportTracePackageWizardPage.java @@ -0,0 +1,450 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.TreeViewerColumn; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.AbstractTracePackageWizardPage; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageBookmarkElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageFilesElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageLabelProvider; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageSupplFileElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageSupplFilesElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageTraceElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; + +/** + * Wizard page for the export trace package wizard + * + * @author Marc-Andre Laperle + */ +public class ExportTracePackageWizardPage extends AbstractTracePackageWizardPage { + + private static final int CONTENT_COL_WIDTH = 300; + private static final int SIZE_COL_WIDTH = 100; + + private static final String ZIP_EXTENSION = ".zip"; //$NON-NLS-1$ + private static final String TAR_EXTENSION = ".tar"; //$NON-NLS-1$ + private static final String TAR_GZ_EXTENSION = ".tar.gz"; //$NON-NLS-1$ + private static final String TGZ_EXTENSION = ".tgz"; //$NON-NLS-1$ + + private static final String ICON_PATH = "icons/wizban/export_wiz.png"; //$NON-NLS-1$ + + /** + * The page name, can be referenced from other pages + */ + public static final String PAGE_NAME = "ExportTracePackageWizardPage"; //$NON-NLS-1$ + // dialog store id constants + private static final String STORE_COMPRESS_CONTENTS_ID = PAGE_NAME + ".STORE_COMPRESS_CONTENTS_ID"; //$NON-NLS-1$ + private static final String STORE_FORMAT_ID = PAGE_NAME + ".STORE_FORMAT_ID"; //$NON-NLS-1$ + + private Button fCompressContentsCheckbox; + private Button fZipFormatButton; + private Button fTargzFormatButton; + private Label fApproximateSizeLabel; + private List<TmfTraceElement> fSelectedTraces; + + /** + * Constructor for the export trace package wizard page + * + * @param selection + * the current object selection + * @param selectedTraces + * the selected traces from the selection + */ + public ExportTracePackageWizardPage(IStructuredSelection selection, List<TmfTraceElement> selectedTraces) { + super(PAGE_NAME, Messages.ExportTracePackageWizardPage_Title, Activator.getDefault().getImageDescripterFromPath(ICON_PATH), selection); + fSelectedTraces = selectedTraces; + } + + /** + * Set the selected trace from the previous page to be displayed in the + * element viewer + * + * @param selectedTraces + * the selected trace + */ + public void setSelectedTraces(List<TmfTraceElement> selectedTraces) { + if (!fSelectedTraces.containsAll(selectedTraces) || !selectedTraces.containsAll(fSelectedTraces)) { + fSelectedTraces = selectedTraces; + CheckboxTreeViewer elementViewer = getElementViewer(); + elementViewer.setInput(createElementViewerInput()); + elementViewer.expandToLevel(2); + setAllChecked(elementViewer, false, true); + updateApproximateSelectedSize(); + } + } + + @Override + public void createControl(Composite parent) { + + initializeDialogUnits(parent); + + Composite composite = new Composite(parent, SWT.NULL); + composite.setLayout(new GridLayout()); + composite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_FILL)); + + createElementViewer(composite); + createButtonsGroup(composite); + createFilePathGroup(composite, Messages.ExportTracePackageWizardPage_ToArchive, SWT.SAVE); + createOptionsGroup(composite); + + restoreWidgetValues(); + setMessage(Messages.ExportTracePackageWizardPage_ChooseContent); + + updateApproximateSelectedSize(); + updatePageCompletion(); + + setControl(composite); + } + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + if (visible) { + updatePageCompletion(); + } else { + setPageComplete(false); + } + } + + /** + * Restore widget values to the values that they held last time this wizard + * was used to completion. + */ + @Override + protected void restoreWidgetValues() { + super.restoreWidgetValues(); + + IDialogSettings settings = getDialogSettings(); + if (settings != null) { + if (getFilePathCombo().getItemCount() > 0) { + String item = getFilePathCombo().getItem(0); + setFilePathValue(item); + } + fCompressContentsCheckbox.setSelection(settings.getBoolean(STORE_COMPRESS_CONTENTS_ID)); + fZipFormatButton.setSelection(settings.getBoolean(STORE_FORMAT_ID)); + fTargzFormatButton.setSelection(!settings.getBoolean(STORE_FORMAT_ID)); + updateWithFilePathSelection(); + } + } + + @Override + protected void createFilePathGroup(Composite parent, String label, int fileDialogStyle) { + super.createFilePathGroup(parent, label, fileDialogStyle); + + getFilePathCombo().addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + updatePageCompletion(); + } + }); + } + + private void createOptionsGroup(Composite parent) { + Group optionsGroup = new Group(parent, SWT.NONE); + optionsGroup.setLayout(new RowLayout(SWT.VERTICAL)); + optionsGroup.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL + | GridData.GRAB_HORIZONTAL)); + optionsGroup.setText(Messages.ExportTracePackageWizardPage_Options); + + SelectionAdapter listener = new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateWithFilePathSelection(); + } + }; + + fZipFormatButton = new Button(optionsGroup, SWT.RADIO | SWT.LEFT); + fZipFormatButton.setText(Messages.ExportTracePackageWizardPage_SaveInZipFormat); + fZipFormatButton.setSelection(true); + fZipFormatButton.addSelectionListener(listener); + + fTargzFormatButton = new Button(optionsGroup, SWT.RADIO | SWT.LEFT); + fTargzFormatButton.setText(Messages.ExportTracePackageWizardPage_SaveInTarFormat); + fTargzFormatButton.setSelection(false); + fTargzFormatButton.addSelectionListener(listener); + + fCompressContentsCheckbox = new Button(optionsGroup, SWT.CHECK | SWT.LEFT); + fCompressContentsCheckbox.setText(Messages.ExportTracePackageWizardPage_CompressContents); + fCompressContentsCheckbox.setSelection(true); + fCompressContentsCheckbox.addSelectionListener(listener); + } + + @Override + protected void createElementViewer(Composite parent) { + super.createElementViewer(parent); + + CheckboxTreeViewer elementViewer = getElementViewer(); + elementViewer.getTree().setHeaderVisible(true); + // Content column + TreeViewerColumn column = new TreeViewerColumn(elementViewer, SWT.NONE); + column.getColumn().setWidth(CONTENT_COL_WIDTH); + column.getColumn().setText(Messages.ExportTracePackageWizardPage_ContentColumnName); + column.setLabelProvider(new TracePackageLabelProvider()); + + // Size column + column = new TreeViewerColumn(elementViewer, SWT.NONE); + column.getColumn().setWidth(SIZE_COL_WIDTH); + column.getColumn().setText(Messages.ExportTracePackageWizardPage_SizeColumnName); + column.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + TracePackageElement tracePackageElement = (TracePackageElement) element; + long size = tracePackageElement.getSize(false); + if (size == 0) { + return null; + } + int level = 0; + TracePackageElement curElement = tracePackageElement.getParent(); + while (curElement != null) { + curElement = curElement.getParent(); + ++level; + } + + return indent(getHumanReadable(size), level); + } + + private String indent(String humanReadable, int level) { + StringBuilder s = new StringBuilder(humanReadable); + for (int i = 0; i < level; ++i) { + final String indentStr = " "; //$NON-NLS-1$ + s.insert(0, indentStr); + } + return s.toString(); + } + }); + + elementViewer.setInput(createElementViewerInput()); + elementViewer.expandToLevel(2); + setAllChecked(elementViewer, false, true); + } + + @Override + protected void updateApproximateSelectedSize() { + long checkedSize = 0; + TracePackageElement[] tracePackageElements = (TracePackageElement[]) getElementViewer().getInput(); + for (TracePackageElement element : tracePackageElements) { + checkedSize += element.getSize(true); + } + checkedSize = Math.max(0, checkedSize); + fApproximateSizeLabel.setText(MessageFormat.format(Messages.ExportTracePackageWizardPage_ApproximateSizeLbl, getHumanReadable(checkedSize))); + } + + /** + * Get the human readable string for a size in bytes. (KB, MB, etc). + * + * @param size + * the size to print in human readable, + * @return the human readable string + */ + private static String getHumanReadable(long size) { + String humanSuffix[] = { Messages.ExportTracePackageWizardPage_SizeByte, Messages.ExportTracePackageWizardPage_SizeKilobyte, + Messages.ExportTracePackageWizardPage_SizeMegabyte, Messages.ExportTracePackageWizardPage_SizeGigabyte, + Messages.ExportTracePackageWizardPage_SizeTerabyte }; + long curSize = size; + + int suffixIndex = 0; + while (curSize >= 1024) { + curSize /= 1024; + ++suffixIndex; + } + + return Long.toString(curSize) + " " + humanSuffix[suffixIndex]; //$NON-NLS-1$ + } + + @Override + protected Object createElementViewerInput() { + List<TracePackageTraceElement> traceElements = new ArrayList<>(); + for (TmfTraceElement tmfTraceElement : fSelectedTraces) { + TracePackageTraceElement traceElement = new TracePackageTraceElement(null, tmfTraceElement); + + // Trace files + List<TracePackageElement> children = new ArrayList<>(); + TracePackageFilesElement filesElement = new TracePackageFilesElement(traceElement, tmfTraceElement.getResource()); + filesElement.setChecked(true); + children.add(filesElement); + + // Supplementary files + IResource[] supplementaryResources = tmfTraceElement.getSupplementaryResources(); + List<TracePackageElement> suppFilesChildren = new ArrayList<>(); + TracePackageSupplFilesElement suppFilesElement = new TracePackageSupplFilesElement(traceElement); + children.add(suppFilesElement); + for (IResource res : supplementaryResources) { + suppFilesChildren.add(new TracePackageSupplFileElement(res, suppFilesElement)); + } + + // Bookmarks + IFile bookmarksFile = tmfTraceElement.getBookmarksFile(); + if (bookmarksFile != null && bookmarksFile.exists()) { + IMarker[] findMarkers; + try { + findMarkers = bookmarksFile.findMarkers(IMarker.BOOKMARK, false, IResource.DEPTH_ZERO); + if (findMarkers.length > 0) { + children.add(new TracePackageBookmarkElement(traceElement, null)); + } + } catch (CoreException e) { + // Should not happen since we just checked bookmarksFile.exists() but log it just in case + Activator.getDefault().logError("Error finding bookmarks", e); //$NON-NLS-1$ + } + } + + traceElements.add(traceElement); + + } + + return traceElements.toArray(new TracePackageTraceElement[] {}); + } + + @Override + protected final Composite createButtonsGroup(Composite parent) { + Composite buttonGroup = super.createButtonsGroup(parent); + + // Add the label on the same row of the select/deselect all buttons + fApproximateSizeLabel = new Label(buttonGroup, SWT.RIGHT); + GridData layoutData = new GridData(GridData.FILL_HORIZONTAL); + layoutData.grabExcessHorizontalSpace = true; + fApproximateSizeLabel.setLayoutData(layoutData); + + return buttonGroup; + } + + /** + * Save widget values to Dialog settings + */ + @Override + protected void saveWidgetValues() { + super.saveWidgetValues(); + + IDialogSettings settings = getDialogSettings(); + if (settings != null) { + settings.put(STORE_COMPRESS_CONTENTS_ID, fCompressContentsCheckbox.getSelection()); + settings.put(STORE_FORMAT_ID, fZipFormatButton.getSelection()); + } + } + + private String getOutputExtension() { + if (fZipFormatButton.getSelection()) { + return ZIP_EXTENSION; + } else if (fCompressContentsCheckbox.getSelection()) { + return TAR_GZ_EXTENSION; + } else { + return TAR_EXTENSION; + } + } + + @Override + protected void updateWithFilePathSelection() { + String filePathValue = getFilePathValue(); + if (filePathValue.isEmpty()) { + return; + } + + filePathValue = stripKnownExtension(filePathValue); + filePathValue = filePathValue.concat(getOutputExtension()); + + setFilePathValue(filePathValue); + } + + private static String stripKnownExtension(String str) { + String ret = str; + if (str.endsWith(TAR_GZ_EXTENSION)) { + ret = ret.substring(0, ret.lastIndexOf('.')); + } + + if (ret.endsWith(ZIP_EXTENSION) || ret.endsWith(TAR_EXTENSION) || ret.endsWith(TGZ_EXTENSION)) { + ret = ret.substring(0, ret.lastIndexOf('.')); + } + + return ret; + } + + /** + * Finish the wizard page + * + * @return true on success + */ + public boolean finish() { + if (!checkForOverwrite()) { + return false; + } + + saveWidgetValues(); + + TracePackageTraceElement[] traceExportElements = (TracePackageTraceElement[]) getElementViewer().getInput(); + boolean useCompression = fCompressContentsCheckbox.getSelection(); + boolean useTar = fTargzFormatButton.getSelection(); + String fileName = getFilePathValue(); + final TracePackageExportOperation exporter = new TracePackageExportOperation(traceExportElements, useCompression, useTar, fileName); + + try { + getContainer().run(true, true, new IRunnableWithProgress() { + + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + exporter.run(monitor); + } + }); + + IStatus status = exporter.getStatus(); + if (status.getSeverity() == IStatus.ERROR) { + handleErrorStatus(status); + } + + } catch (InvocationTargetException e) { + handleError(org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorOperation, e); + } catch (InterruptedException e) { + } + + return exporter.getStatus().getSeverity() == IStatus.OK; + } + + private boolean checkForOverwrite() { + File file = new File(getFilePathValue()); + if (file.exists()) { + return MessageDialog.openQuestion(getContainer().getShell(), null, Messages.ExportTracePackageWizardPage_AlreadyExitst); + } + return true; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ImportTracePackageHandler.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ImportTracePackageHandler.java new file mode 100644 index 0000000000..e8c96ed3f4 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ImportTracePackageHandler.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Handler for importing a trace package + * + * @author Marc-Andre Laperle + */ +public class ImportTracePackageHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ImportTracePackageWizard w = new ImportTracePackageWizard(); + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + + if (window == null) { + return Boolean.FALSE; + } + + ISelection currentSelection = HandlerUtil.getCurrentSelection(event); + IStructuredSelection sec = StructuredSelection.EMPTY; + if (currentSelection instanceof IStructuredSelection) { + sec = (IStructuredSelection) currentSelection; + } + + w.init(PlatformUI.getWorkbench(), sec); + WizardDialog dialog = new WizardDialog(window.getShell(), w); + dialog.open(); + return null; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ImportTracePackageWizard.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ImportTracePackageWizard.java new file mode 100644 index 0000000000..6662a18c0c --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ImportTracePackageWizard.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport; + +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.ui.IImportWizard; +import org.eclipse.ui.IWorkbench; + +/** + * Wizard for importing a trace package + * + * @author Marc-Andre Laperle + */ +public class ImportTracePackageWizard extends Wizard implements IImportWizard { + + private static final String STORE_IMPORT_TRACE_PKG_WIZARD = "ImportTracePackageWizard"; //$NON-NLS-1$ + private IStructuredSelection fSelection; + private ImportTracePackageWizardPage fPage; + + /** + * Constructs the import trace package wizard + */ + public ImportTracePackageWizard() { + IDialogSettings workbenchSettings = Activator.getDefault().getDialogSettings(); + IDialogSettings section = workbenchSettings + .getSection(STORE_IMPORT_TRACE_PKG_WIZARD); + if (section == null) { + section = workbenchSettings.addNewSection(STORE_IMPORT_TRACE_PKG_WIZARD); + } + setDialogSettings(section); + } + + @Override + public void init(IWorkbench workbench, IStructuredSelection selection) { + fSelection = selection; + setNeedsProgressMonitor(true); + } + + @Override + public boolean performFinish() { + return fPage.finish(); + } + + @Override + public void addPages() { + super.addPages(); + fPage = new ImportTracePackageWizardPage(fSelection); + addPage(fPage); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ImportTracePackageWizardPage.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ImportTracePackageWizardPage.java new file mode 100644 index 0000000000..561ea43ce2 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ImportTracePackageWizardPage.java @@ -0,0 +1,417 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.TraverseEvent; +import org.eclipse.swt.events.TraverseListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.AbstractTracePackageOperation; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.AbstractTracePackageWizardPage; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageFilesElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageTraceElement; +import org.eclipse.tracecompass.tmf.core.TmfCommonConstants; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; +import org.eclipse.tracecompass.tmf.ui.project.model.TraceUtils; +import org.eclipse.ui.dialogs.ElementListSelectionDialog; +import org.eclipse.ui.model.WorkbenchLabelProvider; + +/** + * Wizard page for the import trace package wizard + * + * @author Marc-Andre Laperle + */ +public class ImportTracePackageWizardPage extends AbstractTracePackageWizardPage { + + private static final String ICON_PATH = "icons/wizban/trace_import_wiz.png"; //$NON-NLS-1$ + private static final String PAGE_NAME = "ImportTracePackagePage"; //$NON-NLS-1$ + private static final String STORE_PROJECT_NAME_ID = PAGE_NAME + ".STORE_PROJECT_NAME_ID"; //$NON-NLS-1$ + + private String fValidatedFilePath; + private TmfTraceFolder fTmfTraceFolder; + private Text fProjectText; + private List<IProject> fOpenedTmfProjects; + + /** + * Constructor for the import trace package wizard page + * + * @param selection + * the current object selection + */ + public ImportTracePackageWizardPage(IStructuredSelection selection) { + super(PAGE_NAME, Messages.ImportTracePackageWizardPage_Title, Activator.getDefault().getImageDescripterFromPath(ICON_PATH), selection); + + if (getSelection().getFirstElement() instanceof TmfTraceFolder) { + fTmfTraceFolder = (TmfTraceFolder) getSelection().getFirstElement(); + } + } + + @Override + public void createControl(Composite parent) { + initializeDialogUnits(parent); + + Composite composite = new Composite(parent, SWT.NULL); + composite.setLayout(new GridLayout()); + composite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL + | GridData.HORIZONTAL_ALIGN_FILL)); + composite.setFont(parent.getFont()); + + createFilePathGroup(composite, Messages.ImportTracePackageWizardPage_FromArchive, SWT.OPEN); + createElementViewer(composite); + createButtonsGroup(composite); + if (fTmfTraceFolder == null) { + createProjectSelectionGroup(composite); + } + + restoreWidgetValues(); + setMessage(Messages.ImportTracePackageWizardPage_Message); + updatePageCompletion(); + + setControl(composite); + } + + private void createProjectSelectionGroup(Composite parent) { + + Composite projectSelectionGroup = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + projectSelectionGroup.setLayout(layout); + projectSelectionGroup.setLayoutData(new GridData( + GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL)); + + Label projectLabel = new Label(projectSelectionGroup, SWT.NONE); + projectLabel.setText(Messages.ImportTracePackageWizardPage_Project); + + fProjectText = new Text(projectSelectionGroup, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY); + GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL + | GridData.GRAB_HORIZONTAL); + data.grabExcessHorizontalSpace = true; + fProjectText.setLayoutData(data); + + fOpenedTmfProjects = TraceUtils.getOpenedTmfProjects(); + + // No project to import to, create a default project if it doesn't exist + if (fOpenedTmfProjects.isEmpty()) { + IProject defaultProject = ResourcesPlugin.getWorkspace().getRoot().getProject(TmfCommonConstants.DEFAULT_TRACE_PROJECT_NAME); + if (!defaultProject.exists()) { + IProject project = TmfProjectRegistry.createProject(TmfCommonConstants.DEFAULT_TRACE_PROJECT_NAME, null, null); + fOpenedTmfProjects.add(project); + } + } + + if (!fOpenedTmfProjects.isEmpty()) { + selectProject(fOpenedTmfProjects.get(0)); + } + + Button button = new Button(projectSelectionGroup, + SWT.PUSH); + button.setText(Messages.ImportTracePackageWizardPage_SelectProjectButton); + button.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + ElementListSelectionDialog d = new ElementListSelectionDialog(getContainer().getShell(), new WorkbenchLabelProvider()); + + d.setBlockOnOpen(true); + d.setTitle(Messages.ImportTracePackageWizardPage_SelectProjectDialogTitle); + + d.setElements(fOpenedTmfProjects.toArray(new IProject[] {})); + + d.open(); + if (d.getFirstResult() != null) { + IProject project = (IProject) d.getFirstResult(); + selectProject(project); + } + } + }); + setButtonLayoutData(button); + } + + @Override + protected void restoreWidgetValues() { + super.restoreWidgetValues(); + IDialogSettings settings = getDialogSettings(); + if (settings != null && fProjectText != null) { + + // Restore last selected project + String projectName = settings.get(STORE_PROJECT_NAME_ID); + if (projectName != null && !projectName.isEmpty()) { + for (IProject project : fOpenedTmfProjects) { + if (project.getName().equals(projectName)) { + selectProject(project); + break; + } + } + } + } + } + + @Override + protected void saveWidgetValues() { + super.saveWidgetValues(); + + IDialogSettings settings = getDialogSettings(); + if (settings != null) { + settings.put(STORE_PROJECT_NAME_ID, fTmfTraceFolder.getProject().getResource().getName()); + } + } + + private void selectProject(IProject project) { + fProjectText.setText(project.getName()); + fTmfTraceFolder = TmfProjectRegistry.getProject(project, true).getTracesFolder(); + updatePageCompletion(); + } + + @Override + protected boolean determinePageCompletion() { + return super.determinePageCompletion() && fTmfTraceFolder != null; + } + + /** + * Create the operation that will be responsible of creating the manifest + * based on the file name. + * + * @param fileName the file name to generate the manifest from + * + * @return the operation that will extract the manifest + */ + protected AbstractTracePackageOperation createExtractManifestOperation(String fileName) { + return new TracePackageExtractManifestOperation(fileName); + } + + @Override + protected Object createElementViewerInput() { + + final AbstractTracePackageOperation op = createExtractManifestOperation(getFilePathValue()); + + try { + getContainer().run(true, true, new IRunnableWithProgress() { + + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + monitor.beginTask(Messages.ImportTracePackageWizardPage_ReadingPackage, 10); + op.run(monitor); + monitor.done(); + } + + }); + + IStatus status = op.getStatus(); + if (status.getSeverity() == IStatus.ERROR) { + handleErrorStatus(status); + } + } catch (InvocationTargetException e1) { + handleError(Messages.TracePackageExtractManifestOperation_ErrorReadingManifest, e1); + } catch (InterruptedException e1) { + // Canceled + } + + TracePackageElement[] resultElements = op.getResultElements(); + if (resultElements == null || resultElements.length == 0) { + return null; + } + + return resultElements; + } + + @Override + protected void createFilePathGroup(Composite parent, String label, int fileDialogStyle) { + super.createFilePathGroup(parent, label, fileDialogStyle); + + Combo filePathCombo = getFilePathCombo(); + filePathCombo.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateWithFilePathSelection(); + } + }); + + // User can type-in path and press return to validate + filePathCombo.addTraverseListener(new TraverseListener() { + @Override + public void keyTraversed(TraverseEvent e) { + if (e.detail == SWT.TRAVERSE_RETURN) { + e.doit = false; + updateWithFilePathSelection(); + } + } + }); + } + + @Override + protected void updateWithFilePathSelection() { + if (!isFilePathValid()) { + setErrorMessage(Messages.ImportTracePackageWizardPage_ErrorFileNotFound); + getElementViewer().setInput(null); + return; + } + setErrorMessage(null); + + getContainer().getShell().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + CheckboxTreeViewer elementViewer = getElementViewer(); + Object elementViewerInput = createElementViewerInput(); + elementViewer.setInput(elementViewerInput); + if (elementViewerInput != null) { + elementViewer.expandToLevel(2); + setAllChecked(elementViewer, false, true); + fValidatedFilePath = getFilePathValue(); + } + + updatePageCompletion(); + } + }); + } + + private boolean isFilePathValid() { + return new File(getFilePathValue()).exists(); + } + + /** + * Finish the wizard page + * + * @return true on success + */ + public boolean finish() { + if (!checkForOverwrite()) { + return false; + } + + saveWidgetValues(); + + Object input = getElementViewer().getInput(); + TracePackageElement[] traceElements = (TracePackageElement[]) input; + final TracePackageImportOperation importOperation = new TracePackageImportOperation(fValidatedFilePath, traceElements, fTmfTraceFolder); + + try { + getContainer().run(true, true, new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + importOperation.run(monitor); + } + }); + + IStatus status = importOperation.getStatus(); + if (status.getSeverity() == IStatus.ERROR) { + handleErrorStatus(status); + } + + } catch (InvocationTargetException e) { + handleError(Messages.ImportTracePackageWizardPage_ErrorOperation, e); + } catch (InterruptedException e) { + } + + return importOperation.getStatus().getSeverity() == IStatus.OK; + } + + private boolean checkForOverwrite() { + TracePackageElement[] traceElements = (TracePackageElement[]) getElementViewer().getInput(); + List<TracePackageTraceElement> noImportTraces = new ArrayList<>(); + boolean noToAll = false; + for (TracePackageElement packageElement : traceElements) { + TracePackageTraceElement traceElement = (TracePackageTraceElement) packageElement; + if (!AbstractTracePackageOperation.isFilesChecked(traceElement)) { + continue; + } + + if (noToAll) { + noImportTraces.add(traceElement); + continue; + } + + if (traceExists(traceElement)) { + int returnCode = promptForOverwrite(traceElement.getDestinationElementPath()); + // The return code is an index to a button in the dialog but the + // 'X' button in the window corner is not considered a button + // therefore it returns -1 and unfortunately, there is no + // constant for that. + if (returnCode < 0) { + return false; + } + + final String[] response = new String[] { IDialogConstants.NO_TO_ALL_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.YES_TO_ALL_LABEL, IDialogConstants.YES_LABEL }; + if (response[returnCode].equals(IDialogConstants.YES_TO_ALL_LABEL)) { + break; + } else if (response[returnCode].equals(IDialogConstants.NO_TO_ALL_LABEL)) { + noToAll = true; + noImportTraces.add(traceElement); + } else if (response[returnCode].equals(IDialogConstants.NO_LABEL)) { + noImportTraces.add(traceElement); + } + } + } + + // Unselect the traces that the user decided not to import + for (TracePackageTraceElement t : noImportTraces) { + for (TracePackageElement e : t.getChildren()) { + if (e instanceof TracePackageFilesElement) { + ((TracePackageFilesElement) e).setChecked(false); + } + } + } + + return true; + } + + private boolean traceExists(TracePackageTraceElement traceElement) { + IResource traceRes = fTmfTraceFolder.getResource().findMember(traceElement.getDestinationElementPath()); + return traceRes != null; + } + + private int promptForOverwrite(String traceName) { + final MessageDialog dialog = new MessageDialog(getContainer() + .getShell(), null, null, MessageFormat.format(Messages.ImportTracePackageWizardPage_AlreadyExists, traceName), + MessageDialog.QUESTION, new String[] { + IDialogConstants.NO_TO_ALL_LABEL, + IDialogConstants.NO_LABEL, + IDialogConstants.YES_TO_ALL_LABEL, + IDialogConstants.YES_LABEL, + }, 3) { + @Override + protected int getShellStyle() { + return super.getShellStyle() | SWT.SHEET; + } + }; + return dialog.open(); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ManifestReader.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ManifestReader.java new file mode 100644 index 0000000000..3deb4ba1de --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/ManifestReader.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.ITracePackageConstants; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageBookmarkElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageFilesElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageSupplFileElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageSupplFilesElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageTraceElement; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +/** + * Reads a manifest from an input stream + * + * @author Marc-Andre Laperle + */ +public class ManifestReader { + + private static final String SCHEMA_FOLDER_NAME = "schema"; //$NON-NLS-1$ + private static final String EXPORT_MANIFEST_SCHEMA_FILE_NAME = "export-manifest.xsd"; //$NON-NLS-1$ + private static final TracePackageElement [] EMPTY_ARRAY = new TracePackageElement[0]; + + /** + * Validate the content of a manifest from an input stream + * + * @param input the input stream to validate from + * @throws IOException on error + */ + public static void validateManifest(InputStream input) throws IOException + { + URL schemaFileUrl = FileLocator.find(Activator.getDefault().getBundle(), new Path(SCHEMA_FOLDER_NAME).append(EXPORT_MANIFEST_SCHEMA_FILE_NAME), null); + if (schemaFileUrl == null) { + throw new IOException(MessageFormat.format(Messages.TracePackageExtractManifestOperation_SchemaFileNotFound, EXPORT_MANIFEST_SCHEMA_FILE_NAME)); + } + + try { + SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema = factory.newSchema(new StreamSource(schemaFileUrl.openStream())); + Validator validator = schema.newValidator(); + validator.validate(new StreamSource(input)); + } catch (SAXException e) { + throw new IOException(Messages.TracePackageExtractManifestOperation_ErrorManifestNotValid, e); + } catch (IOException e) { + throw new IOException(Messages.TracePackageExtractManifestOperation_ErrorManifestNotValid, e); + } + } + + /** + * Load package elements from a manifest (input stream) + * + * The manifest looks like this: + * + * <?xml version="1.0" encoding="UTF-8" standalone="no"?> + * <tmf-export> + * <trace name="trace2" type="org.eclipse.linuxtools.lttng2.kernel.tracetype"> + * <file name="Traces/trace2"/> <supplementary-file name=".tracing/trace2/stateHistory.ht"/> + * <bookmarks> + * <bookmark location="4" message= "15:50:47.314 069 885, channel0_0, sys_recvmsg, fd=16, msg=0x7faada7d1ae0, flags=256" /> + * </bookmarks> + * </trace> + * </tmf-export> + * + * See schema/export-manifest.xsd for details. + * + * @param inputStream + * the input stream that contains the manifest + * @return the loaded elements + * @throws IOException + * when an error occurs when parsing + * @throws SAXException + * when an error occurs when parsing + * @throws ParserConfigurationException + * when an error occurs when parsing + */ + public static TracePackageElement[] loadElementsFromManifest(InputStream inputStream) throws IOException, SAXException, ParserConfigurationException { + Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream); + Element rootElement = doc.getDocumentElement(); + return loadElementsFromNode(rootElement); + } + + /** + * Load package elements from a manifest (XML element) + * + * @param rootElement + * the root element to start loading from + * @return the loaded elements + */ + public static TracePackageElement[] loadElementsFromNode(Element rootElement) { + List<TracePackageElement> packageElements = new ArrayList<>(); + NodeList traceElements = rootElement.getElementsByTagName(ITracePackageConstants.TRACE_ELEMENT); + for (int i = 0; i < traceElements.getLength(); i++) { + Node traceNode = traceElements.item(i); + if (traceNode.getNodeType() == Node.ELEMENT_NODE) { + Element traceElement = (Element) traceNode; + String traceName = traceElement.getAttribute(ITracePackageConstants.TRACE_NAME_ATTRIB); + String traceType = traceElement.getAttribute(ITracePackageConstants.TRACE_TYPE_ATTRIB); + TracePackageElement element = new TracePackageTraceElement(null, traceName, traceType); + NodeList fileElements = traceElement.getElementsByTagName(ITracePackageConstants.TRACE_FILE_ELEMENT); + for (int j = 0; j < fileElements.getLength(); j++) { + Node fileNode = fileElements.item(j); + if (fileNode.getNodeType() == Node.ELEMENT_NODE) { + Element fileElement = (Element) fileNode; + String fileName = fileElement.getAttribute(ITracePackageConstants.TRACE_FILE_NAME_ATTRIB); + new TracePackageFilesElement(element, fileName); + } + } + + // Supplementary files + NodeList suppFilesElements = traceElement.getElementsByTagName(ITracePackageConstants.SUPPLEMENTARY_FILE_ELEMENT); + if (suppFilesElements.getLength() > 0) { + TracePackageSupplFilesElement supplFilesElement = new TracePackageSupplFilesElement(element); + for (int j = 0; j < suppFilesElements.getLength(); j++) { + Node suppFileNode = suppFilesElements.item(j); + if (suppFileNode.getNodeType() == Node.ELEMENT_NODE) { + Element suppFileElement = (Element) suppFileNode; + String fileName = suppFileElement.getAttribute(ITracePackageConstants.SUPPLEMENTARY_FILE_NAME_ATTRIB); + new TracePackageSupplFileElement(fileName, supplFilesElement); + } + } + } + + // bookmarks + List<Map<String, String>> bookmarkAttribs = new ArrayList<>(); + NodeList bookmarksElements = traceElement.getElementsByTagName(ITracePackageConstants.BOOKMARKS_ELEMENT); + for (int j = 0; j < bookmarksElements.getLength(); j++) { + Node bookmarksNode = bookmarksElements.item(j); + if (bookmarksNode.getNodeType() == Node.ELEMENT_NODE) { + NodeList bookmarkElements = traceElement.getElementsByTagName(ITracePackageConstants.BOOKMARK_ELEMENT); + for (int k = 0; k < bookmarkElements.getLength(); k++) { + Node bookmarkNode = bookmarkElements.item(k); + if (bookmarkNode.getNodeType() == Node.ELEMENT_NODE) { + Element bookmarkElement = (Element) bookmarkNode; + NamedNodeMap attributesMap = bookmarkElement.getAttributes(); + Map<String, String> attribs = new HashMap<>(); + for (int l = 0; l < attributesMap.getLength(); l++) { + Node item = attributesMap.item(l); + attribs.put(item.getNodeName(), item.getNodeValue()); + } + bookmarkAttribs.add(attribs); + } + } + } + } + if (!bookmarkAttribs.isEmpty()) { + new TracePackageBookmarkElement(element, bookmarkAttribs); + } + + packageElements.add(element); + } + } + return packageElements.toArray(EMPTY_ARRAY); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/Messages.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/Messages.java new file mode 100644 index 0000000000..684a8c53c9 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/Messages.java @@ -0,0 +1,239 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport; + +import org.eclipse.osgi.util.NLS; + +/** + * Messages for the trace package export wizard + * + * @author Marc-Andre Laperle + */ +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport.messages"; //$NON-NLS-1$ + + /** + * The message under the select trace wizard page title + */ + public static String ExportTracePackageSelectTraceWizardPage_ChooseTrace; + + /** + * The description of the project selection list + */ + public static String ExportTracePackageSelectTraceWizardPage_ProjectSelection; + + /** + * The description of the trace selection list + */ + public static String ExportTracePackageSelectTraceWizardPage_TraceSelection; + + /** + * Dialog text when target file already exists + */ + public static String ExportTracePackageWizardPage_AlreadyExitst; + + /** + * The approximate size label + */ + public static String ExportTracePackageWizardPage_ApproximateSizeLbl; + + /** + * The message under the wizard page title + */ + public static String ExportTracePackageWizardPage_ChooseContent; + + /** + * Text for the compress contents checkbox + */ + public static String ExportTracePackageWizardPage_CompressContents; + + /** + * Text for the first column (content) + */ + public static String ExportTracePackageWizardPage_ContentColumnName; + + /** + * Text for the options group + */ + public static String ExportTracePackageWizardPage_Options; + + /** + * Text for the tar format option + */ + public static String ExportTracePackageWizardPage_SaveInTarFormat; + + /** + * Text for the zip format option + */ + public static String ExportTracePackageWizardPage_SaveInZipFormat; + + /** + * Byte units + */ + public static String ExportTracePackageWizardPage_SizeByte; + + /** + * Text for the second column (size) + */ + public static String ExportTracePackageWizardPage_SizeColumnName; + + /** + * Gigabyte units + */ + public static String ExportTracePackageWizardPage_SizeGigabyte; + + /** + * Kilobyte units + */ + public static String ExportTracePackageWizardPage_SizeKilobyte; + + /** + * Megabyte units + */ + public static String ExportTracePackageWizardPage_SizeMegabyte; + + /** + * Terabyte units + */ + public static String ExportTracePackageWizardPage_SizeTerabyte; + + /** + * Title for the wizard page + */ + public static String ExportTracePackageWizardPage_Title; + + /** + * Label for the file path + */ + public static String ExportTracePackageWizardPage_ToArchive; + + /** + * Dialog text when a trace with the same name already exists + */ + public static String ImportTracePackageWizardPage_AlreadyExists; + + /** + * Title for the import page + */ + public static String ImportTracePackageWizardPage_Title; + + /** + * Text for the source archive label + */ + public static String ImportTracePackageWizardPage_FromArchive; + + /** + * Text for the reading package job + */ + public static String ImportTracePackageWizardPage_ReadingPackage; + + /** + * Message when file is not found + */ + public static String ImportTracePackageWizardPage_ErrorFileNotFound; + + /** + * Message when trace type could not be set + */ + public static String ImportTracePackageWizardPage_ErrorSettingTraceType; + + /** + * Message when the trace could not be found after importing the files + */ + public static String ImportTracePackageWizardPage_ErrorFindingImportedTrace; + + /** + * The message displayed under the title + */ + public static String ImportTracePackageWizardPage_Message; + + /** + * Generic error message for the import operation + */ + public static String ImportTracePackageWizardPage_ErrorOperation; + + /** + * Project text label + */ + public static String ImportTracePackageWizardPage_Project; + + /** + * The select project button text + */ + public static String ImportTracePackageWizardPage_SelectProjectButton; + + /** + * The select project dialog title + */ + public static String ImportTracePackageWizardPage_SelectProjectDialogTitle; + + /** + * Text for the generating package job + */ + public static String TracePackageExportOperation_GeneratingPackage; + + /** + * Text when error occurs creating a bookmark + */ + public static String TracePackageImportOperation_ErrorCreatingBookmark; + + /** + * Text for the detecting trace type job + */ + public static String TracePackageImportOperation_DetectingTraceType; + + /** + * Text when error occurs creating a bookmark file + */ + public static String TracePackageImportOperation_ErrorCreatingBookmarkFile; + + /** + * Text for the importing package job + */ + public static String TracePackageImportOperation_ImportingPackage; + + /** + * Text when error occurs when the manifest is not found in the archive + */ + public static String TracePackageExtractManifestOperation_ErrorManifestNotFound; + + /** + * Text when error occurs when the manifest is not valid + */ + public static String TracePackageExtractManifestOperation_ErrorManifestNotValid; + + /** + * Generic error message when reading the manifest + */ + public static String TracePackageExtractManifestOperation_ErrorReadingManifest; + + /** + * Error message when the file is an invalid format + */ + public static String TracePackageExtractManifestOperation_InvalidFormat; + + /** + * Error when the schema file cannot be found to validate the export + * manifest + */ + public static String TracePackageExtractManifestOperation_SchemaFileNotFound; + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/TracePackageExportOperation.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/TracePackageExportOperation.java new file mode 100644 index 0000000000..5170c32e9a --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/TracePackageExportOperation.java @@ -0,0 +1,302 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport; + +import java.io.ByteArrayInputStream; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.jface.operation.ModalContext; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.AbstractTracePackageOperation; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.ITracePackageConstants; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageBookmarkElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageFilesElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageSupplFileElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageSupplFilesElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageTraceElement; +import org.eclipse.tracecompass.tmf.core.TmfCommonConstants; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TraceUtils; +import org.eclipse.ui.internal.wizards.datatransfer.ArchiveFileExportOperation; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * An operation that exports a trace package to an archive + * + * @author Marc-Andre Laperle + */ +@SuppressWarnings("restriction") +public class TracePackageExportOperation extends AbstractTracePackageOperation { + + private static final String TRACE_EXPORT_TEMP_FOLDER = ".traceExport"; //$NON-NLS-1$ + + private final TracePackageTraceElement[] fTraceExportElements; + private final boolean fUseCompression; + private final boolean fUseTar; + private final Set<IResource> fResources; + private IFolder fExportFolder; + + /** + * Constructs a new export operation + * + * @param traceExportElements + * the trace elements to be exported + * @param useCompression + * whether or not to use compression + * @param useTar + * use tar format or zip + * @param fileName + * the output file name + */ + public TracePackageExportOperation(TracePackageTraceElement[] traceExportElements, boolean useCompression, boolean useTar, String fileName) { + super(fileName); + fTraceExportElements = traceExportElements; + fUseCompression = useCompression; + fUseTar = useTar; + fResources = new HashSet<>(); + } + + /** + * Run the operation. The status (result) of the operation can be obtained + * with {@link #getStatus} + * + * @param progressMonitor + * the progress monitor to use to display progress and receive + * requests for cancellation + */ + @Override + public void run(IProgressMonitor progressMonitor) { + + try { + int totalWork = getNbCheckedElements(fTraceExportElements) * 2; + progressMonitor.beginTask(Messages.TracePackageExportOperation_GeneratingPackage, totalWork); + + fExportFolder = createExportFolder(progressMonitor); + + Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + Element createElement = doc.createElement(ITracePackageConstants.TMF_EXPORT_ELEMENT); + Node tmfNode = doc.appendChild(createElement); + + for (TracePackageTraceElement tracePackageElement : fTraceExportElements) { + if (!isFilesChecked(tracePackageElement)) { + continue; + } + + exportTrace(progressMonitor, tmfNode, tracePackageElement); + } + + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); //$NON-NLS-1$ //$NON-NLS-2$ + DOMSource source = new DOMSource(doc); + StringWriter buffer = new StringWriter(); + StreamResult result = new StreamResult(buffer); + transformer.transform(source, result); + String content = buffer.getBuffer().toString(); + + ModalContext.checkCanceled(progressMonitor); + + exportManifest(content); + + setStatus(exportToArchive(progressMonitor, totalWork)); + + fExportFolder.delete(true, new SubProgressMonitor(progressMonitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + + progressMonitor.done(); + + } catch (InterruptedException e) { + setStatus(Status.CANCEL_STATUS); + } catch (Exception e) { + setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorOperation, e)); + } + } + + private IFolder createExportFolder(IProgressMonitor monitor) throws CoreException { + IFolder folder = fTraceExportElements[0].getTraceElement().getProject().getResource().getFolder(TRACE_EXPORT_TEMP_FOLDER); + if (folder.exists()) { + folder.delete(true, null); + } + folder.create(IResource.FORCE | IResource.HIDDEN, true, new SubProgressMonitor(monitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + return folder; + } + + private void exportTrace(IProgressMonitor monitor, Node tmfNode, TracePackageTraceElement tracePackageElement) throws InterruptedException, CoreException { + TmfTraceElement traceElement = tracePackageElement.getTraceElement(); + Element traceXmlElement = tmfNode.getOwnerDocument().createElement(ITracePackageConstants.TRACE_ELEMENT); + traceXmlElement.setAttribute(ITracePackageConstants.TRACE_NAME_ATTRIB, traceElement.getResource().getName()); + traceXmlElement.setAttribute(ITracePackageConstants.TRACE_TYPE_ATTRIB, traceElement.getTraceType()); + Node traceNode = tmfNode.appendChild(traceXmlElement); + + for (TracePackageElement element : tracePackageElement.getChildren()) { + ModalContext.checkCanceled(monitor); + if (!element.isChecked()) { + continue; + } + + if (element instanceof TracePackageSupplFilesElement) { + exportSupplementaryFiles(monitor, traceNode, traceElement, (TracePackageSupplFilesElement) element); + } else if (element instanceof TracePackageBookmarkElement) { + exportBookmarks(monitor, traceNode, (TracePackageBookmarkElement) element); + } else if (element instanceof TracePackageFilesElement) { + exportTraceFiles(monitor, traceNode, (TracePackageFilesElement) element); + } + + monitor.worked(1); + } + } + + private void exportSupplementaryFiles(IProgressMonitor monitor, Node traceNode, TmfTraceElement traceElement, TracePackageSupplFilesElement element) throws InterruptedException, CoreException { + Document doc = traceNode.getOwnerDocument(); + if (element.getChildren().length > 0) { + + IPath projectPath = traceElement.getProject().getPath(); + + for (TracePackageElement child : element.getChildren()) { + TracePackageSupplFileElement supplFile = (TracePackageSupplFileElement) child; + ModalContext.checkCanceled(monitor); + IResource res = supplFile.getResource(); + // project/.tracing/A/B/statistics.ht -> .tracing/A/B/statistics.ht + IPath relativeToExportFolder = res.getFullPath().makeRelativeTo(projectPath); + + // project/.traceExport/.tracing/A/B + IFolder folder = fExportFolder.getFolder(relativeToExportFolder.removeLastSegments(1)); + TraceUtils.createFolder(folder, new SubProgressMonitor(monitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + + res.refreshLocal(0, new SubProgressMonitor(monitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + createExportResource(folder, res); + Element suppFileElement = doc.createElement(ITracePackageConstants.SUPPLEMENTARY_FILE_ELEMENT); + + suppFileElement.setAttribute(ITracePackageConstants.SUPPLEMENTARY_FILE_NAME_ATTRIB, relativeToExportFolder.toString()); + traceNode.appendChild(suppFileElement); + } + + IFolder suppFilesFolder = fExportFolder.getFolder(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER_NAME); + fResources.add(suppFilesFolder); + } + } + + private void exportTraceFiles(IProgressMonitor monitor, Node traceNode, TracePackageFilesElement element) throws CoreException { + Document doc = traceNode.getOwnerDocument(); + TmfTraceElement traceElement = ((TracePackageTraceElement) element.getParent()).getTraceElement(); + IResource resource = traceElement.getResource(); + IPath traceFolderPath = traceElement.getProject().getTracesFolder().getPath(); + + // project/Traces/A/B/Kernel -> A/B/Kernel + IPath relativeToExportFolder = resource.getFullPath().makeRelativeTo(traceFolderPath); + + // project/.traceExport/A/B + IFolder folder = fExportFolder.getFolder(relativeToExportFolder.removeLastSegments(1)); + TraceUtils.createFolder(folder, new SubProgressMonitor(monitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + + createExportResource(folder, resource); + Element fileElement = doc.createElement(ITracePackageConstants.TRACE_FILE_ELEMENT); + + fileElement.setAttribute(ITracePackageConstants.TRACE_FILE_NAME_ATTRIB, relativeToExportFolder.toString()); + traceNode.appendChild(fileElement); + + // Always export the top-most folder containing the trace or the trace itself + IResource exportedResource = fExportFolder.findMember(relativeToExportFolder.segment(0)); + fResources.add(exportedResource); + } + + /** + * Creates a linked resource in the specified folder + * + * @param exportFolder the folder that will contain the linked resource + * @param res the resource to export + * @throws CoreException when createLink fails + * @return the created linked resource + */ + private static IResource createExportResource(IFolder exportFolder, IResource res) throws CoreException { + IResource ret = null; + // Note: The resources cannot be HIDDEN or else they are ignored by ArchiveFileExportOperation + if (res instanceof IFolder) { + IFolder folder = exportFolder.getFolder(res.getName()); + folder.createLink(res.getLocationURI(), IResource.NONE, null); + ret = folder; + } else if (res instanceof IFile) { + IFile file = exportFolder.getFile(res.getName()); + file.createLink(res.getLocationURI(), IResource.NONE, null); + ret = file; + } + return ret; + } + + private static void exportBookmarks(IProgressMonitor monitor, Node traceNode, TracePackageBookmarkElement element) throws CoreException, InterruptedException { + Document doc = traceNode.getOwnerDocument(); + IFile bookmarksFile = ((TracePackageTraceElement) element.getParent()).getTraceElement().getBookmarksFile(); + if (bookmarksFile != null && bookmarksFile.exists()) { + IMarker[] findMarkers = bookmarksFile.findMarkers(IMarker.BOOKMARK, false, IResource.DEPTH_ZERO); + if (findMarkers.length > 0) { + Element bookmarksXmlElement = doc.createElement(ITracePackageConstants.BOOKMARKS_ELEMENT); + Node bookmarksNode = traceNode.appendChild(bookmarksXmlElement); + + for (IMarker marker : findMarkers) { + ModalContext.checkCanceled(monitor); + + Element singleBookmarkXmlElement = doc.createElement(ITracePackageConstants.BOOKMARK_ELEMENT); + for (String key : marker.getAttributes().keySet()) { + singleBookmarkXmlElement.setAttribute(key, marker.getAttribute(key).toString()); + } + + bookmarksNode.appendChild(singleBookmarkXmlElement); + } + } + } + } + + private void exportManifest(String content) throws CoreException { + IFile file = fExportFolder.getFile(ITracePackageConstants.MANIFEST_FILENAME); + ByteArrayInputStream inputStream = new ByteArrayInputStream(content.getBytes()); + if (file.exists()) { + file.setContents(inputStream, IResource.FORCE, null); + } else { + file.create(inputStream, IResource.FORCE | IResource.HIDDEN, null); + } + fResources.add(file); + } + + private IStatus exportToArchive(IProgressMonitor monitor, int totalWork) throws InvocationTargetException, InterruptedException { + ArchiveFileExportOperation op = new ArchiveFileExportOperation(new ArrayList<>(fResources), getFileName()); + op.setCreateLeadupStructure(false); + op.setUseCompression(fUseCompression); + op.setUseTarFormat(fUseTar); + op.run(new SubProgressMonitor(monitor, totalWork / 2, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + + return op.getStatus(); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/TracePackageExtractManifestOperation.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/TracePackageExtractManifestOperation.java new file mode 100644 index 0000000000..b31e01fc41 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/TracePackageExtractManifestOperation.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2013, 2014 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport; + +import java.io.InputStream; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.operation.ModalContext; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.AbstractTracePackageOperation; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.ITracePackageConstants; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageFilesElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageTraceElement; + +/** + * An operation that extracts information from the manifest located in an + * archive + * + * @author Marc-Andre Laperle + */ +public class TracePackageExtractManifestOperation extends AbstractTracePackageOperation { + + /** + * Constructs a new import operation for reading the manifest + * + * @param fileName + * the output file name + */ + public TracePackageExtractManifestOperation(String fileName) { + super(fileName); + } + + /** + * Run extract the manifest operation. The status (result) of the operation + * can be obtained with {@link #getStatus} + * + * @param progressMonitor + * the progress monitor to use to display progress and receive + * requests for cancellation + */ + @Override + public void run(IProgressMonitor progressMonitor) { + TracePackageElement[] elements = null; + try { + progressMonitor.worked(1); + ArchiveFile archiveFile = getSpecifiedArchiveFile(); + progressMonitor.worked(1); + if (archiveFile == null) { + setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.TracePackageExtractManifestOperation_InvalidFormat)); + return; + } + + Enumeration<?> entries = archiveFile.entries(); + + boolean found = false; + while (entries.hasMoreElements()) { + ModalContext.checkCanceled(progressMonitor); + + ArchiveEntry entry = (ArchiveEntry) entries.nextElement(); + IPath p = new Path(entry.getName()); + //Remove project name + p = p.removeFirstSegments(1); + + if (entry.getName().endsWith(ITracePackageConstants.MANIFEST_FILENAME)) { + found = true; + InputStream inputStream = archiveFile.getInputStream(entry); + ManifestReader.validateManifest(inputStream); + + inputStream = archiveFile.getInputStream(entry); + elements = ManifestReader.loadElementsFromManifest(inputStream); + break; + } + + progressMonitor.worked(1); + } + + if (found) { + setStatus(Status.OK_STATUS); + } + else { + elements = generateElementsFromArchive(); + if (elements.length > 0) { + setStatus(Status.OK_STATUS); + } else { + setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, MessageFormat.format(Messages.TracePackageExtractManifestOperation_ErrorManifestNotFound, ITracePackageConstants.MANIFEST_FILENAME))); + } + } + + setResultElements(elements); + + } catch (InterruptedException e) { + setStatus(Status.CANCEL_STATUS); + } catch (Exception e) { + setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.TracePackageExtractManifestOperation_ErrorReadingManifest, e)); + } + } + + private TracePackageElement[] generateElementsFromArchive() { + ArchiveFile archiveFile = getSpecifiedArchiveFile(); + Enumeration<?> entries = archiveFile.entries(); + Set<String> traceFileNames = new HashSet<>(); + while (entries.hasMoreElements()) { + ArchiveEntry entry = (ArchiveEntry) entries.nextElement(); + String entryName = entry.getName(); + IPath fullArchivePath = new Path(entryName); + if (!fullArchivePath.hasTrailingSeparator() && fullArchivePath.segmentCount() > 0) { + traceFileNames.add(fullArchivePath.segment(0)); + } + } + + List<TracePackageElement> packageElements = new ArrayList<>(); + for (String traceFileName : traceFileNames) { + TracePackageTraceElement traceElement = new TracePackageTraceElement(null, traceFileName, null); + new TracePackageFilesElement(traceElement, traceFileName); + packageElements.add(traceElement); + } + + return packageElements.toArray(new TracePackageElement[] {}); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/TracePackageImportOperation.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/TracePackageImportOperation.java new file mode 100644 index 0000000000..0a9a863a1a --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/TracePackageImportOperation.java @@ -0,0 +1,493 @@ +/******************************************************************************* + * Copyright (c) 2013, 2015 Ericsson + * + * 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 + * + * Contributors: + * Marc-Andre Laperle - Initial API and implementation + * Patrick Tasse - Add support for source location + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.importexport; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.core.runtime.URIUtil; +import org.eclipse.jface.operation.ModalContext; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.AbstractTracePackageOperation; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageBookmarkElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageFilesElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageSupplFileElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageSupplFilesElement; +import org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.TracePackageTraceElement; +import org.eclipse.tracecompass.tmf.core.TmfCommonConstants; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceImportException; +import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType; +import org.eclipse.tracecompass.tmf.core.project.model.TraceTypeHelper; +import org.eclipse.tracecompass.tmf.core.util.Pair; +import org.eclipse.tracecompass.tmf.ui.editors.TmfEventsEditor; +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.TmfTraceTypeUIUtils; +import org.eclipse.ui.dialogs.IOverwriteQuery; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.internal.wizards.datatransfer.TarException; +import org.eclipse.ui.wizards.datatransfer.IImportStructureProvider; +import org.eclipse.ui.wizards.datatransfer.ImportOperation; + +/** + * An operation that imports a trace package from an archive + * + * @author Marc-Andre Laperle + */ +@SuppressWarnings("restriction") +public class TracePackageImportOperation extends AbstractTracePackageOperation implements IOverwriteQuery { + + private final TracePackageElement[] fImportTraceElements; + private final TmfTraceFolder fTmfTraceFolder; + + /** + * Constructs a new import operation + * + * @param importTraceElements + * the trace element to be imported + * @param fileName + * the output file name + * @param tmfTraceFolder + * the destination folder + */ + public TracePackageImportOperation(String fileName, TracePackageElement[] importTraceElements, TmfTraceFolder tmfTraceFolder) { + super(fileName); + fImportTraceElements = importTraceElements; + fTmfTraceFolder = tmfTraceFolder; + } + + private class ImportProvider implements IImportStructureProvider { + + private Exception fException; + + @Override + public List getChildren(Object element) { + return null; + } + + @Override + public InputStream getContents(Object element) { + InputStream inputStream = null; + // We can add throws + try { + inputStream = ((ArchiveProviderElement) element).getContents(); + } catch (IOException e) { + fException = e; + } catch (TarException e) { + fException = e; + } + return inputStream; + } + + @Override + public String getFullPath(Object element) { + return ((ArchiveProviderElement) element).getFullPath(); + } + + @Override + public String getLabel(Object element) { + return ((ArchiveProviderElement) element).getLabel(); + } + + @Override + public boolean isFolder(Object element) { + return ((ArchiveProviderElement) element).isFolder(); + } + + public Exception getException() { + return fException; + } + } + + private class ArchiveProviderElement { + + private final String fPath; + private final String fLabel; + + private ArchiveFile fArchiveFile; + private ArchiveEntry fEntry; + + public ArchiveProviderElement(String destinationPath, String label, ArchiveFile archiveFile, ArchiveEntry entry) { + fPath = destinationPath; + fLabel = label; + this.fArchiveFile = archiveFile; + this.fEntry = entry; + } + + public InputStream getContents() throws TarException, IOException { + return fArchiveFile.getInputStream(fEntry); + } + + public String getFullPath() { + return fPath; + } + + public String getLabel() { + return fLabel; + } + + public boolean isFolder() { + return false; + } + } + + /** + * Run the operation. The status (result) of the operation can be obtained + * with {@link #getStatus} + * + * @param progressMonitor + * the progress monitor to use to display progress and receive + * requests for cancellation + */ + @Override + public void run(IProgressMonitor progressMonitor) { + int totalWork = getNbCheckedElements(fImportTraceElements) * 2; + progressMonitor.beginTask(Messages.TracePackageImportOperation_ImportingPackage, totalWork); + doRun(progressMonitor); + progressMonitor.done(); + } + + private void doRun(IProgressMonitor progressMonitor) { + try { + setStatus(deleteExistingTraces(progressMonitor)); + if (getStatus().getSeverity() != IStatus.OK) { + return; + } + + TracePackageFilesElement traceFilesElement = null; + for (TracePackageElement packageElement : fImportTraceElements) { + TracePackageTraceElement traceElement = (TracePackageTraceElement) packageElement; + if (!isFilesChecked(packageElement)) { + continue; + } + + TracePackageElement[] children = traceElement.getChildren(); + for (TracePackageElement element : children) { + ModalContext.checkCanceled(progressMonitor); + + if (element instanceof TracePackageFilesElement) { + traceFilesElement = (TracePackageFilesElement) element; + setStatus(importTraceFiles(traceFilesElement, traceElement, progressMonitor)); + + } else if (element instanceof TracePackageSupplFilesElement) { + TracePackageSupplFilesElement suppFilesElement = (TracePackageSupplFilesElement) element; + setStatus(importSupplFiles(suppFilesElement, traceElement, progressMonitor)); + } + + if (getStatus().getSeverity() != IStatus.OK) { + return; + } + } + } + + } catch (InterruptedException e) { + setStatus(Status.CANCEL_STATUS); + } + } + + /** + * Returns whether or not the Files element is checked under the given trace + * package element + * + * @param tracePackageElement + * the trace package element + * @return whether or not the Files element is checked under the given trace + * package element + */ + public static boolean isFilesChecked(TracePackageElement tracePackageElement) { + for (TracePackageElement element : tracePackageElement.getChildren()) { + if (element instanceof TracePackageFilesElement) { + return element.isChecked(); + } + } + + return false; + } + + /** + * Return the matching TmfTraceElement for a given trace element. + */ + private TmfTraceElement getMatchingTraceElement(TracePackageTraceElement tracePackageElement) { + IPath tracePath = fTmfTraceFolder.getPath().append(tracePackageElement.getDestinationElementPath()); + List<TmfTraceElement> traces = fTmfTraceFolder.getTraces(); + for (TmfTraceElement t : traces) { + if (t.getPath().equals(tracePath)) { + return t; + } + } + + return null; + } + + private IStatus deleteExistingTraces(IProgressMonitor progressMonitor) { + for (TracePackageElement packageElement : fImportTraceElements) { + TracePackageTraceElement traceElement = (TracePackageTraceElement) packageElement; + if (!isFilesChecked(traceElement)) { + continue; + } + + TmfTraceElement existingTrace = getMatchingTraceElement(traceElement); + if (existingTrace != null) { + try { + existingTrace.delete(new SubProgressMonitor(progressMonitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + } catch (CoreException e) { + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorOperation, e); + } + } + } + + return Status.OK_STATUS; + } + + private void importBookmarks(IResource traceRes, TracePackageTraceElement traceElement, IProgressMonitor monitor) { + for (TracePackageElement o : traceElement.getChildren()) { + if (o instanceof TracePackageBookmarkElement && o.isChecked()) { + + // Get element + IFile bookmarksFile = null; + TmfTraceElement tmfTraceElement = getMatchingTraceElement(traceElement); + if (tmfTraceElement != null) { + try { + bookmarksFile = tmfTraceElement.createBookmarksFile(); + + // Make sure that if a bookmark is double-clicked first + // before opening the trace, it opens the right editor + + // Get the editor id from the extension point + String traceEditorId = tmfTraceElement.getEditorId(); + final String editorId = (traceEditorId != null) ? traceEditorId : TmfEventsEditor.ID; + IDE.setDefaultEditor(bookmarksFile, editorId); + + } catch (CoreException e) { + Activator.getDefault().logError(MessageFormat.format(Messages.TracePackageImportOperation_ErrorCreatingBookmarkFile, traceRes.getName()), e); + } + } + + if (bookmarksFile == null) { + break; + } + + TracePackageBookmarkElement bookmarkElement = (TracePackageBookmarkElement) o; + + List<Map<String, String>> bookmarks = bookmarkElement.getBookmarks(); + for (Map<String, String> attrs : bookmarks) { + IMarker createMarker = null; + try { + createMarker = bookmarksFile.createMarker(IMarker.BOOKMARK); + } catch (CoreException e) { + Activator.getDefault().logError(MessageFormat.format(Messages.TracePackageImportOperation_ErrorCreatingBookmark, traceRes.getName()), e); + } + if (createMarker != null && createMarker.exists()) { + try { + for (Entry<String, String> entry : attrs.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + if (key.equals(IMarker.LOCATION)) { + createMarker.setAttribute(IMarker.LOCATION, Integer.valueOf(value).intValue()); + } else { + createMarker.setAttribute(key, value); + } + } + } catch (CoreException e) { + Activator.getDefault().logError(MessageFormat.format(Messages.TracePackageImportOperation_ErrorCreatingBookmark, traceRes.getName()), e); + } + } + } + } + } + + monitor.worked(1); + } + + private IStatus importTraceFiles(TracePackageFilesElement traceFilesElement, TracePackageTraceElement traceElement, IProgressMonitor monitor) { + List<Pair<String, String>> fileNameAndLabelPairs = new ArrayList<>(); + + String sourceName = checkNotNull(traceFilesElement.getFileName()); + String destinationName = checkNotNull(traceElement.getImportName()); + + fileNameAndLabelPairs.add(new Pair<>(sourceName, destinationName)); + + IPath containerPath = fTmfTraceFolder.getPath(); + IStatus status = importFiles(getSpecifiedArchiveFile(), fileNameAndLabelPairs, containerPath, Path.EMPTY, monitor); + if (getStatus().getSeverity() != IStatus.OK) { + return status; + } + + // We need to set the trace type before importing the supplementary files so we do it here + IResource traceRes = fTmfTraceFolder.getResource().findMember(traceElement.getDestinationElementPath()); + if (traceRes == null || !traceRes.exists()) { + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, MessageFormat.format(Messages.ImportTracePackageWizardPage_ErrorFindingImportedTrace, destinationName)); + } + + TraceTypeHelper traceType = null; + String traceTypeStr = traceElement.getTraceType(); + if (traceTypeStr != null) { + traceType = TmfTraceType.getTraceType(traceTypeStr); + if (traceType == null) { + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, MessageFormat.format(Messages.ImportTracePackageWizardPage_ErrorSettingTraceType, traceElement.getTraceType(), destinationName)); + } + } else { + try { + monitor.subTask(MessageFormat.format(Messages.TracePackageImportOperation_DetectingTraceType, destinationName)); + traceType = TmfTraceTypeUIUtils.selectTraceType(traceRes.getLocation().toOSString(), null, null); + } catch (TmfTraceImportException e) { + // Could not figure out the type + } + } + + if (traceType != null) { + try { + TmfTraceTypeUIUtils.setTraceType(traceRes, traceType); + } catch (CoreException e) { + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, MessageFormat.format(Messages.ImportTracePackageWizardPage_ErrorSettingTraceType, traceElement.getTraceType(), destinationName), e); + } + } + + importBookmarks(traceRes, traceElement, monitor); + + try { + URI uri = new File(getFileName()).toURI(); + IPath entryPath = new Path(traceFilesElement.getFileName()); + if (traceRes instanceof IFolder) { + entryPath = entryPath.addTrailingSeparator(); + } + String sourceLocation = URIUtil.toUnencodedString(URIUtil.toJarURI(uri, entryPath)); + traceRes.setPersistentProperty(TmfCommonConstants.SOURCE_LOCATION, sourceLocation); + } catch (CoreException e) { + } + + return status; + } + + private IStatus importSupplFiles(TracePackageSupplFilesElement suppFilesElement, TracePackageTraceElement traceElement, IProgressMonitor monitor) { + List<Pair<String, String>> fileNameAndLabelPairs = new ArrayList<>(); + for (TracePackageElement child : suppFilesElement.getChildren()) { + if (child.isChecked()) { + TracePackageSupplFileElement supplFile = (TracePackageSupplFileElement) child; + fileNameAndLabelPairs.add(new Pair<>(checkNotNull(supplFile.getText()), checkNotNull(new Path(supplFile.getText()).lastSegment()))); + } + } + + if (!fileNameAndLabelPairs.isEmpty()) { + TmfTraceElement existingTrace = getMatchingTraceElement(traceElement); + if (existingTrace != null) { + ArchiveFile archiveFile = getSpecifiedArchiveFile(); + existingTrace.refreshSupplementaryFolder(); + // Project/Traces/A/B -> A/B + IPath traceFolderRelativePath = fTmfTraceFolder.getPath().makeRelativeTo(fTmfTraceFolder.getProject().getTracesFolder().getPath()); + // Project/.tracing/A/B/ + IFolder traceSupplementaryFolder = fTmfTraceFolder.getTraceSupplementaryFolder(traceFolderRelativePath.toString()); + IPath destinationContainerPath = traceSupplementaryFolder.getFullPath(); + // Remove the .tracing segment at the beginnin so that a file in folder .tracing/A/B/ imports destinationContainerPath/A/B/ + Path baseSourcePath = new Path(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER_NAME); + return importFiles(archiveFile, fileNameAndLabelPairs, destinationContainerPath, baseSourcePath, monitor); + } + } + + return Status.OK_STATUS; + } + + private IStatus importFiles(ArchiveFile archiveFile, List<Pair<String, String>> fileNameAndLabelPairs, IPath destinationContainerPath, IPath baseSourcePath, IProgressMonitor monitor) { + List<ArchiveProviderElement> objects = new ArrayList<>(); + Enumeration<?> entries = archiveFile.entries(); + while (entries.hasMoreElements()) { + ArchiveEntry entry = (ArchiveEntry) entries.nextElement(); + String entryName = entry.getName(); + IPath fullArchivePath = new Path(entryName); + if (fullArchivePath.hasTrailingSeparator()) { + // We only care about file entries as the folders will get created by the ImportOperation + continue; + } + + for (Pair<String, String> fileNameAndLabel : fileNameAndLabelPairs) { + + // Examples: Traces/aaa/kernel/ .tracing/aaa/testtexttrace.txt/statistics.ht + IPath searchedArchivePath = new Path(fileNameAndLabel.getFirst()); + + // Check if this archive entry matches the searched file name at this archive location + boolean fileMatch = entryName.equalsIgnoreCase(searchedArchivePath.toString()); + // For example Traces/aaa/kernel/metadata matches Traces/aaa/kernel/ + boolean folderMatch = entryName.startsWith(searchedArchivePath + "/"); //$NON-NLS-1$ + + if (fileMatch || folderMatch) { + // .tracing/aaa/testtexttrace.txt/statistics.ht -> aaa/testtexttrace.txt/statistics.ht + IPath destinationPath = fullArchivePath.makeRelativeTo(baseSourcePath); + + // metadata statistics.ht + // We don't use the label when the entry is a folder match because the labels for individual files + // under the folder are not specified in the manifest so just use the last segment. + String resourceLabel = folderMatch ? fullArchivePath.lastSegment() : fileNameAndLabel.getSecond(); + + ArchiveProviderElement pe = new ArchiveProviderElement(destinationPath.toString(), resourceLabel, archiveFile, entry); + objects.add(pe); + break; + } + } + } + + ImportProvider provider = new ImportProvider(); + + ImportOperation operation = new ImportOperation(destinationContainerPath, + null, provider, this, + objects); + operation.setCreateContainerStructure(true); + operation.setOverwriteResources(true); + + try { + operation.run(new SubProgressMonitor(monitor, fileNameAndLabelPairs.size(), SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); + archiveFile.close(); + } catch (InvocationTargetException e) { + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorOperation, e); + } catch (InterruptedException e) { + return Status.CANCEL_STATUS; + } catch (IOException e) { + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorOperation, e); + } + + if (provider.getException() != null) { + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, org.eclipse.tracecompass.internal.tmf.ui.project.wizards.tracepkg.Messages.TracePackage_ErrorOperation, provider.getException()); + } + + return operation.getStatus(); + } + + @Override + public String queryOverwrite(String pathString) { + // We always overwrite once we reach this point + return null; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/messages.properties b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/messages.properties new file mode 100644 index 0000000000..375a6f2363 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/importexport/messages.properties @@ -0,0 +1,53 @@ +############################################################################### +# Copyright (c) 2013, 2014 Ericsson +# +# 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 +# +# Contributors: +# Marc-Andre Laperle - Initial API and implementation +############################################################################### + +ExportTracePackageSelectTraceWizardPage_ChooseTrace=Choose traces to export +ExportTracePackageSelectTraceWizardPage_ProjectSelection=Project +ExportTracePackageSelectTraceWizardPage_TraceSelection=Traces +ExportTracePackageWizardPage_AlreadyExitst = Target file already exists. Would you like to overwrite it? +ExportTracePackageWizardPage_ApproximateSizeLbl=Approximate uncompressed size: {0} +ExportTracePackageWizardPage_ChooseContent=Choose the content to export +ExportTracePackageWizardPage_CompressContents=Co&mpress the contents of the file +ExportTracePackageWizardPage_ContentColumnName=Content +ExportTracePackageWizardPage_Options=Options +ExportTracePackageWizardPage_SaveInTarFormat=Sa&ve in tar format +ExportTracePackageWizardPage_SaveInZipFormat=Save in &zip format +ExportTracePackageWizardPage_SizeByte=B +ExportTracePackageWizardPage_SizeColumnName=Size +ExportTracePackageWizardPage_SizeGigabyte=GB +ExportTracePackageWizardPage_SizeKilobyte=KB +ExportTracePackageWizardPage_SizeMegabyte=MB +ExportTracePackageWizardPage_SizeTerabyte=TB +ExportTracePackageWizardPage_Title=Export trace package +ExportTracePackageWizardPage_ToArchive=To &archive file: +ImportTracePackageWizardPage_AlreadyExists=A trace with the name ''{0}'' already exists. Would you like to overwrite it? +ImportTracePackageWizardPage_ErrorFileNotFound=File does not exist +ImportTracePackageWizardPage_ErrorOperation=Error occurred during import trace operation +ImportTracePackageWizardPage_ErrorSettingTraceType=Error setting the type {0} for the trace {1} +ImportTracePackageWizardPage_ErrorFindingImportedTrace=Could not find the imported trace {0} in the workspace +ImportTracePackageWizardPage_FromArchive=From &archive file: +ImportTracePackageWizardPage_Message=Choose the content to import +ImportTracePackageWizardPage_Project=Into project: +ImportTracePackageWizardPage_ReadingPackage=Reading package +ImportTracePackageWizardPage_SelectProjectButton=Select +ImportTracePackageWizardPage_SelectProjectDialogTitle=Select project +ImportTracePackageWizardPage_Title=Import trace package +TracePackageExportOperation_GeneratingPackage=Generating package +TracePackageExtractManifestOperation_ErrorManifestNotFound=The required manifest file {0} could not be found. +TracePackageExtractManifestOperation_ErrorManifestNotValid=The manifest file is not valid. +TracePackageExtractManifestOperation_ErrorReadingManifest=An error occurred when reading the manifest +TracePackageExtractManifestOperation_InvalidFormat=The selected file is not a supported file format +TracePackageExtractManifestOperation_SchemaFileNotFound=The schema file {0} could not be found. +TracePackageImportOperation_ErrorCreatingBookmark=Error creating bookmark for the trace {0} +TracePackageImportOperation_ErrorCreatingBookmarkFile=Error creating bookmark file for the trace {0} +TracePackageImportOperation_ImportingPackage=Importing package +TracePackageImportOperation_DetectingTraceType=Detecting trace type for ''{0}'' diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/messages.properties b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/messages.properties new file mode 100644 index 0000000000..217ed38302 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/project/wizards/tracepkg/messages.properties @@ -0,0 +1,22 @@ +############################################################################### +# Copyright (c) 2013, 2014 Ericsson +# +# 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 +# +# Contributors: +# Marc-Andre Laperle - Initial API and implementation +############################################################################### + +TracePackage_Bookmarks=Bookmarks +TracePackage_Browse=B&rowse... +TracePackage_DeselectAll=Deselect All +TracePackage_ErrorOperation=Error occurred during trace package operation +TracePackage_ErrorMultipleProblems=Multiple problems. Click Details for more information. +TracePackage_FileDialogTitle=Choose Archive File +TracePackage_InternalErrorTitle=Internal error +TracePackage_SelectAll=Select All +TracePackage_SupplementaryFiles=Supplementary files +TracePackage_TraceElement=Trace
\ No newline at end of file |