/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.jsdt.internal.ui.refactoring.reorg;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
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.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ResourceTransfer;
import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
import org.eclipse.wst.jsdt.core.IJavaScriptElement;
import org.eclipse.wst.jsdt.core.IType;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.internal.corext.refactoring.TypedSource;
import org.eclipse.wst.jsdt.internal.corext.refactoring.reorg.JavaElementTransfer;
import org.eclipse.wst.jsdt.internal.corext.refactoring.reorg.ParentChecker;
import org.eclipse.wst.jsdt.internal.corext.refactoring.reorg.ReorgUtils;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.JavaElementUtil;
import org.eclipse.wst.jsdt.internal.corext.util.JavaModelUtil;
import org.eclipse.wst.jsdt.internal.ui.IJavaHelpContextIds;
import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
import org.eclipse.wst.jsdt.internal.ui.util.ExceptionHandler;
import org.eclipse.wst.jsdt.ui.JavaScriptElementLabelProvider;
import org.eclipse.wst.jsdt.ui.actions.SelectionDispatchAction;
public class CopyToClipboardAction extends SelectionDispatchAction{
private final Clipboard fClipboard;
private boolean fAutoRepeatOnFailure= false;
public CopyToClipboardAction(IWorkbenchSite site, Clipboard clipboard) {
super(site);
setText(ReorgMessages.CopyToClipboardAction_0);
setDescription(ReorgMessages.CopyToClipboardAction_1);
Assert.isNotNull(clipboard);
fClipboard= clipboard;
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));
update(getSelection());
PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.COPY_ACTION);
}
public void setAutoRepeatOnFailure(boolean autorepeatOnFailure){
fAutoRepeatOnFailure= autorepeatOnFailure;
}
private static ISharedImages getWorkbenchSharedImages() {
return JavaScriptPlugin.getDefault().getWorkbench().getSharedImages();
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.ui.actions.SelectionDispatchAction#selectionChanged(org.eclipse.jface.viewers.IStructuredSelection)
*/
public void selectionChanged(IStructuredSelection selection) {
try {
List elements= selection.toList();
IResource[] resources= ReorgUtils.getResources(elements);
IJavaScriptElement[] javaElements= ReorgUtils.getJavaElements(elements);
if (elements.size() != resources.length + javaElements.length)
setEnabled(false);
else
setEnabled(canEnable(resources, javaElements));
} catch (JavaScriptModelException e) {
//no ui here - this happens on selection changes
// http://bugs.eclipse.org/bugs/show_bug.cgi?id=19253
if (JavaModelUtil.isExceptionToBeLogged(e))
JavaScriptPlugin.log(e);
setEnabled(false);
}
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.ui.actions.SelectionDispatchAction#run(org.eclipse.jface.viewers.IStructuredSelection)
*/
public void run(IStructuredSelection selection) {
try {
List elements= selection.toList();
IResource[] resources= ReorgUtils.getResources(elements);
IJavaScriptElement[] javaElements= ReorgUtils.getJavaElements(elements);
if (elements.size() == resources.length + javaElements.length && canEnable(resources, javaElements))
doRun(resources, javaElements);
} catch (CoreException e) {
ExceptionHandler.handle(e, getShell(), ReorgMessages.CopyToClipboardAction_2, ReorgMessages.CopyToClipboardAction_3);
}
}
private void doRun(IResource[] resources, IJavaScriptElement[] javaElements) throws CoreException {
new ClipboardCopier(resources, javaElements, fClipboard, getShell(), fAutoRepeatOnFailure).copyToClipboard();
}
private boolean canEnable(IResource[] resources, IJavaScriptElement[] javaElements) throws JavaScriptModelException {
return new CopyToClipboardEnablementPolicy(resources, javaElements).canEnable();
}
//----------------------------------------------------------------------------------------//
private static class ClipboardCopier{
private final boolean fAutoRepeatOnFailure;
private final IResource[] fResources;
private final IJavaScriptElement[] fJavaElements;
private final Clipboard fClipboard;
private final Shell fShell;
private final ILabelProvider fLabelProvider;
private ClipboardCopier(IResource[] resources, IJavaScriptElement[] 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 CoreException{
//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);
IJavaScriptUnit[] 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));
IJavaScriptElement[] javaElementsForClipboard= ReorgUtils.union(fJavaElements, cusOfMainTypes);
TypedSource[] typedSources= TypedSource.createTypedSources(javaElementsForClipboard);
String[] fileNameArray= (String[]) fileNames.toArray(new String[fileNames.size()]);
copyToClipboard(resourcesForClipboard, fileNameArray, namesBuf.toString(), javaElementsForClipboard, typedSources, 0);
}
private static IJavaScriptElement[] getCompilationUnits(IJavaScriptElement[] javaElements) {
List cus= ReorgUtils.getElementsOfType(javaElements, IJavaScriptElement.JAVASCRIPT_UNIT);
return (IJavaScriptUnit[]) cus.toArray(new IJavaScriptUnit[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++) {
IJavaScriptElement element= fJavaElements[i];
switch (element.getElementType()) {
case IJavaScriptElement.JAVASCRIPT_PROJECT :
case IJavaScriptElement.PACKAGE_FRAGMENT_ROOT :
case IJavaScriptElement.PACKAGE_FRAGMENT :
case IJavaScriptElement.JAVASCRIPT_UNIT :
case IJavaScriptElement.CLASS_FILE :
addFileName(fileNames, ReorgUtils.getResource(element));
break;
default :
break;
}
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();
if (location != null) {
fileName.add(location.toOSString());
} else {
// not a file system path. skip file.
}
}
private void copyToClipboard(IResource[] resources, String[] fileNames, String names, IJavaScriptElement[] 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.sleep(500);
} catch (InterruptedException e1) {
// do nothing.
}
}
if (fAutoRepeatOnFailure || MessageDialog.openQuestion(fShell, ReorgMessages.CopyToClipboardAction_4, ReorgMessages.CopyToClipboardAction_5))
copyToClipboard(resources, fileNames, names, javaElements, typedSources, repeat+1);
}
}
private static Transfer[] createDataTypeArray(IResource[] resources, IJavaScriptElement[] 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, IJavaScriptElement[] 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 JavaScriptElementLabelProvider(
JavaScriptElementLabelProvider.SHOW_VARIABLE
+ JavaScriptElementLabelProvider.SHOW_PARAMETERS
+ JavaScriptElementLabelProvider.SHOW_TYPE
);
}
private String getName(IResource resource){
return fLabelProvider.getText(resource);
}
private String getName(IJavaScriptElement javaElement){
return fLabelProvider.getText(javaElement);
}
}
private static class CopyToClipboardEnablementPolicy {
private final IResource[] fResources;
private final IJavaScriptElement[] fJavaElements;
public CopyToClipboardEnablementPolicy(IResource[] resources, IJavaScriptElement[] javaElements){
Assert.isNotNull(resources);
Assert.isNotNull(javaElements);
fResources= resources;
fJavaElements= javaElements;
}
public boolean canEnable() throws JavaScriptModelException{
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 JavaScriptModelException {
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(IJavaScriptElement element) throws JavaScriptModelException {
if (element == null || ! element.exists())
return false;
if (JavaElementUtil.isDefaultPackage(element))
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;
}
}
}