package de.plushnikov.intellij.plugin.action.delombok;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilBase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public abstract class BaseDelombokAction extends AnAction {
private final BaseDelombokHandler myHandler;
protected BaseDelombokAction(BaseDelombokHandler handler) {
myHandler = handler;
}
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
final Project project = event.getProject();
if (project == null) {
return;
}
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
if (psiDocumentManager.hasUncommitedDocuments()) {
psiDocumentManager.commitAllDocuments();
}
final DataContext dataContext = event.getDataContext();
final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
if (null != editor) {
final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project);
if (null != psiFile) {
final PsiClass targetClass = getTargetClass(editor, psiFile);
if (null != targetClass) {
process(project, psiFile, targetClass);
}
}
} else {
final VirtualFile[] files = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
if (null != files) {
for (VirtualFile file : files) {
if (file.isDirectory()) {
processDirectory(project, file);
} else {
processFile(project, file);
}
}
}
}
}
private void processDirectory(@NotNull final Project project, @NotNull VirtualFile vFile) {
VfsUtilCore.visitChildrenRecursively(vFile, new VirtualFileVisitor() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
if (!file.isDirectory()) {
processFile(project, file);
}
return true;
}
});
}
private void processFile(Project project, VirtualFile file) {
if (StdFileTypes.JAVA.equals(file.getFileType())) {
final PsiManager psiManager = PsiManager.getInstance(project);
PsiJavaFile psiFile = (PsiJavaFile) psiManager.findFile(file);
if (psiFile != null) {
process(project, psiFile);
}
}
}
protected void process(@NotNull final Project project, @NotNull final PsiJavaFile psiJavaFile) {
executeCommand(project, new Runnable() {
@Override
public void run() {
getHandler().invoke(project, psiJavaFile);
}
});
}
protected void process(@NotNull final Project project, @NotNull final PsiFile psiFile, @NotNull final PsiClass psiClass) {
executeCommand(project, new Runnable() {
@Override
public void run() {
getHandler().invoke(project, psiFile, psiClass);
}
});
}
private void executeCommand(final Project project, final Runnable action) {
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(action);
}
}, getCommandName(), null);
}
private BaseDelombokHandler getHandler() {
return myHandler;
}
@Override
public void update(@NotNull AnActionEvent event) {
final Presentation presentation = event.getPresentation();
final DataContext dataContext = event.getDataContext();
final Project project = event.getProject();
if (project == null) {
presentation.setEnabled(false);
return;
}
final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
if (null != editor) {
final PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, project);
presentation.setEnabled(file != null && isValidForFile(editor, file));
return;
}
boolean isValid = false;
final VirtualFile[] files = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
if (null != files) {
PsiManager psiManager = PsiManager.getInstance(project);
for (VirtualFile file : files) {
if (file.isDirectory()) {
//directory is valid
isValid = true;
break;
}
if (StdFileTypes.JAVA.equals(file.getFileType())) {
PsiJavaFile psiFile = (PsiJavaFile) psiManager.findFile(file);
if (psiFile != null) {
for (PsiClass psiClass : psiFile.getClasses()) {
if (isValidForClass(psiClass)) {
isValid = true;
break;
}
for (PsiClass innerClass : psiClass.getAllInnerClasses()) {
if (isValidForClass(innerClass)) {
isValid = true;
break;
}
}
}
}
}
if (isValid) {
break;
}
}
}
presentation.setEnabled(isValid);
}
private boolean isValidForClass(@NotNull PsiClass targetClass) {
if (!targetClass.isInterface()) {
Collection<PsiAnnotation> psiAnnotations = myHandler.collectProcessableAnnotations(targetClass);
return !psiAnnotations.isEmpty();
}
return false;
}
@Nullable
private PsiClass getTargetClass(Editor editor, PsiFile file) {
int offset = editor.getCaretModel().getOffset();
PsiElement element = file.findElementAt(offset);
if (element == null) {
return null;
}
final PsiClass target = PsiTreeUtil.getParentOfType(element, PsiClass.class);
return target instanceof SyntheticElement ? null : target;
}
private boolean isValidForFile(@NotNull Editor editor, @NotNull PsiFile file) {
if (!(file instanceof PsiJavaFile)) {
return false;
}
if (file instanceof PsiCompiledElement) {
return false;
}
if (!file.isWritable()) {
return false;
}
PsiClass targetClass = getTargetClass(editor, file);
return targetClass != null && isValidForClass(targetClass);
}
private String getCommandName() {
String text = getTemplatePresentation().getText();
return text == null ? "" : text;
}
}