| /* |
| * Copyright 2000-2012 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.ide.actions; |
| |
| import com.intellij.codeInsight.TargetElementUtilBase; |
| import com.intellij.codeInsight.daemon.impl.IdentifierUtil; |
| import com.intellij.codeInsight.highlighting.HighlightManager; |
| import com.intellij.ide.IdeBundle; |
| import com.intellij.ide.dnd.FileCopyPasteUtil; |
| import com.intellij.openapi.actionSystem.*; |
| import com.intellij.openapi.editor.Document; |
| import com.intellij.openapi.editor.Editor; |
| import com.intellij.openapi.editor.colors.EditorColors; |
| import com.intellij.openapi.editor.colors.EditorColorsManager; |
| import com.intellij.openapi.editor.markup.TextAttributes; |
| import com.intellij.openapi.extensions.Extensions; |
| import com.intellij.openapi.fileEditor.FileDocumentManager; |
| import com.intellij.openapi.ide.CopyPasteManager; |
| import com.intellij.openapi.project.DumbAwareAction; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.roots.ProjectRootManager; |
| import com.intellij.openapi.util.io.FileUtil; |
| import com.intellij.openapi.vfs.VfsUtil; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.openapi.wm.WindowManager; |
| import com.intellij.openapi.wm.ex.StatusBarEx; |
| import com.intellij.psi.*; |
| import com.intellij.util.ArrayUtil; |
| import com.intellij.util.LogicalRoot; |
| import com.intellij.util.LogicalRootsManager; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.awt.datatransfer.DataFlavor; |
| import java.awt.datatransfer.StringSelection; |
| import java.awt.datatransfer.Transferable; |
| import java.awt.datatransfer.UnsupportedFlavorException; |
| import java.io.IOException; |
| |
| /** |
| * @author Alexey |
| */ |
| public class CopyReferenceAction extends DumbAwareAction { |
| public static final DataFlavor ourFlavor = FileCopyPasteUtil.createJvmDataFlavor(MyTransferable.class); |
| |
| public CopyReferenceAction() { |
| super(); |
| setEnabledInModalContext(true); |
| setInjectedContext(true); |
| } |
| |
| @Override |
| public void update(AnActionEvent e) { |
| DataContext dataContext = e.getDataContext(); |
| Editor editor = CommonDataKeys.EDITOR.getData(dataContext); |
| boolean enabled = (editor != null && FileDocumentManager.getInstance().getFile(editor.getDocument()) != null) || |
| getElementToCopy(editor, dataContext) != null; |
| e.getPresentation().setEnabled(enabled); |
| if (ActionPlaces.isPopupPlace(e.getPlace())) { |
| e.getPresentation().setVisible(enabled); |
| } |
| else { |
| e.getPresentation().setVisible(true); |
| } |
| } |
| |
| @Override |
| public void actionPerformed(AnActionEvent e) { |
| DataContext dataContext = e.getDataContext(); |
| Editor editor = CommonDataKeys.EDITOR.getData(dataContext); |
| Project project = CommonDataKeys.PROJECT.getData(dataContext); |
| PsiElement element = getElementToCopy(editor, dataContext); |
| |
| if (!doCopy(element, project, editor) && editor != null) { |
| Document document = editor.getDocument(); |
| PsiFile file = PsiDocumentManager.getInstance(project).getCachedPsiFile(document); |
| if (file != null) { |
| String toCopy = getFileFqn(file) + ":" + (editor.getCaretModel().getLogicalPosition().line + 1); |
| CopyPasteManager.getInstance().setContents(new StringSelection(toCopy)); |
| setStatusBarText(project, toCopy + " has been copied"); |
| } |
| return; |
| } |
| |
| HighlightManager highlightManager = HighlightManager.getInstance(project); |
| EditorColorsManager manager = EditorColorsManager.getInstance(); |
| TextAttributes attributes = manager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); |
| if (element != null && editor != null) { |
| PsiElement nameIdentifier = IdentifierUtil.getNameIdentifier(element); |
| if (nameIdentifier != null) { |
| highlightManager.addOccurrenceHighlights(editor, new PsiElement[]{nameIdentifier}, attributes, true, null); |
| } else { |
| PsiReference reference = TargetElementUtilBase.findReference(editor, editor.getCaretModel().getOffset()); |
| if (reference != null) { |
| highlightManager.addOccurrenceHighlights(editor, new PsiReference[]{reference}, attributes, true, null); |
| } else if (element != PsiDocumentManager.getInstance(project).getCachedPsiFile(editor.getDocument())) { |
| highlightManager.addOccurrenceHighlights(editor, new PsiElement[]{element}, attributes, true, null); |
| } |
| } |
| } |
| } |
| |
| @Nullable |
| private static PsiElement getElementToCopy(@Nullable final Editor editor, final DataContext dataContext) { |
| PsiElement element = null; |
| if (editor != null) { |
| PsiReference reference = TargetElementUtilBase.findReference(editor); |
| if (reference != null) { |
| element = reference.getElement(); |
| } |
| } |
| |
| if (element == null) { |
| element = CommonDataKeys.PSI_ELEMENT.getData(dataContext); |
| } |
| if (element == null && editor == null) { |
| VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext); |
| Project project = CommonDataKeys.PROJECT.getData(dataContext); |
| if (virtualFile != null && project != null) { |
| element = PsiManager.getInstance(project).findFile(virtualFile); |
| } |
| } |
| if (element instanceof PsiFile && !((PsiFile)element).getViewProvider().isPhysical()) { |
| return null; |
| } |
| |
| for (QualifiedNameProvider provider : Extensions.getExtensions(QualifiedNameProvider.EP_NAME)) { |
| PsiElement adjustedElement = provider.adjustElementToCopy(element); |
| if (adjustedElement != null) return adjustedElement; |
| } |
| return element; |
| } |
| |
| public static boolean doCopy(final PsiElement element, final Project project) { |
| return doCopy(element, project, null); |
| } |
| |
| private static boolean doCopy(final PsiElement element, @Nullable final Project project, @Nullable Editor editor) { |
| String fqn = elementToFqn(element, editor); |
| if (fqn == null) return false; |
| |
| CopyPasteManager.getInstance().setContents(new MyTransferable(fqn)); |
| |
| setStatusBarText(project, IdeBundle.message("message.reference.to.fqn.has.been.copied", fqn)); |
| return true; |
| } |
| |
| private static void setStatusBarText(Project project, String message) { |
| if (project != null) { |
| final StatusBarEx statusBar = (StatusBarEx)WindowManager.getInstance().getStatusBar(project); |
| if (statusBar != null) { |
| statusBar.setInfo(message); |
| } |
| } |
| } |
| |
| private static class MyTransferable implements Transferable { |
| private final String fqn; |
| |
| public MyTransferable(String fqn) { |
| this.fqn = fqn; |
| } |
| |
| @Override |
| public DataFlavor[] getTransferDataFlavors() { |
| return new DataFlavor[]{ourFlavor, DataFlavor.stringFlavor}; |
| } |
| |
| @Override |
| public boolean isDataFlavorSupported(DataFlavor flavor) { |
| return ArrayUtil.find(getTransferDataFlavors(), flavor) != -1; |
| } |
| |
| @Override |
| @Nullable |
| public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { |
| if (isDataFlavorSupported(flavor)) { |
| return fqn; |
| } |
| return null; |
| } |
| } |
| |
| @Nullable |
| public static String elementToFqn(final PsiElement element) { |
| return elementToFqn(element, null); |
| } |
| |
| @Nullable |
| public static String elementToFqn(final PsiElement element, @Nullable Editor editor) { |
| String result = getQualifiedNameFromProviders(element); |
| if (result != null) return result; |
| |
| if (editor != null) { //IDEA-70346 |
| PsiReference reference = TargetElementUtilBase.findReference(editor, editor.getCaretModel().getOffset()); |
| if (reference != null) { |
| result = getQualifiedNameFromProviders(reference.resolve()); |
| if (result != null) return result; |
| } |
| } |
| |
| String fqn = null; |
| if (element instanceof PsiFile) { |
| final PsiFile file = (PsiFile)element; |
| fqn = FileUtil.toSystemIndependentName(getFileFqn(file)); |
| } |
| return fqn; |
| } |
| |
| @Nullable |
| private static String getQualifiedNameFromProviders(@Nullable PsiElement element) { |
| if (element == null) return null; |
| for (QualifiedNameProvider provider : Extensions.getExtensions(QualifiedNameProvider.EP_NAME)) { |
| String result = provider.getQualifiedName(element); |
| if (result != null) return result; |
| } |
| return null; |
| } |
| |
| @NotNull |
| private static String getFileFqn(final PsiFile file) { |
| final VirtualFile virtualFile = file.getVirtualFile(); |
| if (virtualFile == null) { |
| return file.getName(); |
| } |
| final Project project = file.getProject(); |
| final LogicalRoot logicalRoot = LogicalRootsManager.getLogicalRootsManager(project).findLogicalRoot(virtualFile); |
| if (logicalRoot != null) { |
| String logical = FileUtil.toSystemIndependentName(VfsUtil.virtualToIoFile(logicalRoot.getVirtualFile()).getPath()); |
| String path = FileUtil.toSystemIndependentName(VfsUtil.virtualToIoFile(virtualFile).getPath()); |
| return "/" + FileUtil.getRelativePath(logical, path, '/'); |
| } |
| |
| final VirtualFile contentRoot = ProjectRootManager.getInstance(project).getFileIndex().getContentRootForFile(virtualFile); |
| if (contentRoot != null) { |
| return "/" + FileUtil.getRelativePath(VfsUtil.virtualToIoFile(contentRoot), VfsUtil.virtualToIoFile(virtualFile)); |
| } |
| return virtualFile.getPath(); |
| } |
| } |