blob: f669e52c69d08943d4eb52f2f7b7c877d3e5c074 [file] [log] [blame]
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<T extends PsiElement> extends AnAction {
@NotNull
protected final Class<T> myClass;
@NotNull
protected final Class<? extends PsiFile> myFileClass;
protected SelectionBasedPsiElementInternalAction(@NotNull Class<T> aClass, @NotNull Class<? extends PsiFile> 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<T> expressions = getElement(editor, file);
T first = ContainerUtil.getFirstItem(expressions);
if (expressions.size() > 1) {
IntroduceTargetChooser.showChooser(
editor, expressions,
new Pass<T>() {
@Override
public void pass(@NotNull T expression) {
performOnElement(editor, expression);
}
},
new Function<T, String>() {
@Override
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<T> 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<T> 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 CommonDataKeys.EDITOR.getData(e.getDataContext());
}
@Nullable
private static PsiFile getPsiFile(@NotNull AnActionEvent e) {
return CommonDataKeys.PSI_FILE.getData(e.getDataContext());
}
}