/******************************************************************************* * Copyright (c) 2009, 2014 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 *******************************************************************************/ package fr.inria.linuxtools.internal.tmf.ui.project.wizards.importtrace; import java.io.File; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IContainer; 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.dialogs.MessageDialog; 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.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; 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.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.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.dialogs.FileSystemElement; import org.eclipse.ui.dialogs.IOverwriteQuery; import org.eclipse.ui.dialogs.WizardResourceImportPage; import org.eclipse.ui.internal.ide.DialogUtil; import org.eclipse.ui.internal.ide.dialogs.IElementFilter; 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; import fr.inria.linuxtools.internal.tmf.ui.Activator; import fr.inria.linuxtools.tmf.core.TmfCommonConstants; import fr.inria.linuxtools.tmf.core.TmfProjectNature; import fr.inria.linuxtools.tmf.core.project.model.TmfTraceImportException; import fr.inria.linuxtools.tmf.core.project.model.TmfTraceType; import fr.inria.linuxtools.tmf.core.project.model.TraceTypeHelper; import fr.inria.linuxtools.tmf.ui.project.model.TmfProjectElement; import fr.inria.linuxtools.tmf.ui.project.model.TmfProjectRegistry; import fr.inria.linuxtools.tmf.ui.project.model.TmfTraceElement; import fr.inria.linuxtools.tmf.ui.project.model.TmfTraceFolder; import fr.inria.linuxtools.tmf.ui.project.model.TmfTraceTypeUIUtils; import fr.inria.linuxtools.tmf.ui.project.model.TmfTracesFolder; /** * 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 * @since 2.0 */ @SuppressWarnings("restriction") public class ImportTraceWizardPage extends WizardResourceImportPage { // ------------------------------------------------------------------------ // Constants // ------------------------------------------------------------------------ private static final String IMPORT_WIZARD_PAGE = "ImportTraceWizardPage"; //$NON-NLS-1$ private static final String IMPORT_WIZARD_ROOT_DIRECTORY_ID = IMPORT_WIZARD_PAGE + ".import_root_directory_id"; //$NON-NLS-1$ private static final String IMPORT_WIZARD_IMPORT_UNRECOGNIZED_ID = IMPORT_WIZARD_PAGE + ".import_unrecognized_traces_id"; //$NON-NLS-1$ private static final String IMPORT_WIZARD_PRESERVE_FOLDERS_ID = IMPORT_WIZARD_PAGE + ".import_preserve_folders_id"; //$NON-NLS-1$ private static final String SEPARATOR = ":"; //$NON-NLS-1$ private static final String AUTO_DETECT = Messages.ImportTraceWizard_AutoDetection; // ------------------------------------------------------------------------ // 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; // 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 directory name field */ protected Combo directoryNameField; /** The directory browse button. */ protected Button directoryBrowseButton; /** * ResourceTreeAndListGroup was internal in Kepler and we referenced it. It * is now removed in Luna. To keep our builds compatible with Kepler, we * need to have our own version of this class. Once we stop supporting * Kepler, we can delete this class and use the public one from the * platform. */ private ResourceTreeAndListGroup fSelectionGroup; // ------------------------------------------------------------------------ // 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); } /** * 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); } /** * Constructor * * @param workbench * The workbench reference. * @param selection * The current selection */ public ImportTraceWizardPage(IWorkbench workbench, IStructuredSelection selection) { this(IMPORT_WIZARD_PAGE, 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); } } // ------------------------------------------------------------------------ // WizardResourceImportPage // ------------------------------------------------------------------------ @Override protected void createSourceGroup(Composite parent) { createDirectorySelectionGroup(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 directory selection group. * * @param parent * the parent composite */ protected void createDirectorySelectionGroup(Composite parent) { Composite directoryContainerGroup = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(); layout.numColumns = 3; directoryContainerGroup.setLayout(layout); directoryContainerGroup.setFont(parent.getFont()); directoryContainerGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); // Label ("Trace directory:") Label groupLabel = new Label(directoryContainerGroup, SWT.NONE); groupLabel.setText(Messages.ImportTraceWizard_DirectoryLocation); groupLabel.setFont(parent.getFont()); // Directory name entry field directoryNameField = new Combo(directoryContainerGroup, SWT.BORDER); GridData data = new GridData(SWT.FILL, SWT.FILL, true, false); data.widthHint = SIZING_TEXT_FIELD_WIDTH; directoryNameField.setLayoutData(data); directoryNameField.setFont(parent.getFont()); directoryNameField.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateFromSourceField(); } }); directoryNameField.addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { if (e.character == SWT.CR) { // Windows... entryChanged = false; updateFromSourceField(); } } @Override public void keyReleased(KeyEvent e) { } }); directoryNameField.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { // Do nothing when getting focus } @Override public void focusLost(FocusEvent e) { // Clear the flag to prevent constant update if (entryChanged) { entryChanged = false; updateFromSourceField(); } } }); directoryNameField.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { entryChanged = true; } }); // Browse button directoryBrowseButton = new Button(directoryContainerGroup, SWT.PUSH); directoryBrowseButton.setText(Messages.ImportTraceWizard_BrowseButton); directoryBrowseButton.addListener(SWT.Selection, this); directoryBrowseButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); directoryBrowseButton.setFont(parent.getFont()); setButtonLayoutData(directoryBrowseButton); } // ------------------------------------------------------------------------ // 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 (fIsDestinationChanged) { if (fIsDestinationChanged == false) { event.display.asyncExec(new Runnable() { @Override public void run() { synchronized (fIsDestinationChanged) { 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); setSourceName(selectedDirectory); } } private File getSourceDirectory() { return getSourceDirectory(directoryNameField.getText()); } private static File getSourceDirectory(String path) { File sourceDirectory = new File(getSourceDirectoryName(path)); if (!sourceDirectory.exists() || !sourceDirectory.isDirectory()) { return null; } return sourceDirectory; } 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() { setSourceName(directoryNameField.getText()); updateWidgetEnablements(); } private void setSourceName(String path) { if (path.length() > 0) { String[] currentItems = directoryNameField.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; directoryNameField.setItems(newItems); selectionIndex = oldLength; } directoryNameField.select(selectionIndex); } resetSelection(); } // ------------------------------------------------------------------------ // File Selection Group (forked WizardFileSystemResourceImportPage1) // ------------------------------------------------------------------------ private void resetSelection() { TraceFileSystemElement root = getFileSystemTree(); fSelectionGroup.setRoot(root); } private TraceFileSystemElement getFileSystemTree() { File sourceDirectory = getSourceDirectory(); if (sourceDirectory == null) { return null; } return selectFiles(sourceDirectory, FileSystemStructureProvider.INSTANCE); } private TraceFileSystemElement selectFiles(final Object rootFileSystemObject, final IImportStructureProvider 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] = createRootElement(rootFileSystemObject, structureProvider); } }); return results[0]; } private static TraceFileSystemElement createRootElement(Object fileSystemObject, IImportStructureProvider provider) { boolean isContainer = provider.isFolder(fileSystemObject); String elementLabel = provider.getLabel(fileSystemObject); // 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);//$NON-NLS-1$ dummyParent.setFileSystemObject(((File)fileSystemObject).getParentFile()); dummyParent.setPopulated(); TraceFileSystemElement result = new TraceFileSystemElement( elementLabel, dummyParent, isContainer); result.setFileSystemObject(fileSystemObject); //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] = 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(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 sourceDirectory = getSourceDirectory(); if (sourceDirectory == null) { setMessage(Messages.ImportTraceWizard_SelectTraceSourceEmpty); return false; } if (sourceConflictsWithDestination(new Path(sourceDirectory.getPath()))) { setMessage(null); setErrorMessage(getSourceConflictMessage()); 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; } @Override protected void restoreWidgetValues() { super.restoreWidgetValues(); IDialogSettings settings = getDialogSettings(); boolean value; if (settings.get(IMPORT_WIZARD_IMPORT_UNRECOGNIZED_ID) == null) { value = true; } else { value = settings.getBoolean(IMPORT_WIZARD_IMPORT_UNRECOGNIZED_ID); } fImportUnrecognizedButton.setSelection(value); if (settings.get(IMPORT_WIZARD_PRESERVE_FOLDERS_ID) == null) { value = true; } else { value = settings.getBoolean(IMPORT_WIZARD_PRESERVE_FOLDERS_ID); } fPreserveFolderStructureButton.setSelection(value); String[] directoryNames = settings.getArray(IMPORT_WIZARD_ROOT_DIRECTORY_ID); if ((directoryNames != null) && (directoryNames.length != 0)) { for (int i = 0; i < directoryNames.length; i++) { directoryNameField.add(directoryNames[i]); } } } @Override protected void saveWidgetValues() { // Persist dialog settings IDialogSettings settings = getDialogSettings(); settings.put(IMPORT_WIZARD_IMPORT_UNRECOGNIZED_ID, fImportUnrecognizedButton.getSelection()); settings.put(IMPORT_WIZARD_PRESERVE_FOLDERS_ID, fPreserveFolderStructureButton.getSelection()); // update directory names history String[] directoryNames = settings.getArray(IMPORT_WIZARD_ROOT_DIRECTORY_ID); if (directoryNames == null) { directoryNames = new String[0]; } String items[] = directoryNameField.getItems(); for (int i = 0; i < items.length; i++) { directoryNames = addToHistory(directoryNames, items[i]); } settings.put(IMPORT_WIZARD_ROOT_DIRECTORY_ID, directoryNames); } // ------------------------------------------------------------------------ // Import the trace(s) // ------------------------------------------------------------------------ /** * Finish the import. * * @return <code>true</code> if successful else <code>false</code> */ public boolean finish() { String traceTypeName = fTraceTypes.getText(); String traceId = null; if (!AUTO_DETECT.equals(traceTypeName)) { String tokens[] = traceTypeName.split(SEPARATOR, 2); if (tokens.length < 2) { return false; } traceId = TmfTraceType.getTraceTypeId(tokens[0], tokens[1]); } // Save dialog settings saveWidgetValues(); IPath baseSourceContainerPath = new Path(getSourceDirectory().getAbsolutePath()); final TraceValidateAndImportOperation operation = new TraceValidateAndImportOperation(traceId, baseSourceContainerPath, getContainerFullPath(), fImportUnrecognizedButton.getSelection(), fOverwriteExistingResourcesCheckbox.getSelection(), fCreateLinksInWorkspaceButton.getSelection(), fPreserveFolderStructureButton.getSelection()); 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; } finally { 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; } // ------------------------------------------------------------------------ // Classes // ------------------------------------------------------------------------ private class TraceValidateAndImportOperation { private IStatus fStatus; private String fTraceType; private IPath fDestinationContainerPath; private IPath fBaseSourceContainerPath; private boolean fImportUnrecognizedTraces; private boolean fLink; private boolean fPreserveFolderStructure; private ImportConfirmation fConfirmationMode = ImportConfirmation.SKIP; private TraceValidateAndImportOperation(String traceId, IPath baseSourceContainerPath, IPath destinationContainerPath, boolean doImport, boolean overwrite, boolean link, boolean preserveFolderStructure) { fTraceType = traceId; fBaseSourceContainerPath = baseSourceContainerPath; fDestinationContainerPath = destinationContainerPath; fImportUnrecognizedTraces = doImport; if (overwrite) { fConfirmationMode = ImportConfirmation.OVERWRITE_ALL; } fLink = link; fPreserveFolderStructure = preserveFolderStructure; } public void run(IProgressMonitor progressMonitor) { String currentPath = null; final Map<String, TraceFileSystemElement> folderElements = new HashMap<>(); try { final ArrayList<TraceFileSystemElement> fileSystemElements = new ArrayList<>(); IElementFilter passThroughFilter = new IElementFilter() { @Override public void filterElements(Collection elements, IProgressMonitor monitor) { fileSystemElements.addAll(elements); } @Override public void filterElements(Object[] elements, IProgressMonitor monitor) { for (int i = 0; i < elements.length; i++) { fileSystemElements.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); Iterator<TraceFileSystemElement> fileSystemElementsIter = fileSystemElements.iterator(); subMonitor = SubMonitor.convert(progressMonitor, fileSystemElements.size()); while (fileSystemElementsIter.hasNext()) { ModalContext.checkCanceled(progressMonitor); currentPath = null; TraceFileSystemElement element = fileSystemElementsIter.next(); File fileResource = (File) element.getFileSystemObject(); String resourcePath = fileResource.getAbsolutePath(); element.setDestinationContainerPath(computeDestinationContainerPath(new Path(resourcePath))); currentPath = resourcePath; SubMonitor sub = subMonitor.newChild(1); if (element.isDirectory()) { if (!folderElements.containsKey(resourcePath)) { if (isDirectoryTrace(element)) { folderElements.put(resourcePath, element); validateAndImportTrace(element, sub); } } } else { TraceFileSystemElement parentElement = (TraceFileSystemElement)element.getParent(); File parentFile = (File) parentElement.getFileSystemObject(); String parentPath = parentFile.getAbsolutePath(); parentElement.setDestinationContainerPath(computeDestinationContainerPath(new Path(parentPath))); currentPath = parentPath; if (!folderElements.containsKey(parentPath)) { if (isDirectoryTrace(parentElement)) { folderElements.put(parentPath, parentElement); validateAndImportTrace(parentElement, sub); } else { if (fileResource.exists()) { validateAndImportTrace(element, sub); } } } } } setStatus(Status.OK_STATUS); } catch (InterruptedException e) { setStatus(Status.CANCEL_STATUS); } catch (Exception e) { String errorMessage = Messages.ImportTraceWizard_ImportProblem + ": " + //$NON-NLS-1$ (currentPath != null ? currentPath : ""); //$NON-NLS-1$ Activator.getDefault().logError(errorMessage, e); setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, errorMessage , e)); } } 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 (fPreserveFolderStructure) { // /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; } private void validateAndImportTrace(TraceFileSystemElement fileSystemElement, IProgressMonitor monitor) throws TmfTraceImportException, CoreException, InvocationTargetException, InterruptedException { File file = (File) fileSystemElement.getFileSystemObject(); String path = file.getAbsolutePath(); TraceTypeHelper traceTypeHelper = null; 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 (fImportUnrecognizedTraces) { 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 { ImportConfirmation mode = checkForNameClashes(fileSystemElement); switch (mode) { case RENAME: case RENAME_ALL: rename(fileSystemElement); break; case OVERWRITE: case OVERWRITE_ALL: delete(fileSystemElement, monitor); break; case CONTINUE: break; case SKIP: case SKIP_ALL: default: return null; } List<TraceFileSystemElement> subList = new ArrayList<>(); FileSystemElement parentFolder = fileSystemElement.getParent(); IPath containerPath = fileSystemElement.getDestinationContainerPath(); IPath tracePath = containerPath.addTrailingSeparator().append(fileSystemElement.getLabel()); if (fileSystemElement.isDirectory() && (!fLink)) { 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 + " " + ((File)fileSystemElement.getFileSystemObject()).getAbsolutePath()); //$NON-NLS-1$ ImportOperation operation = new ImportOperation(containerPath, parentFolder, fileSystemStructureProvider, myQueryImpl, subList); operation.setContext(getShell()); operation.setCreateContainerStructure(false); operation.setOverwriteResources(false); operation.setCreateLinks(fLink); operation.setVirtualFolders(false); operation.run(new SubProgressMonitor(monitor, 1, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); File file = (File) fileSystemElement.getFileSystemObject(); 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()); } IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(tracePath); resource.setPersistentProperty(TmfCommonConstants.SOURCE_LOCATION, sourceLocation); return resource; } private boolean isDirectoryTrace(FileSystemElement fileSystemElement) { File file = (File) fileSystemElement.getFileSystemObject(); String path = file.getAbsolutePath(); if (TmfTraceType.isDirectoryTrace(path)) { return true; } return false; } private ImportConfirmation checkForNameClashes(TraceFileSystemElement fileSystemElement) throws InterruptedException { IPath tracePath = getInitialDestinationPath(fileSystemElement); // 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(getContainer() .getShell(), 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]; getShell().getDisplay().syncExec(new Runnable() { @Override public void run() { returnValue[0] = dialog.open(); } }); return returnValue[0]; } /** * @return the initial destination path, before rename, if any */ private IPath getInitialDestinationPath(TraceFileSystemElement fileSystemElement) { IPath traceFolderPath = fileSystemElement.getDestinationContainerPath(); return traceFolderPath.append(((File)fileSystemElement.getFileSystemObject()).getName()); } private void rename(TraceFileSystemElement fileSystemElement) { IPath tracePath = getInitialDestinationPath(fileSystemElement); TmfTraceElement trace = getExistingTrace(tracePath); if (trace == null) { return; } // 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) { fileSystemElement.setLabel(name); return; } } } private void delete(TraceFileSystemElement fileSystemElement, IProgressMonitor monitor) throws CoreException { IPath tracePath = getInitialDestinationPath(fileSystemElement); 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; } /** * 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; public TraceFileSystemElement(String name, FileSystemElement parent, boolean isDirectory) { super(name, parent, isDirectory); } 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) { //Get the name - if it is empty then return the path as it is a file root File file = (File) getFileSystemObject(); String name = file.getName(); if (name.length() == 0) { return file.getPath(); } return name; } 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() { FileSystemStructureProvider provider = FileSystemStructureProvider.INSTANCE; List<File> allchildren = provider.getChildren(this.getFileSystemObject()); File child = null; TraceFileSystemElement newelement = null; Iterator<File> iter = allchildren.iterator(); while(iter.hasNext()) { child = iter.next(); newelement = new TraceFileSystemElement(provider.getLabel(child), this, provider.isFolder(child)); newelement.setFileSystemObject(child); } setPopulated(); } } private class ImportProvider implements IImportStructureProvider { private FileSystemStructureProvider provider = FileSystemStructureProvider.INSTANCE; 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 provider.getContents(resource.getFileSystemObject()); } @Override public String getFullPath(Object element) { TraceFileSystemElement resource = (TraceFileSystemElement)element; return provider.getFullPath(resource.getFileSystemObject()); } @Override public boolean isFolder(Object element) { TraceFileSystemElement resource = (TraceFileSystemElement)element; return resource.isDirectory(); } } private enum ImportConfirmation { // ------------------------------------------------------------------------ // Enum definition // ------------------------------------------------------------------------ RENAME(Messages.ImportTraceWizard_ImportConfigurationRename), RENAME_ALL(Messages.ImportTraceWizard_ImportConfigurationRenameAll), OVERWRITE(Messages.ImportTraceWizard_ImportConfigurationOverwrite), OVERWRITE_ALL(Messages.ImportTraceWizard_ImportConfigurationOverwriteAll), SKIP(Messages.ImportTraceWizard_ImportConfigurationSkip), SKIP_ALL(Messages.ImportTraceWizard_ImportConfigurationSkipAll), CONTINUE("CONTINUE"); //$NON-NLS-1$ // ------------------------------------------------------------------------ // Attributes // ------------------------------------------------------------------------ /** * Name of enum */ private final String fInName; // ------------------------------------------------------------------------ // Constuctors // ------------------------------------------------------------------------ /** * Private constructor * @param name the name of state */ private ImportConfirmation(String name) { fInName = name; } // ------------------------------------------------------------------------ // Accessors // ------------------------------------------------------------------------ /** * @return state name */ public String getInName() { return fInName; } } }