| /******************************************************************************* |
| * Copyright (c) 2000, 2017 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 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.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.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.ISourceModule; |
| import org.eclipse.dltk.core.IType; |
| import org.eclipse.dltk.core.ModelException; |
| import org.eclipse.dltk.core.ScriptModelUtil; |
| import org.eclipse.dltk.internal.core.ExternalScriptFolder; |
| import org.eclipse.dltk.internal.corext.refactoring.reorg.IReorgEnablementPolicy; |
| import org.eclipse.dltk.internal.corext.refactoring.reorg.ModelElementTransfer; |
| import org.eclipse.dltk.internal.corext.refactoring.reorg.ParentChecker; |
| import org.eclipse.dltk.internal.corext.refactoring.reorg.ReorgUtils; |
| import org.eclipse.dltk.internal.corext.refactoring.util.ModelElementUtil; |
| import org.eclipse.dltk.ui.DLTKUIPlugin; |
| import org.eclipse.dltk.ui.ModelElementLabelProvider; |
| import org.eclipse.dltk.ui.actions.SelectionDispatchAction; |
| import org.eclipse.dltk.ui.util.ExceptionHandler; |
| 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.part.ResourceTransfer; |
| |
| 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(ReorgMessages.CopyToClipboardAction_0); |
| setDescription(ReorgMessages.CopyToClipboardAction_1); |
| 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)); |
| update(getSelection()); |
| |
| if (DLTKCore.DEBUG) { |
| System.err.println("Add help support here..."); //$NON-NLS-1$ |
| } |
| |
| // PlatformUI.getWorkbench().getHelpSystem().setHelp(this, |
| // IScriptHelpContextIds.COPY_ACTION); |
| } |
| |
| public void setAutoRepeatOnFailure(boolean autorepeatOnFailure) { |
| fAutoRepeatOnFailure = autorepeatOnFailure; |
| } |
| |
| private static ISharedImages getWorkbenchSharedImages() { |
| return DLTKUIPlugin.getDefault().getWorkbench().getSharedImages(); |
| } |
| |
| @Override |
| public void selectionChanged(IStructuredSelection selection) { |
| try { |
| List elements = selection.toList(); |
| IResource[] resources = ReorgUtils.getResources(elements); |
| IModelElement[] modelElements = ReorgUtils |
| .getModelElements(elements); |
| if (elements.size() != resources.length + modelElements.length) |
| setEnabled(false); |
| else |
| setEnabled(canEnable(resources, modelElements)); |
| } catch (ModelException e) { |
| // no ui here - this happens on selection changes |
| // http://bugs.eclipse.org/bugs/show_bug.cgi?id=19253 |
| if (ScriptModelUtil.isExceptionToBeLogged(e)) |
| DLTKUIPlugin.log(e); |
| setEnabled(false); |
| } |
| } |
| |
| @Override |
| public void run(IStructuredSelection selection) { |
| try { |
| List elements = selection.toList(); |
| IResource[] resources = ReorgUtils.getResources(elements); |
| IModelElement[] modelElements = ReorgUtils |
| .getModelElements(elements); |
| if (elements.size() == resources.length + modelElements.length |
| && canEnable(resources, modelElements)) |
| doRun(resources, modelElements); |
| } catch (CoreException e) { |
| ExceptionHandler.handle(e, getShell(), |
| ReorgMessages.CopyToClipboardAction_2, |
| ReorgMessages.CopyToClipboardAction_3); |
| } |
| } |
| |
| private void doRun(IResource[] resources, IModelElement[] modelElements) |
| throws CoreException { |
| new ClipboardCopier(resources, modelElements, 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, |
| IModelElement[] modelElements) throws ModelException { |
| return new CopyToClipboardEnablementPolicy(resources, modelElements) |
| .canEnable(); |
| } |
| |
| // ----------------------------------------------------------------------------------------// |
| |
| private static class ClipboardCopier { |
| private final boolean fAutoRepeatOnFailure; |
| private final IResource[] fResources; |
| private final IModelElement[] fScriptElements; |
| private final Clipboard fClipboard; |
| private final Shell fShell; |
| private final ILabelProvider fLabelProvider; |
| |
| private ClipboardCopier(IResource[] resources, |
| IModelElement[] modelElements, Clipboard clipboard, Shell shell, |
| boolean autoRepeatOnFailure) { |
| Assert.isNotNull(resources); |
| Assert.isNotNull(modelElements); |
| Assert.isNotNull(clipboard); |
| Assert.isNotNull(shell); |
| fResources = resources; |
| fScriptElements = modelElements; |
| fClipboard = clipboard; |
| fShell = shell; |
| fLabelProvider = createLabelProvider(); |
| fAutoRepeatOnFailure = autoRepeatOnFailure; |
| } |
| |
| public void copyToClipboard() throws CoreException { |
| // Set<String> fileNames |
| Set<String> fileNames = new HashSet<>( |
| fResources.length + fScriptElements.length); |
| StringBuffer namesBuf = new StringBuffer(); |
| processResources(fileNames, namesBuf); |
| processScriptElements(fileNames, namesBuf); |
| |
| List typesList = ReorgUtils.getElementsOfType(fScriptElements, |
| IModelElement.TYPE); |
| IType types[] = (IType[]) typesList |
| .toArray(new IType[typesList.size()]); |
| ISourceModule[] cusOfMainTypes = ReorgUtils.getSourceModules(types); |
| IResource[] resourcesOfMainTypes = ReorgUtils |
| .getResources(cusOfMainTypes); |
| addFileNames(fileNames, resourcesOfMainTypes); |
| |
| IResource[] cuResources = ReorgUtils |
| .getResources(getSourceModules(fScriptElements)); |
| addFileNames(fileNames, cuResources); |
| |
| IResource[] resourcesForClipboard = ReorgUtils.union(fResources, |
| ReorgUtils.union(cuResources, resourcesOfMainTypes)); |
| IModelElement[] modelElementsForClipboard = ReorgUtils |
| .union(fScriptElements, cusOfMainTypes); |
| |
| // TypedSource[] typedSources= |
| // TypedSource.createTypedSources(modelElementsForClipboard); |
| String[] fileNameArray = fileNames |
| .toArray(new String[fileNames.size()]); |
| copyToClipboard(resourcesForClipboard, fileNameArray, |
| namesBuf.toString(), |
| modelElementsForClipboard/* , typedSources */, 0); |
| } |
| |
| private static IModelElement[] getSourceModules( |
| IModelElement[] modelElements) { |
| List cus = ReorgUtils.getElementsOfType(modelElements, |
| IModelElement.SOURCE_MODULE); |
| return (ISourceModule[]) cus.toArray(new ISourceModule[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 processScriptElements(Set fileNames, |
| StringBuffer namesBuf) { |
| for (int i = 0; i < fScriptElements.length; i++) { |
| IModelElement element = fScriptElements[i]; |
| switch (element.getElementType()) { |
| case IModelElement.SCRIPT_PROJECT: |
| case IModelElement.PROJECT_FRAGMENT: |
| case IModelElement.SCRIPT_FOLDER: |
| case IModelElement.SOURCE_MODULE: |
| 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, IModelElement[] modelElements, |
| /* |
| * TypedSource[] typedSources, |
| */int repeat) { |
| final int repeat_max_count = 10; |
| try { |
| fClipboard.setContents( |
| createDataArray(resources, modelElements, fileNames, |
| names/* , typedSources */), |
| createDataTypeArray(resources, modelElements, |
| 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, |
| modelElements/* , typedSources */, repeat + 1); |
| } |
| } |
| |
| private static Transfer[] createDataTypeArray(IResource[] resources, |
| IModelElement[] modelElements, |
| String[] fileNames/* |
| * , TypedSource[] typedSources |
| */) { |
| List<Transfer> result = new ArrayList<>(4); |
| if (resources.length != 0) |
| result.add(ResourceTransfer.getInstance()); |
| if (modelElements.length != 0) |
| result.add(ModelElementTransfer.getInstance()); |
| if (fileNames.length != 0) |
| result.add(FileTransfer.getInstance()); |
| // if (typedSources.length != 0) |
| // result.add(TypedSourceTransfer.getInstance()); |
| result.add(TextTransfer.getInstance()); |
| return result.toArray(new Transfer[result.size()]); |
| } |
| |
| private static Object[] createDataArray(IResource[] resources, |
| IModelElement[] modelElements, String[] fileNames, |
| String names/* |
| * , TypedSource [ ] typedSources |
| */) { |
| List result = new ArrayList(4); |
| if (resources.length != 0) |
| result.add(resources); |
| if (modelElements.length != 0) |
| result.add(modelElements); |
| 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 ModelElementLabelProvider( |
| ModelElementLabelProvider.SHOW_VARIABLE |
| + ModelElementLabelProvider.SHOW_PARAMETERS |
| + ModelElementLabelProvider.SHOW_TYPE |
| + ModelElementLabelProvider.SHOW_RETURN_TYPE); |
| } |
| |
| private String getName(IResource resource) { |
| return fLabelProvider.getText(resource); |
| } |
| |
| private String getName(IModelElement modelElement) { |
| return fLabelProvider.getText(modelElement); |
| } |
| } |
| |
| private static class CopyToClipboardEnablementPolicy |
| implements IReorgEnablementPolicy { |
| private final IResource[] fResources; |
| private final IModelElement[] fScriptElements; |
| |
| public CopyToClipboardEnablementPolicy(IResource[] resources, |
| IModelElement[] modelElements) { |
| Assert.isNotNull(resources); |
| Assert.isNotNull(modelElements); |
| fResources = resources; |
| fScriptElements = modelElements; |
| } |
| |
| @Override |
| public boolean canEnable() throws ModelException { |
| if (fResources.length + fScriptElements.length == 0) |
| return false; |
| if (hasProjects() && hasNonProjects()) |
| return false; |
| if (!canCopyAllToClipboard()) |
| return false; |
| if (!new ParentChecker(fResources, fScriptElements) |
| .haveCommonParent()) |
| return false; |
| return true; |
| } |
| |
| private boolean canCopyAllToClipboard() throws ModelException { |
| for (int i = 0; i < fResources.length; i++) { |
| if (!canCopyToClipboard(fResources[i])) |
| return false; |
| } |
| for (int i = 0; i < fScriptElements.length; i++) { |
| if (!canCopyToClipboard(fScriptElements[i])) |
| return false; |
| } |
| return true; |
| } |
| |
| private static boolean canCopyToClipboard(IModelElement element) |
| throws ModelException { |
| if (element == null || !element.exists()) |
| return false; |
| |
| if (ModelElementUtil.isDefaultPackage(element)) |
| return false; |
| |
| if (DLTKCore.DEBUG) { |
| System.err.println("TODO: Add inner element copy action.."); //$NON-NLS-1$ |
| } |
| // TODO: Add copy operation for external script folders.. Posible |
| // this is not required at all. |
| if (element instanceof ExternalScriptFolder) { |
| return false; |
| } |
| if (element.getElementType() > IModelElement.BINARY_MODULE) { |
| 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 < fScriptElements.length; i++) { |
| if (ReorgUtils.isProject(fScriptElements[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 < fScriptElements.length; i++) { |
| if (!ReorgUtils.isProject(fScriptElements[i])) |
| return true; |
| } |
| return false; |
| } |
| } |
| } |