blob: be229b3959a866a96cee9cec32e7cb02ae625de2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.ui.refactoring.reorg;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.resources.IResource;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.help.WorkbenchHelp;
import org.eclipse.ui.part.ResourceTransfer;
import org.eclipse.jdt.internal.corext.Assert;
import org.eclipse.jdt.internal.corext.refactoring.reorg.IReorgEnablementPolicy;
import org.eclipse.jdt.internal.corext.refactoring.reorg.JavaElementTransfer;
import org.eclipse.jdt.internal.corext.refactoring.reorg.ParentChecker;
import org.eclipse.jdt.internal.corext.refactoring.reorg.ReorgUtils;
import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil;
import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jdt.ui.actions.SelectionDispatchAction;
public class CopyToClipboardAction extends SelectionDispatchAction{
private final Clipboard fClipboard;
private SelectionDispatchAction fPasteAction;//may be null
private boolean fAutoRepeatOnFailure= false;
public CopyToClipboardAction(IWorkbenchSite site, Clipboard clipboard, SelectionDispatchAction pasteAction) {
super(site);
setText("&Copy");
setDescription("Copy the selected elements to the clipboard");
Assert.isNotNull(clipboard);
fClipboard= clipboard;
fPasteAction= pasteAction;
ISharedImages workbenchImages= getWorkbenchSharedImages();
setDisabledImageDescriptor(workbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED));
setImageDescriptor(workbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
setHoverImageDescriptor(workbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY_HOVER));
update(getSelection());
WorkbenchHelp.setHelp(this, IJavaHelpContextIds.COPY_ACTION);
}
public void setAutoRepeatOnFailure(boolean autorepeatOnFailure){
fAutoRepeatOnFailure= autorepeatOnFailure;
}
private static ISharedImages getWorkbenchSharedImages() {
return JavaPlugin.getDefault().getWorkbench().getSharedImages();
}
/* (non-Javadoc)
* @see org.eclipse.jdt.ui.actions.SelectionDispatchAction#selectionChanged(org.eclipse.jface.viewers.IStructuredSelection)
*/
public void selectionChanged(IStructuredSelection selection) {
try {
List elements= selection.toList();
IResource[] resources= ReorgUtils.getResources(elements);
IJavaElement[] javaElements= ReorgUtils.getJavaElements(elements);
if (elements.size() != resources.length + javaElements.length)
setEnabled(false);
else
setEnabled(canEnable(resources, javaElements));
} catch (JavaModelException e) {
//no ui here - this happens on selection changes
setEnabled(false);
}
}
/* (non-Javadoc)
* @see org.eclipse.jdt.ui.actions.SelectionDispatchAction#run(org.eclipse.jface.viewers.IStructuredSelection)
*/
public void run(IStructuredSelection selection) {
try {
List elements= selection.toList();
IResource[] resources= ReorgUtils.getResources(elements);
IJavaElement[] javaElements= ReorgUtils.getJavaElements(elements);
if (elements.size() == resources.length + javaElements.length && canEnable(resources, javaElements))
doRun(resources, javaElements);
} catch (JavaModelException e) {
ExceptionHandler.handle(e, getShell(), "Copy To Clipboard", "Internal error. See log for details.");
}
}
private void doRun(IResource[] resources, IJavaElement[] javaElements) throws JavaModelException {
new ClipboardCopier(resources, javaElements, fClipboard, getShell(), fAutoRepeatOnFailure).copyToClipboard();
// update the enablement of the paste action
// workaround since the clipboard does not support callbacks
if (fPasteAction != null && fPasteAction.getSelection() != null)
fPasteAction.update(fPasteAction.getSelection());
}
private boolean canEnable(IResource[] resources, IJavaElement[] javaElements) throws JavaModelException {
return new CopyToClipboardEnablementPolicy(resources, javaElements).canEnable();
}
//----------------------------------------------------------------------------------------//
private static class ClipboardCopier{
private final boolean fAutoRepeatOnFailure;
private final IResource[] fResources;
private final IJavaElement[] fJavaElements;
private final Clipboard fClipboard;
private final Shell fShell;
private final ILabelProvider fLabelProvider;
private ClipboardCopier(IResource[] resources, IJavaElement[] javaElements, Clipboard clipboard, Shell shell, boolean autoRepeatOnFailure){
Assert.isNotNull(resources);
Assert.isNotNull(javaElements);
Assert.isNotNull(clipboard);
Assert.isNotNull(shell);
fResources= resources;
fJavaElements= javaElements;
fClipboard= clipboard;
fShell= shell;
fLabelProvider= createLabelProvider();
fAutoRepeatOnFailure= autoRepeatOnFailure;
}
public void copyToClipboard() throws JavaModelException{
//Set<String> fileNames
Set fileNames= new HashSet(fResources.length + fJavaElements.length);
StringBuffer namesBuf = new StringBuffer();
processResources(fileNames, namesBuf);
processJavaElements(fileNames, namesBuf);
IType[] mainTypes= ReorgUtils.getMainTypes(fJavaElements);
ICompilationUnit[] cusOfMainTypes= ReorgUtils.getCompilationUnits(mainTypes);
IResource[] resourcesOfMainTypes= ReorgUtils.getResources(cusOfMainTypes);
addFileNames(fileNames, resourcesOfMainTypes);
IResource[] cuResources= ReorgUtils.getResources(getCompilationUnits(fJavaElements));
addFileNames(fileNames, cuResources);
IResource[] resourcesForClipboard= ReorgUtils.union(fResources, ReorgUtils.union(cuResources, resourcesOfMainTypes));
IJavaElement[] javaElementsForClipboard= ReorgUtils.union(fJavaElements, cusOfMainTypes);
TypedSource[] typedSources= TypedSource.createTypeSources(javaElementsForClipboard);
String[] fileNameArray= (String[]) fileNames.toArray(new String[fileNames.size()]);
copyToClipboard(resourcesForClipboard, fileNameArray, namesBuf.toString(), javaElementsForClipboard, typedSources, 0);
}
private static IJavaElement[] getCompilationUnits(IJavaElement[] javaElements) {
List cus= ReorgUtils.getElementsOfType(javaElements, IJavaElement.COMPILATION_UNIT);
return (ICompilationUnit[]) cus.toArray(new ICompilationUnit[cus.size()]);
}
private void processResources(Set fileNames, StringBuffer namesBuf) {
for (int i= 0; i < fResources.length; i++) {
IResource resource= fResources[i];
addFileName(fileNames, resource);
if (i > 0)
namesBuf.append('\n');
namesBuf.append(getName(resource));
}
}
private void processJavaElements(Set fileNames, StringBuffer namesBuf) {
for (int i= 0; i < fJavaElements.length; i++) {
IJavaElement element= fJavaElements[i];
if (! ReorgUtils.isInsideCompilationUnit(element))
addFileName(fileNames, ReorgUtils.getResource(element));
if (fResources.length > 0 || i > 0)
namesBuf.append('\n');
namesBuf.append(getName(element));
}
}
private static void addFileNames(Set fileName, IResource[] resources) {
for (int i= 0; i < resources.length; i++) {
addFileName(fileName, resources[i]);
}
}
private static void addFileName(Set fileName, IResource resource){
if (resource == null)
return;
IPath location = resource.getLocation();
// location may be null. See bug 29491.
if (location != null)
fileName.add(location.toOSString());
}
private void copyToClipboard(IResource[] resources, String[] fileNames, String names, IJavaElement[] javaElements, TypedSource[] typedSources, int repeat){
final int repeat_max_count= 10;
try{
fClipboard.setContents( createDataArray(resources, javaElements, fileNames, names, typedSources),
createDataTypeArray(resources, javaElements, fileNames, typedSources));
} catch (SWTError e) {
if (e.code != DND.ERROR_CANNOT_SET_CLIPBOARD || repeat >= repeat_max_count)
throw e;
if (fAutoRepeatOnFailure) {
try {
Thread.currentThread().sleep(500);
} catch (InterruptedException e1) {
// do nothing.
}
}
if (fAutoRepeatOnFailure || MessageDialog.openQuestion(fShell, "Problem Copying to Clipboard", "There was a problem when accessing the system clipboard. Retry?"))
copyToClipboard(resources, fileNames, names, javaElements, typedSources, repeat+1);
}
}
private static Transfer[] createDataTypeArray(IResource[] resources, IJavaElement[] javaElements, String[] fileNames, TypedSource[] typedSources) {
List result= new ArrayList(4);
if (resources.length != 0)
result.add(ResourceTransfer.getInstance());
if (javaElements.length != 0)
result.add(JavaElementTransfer.getInstance());
if (fileNames.length != 0)
result.add(FileTransfer.getInstance());
if (typedSources.length != 0)
result.add(TypedSourceTransfer.getInstance());
result.add(TextTransfer.getInstance());
return (Transfer[]) result.toArray(new Transfer[result.size()]);
}
private static Object[] createDataArray(IResource[] resources, IJavaElement[] javaElements, String[] fileNames, String names, TypedSource[] typedSources) {
List result= new ArrayList(4);
if (resources.length != 0)
result.add(resources);
if (javaElements.length != 0)
result.add(javaElements);
if (fileNames.length != 0)
result.add(fileNames);
if (typedSources.length != 0)
result.add(typedSources);
result.add(names);
return result.toArray();
}
private static ILabelProvider createLabelProvider(){
return new JavaElementLabelProvider(
JavaElementLabelProvider.SHOW_VARIABLE
+ JavaElementLabelProvider.SHOW_PARAMETERS
+ JavaElementLabelProvider.SHOW_TYPE
);
}
private String getName(IResource resource){
return fLabelProvider.getText(resource);
}
private String getName(IJavaElement javaElement){
return fLabelProvider.getText(javaElement);
}
}
private static class CopyToClipboardEnablementPolicy implements IReorgEnablementPolicy{
private final IResource[] fResources;
private final IJavaElement[] fJavaElements;
public CopyToClipboardEnablementPolicy(IResource[] resources, IJavaElement[] javaElements){
Assert.isNotNull(resources);
Assert.isNotNull(javaElements);
fResources= resources;
fJavaElements= javaElements;
}
public boolean canEnable() throws JavaModelException{
if (fResources.length + fJavaElements.length == 0)
return false;
if (hasProjects() && hasNonProjects())
return false;
if (! canCopyAllToClipboard())
return false;
if (! new ParentChecker(fResources, fJavaElements).haveCommonParent())
return false;
return true;
}
private boolean canCopyAllToClipboard() throws JavaModelException {
for (int i= 0; i < fResources.length; i++) {
if (! canCopyToClipboard(fResources[i])) return false;
}
for (int i= 0; i < fJavaElements.length; i++) {
if (! canCopyToClipboard(fJavaElements[i])) return false;
}
return true;
}
private static boolean canCopyToClipboard(IJavaElement element) throws JavaModelException {
if (element == null || ! element.exists())
return false;
if (element instanceof IJavaModel)
return false;
if (JavaElementUtil.isDefaultPackage(element))
return false;
if (element instanceof IMember && ! ReorgUtils.hasSourceAvailable((IMember)element))
return false;
if (element instanceof IMember){
/* feature in jdt core - initializers from class files are not binary but have no cus
* see bug 37199
* we just say 'no' to them
*/
IMember member= (IMember)element;
if (! member.isBinary() && ReorgUtils.getCompilationUnit(member) == null)
return false;
}
if (ReorgUtils.isDeletedFromEditor(element))
return false;
if (! (element instanceof IMember) && element.isReadOnly())
return false;
return true;
}
private static boolean canCopyToClipboard(IResource resource) {
return resource != null &&
resource.exists() &&
! resource.isPhantom() &&
resource.getType() != IResource.ROOT;
}
private boolean hasProjects() {
for (int i= 0; i < fResources.length; i++) {
if (ReorgUtils.isProject(fResources[i])) return true;
}
for (int i= 0; i < fJavaElements.length; i++) {
if (ReorgUtils.isProject(fJavaElements[i])) return true;
}
return false;
}
private boolean hasNonProjects() {
for (int i= 0; i < fResources.length; i++) {
if (! ReorgUtils.isProject(fResources[i])) return true;
}
for (int i= 0; i < fJavaElements.length; i++) {
if (! ReorgUtils.isProject(fJavaElements[i])) return true;
}
return false;
}
}
}