/*******************************************************************************
* Copyright (c) 2010 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.cdi.ui.wizard;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
import org.eclipse.jdt.internal.corext.util.JavaConventionsUtil;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
import org.eclipse.jdt.internal.ui.dialogs.StatusUtil;
import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
import org.eclipse.jdt.ui.CodeGeneration;
import org.eclipse.jdt.ui.wizards.NewClassWizardPage;
import org.eclipse.jdt.ui.wizards.NewTypeWizardPage.ImportsManager;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog;
import org.jboss.tools.cdi.core.CDIConstants;
import org.jboss.tools.cdi.core.CDICorePlugin;
import org.jboss.tools.cdi.core.CDIImages;
import org.jboss.tools.cdi.core.ICDIAnnotation;
import org.jboss.tools.cdi.core.ICDIProject;
import org.jboss.tools.cdi.core.IQualifier;
import org.jboss.tools.cdi.ui.CDIUIMessages;
import org.jboss.tools.common.java.IParametedType;
import org.jboss.tools.common.java.generation.JavaBeanGenerator;
import org.jboss.tools.common.ui.widget.editor.ButtonFieldEditor;
import org.jboss.tools.common.ui.widget.editor.ButtonFieldEditor.ButtonPressedAction;
import org.jboss.tools.common.ui.widget.editor.CompositeEditor;
import org.jboss.tools.common.ui.widget.editor.IFieldEditor;
import org.jboss.tools.common.ui.widget.editor.LabelFieldEditor;
import org.jboss.tools.common.ui.widget.editor.TextFieldEditor;
/**
*
* @author Viacheslav Kabanovich
*
*/
public class NewAnnotationLiteralWizardPage extends NewClassWizardPage {
protected QualifierSelectionProvider qualifiersProvider = new QualifierSelectionProvider();
CompositeEditor qualifiers = null;
String defaultTypeName = null;
protected StatusInfo qualifierStatus = new StatusInfo();
public NewAnnotationLiteralWizardPage() {
setTitle(CDIUIMessages.NEW_ANNOTATION_LITERAL_WIZARD_PAGE_NAME);
setDescription(CDIUIMessages.NEW_ANNOTATION_LITERAL_WIZARD_DESCRIPTION);
setImageDescriptor(CDIImages.getImageDescriptor(CDIImages.CDI_ANNOTATION_IMAGE));
qualifiersProvider.setMulti(false);
}
public void init(IStructuredSelection selection) {
super.init(selection);
defaultTypeName = null;
if (!selection.isEmpty()) {
Object o = selection.iterator().next();
IType type = null;
if (o instanceof IType) {
type = (IType) o;
} else if (o instanceof ICompilationUnit) {
ICompilationUnit cu = (ICompilationUnit) o;
try {
IType[] ts = cu.getTypes();
if (ts != null && ts.length > 0)
type = ts[0];
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
}
boolean isInterface = false;
try {
isInterface = type != null && type.isInterface();
} catch (JavaModelException e) {
CDICorePlugin.getDefault().logError(e);
}
if (isInterface) {
String name = "";
try {
name = type.getFullyQualifiedParameterizedName();
} catch (JavaModelException e) {
name = type.getFullyQualifiedName();
}
IPackageFragmentRoot r = getPackageFragmentRoot();
if(r != null) {
ICDIProject cdi = NewCDIAnnotationWizardPage.getCDIProject(r.getJavaProject());
IQualifier q = cdi != null ? cdi.getQualifier(name) : null;
if(q != null) {
selected = q;
ArrayList<String> interfacesNames = new ArrayList<String>();
interfacesNames.add(name);
setSuperInterfaces(interfacesNames, true);
superInterfacesChanged();
setSuperClass(CDIConstants.ANNOTATION_LITERAL_TYPE_NAME + "<" + type.getElementName() + ">", false);
setDefaultTypeName(name);
}
}
}
}
doStatusUpdate();
}
void setDefaultTypeName(String interfaceName) {
int d = interfaceName.lastIndexOf('.');
int b = interfaceName.indexOf('<');
if (b < 0)
b = interfaceName.length();
String elementName = interfaceName.substring(d + 1, b);
String typeName = elementName + "Literal";
typeName += interfaceName.substring(b);
String currentTypeName = getTypeName();
boolean isDefault = currentTypeName == null || currentTypeName.length() == 0 || currentTypeName.equals(defaultTypeName);
if(isDefault) {
setTypeName(typeName, true);
typeNameChanged();
}
defaultTypeName = typeName;
}
public void createControl(Composite parent) {
initializeDialogUnits(parent);
Composite composite = new Composite(parent, SWT.NONE);
composite.setFont(parent.getFont());
int nColumns = 4;
GridLayout layout = new GridLayout();
layout.numColumns = nColumns;
composite.setLayout(layout);
// pick & choose the wanted UI components
createContainerControls(composite, nColumns);
createPackageControls(composite, nColumns);
// createEnclosingTypeControls(composite, nColumns);
createSeparator(composite, nColumns);
createTypeNameControls(composite, nColumns);
createModifierControls(composite, nColumns);
// createSuperClassControls(composite, nColumns);
// createSuperInterfacesControls(composite, nColumns);
// createMethodStubSelectionControls(composite, nColumns);
createCustomFields(composite);
createCommentControls(composite, nColumns);
enableCommentControl(true);
setControl(composite);
Dialog.applyDialogFont(composite);
PlatformUI.getWorkbench().getHelpSystem()
.setHelp(composite, IJavaHelpContextIds.NEW_CLASS_WIZARD_PAGE);
onQualifiersChange();
doStatusUpdate();
}
protected void createTypeMembers(IType newType,
final ImportsManager imports, IProgressMonitor monitor)
throws CoreException {
createInheritedMethods(newType, true, true, imports,
new SubProgressMonitor(monitor, 1));
ISourceRange range = newType.getSourceRange();
IBuffer buf = newType.getCompilationUnit().getBuffer();
String lineDelimiter = StubUtility.getLineDelimiterUsed(newType
.getJavaProject());
StringBuffer sb = new StringBuffer();
buf.replace(range.getOffset(), 0, sb.toString());
boolean isDefault = modifyMethodContent(newType, imports, monitor, lineDelimiter);
if(isDefault) {
createInstanceField(newType, imports, monitor, lineDelimiter);
}
}
protected void createCustomFields(Composite composite) {
createQualifierField(composite);
}
protected void createQualifierField(Composite composite) {
qualifiers = (CompositeEditor)createQualifierCompositeEditor("qualifiers", CDIUIMessages.FIELD_EDITOR_QUALIFIER_LABEL, "");
// qualifiers.setProvider(qualifiersProvider);
// qualifiersProvider.setEditorField(qualifiers);
qualifiers.doFillIntoGrid(composite);
setQualifiers(getPackageFragmentRoot());
qualifiers.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
Object o = evt.getNewValue();
validateQualifierSelection(o);
}});
}
void validateQualifierSelection(Object value) {
boolean done = false;
if(value != null) {
String name = value.toString();
IPackageFragmentRoot r = getPackageFragmentRoot();
if(r != null) {
ICDIProject cdi = NewCDIAnnotationWizardPage.getCDIProject(r.getJavaProject());
selected = cdi != null ? cdi.getQualifier(name) : null;
if(selected != null) {
ArrayList<String> interfacesNames = new ArrayList<String>();
interfacesNames.add(name);
setSuperInterfaces(interfacesNames, true);
superInterfacesChanged();
setSuperClass(CDIConstants.ANNOTATION_LITERAL_TYPE_NAME + "<" + selected.getSourceType().getElementName() + ">", false);
setDefaultTypeName(name);
done = true;
}
}
}
if(!done) {
selected = null;
setSuperInterfaces(new ArrayList<String>(), true);
superInterfacesChanged();
}
}
public void setPackageFragmentRoot(IPackageFragmentRoot root, boolean canBeModified) {
super.setPackageFragmentRoot(root, canBeModified);
setQualifiers(root);
if(qualifiers != null) {
validateQualifierSelection(qualifiers.getValue());
}
}
void setQualifiers(IPackageFragmentRoot root) {
qualifiersProvider.setProject(null);
if(root != null) {
IJavaProject jp = root.getJavaProject();
ICDIProject cdi = NewCDIAnnotationWizardPage.getCDIProject(jp);
if(cdi != null) {
qualifiersProvider.setProject(cdi);
}
}
}
protected IField createInstanceField(IType type, ImportsManager imports,
IProgressMonitor monitor, String lineDelimiter)
throws CoreException {
imports.addImport(CDIConstants.ANNOTATION_LITERAL_TYPE_NAME);
IType fieldType = selected.getSourceType();
imports.addImport(fieldType.getFullyQualifiedName());
String access = "public static final ";
String initialization = "new " + type.getElementName() + "()";
IJavaElement[] cs = type.getChildren();
IJavaElement sibling = cs == null || cs.length == 0 ? null : cs[0];
IField m = createField(type, sibling, imports, "INSTANCE", fieldType.getElementName(), access, initialization, monitor, lineDelimiter);
return m;
}
protected IField createField(IType type, IJavaElement sibling, ImportsManager imports, String name, String fieldType, String access, String initialization,
IProgressMonitor monitor, String lineDelimiter)
throws CoreException {
ICompilationUnit cu = type.getCompilationUnit();
JavaModelUtil.reconcile(cu);
CodeGenerationSettings settings = JavaPreferencesSettings
.getCodeGenerationSettings(type.getJavaProject());
settings.createComments = isAddComments();
String fieldHeader = access + " " + fieldType + " " + name;
if(initialization != null) {
fieldHeader += "= " + initialization;
}
fieldHeader += ";" + lineDelimiter; //$NON-NLS-1$ //$NON-NLS-2$
IField m = type.createField(fieldHeader, sibling, true, null);
editField(cu, m, fieldType, fieldHeader, lineDelimiter);
return m;
}
void editField(ICompilationUnit cu, IField m, String javatype, String fieldHeader,
String lineDelimiter) throws CoreException {
synchronized (cu) {
cu.reconcile(ICompilationUnit.NO_AST, true, null, null);
}
ISourceRange range = m.getSourceRange();
IBuffer buf = cu.getBuffer();
StringBuffer sb = new StringBuffer(lineDelimiter);
if (isAddComments()) {
String fieldComment = CodeGeneration.getFieldComment(cu,
javatype, m.getElementName(), lineDelimiter);
sb.append(fieldComment).append(lineDelimiter);
}
sb.append(fieldHeader);
String formattedContent = JavaBeanGenerator.codeFormat2(
CodeFormatter.K_CLASS_BODY_DECLARATIONS, sb.toString(), 1,
lineDelimiter, cu.getJavaProject());
if (formattedContent != null && formattedContent.startsWith("\t")) { //$NON-NLS-1$
formattedContent = formattedContent.substring(1);
}
buf.replace(range.getOffset(), range.getLength(), formattedContent);
}
protected IStatus superInterfacesChanged() {
List list = getSuperInterfaces();
if(list != null && !list.isEmpty()) {
setDefaultTypeName(list.get(0).toString());
}
StatusInfo result = (StatusInfo) super.superInterfacesChanged();
if (!result.isError()) {
if (list == null || list.isEmpty()) {
result.setError("Please select qualifier.");
}
}
return result;
}
private void doStatusUpdate() {
// status of all used components
IStatus[] status = new IStatus[] {
fContainerStatus,
isEnclosingTypeSelected() ? fEnclosingTypeStatus
: fPackageStatus, fTypeNameStatus, fModifierStatus,
fSuperClassStatus, fSuperInterfacesStatus };
// the mode severe status will be displayed and the OK button
// enabled/disabled.
updateStatus(status);
}
protected void updateStatus(IStatus[] status) {
// IStatus[] ns = new IStatus[status.length + 1];
// System.arraycopy(status, 0, ns, 0, status.length);
// ns[status.length] = qualifierStatus;
// status = ns;
updateStatus(StatusUtil.getMostSevere(status));
}
void onQualifiersChange() {
// qualifierStatus = new StatusInfo();
// if(((List)qualifiers.getValue()).isEmpty()) {
// qualifierStatus.setWarning(CDIUIMessages.MESSAGE_QUALIFIER_NOT_SET);
// }
}
public IFieldEditor createQualifierCompositeEditor(String name, String label, String defaultValue) {
if(selected != null) {
defaultValue = selected.getSourceType().getFullyQualifiedName();
}
CompositeEditor editor = new CompositeEditor(name, label, defaultValue);
editor.addFieldEditors(new IFieldEditor[]{new LabelFieldEditor(name,label),
new TextFieldEditor(name,label, defaultValue),
new ButtonFieldEditor(name,createSelectAction(), "")});
return editor;
}
ButtonPressedAction createSelectAction() {
return new ButtonPressedAction("Browse") {
public void run() {
selected = (ICDIAnnotation)runAddAction();
if(selected != null) {
qualifiers.setValue(selected.getSourceType().getFullyQualifiedName());
}
}
};
}
ICDIAnnotation selected = null;
protected Object runAddAction() {
if(qualifiersProvider != null) {
FilteredItemsSelectionDialog dialog = qualifiersProvider.createSelectionDialog();
int result = dialog.open();
if(result == FilteredItemsSelectionDialog.OK) {
Object[] os = dialog.getResult();
if(os != null) {
for (Object o: os) {
Object v = qualifiersProvider.getSelected(o);
if(v != null) {
return v;
}
}
}
}
}
return null;
}
public void setQualifier(String type) {
qualifiers.setValue(type);
}
protected boolean modifyMethodContent(IType type, ImportsManager imports,
IProgressMonitor monitor, String lineDelimiter) throws CoreException {
IMethod[] ms = type.getMethods();
IMethod sibling = null;
List<String[]> fields = new ArrayList<String[]>();
IMethod constructor = null;
for (int i = 0; i < ms.length; i++) {
if(ms[i].isConstructor()) {
constructor = ms[i];
continue;
}
if(sibling == null) {
sibling = ms[i];
}
ICompilationUnit cu = type.getCompilationUnit();
synchronized (cu) {
cu.reconcile(ICompilationUnit.NO_AST, true, null, null);
}
IBuffer buf = cu.getBuffer();
ISourceRange range = ms[i].getSourceRange();
int start = -1;
int end = -1;
StringBuffer sb = new StringBuffer();
if("void".equals(ms[i].getReturnType()) || "V".equals(ms[i].getReturnType())) {
end = buf.getContents().indexOf("}", range.getOffset());
if(end < 0) continue;
end = buf.getContents().lastIndexOf(lineDelimiter, end);
if(end < 0 || end < range.getOffset()) continue;
// end += lineDelimiter.length();
start = end;
} else {
start = buf.getContents().indexOf("return", range.getOffset());
if(start < 0 || start > range.getOffset() + range.getLength()) continue;
start += 7;
end = buf.getContents().indexOf(";", start);
if(end < 0) continue;
end++;
}
String methodName = ms[i].getElementName();
String fieldName = "" + methodName;
sb.append(fieldName).append(";");
buf.replace(start, end - start, sb.toString());
fields.add(new String[]{ms[i].getReturnType(), fieldName});
}
for (int i = 0; i < fields.size(); i++) {
String[] data = fields.get(i);
String fieldType = data[0];
String fieldName = data[1];
IParametedType t = NewCDIAnnotationWizardPage.getCDIProject(getPackageFragmentRoot().getJavaProject()).getNature().getTypeFactory().getParametedType(type, fieldType);
if(t != null) {
data[0] = t.getSimpleName();
createField(type, constructor, imports, fieldName, t.getSimpleName(), "private final", null, monitor, lineDelimiter);
}
}
if(constructor != null) {
constructor.delete(true, monitor);
}
if(!fields.isEmpty()) {
String constructorContents = "public " + type.getElementName() + "(";
String comments = "/**" + lineDelimiter;
for (int i = 0; i < fields.size(); i++) {
String[] data = fields.get(i);
String fieldType = data[0];
String fieldName = data[1];
comments += " * @param " + fieldName + lineDelimiter;
if(i > 0) constructorContents += ", ";
constructorContents += fieldType + " " + fieldName;
}
comments += "*/" + lineDelimiter;
constructorContents += ") {" + lineDelimiter;
for (int i = 0; i < fields.size(); i++) {
String[] data = fields.get(i);
String fieldName = data[1];
constructorContents += "this." + fieldName + " = " + fieldName + ";" + lineDelimiter;
}
constructorContents += "}" + lineDelimiter;
if(isAddComments()) {
constructorContents = comments + constructorContents;
}
IMethod m = type.createMethod(constructorContents, sibling, true, monitor);
}
return fields.isEmpty();
}
}