package com.github.setial.intellijjavadocs.action;
import com.github.setial.intellijjavadocs.exception.TemplateNotFoundException;
import com.github.setial.intellijjavadocs.generator.JavaDocGenerator;
import com.github.setial.intellijjavadocs.generator.impl.ClassJavaDocGenerator;
import com.github.setial.intellijjavadocs.generator.impl.FieldJavaDocGenerator;
import com.github.setial.intellijjavadocs.generator.impl.MethodJavaDocGenerator;
import com.github.setial.intellijjavadocs.operation.JavaDocWriter;
import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataKeys;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
/**
* The type Java doc generate action.
*
* @author Sergey Timofiychuk
*/
public class JavaDocGenerateAction extends BaseAction {
private static final Logger LOGGER = Logger.getInstance(JavaDocGenerateAction.class);
private JavaDocWriter writer;
/**
* Instantiates a new Java doc generate action.
*/
public JavaDocGenerateAction() {
this(new JavaDocHandler());
}
/**
* Instantiates a new Java doc generate action.
*
* @param handler the handler
*/
public JavaDocGenerateAction(CodeInsightActionHandler handler) {
super(handler);
writer = ServiceManager.getService(JavaDocWriter.class);
}
/**
* Action performed.
*
* @param e the Event
*/
@Override
public void actionPerformed(AnActionEvent e) {
DumbService dumbService = DumbService.getInstance(e.getProject());
if (dumbService.isDumb()) {
dumbService.showDumbModeNotification("Javadocs plugin is not available during indexing");
return;
}
Editor editor = DataKeys.EDITOR.getData(e.getDataContext());
if (editor == null) {
LOGGER.error("Cannot get com.intellij.openapi.editor.Editor");
Messages.showErrorDialog("Javadocs plugin is not available", "Javadocs plugin");
return;
}
int startPosition = editor.getSelectionModel().getSelectionStart();
int endPosition = editor.getSelectionModel().getSelectionEnd();
PsiFile file = DataKeys.PSI_FILE.getData(e.getDataContext());
if (file == null) {
LOGGER.error("Cannot get com.intellij.psi.PsiFile");
Messages.showErrorDialog("Javadocs plugin is not available", "Javadocs plugin");
return;
}
List<PsiElement> elements = new LinkedList<PsiElement>();
PsiElement firstElement = getJavaElement(PsiUtilCore.getElementAtOffset(file, startPosition));
if (firstElement != null) {
PsiElement element = firstElement;
do {
if (isAllowedElementType(element)) {
elements.add(element);
}
element = element.getNextSibling();
if (element == null) {
break;
}
} while (isElementInSelection(element, startPosition, endPosition));
}
for (PsiElement element : elements) {
processElement(element);
}
}
/**
* Process element.
*
* @param element the Element
*/
protected void processElement(@NotNull PsiElement element) {
JavaDocGenerator generator = getGenerator(element);
if (generator != null) {
try {
@SuppressWarnings("unchecked")
PsiDocComment javaDoc = generator.generate(element);
if (javaDoc != null) {
writer.write(javaDoc, element);
}
} catch (TemplateNotFoundException e) {
LOGGER.warn(e);
String message = "Javadocs plugin is not available. Can not find suitable template for the element:\n{0}";
Messages.showWarningDialog(MessageFormat.format(message, e.getMessage()), "Javadocs plugin");
}
}
}
/**
* Gets the generator.
*
* @param element the Element
* @return the Generator
*/
@Nullable
protected JavaDocGenerator getGenerator(@NotNull PsiElement element) {
Project project = element.getProject();
JavaDocGenerator generator = null;
if (PsiClass.class.isAssignableFrom(element.getClass())) {
generator = new ClassJavaDocGenerator(project);
} else if (PsiMethod.class.isAssignableFrom(element.getClass())) {
generator = new MethodJavaDocGenerator(project);
} else if (PsiField.class.isAssignableFrom(element.getClass())) {
generator = new FieldJavaDocGenerator(project);
}
return generator;
}
/**
* Gets the java element.
*
* @param element the Element
* @return the Java element
*/
@NotNull
private PsiElement getJavaElement(@NotNull PsiElement element) {
PsiElement result = element;
PsiField field = PsiTreeUtil.getParentOfType(element, PsiField.class);
PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class);
PsiClass clazz = PsiTreeUtil.getParentOfType(element, PsiClass.class);
if (field != null) {
result = field;
} else if (method != null) {
result = method;
} else if (clazz != null) {
result = clazz;
}
return result;
}
private boolean isElementInSelection(@NotNull PsiElement element, int startPosition, int endPosition) {
boolean result = false;
int elementTextOffset = element.getTextRange().getStartOffset();
if (elementTextOffset >= startPosition &&
elementTextOffset <= endPosition) {
result = true;
}
return result;
}
private boolean isAllowedElementType(@NotNull PsiElement element) {
boolean result = false;
if (element instanceof PsiClass ||
element instanceof PsiField ||
element instanceof PsiMethod) {
result = true;
}
return result;
}
}