content: /*******************************************************************************
   * Copyright (c) 2000, 2015 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.actions;
  
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  
  import org.eclipse.core.resources.IResource;
  import org.eclipse.core.runtime.IPath;
  import org.eclipse.jface.dialogs.MessageDialog;
  import org.eclipse.jface.text.ITextSelection;
  import org.eclipse.jface.text.source.ISourceViewer;
  import org.eclipse.jface.viewers.ISelection;
  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.graphics.Point;
  import org.eclipse.ui.IWorkbenchSite;
  import org.eclipse.ui.part.ResourceTransfer;
  import org.eclipse.wst.jsdt.core.IClassFile;
  import org.eclipse.wst.jsdt.core.IImportDeclaration;
  import org.eclipse.wst.jsdt.core.IJavaScriptElement;
  import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
  import org.eclipse.wst.jsdt.core.IMember;
  import org.eclipse.wst.jsdt.core.IPackageFragment;
  import org.eclipse.wst.jsdt.core.JavaScriptModelException;
  import org.eclipse.wst.jsdt.core.dom.ASTNode;
  import org.eclipse.wst.jsdt.core.dom.AnonymousClassDeclaration;
  import org.eclipse.wst.jsdt.core.dom.Expression;
  import org.eclipse.wst.jsdt.core.dom.FunctionDeclaration;
  import org.eclipse.wst.jsdt.core.dom.FunctionInvocation;
  import org.eclipse.wst.jsdt.core.dom.IBinding;
  import org.eclipse.wst.jsdt.core.dom.ImportDeclaration;
  import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit;
  import org.eclipse.wst.jsdt.core.dom.MemberRef;
  import org.eclipse.wst.jsdt.core.dom.Name;
  import org.eclipse.wst.jsdt.core.dom.PackageDeclaration;
  import org.eclipse.wst.jsdt.core.dom.Type;
  import org.eclipse.wst.jsdt.core.dom.TypeDeclaration;
  import org.eclipse.wst.jsdt.core.dom.VariableDeclaration;
  import org.eclipse.wst.jsdt.internal.corext.dom.NodeFinder;
  import org.eclipse.wst.jsdt.internal.ui.JavaPluginImages;
  import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
  import org.eclipse.wst.jsdt.internal.ui.javaeditor.ASTProvider;
  import org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaEditor;
  import org.eclipse.wst.jsdt.ui.JavaScriptElementLabels;
  import org.eclipse.wst.jsdt.ui.JavaScriptUI;
  import org.eclipse.wst.jsdt.ui.actions.SelectionDispatchAction;
  
  public class CopyQualifiedNameAction extends SelectionDispatchAction {
  	
  	private static final long LABEL_FLAGS= JavaScriptElementLabels.F_FULLY_QUALIFIED | JavaScriptElementLabels.M_FULLY_QUALIFIED | JavaScriptElementLabels.I_FULLY_QUALIFIED | JavaScriptElementLabels.T_FULLY_QUALIFIED | JavaScriptElementLabels.M_PARAMETER_TYPES | JavaScriptElementLabels.USE_RESOLVED | JavaScriptElementLabels.T_TYPE_PARAMETERS | JavaScriptElementLabels.CU_QUALIFIED | JavaScriptElementLabels.CF_QUALIFIED;
  
      //TODO: Make API
  	public static final String ACTION_DEFINITION_ID= "org.eclipse.wst.jsdt.ui.edit.text.java.copy.qualified.name"; //$NON-NLS-1$
  
  	//TODO: Make API
  	public static final String ACTION_HANDLER_ID= "org.eclipse.wst.jsdt.ui.actions.CopyQualifiedName"; //$NON-NLS-1$
  
  	private JavaEditor fEditor;
  
      public CopyQualifiedNameAction(JavaEditor editor) {
      	this(editor.getSite());
  		fEditor= editor;
  		setEnabled(true);
  	}
  
  	public CopyQualifiedNameAction(IWorkbenchSite site) {
  		super(site);
  		
  		setText(ActionMessages.CopyQualifiedNameAction_ActionName);
  		setToolTipText(ActionMessages.CopyQualifiedNameAction_ToolTipText);
  		setDisabledImageDescriptor(JavaPluginImages.DESC_DLCL_COPY_QUALIFIED_NAME);
  		setImageDescriptor(JavaPluginImages.DESC_ELCL_COPY_QUALIFIED_NAME);
  	}
  	
  	/**
  	 * {@inheritDoc}
  	 */
  	public void selectionChanged(IStructuredSelection selection) {
  		setEnabled(canEnable(selection.toArray()));
  	}
  	
  	public void selectionChanged(ITextSelection selection) {
  		//Must not create an AST
  	}
  
  	private boolean canEnable(Object[] objects) {
  		for (int i= 0; i < objects.length; i++) {
  			Object element= objects[i];
  			if (isValideElement(element))
  				return true;
  		}
  
  		return false;
  	}
  	
  	private boolean isValideElement(Object element) {
  		if (element instanceof IMember)
  			return true;
  		
  		if (element instanceof IClassFile)
  			return true;
  		
  		if (element instanceof IJavaScriptUnit)
  			return true;
  		
  		if (element instanceof IImportDeclaration)
  			return true;
  		
  		if (element instanceof IPackageFragment)
  			return true;
  		
  		return false;
  	}
  	
  	/* (non-Javadoc)
       * @see org.eclipse.jface.action.Action#run()
       */
      public void run() {
      	
      	try {
  			IJavaScriptElement[] elements= getSelectedElements();
  			if (elements == null) {
  				MessageDialog.openInformation(getShell(), ActionMessages.CopyQualifiedNameAction_InfoDialogTitel, ActionMessages.CopyQualifiedNameAction_NoElementToQualify);
  				return;
  			}
  
  			Object[] data= null;
  			Transfer[] dataTypes= null;
  			
  			if (elements.length == 1) {
  				String qualifiedName= JavaScriptElementLabels.getElementLabel(elements[0], LABEL_FLAGS);
  				IResource resource= elements[0].getCorrespondingResource();
  				
  				if (resource != null) {
  					IPath location= resource.getLocation();
  					if (location != null) {
  						data= new Object[] {qualifiedName, resource, new String[] {location.toOSString()}};
  						dataTypes= new Transfer[] {TextTransfer.getInstance(), ResourceTransfer.getInstance(), FileTransfer.getInstance()};
  					} else {
  						data= new Object[] {qualifiedName, resource};
  						dataTypes= new Transfer[] {TextTransfer.getInstance(), ResourceTransfer.getInstance()};
  					}
  				} else {
  					data= new Object[] {qualifiedName};
  					dataTypes= new Transfer[] {TextTransfer.getInstance()};
  				}
  			} else {
  				StringBuffer buf= new StringBuffer();
  				buf.append(JavaScriptElementLabels.getElementLabel(elements[0], LABEL_FLAGS));
  				for (int i= 1; i < elements.length; i++) {
  					IJavaScriptElement element= elements[i];
  					
  					String qualifiedName= JavaScriptElementLabels.getElementLabel(element, LABEL_FLAGS);
  					buf.append('\r').append('\n').append(qualifiedName);
  				}
  				data= new Object[] {buf.toString()};
  				dataTypes= new Transfer[] {TextTransfer.getInstance()};
  			}
  			
  			Clipboard clipboard= new Clipboard(getShell().getDisplay());
  			try {
  				clipboard.setContents(data, dataTypes);
  			} catch (SWTError e) {
  				if (e.code != DND.ERROR_CANNOT_SET_CLIPBOARD) {
  					throw e;
  				}
  				if (MessageDialog.openQuestion(getShell(), ActionMessages.CopyQualifiedNameAction_ErrorTitle, ActionMessages.CopyQualifiedNameAction_ErrorDescription)) {
  					clipboard.setContents(data, dataTypes);
  				}
  			} finally {
  				clipboard.dispose();
  			}
  		} catch (JavaScriptModelException e) {
  			JavaScriptPlugin.log(e);
  		}
      }
  
      private IJavaScriptElement[] getSelectedElements() throws JavaScriptModelException {
      	if (fEditor != null) {
      		IJavaScriptElement element= getSelectedElement(fEditor);
      		if (element == null)
      			return null;
      		
      		return new IJavaScriptElement[] {element}; 
      	}
      	
      	ISelection selection= getSelection();
      	if (!(selection instanceof IStructuredSelection))
      		return null;
      	
      	List result= new ArrayList();
      	for (Iterator iter= ((IStructuredSelection)selection).iterator(); iter.hasNext();) {
  			Object element= iter.next();
  			if (isValideElement(element))
  				result.add(element);
  		}
      	if (result.isEmpty())
      		return null;
      	
  		return (IJavaScriptElement[])result.toArray(new IJavaScriptElement[result.size()]);
  	}
  
  	private IJavaScriptElement getSelectedElement(JavaEditor editor) {
  		ISourceViewer viewer= editor.getViewer();
  		if (viewer == null)
  			return null;
  		
  		Point selectedRange= viewer.getSelectedRange();
  		int length= selectedRange.y;
  		int offset= selectedRange.x;
  		
  		IJavaScriptElement element= JavaScriptUI.getEditorInputJavaElement(editor.getEditorInput());		
  		JavaScriptUnit ast= ASTProvider.getASTProvider().getAST(element, ASTProvider.WAIT_YES, null);
  		if (ast == null)
  			return null;
  
  		NodeFinder finder= new NodeFinder(offset, length);
  		ast.accept(finder);
  		ASTNode node= finder.getCoveringNode();
  		
  		IBinding binding= null;
  		if (node instanceof Name) {
  			binding= ((Name)node).resolveBinding();
  		} else if (node instanceof FunctionInvocation) {
  			binding= ((FunctionInvocation)node).resolveMethodBinding();
  		} else if (node instanceof FunctionDeclaration) {
  			binding= ((FunctionDeclaration)node).resolveBinding();
  		} else if (node instanceof Type) {
  			binding= ((Type)node).resolveBinding();
  		} else if (node instanceof AnonymousClassDeclaration) {
  			binding= ((AnonymousClassDeclaration)node).resolveBinding();
  		} else if (node instanceof TypeDeclaration) {
  			binding= ((TypeDeclaration)node).resolveBinding();
  		} else if (node instanceof JavaScriptUnit) {
  			return ((JavaScriptUnit)node).getJavaElement();
  		} else if (node instanceof Expression) {
  			binding= ((Expression)node).resolveTypeBinding();
  		} else if (node instanceof ImportDeclaration) {
  			binding= ((ImportDeclaration)node).resolveBinding();
  		} else if (node instanceof MemberRef) {
  			binding= ((MemberRef)node).resolveBinding();
  		} else if (node instanceof PackageDeclaration) {
  			binding= ((PackageDeclaration)node).resolveBinding();
  		} else if (node instanceof VariableDeclaration) {
  			binding= ((VariableDeclaration)node).resolveBinding();
  		} 
  			
  		if (binding != null)
  			return binding.getJavaElement();
  
  		return null;
  	}
  
  }
  