| /******************************************************************************* |
| * Copyright (c) 2010 Oracle. 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: |
| * Oracle - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jpt.jaxb.ui.internal.wizards.schemagen; |
| |
| import java.util.Iterator; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.jdt.core.IClassFile; |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.ui.JavaElementComparator; |
| import org.eclipse.jdt.ui.JavaElementLabelProvider; |
| import org.eclipse.jdt.ui.ProblemsLabelDecorator; |
| import org.eclipse.jdt.ui.StandardJavaElementContentProvider; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.viewers.CheckStateChangedEvent; |
| import org.eclipse.jface.viewers.DecoratingLabelProvider; |
| import org.eclipse.jface.viewers.ICheckStateListener; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.ITreeContentProvider; |
| import org.eclipse.jface.wizard.IWizardPage; |
| import org.eclipse.jpt.jaxb.core.internal.SchemaGenerator; |
| import org.eclipse.jpt.jaxb.ui.internal.JptJaxbUiMessages; |
| import org.eclipse.jpt.jaxb.ui.internal.filters.ContainerFilter; |
| import org.eclipse.jpt.jaxb.ui.internal.filters.EmptyInnerPackageFilter; |
| import org.eclipse.jpt.jaxb.ui.internal.filters.NonArchiveOrExternalElementFilter; |
| import org.eclipse.jpt.jaxb.ui.internal.filters.NonContainerFilter; |
| import org.eclipse.jpt.jaxb.ui.internal.filters.NonJavaElementFilter; |
| import org.eclipse.jpt.utility.internal.ArrayTools; |
| import org.eclipse.jpt.utility.internal.StringTools; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.BusyIndicator; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| 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.Control; |
| import org.eclipse.swt.widgets.FileDialog; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.swt.widgets.TreeItem; |
| import org.osgi.framework.Bundle; |
| |
| public class SchemaGeneratorWizardPage extends AbstractJarDestinationWizardPage { |
| |
| private IStructuredSelection initialSelection; |
| private IJavaProject targetProject; |
| |
| // widgets |
| private SettingsGroup settingsGroup; |
| |
| private Button usesMoxyCheckBox; |
| private boolean usesMoxy; |
| |
| static public String JPT_ECLIPSELINK_UI_PLUGIN_ID = "org.eclipse.jpt.eclipselink.ui"; //$NON-NLS-1$ |
| |
| // other constants |
| private static final int SIZING_SELECTION_WIDGET_WIDTH = 480; |
| private static final int SIZING_SELECTION_WIDGET_HEIGHT = 150; |
| |
| // ********** constructor ********** |
| |
| public SchemaGeneratorWizardPage(IStructuredSelection selection) { |
| super("JAXB Schema Generator", selection, null); //$NON-NLS-1$ |
| |
| this.initialSelection = selection; |
| this.setUsesMoxy(false); |
| this.setTitle(JptJaxbUiMessages.SchemaGeneratorWizardPage_title); |
| this.setDescription(JptJaxbUiMessages.SchemaGeneratorWizardPage_desc); |
| } |
| |
| // ********** IDialogPage implementation ********** |
| @Override |
| public void createControl(Composite parent) { |
| this.setPageComplete(false); |
| this.setControl(this.buildTopLevelControl(parent)); |
| } |
| |
| @Override |
| public void setVisible(boolean visible) { |
| super.setVisible(visible); |
| |
| this.updateTargetProject(); |
| this.setDefaultSchemaFile(); |
| this.updateInputGroupTreeFilter(); |
| |
| // default usesMoxy to true only when JPT EclipseLink bundle exists and MOXy is on the classpath |
| this.updateUsesMoxy(this.jptEclipseLinkBundleExists() && this.moxyIsOnClasspath()); |
| |
| // checkbox visible only if jpt.eclipselink.ui plugin is available |
| // and EclipseLink MOXy is not on the classpath |
| this.usesMoxyCheckBox.setVisible(this.jptEclipseLinkBundleExists() && ! this.moxyIsOnClasspath()); |
| |
| this.validateProjectClasspath(); |
| this.giveFocusToDestination(); |
| } |
| |
| // default the schema name to the project name |
| protected void setDefaultSchemaFile() { |
| String defaultSchemaName = this.targetProject.getProject().getName() + SchemaGeneratorWizard.XSD_EXTENSION; |
| this.settingsGroup.schemaFileText.setText(defaultSchemaName); |
| this.settingsGroup.schemaFileText.setSelection(0, defaultSchemaName.length()); |
| } |
| |
| // ********** IWizardPage implementation ********** |
| |
| @Override |
| public boolean isPageComplete() { |
| boolean complete = this.validateDestinationGroup(); |
| if(complete) { |
| complete = this.validateSourceGroup(); |
| if(complete) { |
| this.validateProjectClasspath(); |
| } |
| } |
| return complete; |
| } |
| |
| @Override |
| public void setPreviousPage(IWizardPage page) { |
| super.setPreviousPage(page); |
| if(this.getControl() != null) |
| this.updatePageCompletion(); |
| } |
| |
| // ********** intra-wizard methods ********** |
| |
| protected IJavaProject getJavaProject() { |
| return this.targetProject; |
| } |
| |
| /** |
| * @return The schema relative path to the project. |
| */ |
| protected String getSchemaPath() { |
| return this.settingsGroup.getSchemaPath(); |
| } |
| |
| protected Object[] getAllCheckedItems() { |
| return ArrayTools.array(this.getInputGroup().getAllCheckedListItems()); |
| } |
| |
| protected boolean usesMoxy() { |
| return this.usesMoxy; |
| } |
| |
| // ********** validation ********** |
| |
| @Override |
| @SuppressWarnings("restriction") |
| protected void updatePageCompletion() { |
| super.updatePageCompletion(); |
| } |
| |
| @Override |
| protected boolean validateDestinationGroup() { |
| boolean complete = this.targetSchemaIsEmpty(); |
| if( ! complete) { |
| this.setErrorMessage(JptJaxbUiMessages.SchemaGeneratorWizardPage_errorNoSchema); |
| return false; |
| } |
| this.setErrorMessage(null); |
| return true; |
| } |
| |
| @Override |
| protected boolean validateSourceGroup() { |
| if(this.getAllCheckedItems().length == 0) { |
| if(this.getErrorMessage() == null) { |
| this.setErrorMessage(JptJaxbUiMessages.SchemaGeneratorWizardPage_errorNoPackage); |
| } |
| return false; |
| } |
| this.setErrorMessage(null); |
| return true; |
| } |
| |
| private void validateProjectClasspath() { |
| //this line will suppress the "default package" warning (which doesn't really apply here |
| //as the JAXB gen uses an org.example.schemaName package by default) and will clear the classpath warnings when necessary |
| setMessage(null); |
| |
| if( ! this.genericJaxbIsOnClasspath()) { |
| this.displayWarning(JptJaxbUiMessages.SchemaGeneratorWizardPage_jaxbLibrariesNotAvailable); |
| } |
| else if(this.usesMoxy() && ! this.moxyIsOnClasspath()) { |
| //this message is being truncated by the wizard width in some cases |
| this.displayWarning(JptJaxbUiMessages.SchemaGeneratorWizardPage_moxyLibrariesNotAvailable); |
| } |
| |
| //this code will intelligently remove our classpath warnings when they are present but no longer apply (as an alternative |
| //to setting the message to null continuously as is currently done) |
| // else if( this.getMessage() != null){ |
| // if (this.getMessage().equals(JptJaxbUiMessages.ClassesGeneratorWizardPage_jaxbLibrariesNotAvailable) || |
| // this.getMessage().equals(JptJaxbUiMessages.ClassesGeneratorWizardPage_moxyLibrariesNotAvailable)) { |
| // setMessage(null); |
| // } |
| // } |
| } |
| |
| /** |
| * Test if the Jaxb compiler is on the classpath. |
| */ |
| private boolean genericJaxbIsOnClasspath() { |
| try { |
| String className = SchemaGenerator.JAXB_GENERIC_SCHEMA_GEN_CLASS; |
| IType genClass = this.targetProject.findType(className); |
| return (genClass != null); |
| } |
| catch(JavaModelException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| // ********** internal methods ********** |
| |
| private Control buildTopLevelControl(Composite parent) { |
| Composite composite = new Composite(parent, SWT.NULL); |
| composite.setLayout(new GridLayout()); |
| |
| this.settingsGroup = new SettingsGroup(composite); |
| |
| this.usesMoxyCheckBox = this.buildUsesMoxyCheckBox(composite); |
| |
| Dialog.applyDialogFont(parent); |
| return composite; |
| } |
| |
| private void updateTargetProject() { |
| IWizardPage previousPage = this.getPreviousPage(); |
| |
| if(previousPage instanceof ProjectWizardPage) { |
| // get project from previousPage |
| this.targetProject = ((ProjectWizardPage)previousPage).getProject(); |
| } |
| else if(initialSelection != null && ! this.initialSelection.isEmpty()) { |
| // no previousPage - get project from initialSelection |
| this.targetProject = this.getProjectFromInitialSelection(); |
| } |
| } |
| |
| private void updateInputGroupTreeFilter() { |
| this.getInputGroup().addTreeFilter(new NonContainerFilter(this.targetProject.getProject().getName())); |
| } |
| |
| private IJavaProject getProjectFromInitialSelection() { |
| IJavaProject project = null; |
| |
| Object firstElement = initialSelection.getFirstElement(); |
| if(firstElement instanceof IJavaElement) { |
| IJavaElement javaElement = (IJavaElement)firstElement; |
| int type = javaElement.getElementType(); |
| if(type == IJavaElement.JAVA_PROJECT) { |
| project = (IJavaProject)javaElement; |
| } |
| else if(type == IJavaElement.PACKAGE_FRAGMENT) { |
| project = ((IPackageFragment)javaElement).getJavaProject(); |
| } |
| } |
| return project; |
| } |
| |
| private boolean targetSchemaIsEmpty() { |
| return ! StringTools.stringIsEmpty(this.getSchemaPath()); |
| } |
| |
| private boolean jptEclipseLinkBundleExists() { |
| return (this.getJptEclipseLinkBundle() != null); |
| } |
| |
| private Bundle getJptEclipseLinkBundle() { |
| return Platform.getBundle(JPT_ECLIPSELINK_UI_PLUGIN_ID); // Cannot reference directly EL plugin. |
| } |
| |
| private void setUsesMoxy(boolean usesMoxy){ |
| this.usesMoxy = usesMoxy; |
| } |
| |
| private void updateUsesMoxy(boolean usesMoxy){ |
| this.setUsesMoxy(usesMoxy); |
| this.usesMoxyCheckBox.setSelection(this.usesMoxy()); |
| this.validateProjectClasspath(); |
| } |
| |
| |
| /** |
| * Test if the EclipseLink Jaxb compiler is on the classpath. |
| */ |
| private boolean moxyIsOnClasspath() { |
| try { |
| String className = SchemaGenerator.JAXB_ECLIPSELINK_SCHEMA_GEN_CLASS; |
| IType genClass = this.targetProject.findType(className); |
| return (genClass != null); |
| } |
| catch (JavaModelException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| private void displayWarning(String message) { |
| this.setMessage(message, WARNING); |
| } |
| |
| private CheckboxTreeAndListGroup getInputGroup() { |
| return this.settingsGroup.inputGroup; |
| } |
| |
| // ********** overrides ********** |
| /** |
| * Returns an iterator over this page's collection of currently-specified |
| * elements to be exported. This is the primary element selection facility |
| * accessor for subclasses. |
| * |
| * @return an iterator over the collection of elements currently selected for export |
| */ |
| @Override |
| protected Iterator<?> getSelectedResourcesIterator() { |
| return this.getInputGroup().getAllCheckedListItems(); |
| } |
| |
| @Override |
| protected void update() { |
| this.updatePageCompletion(); |
| } |
| |
| @Override |
| public final void saveWidgetValues() { |
| // do nothing |
| } |
| |
| @Override |
| protected void internalSaveWidgetValues() { |
| // do nothing |
| } |
| |
| @Override |
| protected void restoreWidgetValues() { |
| // do nothing |
| } |
| |
| |
| @Override |
| protected void initializeJarPackage() { |
| // do nothing |
| } |
| |
| @Override |
| protected void giveFocusToDestination() { |
| this.settingsGroup.giveFocusToDestination(); |
| } |
| |
| // ********** UI components ********** |
| |
| private Button buildUsesMoxyCheckBox(Composite parent) { |
| |
| Button checkBox = new Button(parent, SWT.CHECK); |
| GridData gridData = new GridData(); |
| gridData.verticalIndent = 10; |
| checkBox.setLayoutData(gridData); |
| checkBox.setText(JptJaxbUiMessages.ClassesGeneratorWizardPage_usesMoxyImplementation); |
| checkBox.setSelection(this.usesMoxy()); |
| checkBox.addSelectionListener(this.buildUsesMoxySelectionListener()); |
| |
| return checkBox; |
| } |
| |
| private SelectionListener buildUsesMoxySelectionListener() { |
| return new SelectionListener() { |
| public void widgetDefaultSelected(SelectionEvent event) { |
| this.widgetSelected(event); |
| } |
| |
| public void widgetSelected(SelectionEvent event) { |
| updateUsesMoxy(usesMoxyCheckBox.getSelection()); |
| validateProjectClasspath(); |
| } |
| }; |
| } |
| |
| // ********** SettingsGroup class ********** |
| |
| private class SettingsGroup { |
| |
| private CheckboxTreeAndListGroup inputGroup; |
| private Text schemaFileText; |
| |
| // ********** constructor ********** |
| |
| private SettingsGroup(Composite parent) { |
| super(); |
| initializeDialogUnits(parent); |
| |
| Composite composite = new Composite(parent, SWT.NULL); |
| GridLayout layout = new GridLayout(); |
| layout.marginWidth = 0; |
| layout.marginHeight = 0; |
| composite.setLayout(layout); |
| composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| |
| buildSchemaComposite(composite); |
| |
| |
| // Input Tree |
| createPlainLabel(composite, JptJaxbUiMessages.SchemaGeneratorWizardPage_packages); |
| this.inputGroup = this.createInputGroup(composite); |
| |
| if(initialSelection != null) |
| BusyIndicator.showWhile(parent.getDisplay(), new Runnable() { |
| public void run() { |
| setupBasedOnInitialSelections(); |
| } |
| }); |
| } |
| |
| protected void buildSchemaComposite(Composite parent) { |
| Composite composite = new Composite(parent, SWT.NULL); |
| GridLayout layout = new GridLayout(3, false); // false = do not make columns equal width |
| layout.marginWidth = 0; |
| layout.marginTop = 0; |
| layout.marginBottom = 10; |
| composite.setLayout(layout); |
| composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| |
| // Schema Location |
| this.buildLabel(composite, JptJaxbUiMessages.SchemaGeneratorWizardPage_shemaLocation); |
| this.schemaFileText = this.buildSchemaText(composite); |
| this.buildBrowseButton(composite, 1); |
| |
| } |
| // ********** intra-wizard methods ********** |
| |
| /** |
| * @return The schema relative path to the project. |
| */ |
| protected String getSchemaPath() { |
| return this.schemaFileText.getText(); |
| } |
| |
| protected void giveFocusToDestination() { |
| this.schemaFileText.setFocus(); |
| } |
| |
| // ********** UI components ********** |
| |
| private Label buildLabel(Composite parent, String text) { |
| Label label = new Label(parent, SWT.LEFT); |
| label.setText(text); |
| label.setLayoutData(new GridData()); |
| return label; |
| } |
| |
| private Text buildSchemaText(Composite parent) { |
| |
| Text text = new Text(parent, SWT.BORDER); |
| GridData gridData = new GridData(GridData.FILL_HORIZONTAL); |
| gridData.grabExcessHorizontalSpace = true; |
| text.setLayoutData(gridData); |
| text.addModifyListener(new ModifyListener() { |
| public void modifyText(ModifyEvent e) { |
| updatePageCompletion(); |
| } |
| }); |
| return text; |
| } |
| |
| private Button buildBrowseButton(Composite parent, int horizontalSpan) { |
| |
| Button browseButton = new Button(parent, SWT.PUSH); |
| browseButton.setText(JptJaxbUiMessages.SchemaGeneratorWizardPage_browse); |
| GridData gridData = new GridData(); |
| gridData.horizontalAlignment = GridData.FILL; |
| gridData.horizontalSpan = horizontalSpan; |
| browseButton.setLayoutData(gridData); |
| browseButton.addSelectionListener(new SelectionListener() { |
| public void widgetDefaultSelected(SelectionEvent e) {} |
| |
| public void widgetSelected(SelectionEvent e) { |
| |
| String fileName = promptFile(); |
| if( ! StringTools.stringIsEmpty(fileName)) { |
| schemaFileText.setText(makeRelativeToProjectPath(fileName)); |
| } |
| } |
| }); |
| return browseButton; |
| } |
| |
| /** |
| * The browse button was clicked, its action invokes this action which should |
| * prompt the user to select a file and return it. |
| */ |
| private String promptFile() { |
| FileDialog dialog = new FileDialog(getShell()); |
| dialog.setText(JptJaxbUiMessages.SchemaGeneratorWizardPage_chooseSchemaDialogTitle); |
| dialog.setFilterPath(this.getFilterPath()); |
| dialog.setFilterExtensions(new String[] {"*.xsd"}); //$NON-NLS-1$ |
| String filePath = dialog.open(); |
| |
| return (filePath != null) ? filePath : null; |
| } |
| |
| /** |
| * Creates the checkbox tree and list for selecting resources. |
| * |
| * @param parent the parent control |
| */ |
| protected CheckboxTreeAndListGroup createInputGroup(Composite parent) { |
| CheckboxTreeAndListGroup checkboxTreeGroup; |
| |
| int labelFlags = JavaElementLabelProvider.SHOW_BASICS |
| | JavaElementLabelProvider.SHOW_OVERLAY_ICONS |
| | JavaElementLabelProvider.SHOW_SMALL_ICONS; |
| ITreeContentProvider treeContentProvider= |
| new StandardJavaElementContentProvider() { |
| @Override |
| public boolean hasChildren(Object element) { |
| // prevent the + from being shown in front of packages |
| return !(element instanceof IPackageFragment) && super.hasChildren(element); |
| } |
| }; |
| final DecoratingLabelProvider provider = new DecoratingLabelProvider(new JavaElementLabelProvider(labelFlags), new ProblemsLabelDecorator(null)); |
| checkboxTreeGroup = new CheckboxTreeAndListGroup( |
| parent, |
| JavaCore.create(ResourcesPlugin.getWorkspace().getRoot()), |
| treeContentProvider, |
| provider, |
| new StandardJavaElementContentProvider(), |
| provider, |
| SWT.NONE, |
| SIZING_SELECTION_WIDGET_WIDTH, |
| SIZING_SELECTION_WIDGET_HEIGHT); |
| checkboxTreeGroup.addTreeFilter(new EmptyInnerPackageFilter()); |
| checkboxTreeGroup.setTreeComparator(new JavaElementComparator()); |
| checkboxTreeGroup.setListComparator(new JavaElementComparator()); |
| |
| checkboxTreeGroup.addTreeFilter(new NonJavaElementFilter()); |
| checkboxTreeGroup.addTreeFilter(new NonArchiveOrExternalElementFilter()); |
| |
| checkboxTreeGroup.addListFilter(new ContainerFilter()); |
| checkboxTreeGroup.addListFilter(new NonJavaElementFilter()); |
| |
| checkboxTreeGroup.getTree().addListener(SWT.MouseUp, SchemaGeneratorWizardPage.this); |
| checkboxTreeGroup.getTable().addListener(SWT.MouseUp, SchemaGeneratorWizardPage.this); |
| |
| ICheckStateListener listener = new ICheckStateListener() { |
| public void checkStateChanged(CheckStateChangedEvent event) { |
| update(); |
| } |
| }; |
| |
| checkboxTreeGroup.addCheckStateListener(listener); |
| return checkboxTreeGroup; |
| } |
| |
| // ********** internal methods ********** |
| |
| private String makeRelativeToProjectPath(String filePath) { |
| Path path = new Path(filePath); |
| IPath relativePath = path.makeRelativeTo(targetProject.getProject().getLocation()); |
| return relativePath.toOSString(); |
| } |
| |
| /** |
| * Returns the path that the dialog will use to filter the directories it shows to |
| * the argument, which may be null. |
| * If the string is null, then the operating system's default filter path will be used. |
| * <p> |
| * Note that the path string is platform dependent. For convenience, either |
| * '/' or '\' can be used as a path separator. |
| * </p> |
| * |
| * @return The filter path |
| */ |
| private String getFilterPath() { |
| return targetProject.getProject().getLocation().toOSString(); |
| } |
| |
| private void setupBasedOnInitialSelections() { |
| |
| Iterator<?> iterator = initialSelection.iterator(); |
| while(iterator.hasNext()) { |
| Object selectedElement = iterator.next(); |
| |
| if(selectedElement instanceof IResource && !((IResource)selectedElement).isAccessible()) |
| continue; |
| |
| if(selectedElement instanceof IJavaElement && !((IJavaElement)selectedElement).exists()) |
| continue; |
| |
| if(selectedElement instanceof ICompilationUnit || selectedElement instanceof IClassFile || selectedElement instanceof IFile) |
| this.inputGroup.initialCheckListItem(selectedElement); |
| else { |
| if(selectedElement instanceof IFolder) { |
| // Convert resource to Java element if possible |
| IJavaElement je = JavaCore.create((IResource)selectedElement); |
| if(je != null && je.exists() && je.getJavaProject().isOnClasspath((IResource)selectedElement)) { |
| |
| selectedElement = je; |
| je.toString(); |
| } |
| } |
| this.inputGroup.initialCheckTreeItem(selectedElement); |
| } |
| } |
| |
| TreeItem[] items = this.inputGroup.getTree().getItems(); |
| int i = 0; |
| while(i < items.length && ! items[i].getChecked()) |
| i++; |
| if(i < items.length) { |
| this.inputGroup.getTree().setSelection(new TreeItem[] {items[i]}); |
| this.inputGroup.getTree().showSelection(); |
| this.inputGroup.populateListViewer(items[i].getData()); |
| } |
| } |
| } |
| } |