diff --git a/platform/lang-impl/src/com/intellij/internal/SelectionBasedPsiElementInternalAction.java b/platform/lang-impl/src/com/intellij/internal/SelectionBasedPsiElementInternalAction.java new file mode 100644 index 000000000000..4c3e8cb2ab94 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/internal/SelectionBasedPsiElementInternalAction.java @@ -0,0 +1,145 @@ +package com.intellij.internal; + +import com.intellij.codeInsight.hint.HintManager; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ex.ApplicationManagerEx; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.util.Pass; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.IntroduceTargetChooser; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Nikolay Matveev + */ +public abstract class SelectionBasedPsiElementInternalAction extends AnAction { + @NotNull + protected final Class myClass; + @NotNull + protected final Class myFileClass; + + protected SelectionBasedPsiElementInternalAction(@NotNull Class aClass, @NotNull Class fileClass) { + myClass = aClass; + myFileClass = fileClass; + } + + @Override + public final void actionPerformed(AnActionEvent e) { + final Editor editor = getEditor(e); + final PsiFile file = getPsiFile(e); + if (editor == null || file == null) return; + + final List expressions = getElement(editor, file); + T first = ContainerUtil.getFirstItem(expressions); + + if (expressions.size() > 1) { + IntroduceTargetChooser.showChooser( + editor, expressions, + new Pass() { + @Override + public void pass(@NotNull T expression) { + performOnElement(editor, expression); + } + }, + new Function() { + public String fun(@NotNull T expression) { + return expression.getText(); + } + } + ); + } + else if (expressions.size() == 1 && first != null) { + performOnElement(editor, first); + } + else if (expressions.isEmpty()) { + showError(editor); + } + } + + protected void showError(@NotNull final Editor editor) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + final String errorHint = "Cannot find element of class " + myClass.getSimpleName() + " at selection/offset"; + HintManager.getInstance().showErrorHint(editor, errorHint); + } + }); + } + + private void performOnElement(@NotNull final Editor editor, @NotNull T first) { + final TextRange textRange = first.getTextRange(); + editor.getSelectionModel().setSelection(textRange.getStartOffset(), textRange.getEndOffset()); + final String informationHint = getInformationHint(first); + if (informationHint != null) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + HintManager.getInstance().showInformationHint(editor, informationHint); + } + }); + } + else { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + HintManager.getInstance().showErrorHint(editor, getErrorHint()); + } + }); + } + } + + @Nullable + protected abstract String getInformationHint(@NotNull T element); + + @NotNull + protected abstract String getErrorHint(); + + @NotNull + protected List getElement(@NotNull Editor editor, @NotNull PsiFile file) { + final SelectionModel selectionModel = editor.getSelectionModel(); + if (selectionModel.hasSelection()) { + return ContainerUtil.list(getElementFromSelection(file, selectionModel)); + } + return getElementAtOffset(editor, file); + } + + @NotNull + protected List getElementAtOffset(@NotNull Editor editor, @NotNull PsiFile file) { + return ContainerUtil.list(PsiTreeUtil.findElementOfClassAtOffset(file, editor.getCaretModel().getOffset(), myClass, false)); + } + + @Nullable + protected T getElementFromSelection(@NotNull PsiFile file, @NotNull SelectionModel selectionModel) { + final int selectionStart = selectionModel.getSelectionStart(); + final int selectionEnd = selectionModel.getSelectionEnd(); + return PsiTreeUtil.findElementOfClassAtRange(file, selectionStart, selectionEnd, myClass); + } + + @Override + public final void update(AnActionEvent e) { + final Presentation presentation = e.getPresentation(); + boolean enabled = ApplicationManagerEx.getApplicationEx().isInternal() && getEditor(e) != null && myFileClass.isInstance(getPsiFile(e)); + presentation.setVisible(enabled); + presentation.setEnabled(enabled); + } + + @Nullable + private static Editor getEditor(@NotNull AnActionEvent e) { + return PlatformDataKeys.EDITOR.getData(e.getDataContext()); + } + + @Nullable + private static PsiFile getPsiFile(@NotNull AnActionEvent e) { + return LangDataKeys.PSI_FILE.getData(e.getDataContext()); + } +}