/*
* Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.ui.internal.filesview;
import com.google.dart.tools.core.DartCore;
import com.google.dart.tools.ui.DartToolsPlugin;
import com.google.dart.tools.ui.internal.pub.PubPackageUtils;
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.runtime.Assert;
import org.eclipse.jface.viewers.IStructuredSelection;
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.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.CopyFilesAndFoldersOperation;
import org.eclipse.ui.actions.SelectionListenerAction;
import org.eclipse.ui.internal.views.navigator.ResourceNavigatorMessages;
import org.eclipse.ui.part.ResourceTransfer;
import java.util.List;
/**
* Standard action for pasting resources on the clipboard to the selected resource's location.
* <p>
* Based on the package private <code>org.eclipse.ui.views.navigator.PasteAction</code>.
* </p>
*/
@SuppressWarnings({"restriction", "rawtypes"})
public class PasteAction extends SelectionListenerAction {
/**
* The id of this action.
*/
public static final String ID = DartToolsPlugin.PLUGIN_ID + ".PasteAction";//$NON-NLS-1$
/**
* The shell in which to show any dialogs.
*/
private Shell shell;
/**
* System clipboard
*/
private Clipboard clipboard;
/**
* Creates a new action.
*
* @param shell the shell for any dialogs
* @param clipboard the clipboard
*/
public PasteAction(Shell shell, Clipboard clipboard) {
super(ResourceNavigatorMessages.PasteAction_title);
Assert.isNotNull(shell);
Assert.isNotNull(clipboard);
this.shell = shell;
this.clipboard = clipboard;
setToolTipText(ResourceNavigatorMessages.PasteAction_toolTip);
setId(PasteAction.ID);
setAccelerator(SWT.MOD1 | 'v');
setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(
ISharedImages.IMG_TOOL_PASTE));
setDisabledImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(
ISharedImages.IMG_TOOL_PASTE_DISABLED));
}
@Override
public void run() {
// prepare resources
ResourceTransfer resTransfer = ResourceTransfer.getInstance();
IResource[] resources = (IResource[]) clipboard.getContents(resTransfer);
if (resources == null || resources.length == 0) {
return;
}
// may be project
if (resources[0] instanceof IProject) {
CopyProjectOperation operation = new CopyProjectOperation(this.shell);
operation.copyProject((IProject) resources[0]);
// remove "packages" folders
IProject newProject = operation.newProject;
if (newProject != null) {
try {
DartCore.addToIgnores(newProject);
try {
PubPackageUtils.deletePackageDirectories(newProject);
PubPackageUtils.runPubInstall(newProject);
} finally {
DartCore.removeFromIgnores(newProject);
}
} catch (Throwable e) {
DartToolsPlugin.log(e);
}
}
// done with project
return;
}
// just some resources
IContainer container = getContainer();
CopyFilesAndFoldersOperation operation = new CopyFilesAndFoldersOperation(this.shell);
operation.copyResources(resources, container);
}
/**
* 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() {
@Override
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;
}
/**
* 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();
} else {
return (IContainer) selection.get(0);
}
}
/**
* 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;
}
}