/*******************************************************************************
* Copyright (c) 2012 VMware, Inc.
* All rights reserved. This program and the accompanying materials
* are 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:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.wizard.ui;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.ui.wizards.NewClassCreationWizard;
import org.eclipse.jdt.ui.IJavaElementSearchConstants;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.ui.wizards.NewClassWizardPage;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.SelectionDialog;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMElement;
import org.springframework.ide.eclipse.beans.core.BeansCoreUtils;
import org.springframework.ide.eclipse.config.core.contentassist.XmlBackedContentProposalAdapter;
import org.springframework.ide.eclipse.config.core.contentassist.XmlBackedContentProposalProvider;
import org.springframework.ide.eclipse.config.core.schemas.BeansSchemaConstants;
import org.springframework.ide.eclipse.core.StringUtils;
import org.springframework.ide.eclipse.quickfix.ContentAssistProposalWrapper;
import org.springframework.ide.eclipse.wizard.Messages;
import org.springframework.ide.eclipse.wizard.WizardPlugin;
import org.springframework.ide.eclipse.wizard.core.WizardBeanReferenceContentProposalProvider;
import org.springframework.ide.eclipse.wizard.core.WizardClassContentProposalProvider;
import org.springframework.ide.eclipse.wizard.core.WizardContentAssistConverter;
import org.springsource.ide.eclipse.commons.core.StatusHandler;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
/**
* Wizard page for creating or modifying a bean definition
* @author Terry Denney
* @author Leo Dos Santos
* @author Christian Dupuis
* @since 2.0
*/
@SuppressWarnings("restriction")
public class BeanWizardPage extends AbstractBeanWizardPage {
private Label idLabel, nameLabel, parentLabel;
private Hyperlink classLink;
private Text idText, nameText, classText, parentText, fileText;
private Button ignoreErrorButton, fileBrowseButton;
private static final String DEFAULT_MESSAGE = Messages.getString("NewBeanWizardPage.TITLE_DESCRIPTION"); //$NON-NLS-1$
private String fileErrorMessage, classErrorMessage, parentErrorMessage;
private final Set<XmlBackedContentProposalAdapter> contentProposalAdapters;
private WizardClassContentProposalProvider classProposalProvider;
private WizardBeanReferenceContentProposalProvider parentProposalProvider;
private final boolean fileBrowsingEnabled;
public BeanWizardPage(String pageName, BeanWizard wizard, boolean fileBrowsingEnabled) {
super(pageName, wizard);
setTitle(Messages.getString("NewBeanWizardPage.TITLE")); //$NON-NLS-1$
if (wizard.getBeanFile() == null) {
setDescription(Messages.getString("NewBeanWizardPage.ENTER_BEAN_FILE")); //$NON-NLS-1$
}
else {
setDescription(DEFAULT_MESSAGE);
}
this.wizard = wizard;
this.fileBrowsingEnabled = fileBrowsingEnabled;
this.contentProposalAdapters = new HashSet<XmlBackedContentProposalAdapter>();
}
private void addListener(final Text text, final String attributeName) {
text.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
updateAttribute(attributeName, text.getText());
}
});
}
@Override
public boolean canFlipToNextPage() {
return wizard.getBeanFile() != null
&& (BeanWizard.getIgnoreError() || classText.getText().length() > 0 || parentText.getText().length() > 0);
}
private void createAttribute(String attributeName, Hyperlink link, Text text) {
link.setText(getDisplayText(attributeName) + ":"); //$NON-NLS-1$
link.setUnderlined(true);
link.setLayoutData(new GridData());
link.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
IProject project = BeanWizardPage.this.wizard.getBeanFile().getProject();
String className = classText.getText();
try {
if (project.hasNature(JavaCore.NATURE_ID)) {
IJavaProject javaProject = JavaCore.create(project);
IJavaElement result = null;
if (className.length() > 0) {
result = javaProject.findType(className);
}
if (result != null) {
JavaUI.openInEditor(result);
return;
}
NewClassWizardPage page = new NewClassWizardPage();
int index = className.lastIndexOf(".");
if (index > 0) {
String packageName = className.substring(0, index);
className = className.substring(index + 1);
IPackageFragment[] packageFragments = javaProject.getPackageFragments();
for (IPackageFragment packageFragment : packageFragments) {
if (packageFragment.getElementName().equals(packageName)) {
page.setPackageFragment(packageFragment, true);
IPackageFragmentRoot[] packageFragmentRoots = javaProject
.getAllPackageFragmentRoots();
for (IPackageFragmentRoot packageFragmentRoot : packageFragmentRoots) {
if (packageFragmentRoot.getPath().isPrefixOf(packageFragment.getPath())) {
page.setPackageFragmentRoot(packageFragmentRoot, true);
break;
}
}
break;
}
}
}
page.setTypeName(className, false);
NewClassCreationWizard wizard = new NewClassCreationWizard(page, true);
IWorkbench workbench = PlatformUI.getWorkbench();
wizard.init(workbench, null);
Shell shell = workbench.getActiveWorkbenchWindow().getShell();
WizardDialog dialog = new WizardDialog(shell, wizard);
dialog.create();
dialog.getShell().setText("New Class");
dialog.setBlockOnOpen(true);
if (dialog.open() == Window.OK) {
validateAttribute(BeansSchemaConstants.ATTR_CLASS, className);
}
}
}
catch (CoreException ex) {
}
}
});
createAttrbute(attributeName, text);
}
private void createAttribute(String attributeName, Label label, Text text) {
label.setText(getDisplayText(attributeName) + ":"); //$NON-NLS-1$
label.setLayoutData(new GridData());
createAttrbute(attributeName, text);
}
private void createAttrbute(String attributeName, Text text) {
text.setEditable(true);
text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
IDOMElement newBean = wizard.getNewBean();
String attributeValue = null;
if (newBean != null) {
attributeValue = newBean.getAttribute(attributeName);
}
if (attributeValue != null) {
text.setText(attributeValue);
}
XmlBackedContentProposalProvider proposalProvider = null;
IFile beanFile = wizard.getBeanFile();
Document originalDocument = wizard.getOriginalDocument();
if (attributeName.equals(BeansSchemaConstants.ATTR_CLASS)) {
classProposalProvider = new WizardClassContentProposalProvider(newBean, attributeName, beanFile,
originalDocument);
proposalProvider = classProposalProvider;
}
else if (attributeName.equals(BeansSchemaConstants.ATTR_PARENT)) {
parentProposalProvider = new WizardBeanReferenceContentProposalProvider(newBean, attributeName, beanFile,
originalDocument);
proposalProvider = parentProposalProvider;
}
if (proposalProvider != null) {
contentProposalAdapters.add(new XmlBackedContentProposalAdapter(text, new TextContentAdapter(),
proposalProvider));
}
addListener(text, attributeName);
}
public void createControl(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new GridLayout());
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
createFileComposite(composite);
Composite container = new Composite(composite, SWT.NONE);
container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
GridLayout layout = new GridLayout(2, false);
layout.horizontalSpacing = 10;
container.setLayout(layout);
idLabel = new Label(container, SWT.NONE);
idText = new Text(container, SWT.BORDER);
createAttribute(BeansSchemaConstants.ATTR_ID, idLabel, idText);
nameLabel = new Label(container, SWT.NONE);
nameText = new Text(container, SWT.BORDER);
createAttribute(BeansSchemaConstants.ATTR_NAME, nameLabel, nameText);
classLink = new Hyperlink(container, SWT.UNDERLINE_LINK);
Composite classContainer = new Composite(container, SWT.NONE);
GridLayout classContainerLayout = new GridLayout(2, false);
classContainer.setLayout(classContainerLayout);
classContainerLayout.marginHeight = 0;
classContainerLayout.marginWidth = 0;
classContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
classText = new Text(classContainer, SWT.BORDER);
createAttribute(BeansSchemaConstants.ATTR_CLASS, classLink, classText);
Button browseButton = new Button(classContainer, SWT.NONE);
browseButton.setText(Messages.getString("NewBeanWizardPage.BROWSE_BUTTON_LABEL")); //$NON-NLS-1$
browseButton.setLayoutData(new GridData());
browseButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
String filter = classText.getText();
if (filter == null) {
filter = ""; //$NON-NLS-1$
}
filter = filter.replace('$', '.');
try {
int scope = IJavaElementSearchConstants.CONSIDER_CLASSES;
SelectionDialog dialog = JavaUI.createTypeDialog(getShell(), PlatformUI.getWorkbench()
.getProgressService(), null, scope, false, filter);
dialog.setTitle(Messages.getString("NewBeanWizardPage.SELECT_TYPE_DIALOG_TITLE")); //$NON-NLS-1$
if (dialog.open() == Window.OK) {
IType type = (IType) dialog.getResult()[0];
String newValue = type.getFullyQualifiedName('$');
classText.setText(newValue);
updateAttribute(BeansSchemaConstants.ATTR_CLASS, newValue);
}
}
catch (JavaModelException ex) {
StatusHandler.log(new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, "Failed to select type.", ex));
}
}
});
parentLabel = new Label(container, SWT.NONE);
parentText = new Text(container, SWT.BORDER);
createAttribute(BeansSchemaConstants.ATTR_PARENT, parentLabel, parentText);
Composite buttonComposite = new Composite(container, SWT.NONE);
GridLayout buttonCompositeLayout = new GridLayout();
buttonCompositeLayout.marginWidth = 0;
buttonCompositeLayout.marginHeight = 0;
buttonComposite.setLayout(buttonCompositeLayout);
GridData buttonCompositeData = new GridData(SWT.FILL, SWT.FILL, true, false);
buttonCompositeData.horizontalSpan = 2;
buttonComposite.setLayoutData(buttonCompositeData);
ignoreErrorButton = wizard.createIgnoreErrorButton(buttonComposite, this);
ignoreErrorButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
getWizard().getContainer().updateButtons();
updateMessage();
}
});
updateFieldsEnablement();
setControl(composite);
}
private void createFileComposite(Composite parent) {
Composite fileComposite = new Composite(parent, SWT.NONE);
fileComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
GridLayout compositeLayout = new GridLayout(2, false);
compositeLayout.marginBottom = 10;
fileComposite.setLayout(compositeLayout);
Label fileLabel = new Label(fileComposite, SWT.NONE);
fileLabel.setText(Messages.getString("NewBeanWizardPage.BEAN_FILE_LABEL")); //$NON-NLS-1$
GridData labelData = new GridData(SWT.FILL, SWT.FILL, false, false);
labelData.horizontalSpan = 2;
fileLabel.setLayoutData(labelData);
fileText = new Text(fileComposite, SWT.BORDER);
fileText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
fileText.setEditable(true);
IFile beanFile = wizard.getBeanFile();
if (beanFile != null) {
fileText.setText(beanFile.getFullPath().toOSString());
}
fileText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
String filePath = fileText.getText();
if (filePath.length() == 0) {
fileErrorMessage = Messages.getString("NewBeanWizardPage.EMPTY_BEAN_FILE"); //$NON-NLS-1$
}
else {
IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(filePath));
validateFile(resource);
}
}
});
fileBrowseButton = new Button(fileComposite, SWT.PUSH);
fileBrowseButton.setText(Messages.getString("NewBeanWizardPage.BROWSE_BEAN_FILE")); //$NON-NLS-1$
fileBrowseButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
fileBrowseButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
BeanFileSelectionDialog dialog = new BeanFileSelectionDialog(getShell(), false, ResourcesPlugin
.getWorkspace().getRoot(), IResource.FILE);
dialog.setTitle(Messages.getString("NewBeanWizardPage.BEAN_SELECTION_DIALOG_TITLE")); //$NON-NLS-1$
int status = dialog.open();
if (status == Dialog.OK) {
Object selection = dialog.getFirstResult();
if (selection != null && selection instanceof IFile) {
IFile beanFile = (IFile) selection;
fileText.setText(beanFile.getFullPath().toOSString());
validateFile(beanFile);
}
}
}
});
fileText.setEnabled(fileBrowsingEnabled);
fileBrowseButton.setEnabled(fileBrowsingEnabled);
}
public String getClassName() {
return getInputText(classText);
}
private String getDisplayText(String attributeName) {
return StringUtils.capitalize(attributeName);
}
public String getId() {
return getInputText(idText);
}
private String getInputText(Text text) {
if (text != null) {
String inputText = text.getText();
if (inputText != null) {
return inputText;
}
}
return ""; //$NON-NLS-1$
}
@Override
public String getName() {
return getInputText(nameText);
}
@Override
public boolean isPageComplete() {
if (wizard.getBeanFile() == null) {
return false;
}
if (getErrorMessage() != null && !BeanWizard.getIgnoreError()) {
return false;
}
return super.isPageComplete();
}
private void updateAttribute(String attributeName, String value) {
IDOMElement newBean = wizard.getNewBean();
if (value.length() > 0) {
if (newBean.getAttributeNode(attributeName) != null) {
newBean.setAttribute(attributeName, value);
}
else {
List<Attr> attributes = new ArrayList<Attr>();
boolean found = false;
for (String currAttributeName : BeanWizard.ATTRIBUTES) {
if (currAttributeName == attributeName) {
found = true;
}
else if (found) {
Attr attributeNode = newBean.getAttributeNode(currAttributeName);
if (attributeNode != null) {
attributes.add(attributeNode);
newBean.removeAttributeNode(attributeNode);
}
}
}
newBean.setAttribute(attributeName, value);
for (Attr attribute : attributes) {
newBean.setAttributeNode(attribute);
}
}
}
else {
newBean.removeAttribute(attributeName);
}
validateAttribute(attributeName, value);
}
private void updateFieldsEnablement() {
boolean enabled = fileErrorMessage == null && wizard.getBeanFile() != null;
idText.setEnabled(enabled);
nameText.setEnabled(enabled);
classText.setEnabled(enabled);
parentText.setEnabled(enabled);
ignoreErrorButton.setEnabled(enabled);
}
@Override
public void updateMessage() {
if (fileErrorMessage != null) {
setDialogMessage(fileErrorMessage, false);
}
else if (classErrorMessage != null) {
setDialogMessage(classErrorMessage, true);
}
else if (parentErrorMessage != null) {
setDialogMessage(parentErrorMessage, true);
}
else {
setMessage(DEFAULT_MESSAGE);
}
getWizard().getContainer().updateButtons();
}
private void validateAttribute(String attributeName, String value) {
IDOMElement newBean = wizard.getNewBean();
WizardContentAssistConverter contentAssistConverter = new WizardContentAssistConverter(newBean,
newBean.getAttributeNode(attributeName), wizard.getBeanFile(), wizard.getOriginalDocument());
if (attributeName.equals(BeansSchemaConstants.ATTR_CLASS)) {
if (value.length() > 0) {
Set<ContentAssistProposalWrapper> classAttributeProposals = contentAssistConverter
.getClassAttributeProposals(value, true);
if (classAttributeProposals.isEmpty()) {
classErrorMessage = Messages.getString("NewBeanWizardPage.UNKNOW_CLASS_MESSAGE"); //$NON-NLS-1$
}
else {
classErrorMessage = null;
}
}
else {
classErrorMessage = null;
}
}
else if (attributeName.equals(BeansSchemaConstants.ATTR_PARENT)) {
if (value.length() > 0) {
Set<ContentAssistProposalWrapper> referenceableBeanDescriptions = contentAssistConverter
.getReferenceableBeanDescriptions(value, true);
if (referenceableBeanDescriptions.isEmpty()) {
parentErrorMessage = Messages.getString("NewBeanWizardPage.UNKNOWN_PARENT_MESSAGE"); //$NON-NLS-1$
}
else {
parentErrorMessage = null;
}
}
else {
parentErrorMessage = null;
}
}
updateMessage();
}
private void validateFields() {
validateAttribute(BeansSchemaConstants.ATTR_CLASS, classText.getText());
validateAttribute(BeansSchemaConstants.ATTR_PARENT, parentText.getText());
}
private void validateFile(IResource beanFile) {
if (beanFile != null && BeansCoreUtils.isBeansConfig(beanFile)) {
wizard.setBeanFile((IFile) beanFile);
fileErrorMessage = null;
validateFields();
classProposalProvider.setFile((IFile) beanFile);
parentProposalProvider.setFile((IFile) beanFile);
classProposalProvider.setDocument(wizard.getOriginalDocument());
parentProposalProvider.setDocument(wizard.getOriginalDocument());
for (XmlBackedContentProposalAdapter contentProposalAdapter : contentProposalAdapters) {
contentProposalAdapter.update(wizard.getNewBean());
}
}
else {
fileErrorMessage = Messages.getString("NewBeanWizardPage.BEAN_FILE_ERROR"); //$NON-NLS-1$
}
updateMessage();
updateFieldsEnablement();
}
}