/*******************************************************************************
* Copyright (c) 2015 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.batch.ui.internal.wizard;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
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.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ToolFactory;
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.preferences.JavaPreferencesSettings;
import org.eclipse.jdt.ui.CodeGeneration;
import org.eclipse.jdt.ui.wizards.NewClassWizardPage;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.ui.PlatformUI;
import org.jboss.tools.batch.core.BatchArtifactType;
import org.jboss.tools.batch.core.BatchConstants;
import org.jboss.tools.batch.core.BatchCorePlugin;
import org.jboss.tools.batch.core.IBatchProject;
import org.jboss.tools.batch.ui.JobImages;
import org.jboss.tools.common.ui.widget.editor.IFieldEditor;
import org.jboss.tools.common.util.BeanUtil;
/**
*
* @author Viacheslav Kabanovich
*
*/
public class NewBatchArtifactWizardPage extends NewClassWizardPage implements PropertyChangeListener {
protected String defaultTypeName = null;
IFieldEditor artifacts;
IFieldEditor derivedFrom;
IFieldEditor nameOptions;
IFieldEditor name;
boolean canNameBeModified = true;
IFieldEditor properties;
protected StatusInfo artifactNameStatus = new StatusInfo();
protected StatusInfo propertiesStatus = new StatusInfo();
public NewBatchArtifactWizardPage() {
setTitle(WizardMessages.NEW_BATCH_ARTIFACT_WIZARD_PAGE_NAME);
setDescription(WizardMessages.NEW_BATCH_ARTIFACT_WIZARD_DESCRIPTION);
setImageDescriptor(JobImages.getImageDescriptor(JobImages.NEW_ARTIFACT_IMAGE));
}
/**
* Presets properties to artifact.
* @param propertyNames
*/
public void setProperties(List<String> propertyNames) {
properties.setValue(propertyNames);
}
/**
* Presets the artifact to be created.
* @param type
*/
public void setArtifact(BatchArtifactType type, boolean canBeModified) {
String label = BatchFieldEditorFactory.getArtifactLabel(type);
if(label != null) {
setArtifactByLabel(label);
setArtifactCanBeModified(canBeModified);
}
}
/**
* Presets name for the artifact to be created.
* @param type
*/
public void setArtifactName(String artifactName) {
name.setValue(artifactName);
}
public void setArtifactName(String artifactName, boolean canBeModified) {
name.setValue(artifactName);
canNameBeModified = canBeModified;
name.setEnabled(canBeModified);
}
public String getArtifactName() {
return name.getValueAsString();
}
void setArtifactByLabel(String label) {
artifacts.setValue(label);
}
/**
* Presets artifact extending from abstract class if available for current artifact type.
*/
public void setDeriveFromAbstractClass() {
String artifactName = artifacts.getValueAsString();
BatchArtifactType type = BatchFieldEditorFactory.ARTIFACTS.get(artifactName);
if(type.getClassName() != null) {
derivedFrom.setValue(BatchFieldEditorFactory.DERIVE_FROM_CLASS);
}
}
/**
* Presets artifact implementing from interface.
*/
public void setDeriveFromInterface() {
derivedFrom.setValue(BatchFieldEditorFactory.DERIVE_FROM_INTERFACE);
}
/**
*
* @param b
*/
public void setArtifactCanBeModified(boolean canBeModified) {
artifacts.setEnabled(canBeModified);
}
@Override
public void init(IStructuredSelection selection) {
super.init(selection);
defaultTypeName = null;
setSuperClass(BatchArtifactType.ABSTRACT_BATCHLET_TYPE, false);
List<BatchArtifactType> types = ((NewBatchArtifactWizard)getWizard()).getTypes();
artifacts = types != null && types.size() > 1 ? BatchFieldEditorFactory.createArtifactEditor(getDefaultArtifact(), types)
: BatchFieldEditorFactory.createArtifactEditor(getDefaultArtifact());
derivedFrom = BatchFieldEditorFactory.createDerivedFromEditor();
nameOptions = BatchFieldEditorFactory.createNameOptionsEditor();
name = BatchFieldEditorFactory.createArtifactNameEditor();
properties = BatchFieldEditorFactory.createPropertiesEditor();
doStatusUpdate();
}
@Override
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);
artifacts.doFillIntoGrid(composite);
derivedFrom.doFillIntoGrid(composite);
createSeparator(composite, nColumns);
nameOptions.doFillIntoGrid(composite);
name.doFillIntoGrid(composite);
Control c = (Control)name.getEditorControls()[1];
GridData d = (GridData)c.getLayoutData();
d.horizontalSpan--;
c.setLayoutData(d);
artifacts.addPropertyChangeListener(this);
derivedFrom.addPropertyChangeListener(this);
nameOptions.addPropertyChangeListener(this);
name.addPropertyChangeListener(this);
createSeparator(composite, nColumns);
properties.doFillIntoGrid(composite);
properties.addPropertyChangeListener(this);
setControl(composite);
Dialog.applyDialogFont(composite);
PlatformUI.getWorkbench().getHelpSystem()
.setHelp(composite, IJavaHelpContextIds.NEW_CLASS_WIZARD_PAGE);
onArtifactKindChange();
doStatusUpdate();
}
protected BatchArtifactType getDefaultArtifact() {
return BatchArtifactType.BATCHLET;
}
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);
}
@Override
protected void updateStatus(IStatus[] status) {
IStatus[] ns = new IStatus[status.length + 2];
System.arraycopy(status, 0, ns, 0, status.length);
ns[status.length] = artifactNameStatus;
ns[status.length + 1] = propertiesStatus;
status = ns;
super.updateStatus(status);
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if(BatchFieldEditorFactory.ARTIFACT_EDITOR.equals(name)) {
onArtifactKindChange();
} else if(BatchFieldEditorFactory.DERIVE_FROM_EDITOR.equals(name)) {
onDerivedFromChange();
} else if(BatchFieldEditorFactory.LOADER_OPTIONS_EDITOR.equals(name)) {
onNameOptionChange();
} else if(BatchFieldEditorFactory.NAME_EDITOR.equals(name)) {
onNameChange();
} else if(BatchFieldEditorFactory.PROPERTIES_EDITOR.equals(name)) {
onFieldNameChange();
}
doStatusUpdate();
}
void onArtifactKindChange() {
String artifactName = artifacts.getValueAsString();
BatchArtifactType type = BatchFieldEditorFactory.ARTIFACTS.get(artifactName);
if(type != null) {
boolean hasNoClass = type.getClassName() == null;
if(hasNoClass) {
if(BatchFieldEditorFactory.DERIVE_FROM_CLASS.equals(derivedFrom.getValueAsString())) {
derivedFrom.setValue(BatchFieldEditorFactory.DERIVE_FROM_INTERFACE);
}
}
if(getControl() != null) {
Composite p = (Composite)derivedFrom.getEditorControls()[1];
p.getChildren()[1].setEnabled(!hasNoClass);
}
onDerivedFromChange();
}
}
void onDerivedFromChange() {
String artifactName = artifacts.getValueAsString();
BatchArtifactType type = BatchFieldEditorFactory.ARTIFACTS.get(artifactName);
if(type != null) {
if(BatchFieldEditorFactory.DERIVE_FROM_CLASS.equals(derivedFrom.getValueAsString())) {
setSuperClass(type.getClassName(), false);
setSuperInterfaces(new ArrayList<String>(), false);
} else {
setSuperClass("", false);
setSuperInterfaces(Arrays.asList(type.getInterfaceName()), false);
}
}
}
void onNameOptionChange() {
name.setEnabled(!isArtifactNameQualified());
if(isArtifactNameQualified()) {
name.setValue(getQualifiedName());
} else {
name.setValue(BeanUtil.getDefaultBeanName(getTypeName()));
}
}
void onNameChange() {
artifactNameStatus = new StatusInfo();
if(getJavaProject() == null) {
return;
}
IBatchProject bp = BatchCorePlugin.getBatchProject(getJavaProject().getProject(), true);
if(bp != null) {
String v = name.getValueAsString();
if(v.length() == 0) {
artifactNameStatus.setError(WizardMessages.errorArtifactNameIsEmpty);
} else if(!bp.getArtifacts(v).isEmpty()) {
artifactNameStatus.setError(WizardMessages.errorArtifactNameIsNotUnique);
}
}
}
void onFieldNameChange() {
propertiesStatus = new StatusInfo();
Set<String> fields= new HashSet<String>();
for (String n: ((List<String>)properties.getValue())) {
if(n == null || n.length() == 0) continue;
IStatus val = JavaConventionsUtil.validateFieldName(n, null);
if (val != null && val.getSeverity() == IStatus.ERROR) {
propertiesStatus.setError(NLS.bind(WizardMessages.errorFieldNameIsNotValid, val.getMessage()));
return;
}
if(fields.contains(n)) {
propertiesStatus.setError(NLS.bind(WizardMessages.errorFieldNameIsNotUnique, n));
return;
}
fields.add(n);
}
}
boolean isArtifactNameQualified() {
String nameOption = nameOptions.getValueAsString();
return BatchFieldEditorFactory.LOADER_OPTION_QUALIFIED.equals(nameOption);
}
String getQualifiedName() {
return getPackageText() + "." + getTypeName();
}
boolean isArtifactNameDefault = true;
@Override
protected IStatus typeNameChanged() {
IStatus result = super.typeNameChanged();
if(name != null && canNameBeModified) {
if(isArtifactNameDefault) {
if(!isArtifactNameQualified()) {
name.setValue(BeanUtil.getDefaultBeanName(getTypeName()));
} else {
name.setValue(getPackageText() + "." + getTypeName());
}
}
}
//validate custom fields here
return result;
}
@Override
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();
addAnnotations(imports, sb, lineDelimiter);
buf.replace(range.getOffset(), 0, sb.toString());
createFields(newType, imports, monitor, lineDelimiter);
}
void addAnnotations(ImportsManager imports, StringBuffer sb,
String lineDelimiter) {
if(BatchFieldEditorFactory.LOADER_OPTION_ANNOTATION.equals(nameOptions.getValueAsString())) {
addNamedAnnotation(imports, sb, lineDelimiter);
}
}
protected void addNamedAnnotation(ImportsManager imports,
StringBuffer sb, String lineDelimiter) {
String annotationValue = name.getValueAsString();
if(BeanUtil.getDefaultBeanName(getTypeName()).equals(annotationValue)) {
annotationValue = "";
}
addAnnotation(BatchConstants.NAMED_QUALIFIER_TYPE, annotationValue, imports, sb, lineDelimiter);
}
static void addAnnotation(String typeName, String value, ImportsManager imports, StringBuffer sb, String lineDelimiter) {
int i = typeName.lastIndexOf('.');
String name = typeName.substring(i + 1);
imports.addImport(typeName);
sb.append("@").append(name);
if(value != null && value.length() > 0) {
sb.append("(\"").append(value).append("\")");
}
sb.append(lineDelimiter);
}
protected void createFields(IType type, ImportsManager imports, IProgressMonitor monitor, String lineDelimiter) throws CoreException {
imports.addImport(BatchConstants.INJECT_ANNOTATION_TYPE);
imports.addImport(BatchConstants.BATCH_PROPERTY_QUALIFIER_TYPE);
ICompilationUnit cu = type.getCompilationUnit();
JavaModelUtil.reconcile(cu);
CodeGenerationSettings settings = JavaPreferencesSettings
.getCodeGenerationSettings(type.getJavaProject());
settings.createComments = isAddComments();
String access = "protected";
String javatype = "String";
IJavaElement[] cs = type.getChildren();
IJavaElement sibling = cs == null || cs.length == 0 ? null : cs[0];
for (String fieldName: ((List<String>)properties.getValue())) {
String fieldHeader = "@Inject @BatchProperty " + access + " " + javatype + " " + fieldName + ";" + lineDelimiter; //$NON-NLS-1$ //$NON-NLS-2$
IField m = type.createField(fieldHeader, sibling, true, null);
editField(cu, m, javatype, fieldHeader, lineDelimiter);
}
}
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 = 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);
}
//JavaBeanGenerator
static String codeFormat2(int kind, String sourceString, int indentationLevel, String lineSeparator, IJavaProject project) {
TextEdit edit = ToolFactory.createCodeFormatter(project.getOptions(true)).format(kind, sourceString, 0, sourceString.length(), indentationLevel, lineSeparator);
Document doc = new Document(sourceString);
try {
edit.apply(doc, 0);
return doc.get();
} catch (BadLocationException e) {
return sourceString;
}
}
public BatchArtifactType getArtifactType(){
return BatchFieldEditorFactory.getArtifactType(artifacts.getValueAsString());
}
}