org.eclipse.rcptt.ui.actions.edit.PasteAction.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.rcptt.ui.actions.edit.PasteAction.java

Source

/*******************************************************************************
 * Copyright (c) 2009, 2015 Xored Software Inc and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Xored Software Inc - initial API and implementation and/or initial documentation
 *******************************************************************************/
package org.eclipse.rcptt.ui.actions.edit;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.osgi.util.NLS;
import org.eclipse.rcptt.core.model.IQ7Element;
import org.eclipse.rcptt.core.model.IQ7NamedElement;
import org.eclipse.rcptt.core.model.IQ7Project;
import org.eclipse.rcptt.core.model.ModelException;
import org.eclipse.rcptt.core.model.search.Q7SearchCore;
import org.eclipse.rcptt.core.workspace.RcpttCore;
import org.eclipse.rcptt.internal.core.model.ReferencedProjectScope;
import org.eclipse.rcptt.internal.core.model.index.NamedElementCollector;
import org.eclipse.rcptt.internal.ui.Messages;
import org.eclipse.rcptt.internal.ui.Q7UIPlugin;
import org.eclipse.rcptt.ui.actions.RenameDialog;
import org.eclipse.rcptt.ui.launching.LaunchUtils;
import org.eclipse.rcptt.ui.refactoring.RefactoringSaveHelper;
import org.eclipse.rcptt.ui.utils.WriteAccessChecker;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.CopyFilesAndFoldersOperation;
import org.eclipse.ui.actions.CopyProjectOperation;
import org.eclipse.ui.actions.SelectionListenerAction;
import org.eclipse.ui.ide.undo.CopyResourcesOperation;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
import org.eclipse.ui.internal.ide.dialogs.IDEResourceInfoUtils;
import org.eclipse.ui.part.ResourceTransfer;

@SuppressWarnings("restriction")
public class PasteAction extends SelectionListenerAction {

    private final class Q7ResourceCopyOperation extends CopyResourcesOperation {
        private final List<IQ7NamedElement> namedElements;
        private final IPath[] destinationPath;

        private Q7ResourceCopyOperation(IResource[] resources, IPath[] destinationPaths, String label,
                List<IQ7NamedElement> namedElements) {
            super(resources, destinationPaths, label);
            this.namedElements = namedElements;
            this.destinationPath = destinationPaths;
        }

        private Q7ResourceCopyOperation(IResource[] resources, IPath destinationPath, String label,
                List<IQ7NamedElement> namedElements, IPath targetPaths[]) {
            super(resources, destinationPath, label);
            this.namedElements = namedElements;
            this.destinationPath = targetPaths;
        }

        @Override
        protected void copy(IProgressMonitor monitor, IAdaptable uiInfo) throws CoreException {
            super.copy(monitor, uiInfo);
            // We need to collect all new copied named
            // elements
            for (IPath dest : destinationPath) {
                IQ7Element element = RcpttCore.create(ResourcesPlugin.getWorkspace().getRoot().findMember(dest));
                if (element != null && element.exists()) {
                    NamedElementCollector collector = new NamedElementCollector();
                    element.accept(collector);
                    namedElements.addAll(collector.getElements());
                }
            }
        }
    }

    /**
     * The id of this action.
     */
    public static final String ID = PlatformUI.PLUGIN_ID + ".PasteAction";//$NON-NLS-1$

    /**
     * The shell in which to show any dialogs.
     */
    private final Shell shell;

    /**
     * System clipboard
     */
    private final Clipboard clipboard;

    /**
     * Creates a new action.
     * 
     * @param shell
     *            the shell for any dialogs
     * @param clipboard
     *            the clipboard
     */
    public PasteAction(Shell shell, Clipboard clipboard) {
        super(Messages.PasteAction_Text);
        Assert.isNotNull(shell);
        Assert.isNotNull(clipboard);
        this.shell = shell;
        this.clipboard = clipboard;
        setToolTipText(Messages.PasteAction_ToolTip);
        setId(PasteAction.ID);
        PlatformUI.getWorkbench().getHelpSystem().setHelp(this, "HelpId"); //$NON-NLS-1$      
    }

    /**
     * Returns the actual target of the paste action. Returns null if no valid
     * target is selected.
     * 
     * @return the actual target of the paste action
     */
    private IResource getTarget() {
        List<?> selectedResources = getSelectedResources();

        for (int i = 0; i < selectedResources.size(); i++) {
            IResource resource = (IResource) selectedResources.get(i);

            if (resource instanceof IProject && !((IProject) resource).isOpen()) {
                return null;
            }
            if (resource.getType() == IResource.FILE) {
                resource = resource.getParent();
            }
            if (resource != null) {
                return resource;
            }
        }
        return null;
    }

    /**
     * Returns whether any of the given resources are linked resources.
     * 
     * @param resources
     *            resource to check for linked type. may be null
     * @return true=one or more resources are linked. false=none of the
     *         resources are linked
     */
    private boolean isLinked(IResource[] resources) {
        for (int i = 0; i < resources.length; i++) {
            if (resources[i].isLinked()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Implementation of method defined on <code>IAction</code>.
     */
    @Override
    public void run() {
        if (LaunchUtils.hasLaunchedTestCases()) {
            MessageDialog.openWarning(shell, Messages.PasteAction_ErrorDialogTitle,
                    Messages.PasteAction_ErrorDialogMsg);
            return;
        }
        if (!RefactoringSaveHelper.checkDirtyEditors(shell)) {
            return;
        }
        // try a resource transfer
        ResourceTransfer resTransfer = ResourceTransfer.getInstance();
        IResource[] resourceData = (IResource[]) clipboard.getContents(resTransfer);

        if (resourceData != null && resourceData.length > 0) {
            if (resourceData[0].getType() == IResource.PROJECT) {
                // enablement checks for all projects
                for (int i = 0; i < resourceData.length; i++) {
                    CopyProjectOperation operation = new CopyProjectOperation(this.shell);
                    operation.copyProject((IProject) resourceData[i]);
                }
            } else {
                // enablement should ensure that we always have access to a
                // container
                IContainer container = getContainer();

                try {
                    WriteAccessChecker writeAccessChecker = new WriteAccessChecker(this.shell);
                    if (!writeAccessChecker.makeResourceWritable(container)) {
                        return;
                    }
                } catch (CoreException e) {
                    Q7UIPlugin.log(e);
                }

                final List<IQ7NamedElement> namedElements = new ArrayList<IQ7NamedElement>();
                List<IResource> normalResources = new ArrayList<IResource>();
                for (IResource resource : resourceData) {
                    if (resource instanceof IFile) {
                        IQ7NamedElement namedElement = (IQ7NamedElement) RcpttCore.create((IFile) resource);
                        if (namedElement != null) {
                            namedElements.add(namedElement);
                            continue;
                        }
                    }
                    normalResources.add(resource);
                }
                // paste named elements, if resources was pasted normally
                IQ7NamedElement[] elements = namedElements.toArray(new IQ7NamedElement[namedElements.size()]);
                Map<IQ7NamedElement, IFile> map = RcpttCore.getInstance().getCopyDestinationMap(elements,
                        container);

                if (normalResources.size() > 0) {
                    Q7CopyFilesAndFoldersOperation operation = new Q7CopyFilesAndFoldersOperation(this.shell) {
                        protected org.eclipse.ui.ide.undo.AbstractWorkspaceOperation getUndoableCopyOrMoveOperation(
                                IResource[] resources, boolean renamed, final IPath... destinationPath) {
                            if (renamed) {
                                return new Q7ResourceCopyOperation(resources, destinationPath,
                                        IDEWorkbenchMessages.CopyFilesAndFoldersOperation_copyTitle, namedElements);
                            } else {
                                List<IPath> dests = new ArrayList<IPath>();
                                for (IResource res : resources) {
                                    dests.add(destinationPath[0].append(res.getName()));
                                }
                                return new Q7ResourceCopyOperation(resources, destinationPath[0],
                                        IDEWorkbenchMessages.CopyFilesAndFoldersOperation_copyTitle, namedElements,
                                        dests.toArray(new IPath[dests.size()]));
                            }
                        };
                    };
                    IResource[] result = operation.copyResources(
                            normalResources.toArray(new IResource[normalResources.size()]), container);
                    if (result.length == 0) {
                        // a problem was occurred
                        return;
                    }
                    if (namedElements.size() != elements.length) {
                        // Update elements
                        elements = namedElements.toArray(new IQ7NamedElement[namedElements.size()]);
                    }
                }

                Map<IQ7NamedElement, String> newNames = new HashMap<IQ7NamedElement, String>();
                Set<String> names = CollectNames(container);
                Set<IPath> filesSkip = new HashSet<IPath>();
                List<IQ7NamedElement> skipElements = new ArrayList<IQ7NamedElement>();

                boolean isSameDestination = isDestinationSameAsSource(resourceData, container);
                int overwrite = IDialogConstants.NO_ID;
                IWorkspaceRoot workspaceRoot = container.getWorkspace().getRoot();

                for (Map.Entry<IQ7NamedElement, IFile> e : map.entrySet()) {
                    if (e.getValue().exists()) {
                        if (isSameDestination) {
                            try {
                                RenameDialog dialog = new RenameDialog(shell, e.getKey().getElementName(), names,
                                        e.getValue(), Messages.PasteAction_DialogTitle, filesSkip,
                                        Messages.PasteAction_DialogNewNameProposal);
                                if (dialog.open() == RenameDialog.OK) {
                                    newNames.put(e.getKey(), dialog.getResultName());
                                    names.add(dialog.getResultName());
                                    IPath newFilePath = dialog.getNewFileName();
                                    filesSkip.add(newFilePath);
                                    map.put(e.getKey(),
                                            ResourcesPlugin.getWorkspace().getRoot().getFile(newFilePath));
                                } else {
                                    return; // Cancel operation
                                }
                            } catch (ModelException e2) {
                                Q7UIPlugin.log(e2);
                            }
                        } else {
                            if (overwrite != IDialogConstants.YES_TO_ALL_ID) {
                                IResource source = e.getKey().getResource();
                                IResource destination = workspaceRoot.findMember(e.getValue().getFullPath());
                                overwrite = checkOverwrite(source, destination);
                                if (overwrite == IDialogConstants.NO_ID) {
                                    skipElements.add(e.getKey());
                                }
                                if (overwrite == IDialogConstants.CANCEL_ID) {
                                    return; // Cancel operation
                                }
                            }
                        }
                    }
                }

                // remove skipped from copied elements
                if (skipElements.size() > 0) {
                    for (IQ7NamedElement element : skipElements) {
                        namedElements.remove(element);
                        newNames.remove(element);
                        map.remove(element);
                    }
                    elements = namedElements.toArray(new IQ7NamedElement[namedElements.size()]);
                }

                // Check and update file name
                try {
                    RcpttCore.getInstance().copy(elements, map, newNames);
                } catch (CoreException e) {
                    Q7UIPlugin.log(e);
                }
            }
            return;
        }

        // try a file transfer
        FileTransfer fileTransfer = FileTransfer.getInstance();
        String[] fileData = (String[]) clipboard.getContents(fileTransfer);

        if (fileData != null) {
            // enablement should ensure that we always have access to a
            // container
            IContainer container = getContainer();

            CopyFilesAndFoldersOperation operation = new CopyFilesAndFoldersOperation(this.shell);
            operation.copyFiles(fileData, container);
        }
    }

    /**
     * Returns the container to hold the pasted resources.
     */
    private IContainer getContainer() {
        List<?> selection = getSelectedResources();
        if (selection.get(0) instanceof IFile) {
            return ((IFile) selection.get(0)).getParent();
        }
        return (IContainer) selection.get(0);
    }

    /**
     * The <code>PasteAction</code> implementation of this <code>SelectionListenerAction</code> method enables this
     * action if a
     * resource compatible with what is on the clipboard is selected.
     * 
     * -Clipboard must have IResource or java.io.File -Projects can always be
     * pasted if they are open -Workspace folder may not be copied into itself
     * -Files and folders may be pasted to a single selected folder in open
     * project or multiple selected files in the same folder
     */
    @Override
    protected boolean updateSelection(IStructuredSelection selection) {
        if (!super.updateSelection(selection)) {
            return false;
        }

        final IResource[][] clipboardData = new IResource[1][];
        shell.getDisplay().syncExec(new Runnable() {
            public void run() {
                // clipboard must have resources or files
                ResourceTransfer resTransfer = ResourceTransfer.getInstance();
                clipboardData[0] = (IResource[]) clipboard.getContents(resTransfer);
            }
        });
        IResource[] resourceData = clipboardData[0];
        boolean isProjectRes = resourceData != null && resourceData.length > 0
                && resourceData[0].getType() == IResource.PROJECT;

        if (isProjectRes) {
            for (int i = 0; i < resourceData.length; i++) {
                // make sure all resource data are open projects
                // can paste open projects regardless of selection
                if (resourceData[i].getType() != IResource.PROJECT
                        || ((IProject) resourceData[i]).isOpen() == false) {
                    return false;
                }
            }
            return true;
        }

        if (getSelectedNonResources().size() > 0) {
            return false;
        }

        IResource targetResource = getTarget();
        // targetResource is null if no valid target is selected (e.g., open
        // project)
        // or selection is empty
        if (targetResource == null) {
            return false;
        }

        // can paste files and folders to a single selection (file, folder,
        // open project) or multiple file selection with the same parent
        List<?> selectedResources = getSelectedResources();
        if (selectedResources.size() > 1) {
            for (int i = 0; i < selectedResources.size(); i++) {
                IResource resource = (IResource) selectedResources.get(i);
                if (resource.getType() != IResource.FILE) {
                    return false;
                }
                if (!targetResource.equals(resource.getParent())) {
                    return false;
                }
            }
        }
        if (resourceData != null) {
            // linked resources can only be pasted into projects
            if (isLinked(resourceData) && targetResource.getType() != IResource.PROJECT
                    && targetResource.getType() != IResource.FOLDER) {
                return false;
            }

            if (targetResource.getType() == IResource.FOLDER) {
                // don't try to copy folder to self
                for (int i = 0; i < resourceData.length; i++) {
                    if (targetResource.equals(resourceData[i])) {
                        return false;
                    }
                }
            }
            return true;
        }
        TransferData[] transfers = clipboard.getAvailableTypes();
        FileTransfer fileTransfer = FileTransfer.getInstance();
        for (int i = 0; i < transfers.length; i++) {
            if (fileTransfer.isSupportedType(transfers[i])) {
                return true;
            }
        }
        return false;
    }

    private Set<String> CollectNames(IContainer container) {
        Set<String> names = new HashSet<String>();

        IQ7Project project = RcpttCore.create(container.getProject());
        names.addAll(Arrays.asList(Q7SearchCore.findAllNames(new ReferencedProjectScope(project))));

        return names;
    }

    /**
     * Returns whether any of the given source resources are being recopied to
     * their current container. Copied from
     * org.eclipse.ui.actions.CopyFilesAndFoldersOperation.
     * 
     * @param sourceResources
     *            the source resources
     * @param destination
     *            the destination container
     * @return <code>true</code> if at least one of the given source resource's
     *         parent container is the same as the destination
     */
    boolean isDestinationSameAsSource(IResource[] sourceResources, IContainer destination) {
        IPath destinationLocation = destination.getLocation();

        for (int i = 0; i < sourceResources.length; i++) {
            IResource sourceResource = sourceResources[i];
            if (sourceResource.getParent().equals(destination)) {
                return true;
            } else if (destinationLocation != null) {
                // do thorough check to catch linked resources. Fixes bug 29913.
                IPath sourceLocation = sourceResource.getLocation();
                IPath destinationResource = destinationLocation.append(sourceResource.getName());
                if (sourceLocation != null && sourceLocation.isPrefixOf(destinationResource)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Check if the user wishes to overwrite the supplied resource or all
     * resources. Copied from
     * org.eclipse.ui.actions.CopyFilesAndFoldersOperation.
     * 
     * @param source
     *            the source resource
     * @param destination
     *            the resource to be overwritten
     * @return one of IDialogConstants.YES_ID, IDialogConstants.YES_TO_ALL_ID,
     *         IDialogConstants.NO_ID, IDialogConstants.CANCEL_ID indicating
     *         whether the current resource or all resources can be overwritten,
     *         or if the operation should be canceled.
     */
    private int checkOverwrite(final IResource source, final IResource destination) {
        final int[] result = new int[1];

        // Dialogs need to be created and opened in the UI thread
        Runnable query = new Runnable() {
            public void run() {
                String message;
                int resultId[] = { IDialogConstants.YES_ID, IDialogConstants.YES_TO_ALL_ID, IDialogConstants.NO_ID,
                        IDialogConstants.CANCEL_ID };
                String labels[] = new String[] { IDialogConstants.YES_LABEL, IDialogConstants.YES_TO_ALL_LABEL,
                        IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL };

                String[] bindings = new String[] { IDEResourceInfoUtils.getLocationText(destination),
                        IDEResourceInfoUtils.getDateStringValue(destination),
                        IDEResourceInfoUtils.getLocationText(source),
                        IDEResourceInfoUtils.getDateStringValue(source) };
                message = NLS.bind(IDEWorkbenchMessages.CopyFilesAndFoldersOperation_overwriteWithDetailsQuestion,
                        bindings);

                MessageDialog dialog = new MessageDialog(shell,
                        IDEWorkbenchMessages.CopyFilesAndFoldersOperation_resourceExists, null, message,
                        MessageDialog.QUESTION, labels, 0) {
                    protected int getShellStyle() {
                        return super.getShellStyle() | SWT.SHEET;
                    }
                };
                dialog.open();
                if (dialog.getReturnCode() == SWT.DEFAULT) {
                    // A window close returns SWT.DEFAULT, which has to be
                    // mapped to a cancel
                    result[0] = IDialogConstants.CANCEL_ID;
                } else {
                    result[0] = resultId[dialog.getReturnCode()];
                }
            }
        };
        shell.getDisplay().syncExec(query);
        return result[0];
    }
}