1 /******************************************************************************* 2 * Copyright (c) 2000, 2014 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.jdt.internal.ui.actions; 15 16 import java.util.ArrayList; 17 import java.util.Iterator; 18 import java.util.List; 19 20 import org.eclipse.osgi.util.TextProcessor; 21 22 import org.eclipse.swt.SWTError; 23 import org.eclipse.swt.dnd.Clipboard; 24 import org.eclipse.swt.dnd.DND; 25 import org.eclipse.swt.dnd.FileTransfer; 26 import org.eclipse.swt.dnd.TextTransfer; 27 import org.eclipse.swt.dnd.Transfer; 28 import org.eclipse.swt.graphics.Point; 29 30 import org.eclipse.core.runtime.IPath; 31 32 import org.eclipse.core.resources.IResource; 33 34 import org.eclipse.jface.dialogs.MessageDialog; 35 import org.eclipse.jface.viewers.ISelection; 36 import org.eclipse.jface.viewers.IStructuredSelection; 37 38 import org.eclipse.jface.text.ITextSelection; 39 import org.eclipse.jface.text.source.ISourceViewer; 40 41 import org.eclipse.ui.IWorkbenchSite; 42 import org.eclipse.ui.PlatformUI; 43 import org.eclipse.ui.part.ResourceTransfer; 44 45 import org.eclipse.jdt.core.IClassFile; 46 import org.eclipse.jdt.core.ICompilationUnit; 47 import org.eclipse.jdt.core.IImportDeclaration; 48 import org.eclipse.jdt.core.IJarEntryResource; 49 import org.eclipse.jdt.core.IJavaElement; 50 import org.eclipse.jdt.core.IJavaProject; 51 import org.eclipse.jdt.core.IMember; 52 import org.eclipse.jdt.core.IPackageDeclaration; 53 import org.eclipse.jdt.core.IPackageFragment; 54 import org.eclipse.jdt.core.IPackageFragmentRoot; 55 import org.eclipse.jdt.core.ITypeRoot; 56 import org.eclipse.jdt.core.JavaModelException; 57 import org.eclipse.jdt.core.dom.ASTNode; 58 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; 59 import org.eclipse.jdt.core.dom.ClassInstanceCreation; 60 import org.eclipse.jdt.core.dom.CompilationUnit; 61 import org.eclipse.jdt.core.dom.Expression; 62 import org.eclipse.jdt.core.dom.IBinding; 63 import org.eclipse.jdt.core.dom.ImportDeclaration; 64 import org.eclipse.jdt.core.dom.MemberRef; 65 import org.eclipse.jdt.core.dom.MemberValuePair; 66 import org.eclipse.jdt.core.dom.MethodDeclaration; 67 import org.eclipse.jdt.core.dom.MethodInvocation; 68 import org.eclipse.jdt.core.dom.Name; 69 import org.eclipse.jdt.core.dom.NodeFinder; 70 import org.eclipse.jdt.core.dom.PackageDeclaration; 71 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; 72 import org.eclipse.jdt.core.dom.Type; 73 import org.eclipse.jdt.core.dom.TypeDeclaration; 74 import org.eclipse.jdt.core.dom.TypeParameter; 75 import org.eclipse.jdt.core.dom.VariableDeclaration; 76 import org.eclipse.jdt.core.manipulation.SharedASTProviderCore; 77 78 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 79 80 import org.eclipse.jdt.ui.JavaElementLabels; 81 import org.eclipse.jdt.ui.JavaUI; 82 import org.eclipse.jdt.ui.actions.SelectionDispatchAction; 83 84 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; 85 import org.eclipse.jdt.internal.ui.JavaPlugin; 86 import org.eclipse.jdt.internal.ui.JavaPluginImages; 87 import org.eclipse.jdt.internal.ui.browsing.LogicalPackage; 88 import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; 89 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider; 90 91 92 public class CopyQualifiedNameAction extends SelectionDispatchAction { 93 94 private static final long LABEL_FLAGS= Long.valueOf(JavaElementLabels.F_FULLY_QUALIFIED | JavaElementLabels.M_FULLY_QUALIFIED | JavaElementLabels.I_FULLY_QUALIFIED 95 | JavaElementLabels.T_FULLY_QUALIFIED | JavaElementLabels.M_PARAMETER_TYPES | JavaElementLabels.USE_RESOLVED | JavaElementLabels.T_TYPE_PARAMETERS | JavaElementLabels.CU_QUALIFIED 96 | JavaElementLabels.CF_QUALIFIED).longValue(); 97 98 //TODO: Make API 99 public static final String ACTION_DEFINITION_ID= "org.eclipse.jdt.ui.edit.text.java.copy.qualified.name"; //$NON-NLS-1$ 100 101 //TODO: Make API 102 public static final String ACTION_HANDLER_ID= "org.eclipse.jdt.ui.actions.CopyQualifiedName"; //$NON-NLS-1$ 103 104 private JavaEditor fEditor; 105 CopyQualifiedNameAction(JavaEditor editor)106 public CopyQualifiedNameAction(JavaEditor editor) { 107 this(editor.getSite()); 108 fEditor= editor; 109 setEnabled(true); 110 } 111 CopyQualifiedNameAction(IWorkbenchSite site)112 public CopyQualifiedNameAction(IWorkbenchSite site) { 113 super(site); 114 115 setText(ActionMessages.CopyQualifiedNameAction_ActionName); 116 setToolTipText(ActionMessages.CopyQualifiedNameAction_ToolTipText); 117 setDisabledImageDescriptor(JavaPluginImages.DESC_DLCL_COPY_QUALIFIED_NAME); 118 setImageDescriptor(JavaPluginImages.DESC_ELCL_COPY_QUALIFIED_NAME); 119 PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.COPY_QUALIFIED_NAME_ACTION); 120 } 121 122 @Override selectionChanged(IStructuredSelection selection)123 public void selectionChanged(IStructuredSelection selection) { 124 setEnabled(canEnable(selection.toArray())); 125 } 126 127 @Override selectionChanged(ITextSelection selection)128 public void selectionChanged(ITextSelection selection) { 129 //Must not create an AST 130 } 131 canEnable(Object[] objects)132 private boolean canEnable(Object[] objects) { 133 for (Object element : objects) { 134 if (isValidElement(element)) 135 return true; 136 } 137 138 return false; 139 } 140 isValidElement(Object element)141 private boolean isValidElement(Object element) { 142 if (element instanceof IMember) 143 return true; 144 145 if (element instanceof IClassFile) 146 return true; 147 148 if (element instanceof ICompilationUnit) 149 return true; 150 151 if (element instanceof IPackageDeclaration) 152 return true; 153 154 if (element instanceof IImportDeclaration) 155 return true; 156 157 if (element instanceof IPackageFragment) 158 return true; 159 160 if (element instanceof IPackageFragmentRoot) 161 return true; 162 163 if (element instanceof IJavaProject) 164 return true; 165 166 if (element instanceof IJarEntryResource) 167 return true; 168 169 if (element instanceof IResource) 170 return true; 171 172 if (element instanceof LogicalPackage) 173 return true; 174 175 return false; 176 } 177 178 @Override run()179 public void run() { 180 181 try { 182 Object[] elements= getSelectedElements(); 183 if (elements == null) { 184 MessageDialog.openInformation(getShell(), ActionMessages.CopyQualifiedNameAction_InfoDialogTitel, ActionMessages.CopyQualifiedNameAction_NoElementToQualify); 185 return; 186 } 187 188 Object[] data= null; 189 Transfer[] dataTypes= null; 190 191 if (elements.length == 1) { 192 Object element= elements[0]; 193 String qualifiedName= getQualifiedName(element); 194 IResource resource= null; 195 if (element instanceof IJavaElement) { 196 IJavaElement je= ((IJavaElement)element); 197 if (je.exists()) 198 resource= je.getCorrespondingResource(); 199 } else if (element instanceof IResource) 200 resource= (IResource)element; 201 202 if (resource != null) { 203 IPath location= resource.getLocation(); 204 if (location != null) { 205 data= new Object[] { qualifiedName, resource, new String[] { location.toOSString() } }; 206 dataTypes= new Transfer[] { TextTransfer.getInstance(), ResourceTransfer.getInstance(), FileTransfer.getInstance() }; 207 } else { 208 data= new Object[] { qualifiedName, resource }; 209 dataTypes= new Transfer[] { TextTransfer.getInstance(), ResourceTransfer.getInstance() }; 210 } 211 } else { 212 data= new Object[] { qualifiedName }; 213 dataTypes= new Transfer[] { TextTransfer.getInstance() }; 214 } 215 } else { 216 StringBuilder buf= new StringBuilder(); 217 buf.append(getQualifiedName(elements[0])); 218 for (int i= 1; i < elements.length; i++) { 219 String qualifiedName= getQualifiedName(elements[i]); 220 buf.append(System.lineSeparator()).append(qualifiedName); 221 } 222 data= new Object[] { buf.toString() }; 223 dataTypes= new Transfer[] { TextTransfer.getInstance() }; 224 } 225 226 Clipboard clipboard= new Clipboard(getShell().getDisplay()); 227 try { 228 clipboard.setContents(data, dataTypes); 229 } catch (SWTError e) { 230 if (e.code != DND.ERROR_CANNOT_SET_CLIPBOARD) { 231 throw e; 232 } 233 if (MessageDialog.openQuestion(getShell(), ActionMessages.CopyQualifiedNameAction_ErrorTitle, ActionMessages.CopyQualifiedNameAction_ErrorDescription)) { 234 clipboard.setContents(data, dataTypes); 235 } 236 } finally { 237 clipboard.dispose(); 238 } 239 } catch (JavaModelException e) { 240 JavaPlugin.log(e); 241 } 242 } 243 getQualifiedName(Object element)244 private String getQualifiedName(Object element) throws JavaModelException { 245 if (element instanceof IResource) 246 return ((IResource)element).getFullPath().toString(); 247 248 if (element instanceof IJarEntryResource) 249 return ((IJarEntryResource)element).getFullPath().toString(); 250 251 if (element instanceof LogicalPackage) 252 return ((LogicalPackage)element).getElementName(); 253 254 if (element instanceof IJavaProject || element instanceof IPackageFragmentRoot || element instanceof ITypeRoot) { 255 IResource resource= ((IJavaElement)element).getCorrespondingResource(); 256 if (resource != null) 257 return getQualifiedName(resource); 258 } 259 260 if (element instanceof IBinding) 261 return BindingLabelProvider.getBindingLabel((IBinding)element, LABEL_FLAGS); 262 263 return TextProcessor.deprocess(JavaElementLabels.getTextLabel(element, LABEL_FLAGS)); 264 } 265 getSelectedElements()266 private Object[] getSelectedElements() { 267 if (fEditor != null) { 268 Object element= getSelectedElement(fEditor); 269 if (element == null) 270 return null; 271 272 return new Object[] { element }; 273 } 274 275 ISelection selection= getSelection(); 276 if (!(selection instanceof IStructuredSelection)) 277 return null; 278 279 List<Object> result= new ArrayList<>(); 280 for (Iterator<?> iter= ((IStructuredSelection)selection).iterator(); iter.hasNext();) { 281 Object element= iter.next(); 282 if (isValidElement(element)) 283 result.add(element); 284 } 285 if (result.isEmpty()) 286 return null; 287 288 return result.toArray(new Object[result.size()]); 289 } 290 getSelectedElement(JavaEditor editor)291 private Object getSelectedElement(JavaEditor editor) { 292 ISourceViewer viewer= editor.getViewer(); 293 if (viewer == null) 294 return null; 295 296 Point selectedRange= viewer.getSelectedRange(); 297 int length= selectedRange.y; 298 int offset= selectedRange.x; 299 300 ITypeRoot element= JavaUI.getEditorInputTypeRoot(editor.getEditorInput()); 301 if (element == null) 302 return null; 303 304 CompilationUnit ast= SharedASTProviderCore.getAST(element, SharedASTProviderCore.WAIT_YES, null); 305 if (ast == null) 306 return null; 307 308 NodeFinder finder= new NodeFinder(ast, offset, length); 309 ASTNode node= finder.getCoveringNode(); 310 311 IBinding binding= null; 312 if (node instanceof Name) { 313 binding= getConstructorBindingIfAvailable((Name)node); 314 if (binding != null) 315 return binding; 316 binding= ((Name)node).resolveBinding(); 317 } else if (node instanceof MethodInvocation) { 318 binding= ((MethodInvocation)node).resolveMethodBinding(); 319 } else if (node instanceof MethodDeclaration) { 320 binding= ((MethodDeclaration)node).resolveBinding(); 321 } else if (node instanceof Type) { 322 binding= ((Type)node).resolveBinding(); 323 } else if (node instanceof AnonymousClassDeclaration) { 324 binding= ((AnonymousClassDeclaration)node).resolveBinding(); 325 } else if (node instanceof TypeDeclaration) { 326 binding= ((TypeDeclaration)node).resolveBinding(); 327 } else if (node instanceof CompilationUnit) { 328 return ((CompilationUnit)node).getJavaElement(); 329 } else if (node instanceof Expression) { 330 binding= ((Expression)node).resolveTypeBinding(); 331 } else if (node instanceof ImportDeclaration) { 332 binding= ((ImportDeclaration)node).resolveBinding(); 333 } else if (node instanceof MemberRef) { 334 binding= ((MemberRef)node).resolveBinding(); 335 } else if (node instanceof MemberValuePair) { 336 binding= ((MemberValuePair)node).resolveMemberValuePairBinding(); 337 } else if (node instanceof PackageDeclaration) { 338 binding= ((PackageDeclaration)node).resolveBinding(); 339 } else if (node instanceof TypeParameter) { 340 binding= ((TypeParameter)node).resolveBinding(); 341 } else if (node instanceof VariableDeclaration) { 342 binding= ((VariableDeclaration)node).resolveBinding(); 343 } 344 345 if (binding != null) 346 return binding.getJavaElement(); 347 348 return null; 349 } 350 351 /** 352 * Checks whether the given name belongs to a {@link ClassInstanceCreation} and if so, returns 353 * its constructor binding. 354 * 355 * @param nameNode the name node 356 * @return the constructor binding or <code>null</code> if not found 357 * @since 3.7 358 */ getConstructorBindingIfAvailable(Name nameNode)359 private IBinding getConstructorBindingIfAvailable(Name nameNode) { 360 ASTNode type= ASTNodes.getNormalizedNode(nameNode); 361 StructuralPropertyDescriptor loc= type.getLocationInParent(); 362 if (loc == ClassInstanceCreation.TYPE_PROPERTY) { 363 return ((ClassInstanceCreation) type.getParent()).resolveConstructorBinding(); 364 } 365 return null; 366 } 367 368 } 369