/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.intentions;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.daemon.impl.quickfix.CreateClassFromNewFix;
import com.intellij.codeInsight.daemon.impl.quickfix.CreateClassKind;
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateBuilderImpl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiExpressionList;
import com.intellij.psi.PsiJavaCodeReferenceElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiNewExpression;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.PsiReferenceExpression;
import com.intellij.psi.PsiReferenceList;
import com.intellij.psi.PsiType;
import com.intellij.util.IncorrectOperationException;
import gw.plugin.ij.lang.psi.impl.expressions.GosuTypeLiteralImpl;
import gw.plugin.ij.util.JavaPsiFacadeUtil;
import org.jetbrains.annotations.NotNull;
/**
* @author mike
*/
public class CreateJavaClassFromNewFix extends CreateClassFromNewFix implements ITestableCreateClassFix {
public CreateJavaClassFromNewFix(PsiNewExpression newExpression) {
super(newExpression);
}
@NotNull
protected String getText(final String varName) {
return "Create Java class '" + varName + "'";
// return QuickFixBundle.message("create.class.from.new.text", varName);
}
protected void invokeImpl(PsiClass targetClass) {
assert ApplicationManager.getApplication().isWriteAccessAllowed();
final PsiNewExpression newExpression = getNewExpression();
final PsiJavaCodeReferenceElement referenceElement = getReferenceElement(newExpression);
final GosuTypeLiteralImpl typeLiteral = (GosuTypeLiteralImpl) newExpression.getChildren()[0];
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
final PsiClass psiClass = CreateFromUsageUtils.createClass(referenceElement, CreateClassKind.CLASS, null);
new WriteCommandAction(newExpression.getProject()) {
@Override
protected void run(Result result) throws Throwable {
setupClassFromNewExpression(psiClass, newExpression);
typeLiteral.bindToElement(psiClass);
}
}.execute();
}
});
}
protected void setupClassFromNewExpression(final PsiClass psiClass, @NotNull final PsiNewExpression newExpression) {
assert ApplicationManager.getApplication().isWriteAccessAllowed();
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(newExpression.getProject()).getElementFactory();
PsiClass aClass = psiClass;
if (aClass == null) return;
final PsiJavaCodeReferenceElement classReference = newExpression.getClassReference();
if (classReference != null) {
classReference.bindToElement(aClass);
}
setupInheritance(newExpression, aClass);
PsiExpressionList argList = newExpression.getArgumentList();
Project project = aClass.getProject();
if (argList != null && argList.getExpressions().length > 0) {
PsiMethod constructor = elementFactory.createConstructor();
constructor = (PsiMethod) aClass.add(constructor);
TemplateBuilderImpl templateBuilder = new TemplateBuilderImpl(aClass);
CreateFromUsageUtils.setupMethodParameters(constructor, templateBuilder, argList, getTargetSubstitutor(newExpression));
setupSuperCall(aClass, constructor, templateBuilder);
getReferenceElement(newExpression).bindToElement(aClass);
aClass = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(aClass);
Template template = templateBuilder.buildTemplate();
template.setToReformat(true);
Editor editor = positionCursor(project, aClass.getContainingFile(), aClass);
TextRange textRange = aClass.getTextRange();
editor.getDocument().deleteString(textRange.getStartOffset(), textRange.getEndOffset());
startTemplate(editor, template, project);
} else {
positionCursor(project, aClass.getContainingFile(), aClass);
}
}
private static void setupInheritance(@NotNull PsiNewExpression newExpression, @NotNull PsiClass targetClass) throws IncorrectOperationException {
if (newExpression.getParent() instanceof PsiReferenceExpression) return;
final GosuTypeLiteralImpl typeLiteral = (GosuTypeLiteralImpl) newExpression.getChildren()[0];
PsiType type = CreateGosuClassFromNewFix.getSuperClass(typeLiteral);
if (!(type instanceof PsiClassType)) return;
final PsiClassType classType = (PsiClassType) type;
PsiClass aClass = classType.resolve();
if (aClass == null) return;
if (aClass.equals(targetClass) || aClass.hasModifierProperty(PsiModifier.FINAL)) return;
PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory();
if (aClass.isInterface()) {
PsiReferenceList implementsList = targetClass.getImplementsList();
implementsList.add(factory.createReferenceElementByType(classType));
} else {
PsiReferenceList extendsList = targetClass.getExtendsList();
if (extendsList.getReferencedTypes().length == 0 && !"java.lang.Object".equals(classType.getCanonicalText())) {
extendsList.add(factory.createReferenceElementByType(classType));
}
}
}
public void invokeForTest(@NotNull String packageName) {
assert ApplicationManager.getApplication().isWriteAccessAllowed();
final PsiNewExpression newExpression = getNewExpression();
final PsiPackage pkg = JavaPsiFacadeUtil.findPackage(newExpression.getProject(), packageName);
final PsiDirectory dir = pkg.getDirectories()[0];
final PsiJavaCodeReferenceElement referenceElement = getReferenceElement(newExpression);
final GosuTypeLiteralImpl typeLiteral = (GosuTypeLiteralImpl) newExpression.getChildren()[0];
final PsiClass psiClass = CreateFromUsageUtils.createClass(CreateClassKind.CLASS, dir, referenceElement.getReferenceName(), referenceElement.getManager(), referenceElement, referenceElement.getContainingFile(), null);
new WriteCommandAction(newExpression.getProject()) {
@Override
protected void run(Result result) throws Throwable {
setupClassFromNewExpression(psiClass, newExpression);
typeLiteral.bindToElement(psiClass);
}
}.execute();
}
}