org.eclipse.imp.wizards.IMPWizardPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.imp.wizards.IMPWizardPage.java

Source

/*******************************************************************************
 * Copyright (c) 2007 IBM Corporation.
 * 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:
 *    Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation
 *******************************************************************************/
package org.eclipse.imp.wizards;

import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.imp.WizardPlugin;
import org.eclipse.imp.core.ErrorHandler;
import org.eclipse.imp.ui.dialogs.ListSelectionDialog;
import org.eclipse.imp.ui.dialogs.filters.ViewerFilterForPluginProjects;
import org.eclipse.imp.ui.dialogs.providers.ContentProviderForAllProjects;
import org.eclipse.imp.ui.dialogs.providers.LabelProviderForProjects;
import org.eclipse.imp.ui.dialogs.validators.SelectionValidatorForIDEProjects;
import org.eclipse.imp.ui.dialogs.validators.SelectionValidatorForPluginProjects;
import org.eclipse.imp.utils.ExtensionPointUtils;
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.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.internal.core.BinaryType;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.core.search.JavaWorkspaceScope;
import org.eclipse.jdt.internal.ui.dialogs.FilteredTypesSelectionDialog;
import org.eclipse.jdt.internal.ui.dialogs.PackageSelectionDialog;
import org.eclipse.jdt.internal.ui.wizards.NewClassCreationWizard;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.ui.wizards.NewClassWizardPage;
import org.eclipse.jface.dialogs.IDialogPage;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.plugin.IPluginObject;
import org.eclipse.pde.internal.core.PDECore;
import org.eclipse.pde.internal.core.PluginModelManager;
import org.eclipse.pde.internal.core.ischema.IMetaAttribute;
import org.eclipse.pde.internal.core.ischema.ISchemaAttribute;
import org.eclipse.pde.internal.ui.util.SWTUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
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.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;
import org.eclipse.ui.dialogs.ISelectionValidator;
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.FormToolkit;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.internal.Workbench;
import org.osgi.framework.Bundle;

public class IMPWizardPage extends WizardPage {
    // A simple, extension-point-like name for the component;
    // intended to serve as an internal and reasonably-user-intelligible
    // identifier; expected to be the same as the extension-point
    // id for those components that extend extension points
    protected String fComponentID = "Unspecified";
    protected IMPWizard fOwningWizard;
    protected int fThisPageNumber;
    protected int fTotalPages;
    protected boolean fSkip = false;
    protected boolean fIsOptional;
    protected List<WizardPageField> fFields = new ArrayList<WizardPageField>();
    protected IProject fProject;
    protected Text fProjectText;
    protected Text fDescriptionText;
    protected Text fLanguageText;
    protected Text fQualClassText;
    protected Text fTemplateText = null;
    protected Button fAddThisExtensionPointButton;
    protected boolean fOmitExtensionIDName = true;
    protected String fPackageName;
    protected List<String> fRequiredPlugins = new ArrayList<String>();
    protected boolean fDone = true;
    protected static String sLanguage = "";
    protected static String sProjectName = "";
    // SMS 23 Nov 2007
    protected List<ISelectionValidator> projectValidators = new ArrayList<ISelectionValidator>();

    public IMPWizardPage(String pageName) {
        super(pageName);
    }

    public IMPWizardPage(String wizardName, IMPWizard owner, int pageNumber, int totalPages, boolean isOptional) {
        super(wizardName);
        this.fIsOptional = isOptional;
        this.fThisPageNumber = pageNumber;
        this.fTotalPages = totalPages;
        this.fOwningWizard = owner;
    }

    public boolean canFlipToNextPage() {
        return super.canFlipToNextPage();
    }

    public List<WizardPageField> getFields() {
        return fFields;
    }

    public List<String> getRequires() {
        return fRequiredPlugins;
    }

    public boolean hasBeenSkipped() {
        return fSkip;
    }

    public String getProjectNameFromField() {
        return fProjectText.getText();
    }

    public IProject getProjectOfRecord() {
        return fProject;
    }

    protected void setProjectName(String newProjectName) {
        if (newProjectName.startsWith("P\\"))
            sProjectName = newProjectName.substring(2);
        else if (newProjectName.startsWith("\\"))
            sProjectName = newProjectName.substring(1);
        else
            sProjectName = newProjectName;
    }

    protected final class FocusDescriptionListener extends FocusAdapter {
        public void focusGained(FocusEvent e) {
            Text text = (Text) e.widget;
            WizardPageField field = (WizardPageField) text.getData();
            fDescriptionText.setText(field.fDescription);
        }
    }

    protected final class ProjectTextModifyListener implements ModifyListener {
        public void modifyText(ModifyEvent e) {
            Text text = (Text) e.widget;
            String projectName = text.getText();
            setProjectName(projectName);
            fProject = getProjectBasedOnNameField();
            discoverProjectLanguage();
            // RMF Don't add imports yet; wait for user to press "Finish"
            // ExtensionPointEnabler.addImports(ExtensionPointWizardPage.this);
            String errorMessage = validateProjectField();
            if (errorMessage != null && errorMessage.length() > 0) {
                setPageComplete(false);
                setErrorMessage(errorMessage);
                return;
            }
            dialogChanged();
        }
    }

    /*
     * Creates a ContainerSelectionDialog for selecting projects. Selected
     * projects are optionally subject to validation as plug-in or IMP IDE
     * projects.
     */
    protected class ProjectBrowseSelectionListener extends SelectionAdapter {
        private IProject project;

        protected ProjectBrowseSelectionListener(IProject project) {
            this(project, false, false);
        }

        protected ProjectBrowseSelectionListener(IProject project, boolean validateForPluginProject,
                boolean validateForIDEProject) {
            super();
            this.project = project;
        }

        public void widgetSelected(SelectionEvent e) {
            ListSelectionDialog dialog = new ListSelectionDialog(getShell(),
                    ResourcesPlugin.getWorkspace().getRoot(), // project,
                    new ContentProviderForAllProjects(), new LabelProviderForProjects(), "Select a project");
            if (project != null)
                dialog.setInitialSelections(new Object[] { project.getFullPath() });
            // Add a viewer filter and/or selection validator to the dialog.
            // If the filter is sufficiently specific, then the validator
            // will be redundant.
            addFilterToDialog(dialog);
            addValidatorToDialog(dialog);
            if (dialog.open() == ContainerSelectionDialog.OK) {
                Object[] result = dialog.getResult();
                // IProject selectedProject=
                // ResourcesPlugin.getWorkspace().getRoot().getProject(result[0].toString());
                if (result.length >= 1 && result[0] instanceof IProject) {
                    IProject selectedProject = (IProject) result[0];
                    // fProjectText.setText(((Path) result[0]).toOSString());
                    fProjectText.setText(selectedProject.getName());
                    sProjectName = selectedProject.getName();
                    // SMS 9 Oct 2007
                    // System.out.println("IMPWizardPage:projectBrowseSelectionAdapter:  updating fProject = "
                    // + sProjectName);
                    fProject = selectedProject; // getProjectBasedOnNameField();
                    // // probably wrong!
                } else {
                    // SMS 9 Oct 2007
                    // System.out.println("IMPWizardPage:projectBrowseSelectionAdapter:  not updating fProject (or other project data)");
                }
            }
        }
    }

    /**
     * Add a ViewerFilter to a given dialog.
     * 
     * The viewer filter that is added is the one provided by a call to
     * getViewerFilterForProjects(), which returns (in effect) a default viewer
     * filter for IMP wizard pages. Wizard pages that require a different viewer
     * filter can override this method or that one, as seems most appropriate.
     * Wizard pages that wish to omit viewer filtering can override this method
     * so that it has no effect.
     * 
     * @param dialog The dialog to which the ViewerFilter is to be added
     */
    protected void addFilterToDialog(ListSelectionDialog dialog) {
        dialog.addFilter(getViewerFilterForProjects());
    }

    /**
     * Add a SelectionValidator to the given dialog.
     * 
     * This method does nothing, on the assumption that viewer filtering will
     * eliminate any potentially invalid selections. Wizard pages that wish to
     * enable selection validation can override this method so that it has the
     * desired effect. The particular selection validator to be used in that
     * case can be specified in the overriding method. Alternatively, the
     * overriding mehtod can call getSelectionValidatorForProjects() (and that
     * method can be overridden as needed to return the appropriate validator).
     * 
     * @param dialog The dialog to which the SelectionValidator is to be added.
     */
    protected void addValidatorToDialog(ListSelectionDialog dialog) {
        dialog.addValidator(getSelectionValidatorForProjects());
    }

    /**
     * Returns a ViewerFilter for filtering views of projects opened by this
     * wizard page. In effect this is the default project-viewer filter for IMP
     * wizard pages. The viewer filter returned passes IDE projects, on the
     * assumption that this will be the most common kind of filtering needed for
     * these pages. Wizard pages that require other filtering criteria should
     * override this method.
     * 
     * The filter has one anticipated use, that is, in filtering the values that
     * appear in a project selection dialog. As a result, it is not strictly
     * necessary, as the desired viewer can be constructed in place of a call to
     * this method. This method is provided mainly to keep the treatment of
     * viewer filters consistent with that of selection validators. (And maybe
     * it will be of some unanticipated use someday.)
     * 
     * @return a ViewerFilter for filtering views of projects opened by this
     *         wizard page
     */
    protected ViewerFilter getViewerFilterForProjects() {
        return new ViewerFilterForPluginProjects();
    }

    /**
     * Return a ISelectionValidator to use in validating projects selected or
     * specified on this page. In effect this is the default project-validator
     * for IMP wizard pages. The validator accepts IDE projects, on the
     * assumption that this will be the most common kind of valid project for
     * these wizard pages. Wizard pages that require other validation criteria
     * should override this method.
     * 
     * Note that this validator has two potential uses. One is by the page in
     * validating values assigned to a project field. The other is by
     * project-selection dialogs opened by the page, in validating values
     * selected in those dialogs. This method provides a single source of
     * validators to help assure their consistency across those roles.
     * 
     * Note that, if desired, different validators can be used for field values
     * on the page and selections in a dialog. The validator to be used on pages
     * can be set by overriding this method. A different validator to be used in
     * selection dialogs can be set by overriding addValidatorToDialog().
     * 
     * @return A project-selection validator to use on this page.
     */
    protected ISelectionValidator getSelectionValidatorForProjects() {
        return new SelectionValidatorForPluginProjects();
    }

    /**
     * Replaces the current list of validators for projects with a new one. If
     * the given validator is not null then it is added to the new list.
     * 
     * Assumes that there is just one project-valued field.
     * 
     * @param validator A selection validator (may be null)
     */
    public void setSelectionValidatorForProjects(ISelectionValidator validator) {
        projectValidators = new ArrayList<ISelectionValidator>();
        if (validator != null)
            projectValidators.add(validator);
    }

    /**
     * Adds a given validator to the current list of validators. Creates the
     * list if it does not already exist. If the given validator is null then no
     * validator is added (but this is not an error).
     * 
     * @param validator The validator to be added
     */
    public void addSelectionValdatorForProjects(ISelectionValidator validator) {
        if (projectValidators == null) {
            projectValidators = new ArrayList<ISelectionValidator>();
        }
        projectValidators.add(validator);
    }

    protected class FileBrowseSelectionAdapter extends SelectionAdapter {
        private WizardPageField field;

        public FileBrowseSelectionAdapter(WizardPageField field) {
            this.field = field;
        }

        public void widgetSelected(SelectionEvent e) {
            String newValue = null;
            File f = new File(field.getText());
            if (!f.exists())
                f = null;
            File d = getFile(f);
            if (d != null)
                newValue = d.getAbsolutePath();
            if (newValue != null) {
                field.setText(newValue);
            }
        }

        /**
         * Helper to open the file chooser dialog.
         * 
         * @param startingDirectory the directory to open the dialog on.
         * @return File The File the user selected or <code>null</code> if they
         *         do not.
         */
        private File getFile(File startingDirectory) {
            FileDialog dialog = new FileDialog(getShell(), SWT.OPEN);
            dialog.setText("File Browse");
            if (startingDirectory != null)
                dialog.setFileName(startingDirectory.getPath());
            // if (extensions != null)
            // dialog.setFilterExtensions(extensions);
            String file = dialog.open();
            if (file != null) {
                file = file.trim();
                if (file.length() > 0)
                    return new File(file);
            }
            return null;
        }
    }

    private void createFolderBrowseButton(Composite container, WizardPageField field, Text text) {
        Button button = new Button(container, SWT.PUSH);
        button.setText("Browse...");
        button.setData(text);
        button.addSelectionListener(new FolderBrowseSelectionAdapter(/* container, */ field));
        if (field != null)
            field.fButton = button;
    }

    protected class FolderBrowseSelectionAdapter extends SelectionAdapter {
        private WizardPageField field;

        public FolderBrowseSelectionAdapter(WizardPageField field) {
            this.field = field;
        }

        public void widgetSelected(SelectionEvent e) {
            String newValue = null;
            File f = new File(field.getText());
            if (!f.exists()) {
                IFolder srcFolder = getProjectOfRecord().getFolder("src");
                if (srcFolder.exists()) {
                    f = srcFolder.getLocation().toFile();
                } else {
                    f = getProjectOfRecord().getLocation().toFile();
                }
            }
            File d = getDirectory(f);
            if (d != null)
                newValue = d.getAbsolutePath();
            if (newValue != null) {
                field.setText(newValue);
            }
        }

        /**
         * Helper that opens the folder chooser dialog.
         * 
         * @param startingDirectory The directory the dialog will open in.
         * @return File File or <code>null</code>.
         * 
         */
        private File getDirectory(File startingDirectory) {
            DirectoryDialog folderDialog = new DirectoryDialog(getShell(), SWT.OPEN);
            folderDialog.setText("Folder Browse");
            // Dialog should not return with a null value, although it might
            // return with an invalid one
            if (startingDirectory != null)
                folderDialog.setFilterPath(startingDirectory.getPath());
            String dir = folderDialog.open();
            if (dir != null) {
                dir = dir.trim();
                if (dir.length() > 0)
                    return new File(dir);
            }
            return null;
        }
    }

    protected void addServiceEnablerCheckbox(Composite container) {
        Label label = new Label(container, SWT.NONE);
        label.setText("Add this service:");
        // label.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
        fAddThisExtensionPointButton = new Button(container, SWT.CHECK);
        fAddThisExtensionPointButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                fSkip = !fAddThisExtensionPointButton.getSelection();
                dialogChanged();
            }
        });
        // fAddThisExtensionPointButton.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
        fAddThisExtensionPointButton.setSelection(true);
        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
        gd.horizontalSpan = 2;
        fAddThisExtensionPointButton.setLayoutData(gd);
    }

    /**
     * Attempt to find the languageDescription extension for the specified
     * project (if any), and use the language name from that extension to
     * populate the language name field in the dialog.
     */
    protected void discoverProjectLanguage() {
        if (fProjectText.getText().length() == 0)
            return;
        if (fProject == null) {
            // System.out.println("IMPWIzardPage.discoverProjectLanguage():  fProject == null");
            fProject = ResourcesPlugin.getWorkspace().getRoot().getProject(fProjectText.getText());
            // System.out.println("IMPWIzardPage.discoverProjectLanguage():  updated fProject == "
            // + fProject.getName());
        }
        String languageName = ExtensionPointUtils.discoverLanguageForProject(fProject);
        if (languageName != null) {
            fLanguageText.setText(languageName);
        }
    }

    // SMS 9 Oct 2007
    public IProject discoverSelectedProject() {
        ISelectionService service = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService();
        ISelection selection = service.getSelection();
        IProject project = getProject(selection);
        if (project != null) {
            fProject = project;
            sProjectName = project.getName();
            fProjectText.setText(sProjectName);
        }
        return project;
    }

    public IProject getProjectBasedOnNameField() {
        try {
            IProject project = null;
            if (sProjectName != null && sProjectName.length() > 0)
                project = ResourcesPlugin.getWorkspace().getRoot().getProject(sProjectName);
            // if (project == null)
            // project= discoverSelectedProject();
            if (project != null && project.exists())
                return project;
        } catch (Exception e) {
        }
        return null;
    }

    public IProject getSelectedProject() {
        ISelectionService service = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService();
        ISelection selection = service.getSelection();
        IProject project = getProject(selection);
        if (project != null) {
            fProject = project;
            sProjectName = project.getName();
            fProjectText.setText(sProjectName);
        }
        return project;
    }

    /*
     * This new version of discoverSelectedProject(WithoutUpdating)() is now
     * also called from getProject(); it differs from the original in not
     * updating fProjectText. That allows getProject() to get a selected project
     * without triggering a recursive call, which means it can be used to test
     * for a newly selected project even after another project has been
     * previously selected. SMS 23 May 2007
     * 
     * Updated to better address the case in which there is no active workbench
     * window. SMS 25 May 2007
     */
    protected IProject discoverSelectedProjectWithoutUpdating() {
        try {
            IWorkbenchWindow activeWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
            if (activeWindow == null)
                return null;
            ISelectionService service = activeWindow.getSelectionService();
            ISelection selection = service.getSelection();
            IProject project = getProject(selection);
            return project;
        } catch (NullPointerException e) {
            return null;
        }
    }

    protected IProject getProject(ISelection selection) {
        if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
            IStructuredSelection ssel = (IStructuredSelection) selection;
            if (ssel.size() > 1)
                return null;
            Object obj = ssel.getFirstElement();
            if (obj instanceof IJavaElement)
                obj = ((IJavaElement) obj).getResource();
            if (obj instanceof IResource) {
                return ((IResource) obj).getProject();
            }
            if (obj instanceof JavaProject) {
                return ((JavaProject) obj).getProject();
            }
            if (obj instanceof IPluginObject) {
                IPluginObject pluginObj = (IPluginObject) obj;
                IPluginModelBase pluginBase = pluginObj.getPluginModel();
                IProject proj = pluginBase.getUnderlyingResource().getProject();
                if (proj != null && proj.exists()) {
                    return proj;
                }
            }
        }
        if (selection instanceof ITextSelection || selection == null) {
            IEditorPart editorPart = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
                    .getActiveEditor();
            IEditorInput editorInput = editorPart.getEditorInput();
            if (editorInput instanceof IFileEditorInput) {
                IFileEditorInput fileInput = (IFileEditorInput) editorInput;
                return fileInput.getFile().getProject();
            }
        }
        return null;
    }

    protected IPluginModelBase getPluginModel() {
        IProject project = null;
        try {
            PluginModelManager pmm = PDECore.getDefault().getModelManager();
            // SMS 28 Apr 2008
            IPluginModelBase[] plugins = pmm.getWorkspaceModels(); // getAllPlugins();
            project = getProjectOfRecord();
            if (project == null)
                return null;
            for (int n = 0; n < plugins.length; n++) {
                IPluginModelBase plugin = plugins[n];
                IResource resource = plugin.getUnderlyingResource();
                if (resource != null && project.equals(resource.getProject())) {
                    return plugin;
                }
            }
        } catch (Exception e) {
            ErrorHandler.reportError("Could not enable extension point for " + project.getName(), e);
        }
        return null;
    }

    public static IPluginModelBase getPluginModel(String projectName) {
        try {
            if (projectName == null)
                return null;
            PluginModelManager pmm = PDECore.getDefault().getModelManager();
            // SMS 28 Apr 2008
            IPluginModelBase[] plugins = pmm.getWorkspaceModels(); // getAllPlugins();
            for (int n = 0; n < plugins.length; n++) {
                IPluginModelBase plugin = plugins[n];
                IResource resource = plugin.getUnderlyingResource();
                if (resource != null && projectName.equals(resource.getProject().getName())) {
                    return plugin;
                }
            }
        } catch (Exception e) {
            ErrorHandler.reportError("Could not enable extension point for " + projectName, e);
        }
        return null;
    }

    // SMS 23 Nov 2007
    // Rewritten to make use of dynamically determined
    // validators for the project field
    protected void dialogChanged() {
        setErrorMessage(null);
        if (fSkip) {
            setPageComplete(true);
            return;
        }
        String errorMessage = validateProjectField();
        if (errorMessage != null && errorMessage.length() > 0) {
            setPageComplete(false);
            setErrorMessage(errorMessage);
            return;
        }
        WizardPageField field = getUncompletedField();
        if (field != null) {
            setErrorMessage("Please provide a value for the required field \"" + field.fLabel + "\"");
            setPageComplete(false);
            return;
        }
        setPageComplete(true);
    }

    protected String validateProjectField() {
        IProject project = getProjectBasedOnNameField();
        if (project == null) {
            setPageComplete(false);
            return "Please select a project";
        }
        String errorMessage = null;
        for (int i = 0; i < projectValidators.size(); i++) {
            errorMessage = projectValidators.get(i).isValid(project);
            // RMF 5/29/2009 - Allow non-IDE projects, but enable the language
            // ID field if the user selects one of those
            if (SelectionValidatorForIDEProjects.ERROR_MSG_NOT_IDE_PROJECT.equals(errorMessage)) {
                fLanguageText.setEnabled(true);
                continue;
            }
            if (errorMessage == null || errorMessage.length() == 0)
                continue;
            return errorMessage;
        }
        if (fLanguageText != null) {
            if (new SelectionValidatorForIDEProjects().isValid(project) == null) {
                fLanguageText.setEnabled(false); // an IDE project was selected
            } else {
                fLanguageText.setEnabled(true); // a non-IDE project was
                // selected
            }
        }
        return null;
    }

    protected WizardPageField getUncompletedField() {
        // BUG Prevents clicking "Finish" if an element is optional but one of
        // its attributes isn't
        for (int n = 0; n < fFields.size(); n++) {
            WizardPageField field = (WizardPageField) fFields.get(n);
            if (field.fRequired && field.fValue.length() == 0) {
                return field;
            }
        }
        return null;
    }

    public WizardPageField getField(String name) {
        for (int n = 0; n < fFields.size(); n++) {
            WizardPageField field = (WizardPageField) fFields.get(n);
            // SMS 13 Jun 2007: added toLowerCase of name
            if (field.fAttributeName.toLowerCase().equals(name.toLowerCase())) {
                return field;
            }
        }
        return null;
    }

    public String getValue(String name) {
        for (int n = 0; n < fFields.size(); n++) {
            WizardPageField field = (WizardPageField) fFields.get(n);
            // SMS 27 Sep 2007: lower-cased name
            if (field.fAttributeName.toLowerCase().equals(name.toLowerCase())) {
                return field.fValue;
            }
        }
        return "No such field: " + name;
    }

    protected String upperCaseFirst(String language) {
        return (language == null || language.length() == 0) ? null
                : Character.toUpperCase(language.charAt(0)) + language.substring(1);
    }

    protected String lowerCaseFirst(String s) {
        return (s == null || s.length() == 0) ? null : Character.toLowerCase(s.charAt(0)) + s.substring(1);
    }

    /**
     * Creates additional controls that are to appear below the schema
     * attributes on the wizard page. Derived classes may override.
     * 
     * @param parent
     */
    protected void createAdditionalControls(Composite parent) {
    }

    // SMS 28 Jul 2008: experimenting with adding field to select the template
    // (not appropriate for all wizard pages, but maybe for enough to try it
    // here)
    // Note: needs to be overridden where there is no template or more than one
    // template
    public WizardPageField createTemplateBrowseField(Composite parent, String componentID) {
        // Get the default template path
        String templatePath = WizardUtilities.getStandardTemplateFolderLocation();
        if (templatePath != null) {
            if (!templatePath.endsWith(File.separator))
                templatePath = templatePath + File.separator;
            String templateName = WizardUtilities.getStandardTemplateFileName(fOwningWizard, componentID);
            if (templateName != null) {
                templatePath = templatePath + templateName;
            }
        }
        WizardPageField templateField = new WizardPageField(componentID, "template", "template", templatePath, 0,
                true, "The template flie to use in generating the initial implementation of " + componentID);
        fTemplateText = createLabelTextBrowse(parent, templateField, "FileBrowse");
        fTemplateText.setData(templateField);
        fTemplateText.setEnabled(true);
        fFields.add(templateField);
        return templateField;
    }

    private void createClassBrowseButton(Composite container, WizardPageField field, Text text) {
        Button button = new Button(container, SWT.PUSH);
        button.setText("Browse...");
        button.setData(text);
        button.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                try {
                    IRunnableContext context = PlatformUI.getWorkbench().getProgressService();
                    IJavaSearchScope scope = new JavaWorkspaceScope();
                    FilteredTypesSelectionDialog dialog = new FilteredTypesSelectionDialog(null, false, context,
                            scope, IJavaSearchConstants.CLASS);
                    dialog.setTitle("Class Browse");
                    if (dialog.open() == FilteredTypesSelectionDialog.OK) {
                        Text text = (Text) e.widget.getData();
                        // BinaryType type= (BinaryType)
                        // dialog.getFirstResult();
                        Object type = dialog.getFirstResult();
                        if (type instanceof BinaryType) {
                            text.setText(((BinaryType) type).getFullyQualifiedName());
                        } else if (type instanceof SourceType) {
                            text.setText(((SourceType) type).getFullyQualifiedName());
                        } else {
                            throw new Exception("Type selected in dialog not of recognized type");
                        }
                    }
                } catch (Exception ee) {
                    ErrorHandler.reportError("Could not browse type", ee);
                }
            }
        });
        if (field != null)
            field.fButton = button;
    }

    /**
     * @override
     * @see IDialogPage#createControl(Composite)
     */
    public void createControl(Composite parent) {
    }

    protected void createDescriptionText(Composite container, String text) {
        fDescriptionText = new Text(container, SWT.MULTI | SWT.V_SCROLL | SWT.WRAP);
        fDescriptionText.setBackground(container.getBackground());
        GridData gd = new GridData(GridData.FILL_BOTH);
        gd.horizontalSpan = 3;
        gd.widthHint = 450;
        fDescriptionText.setLayoutData(gd);
        fDescriptionText.setEditable(false);
        // if (fSchema != null)
        // fDescriptionText.setText(fSchema.getDescription());
        fDescriptionText.setText(text); // fWizardDescription);
    }

    /*
     * For creating an element from a schema attribute; "generated components"
     * don't rely on extension schemas but some types of generated component may
     * nevertheless define their fields using schema attributes.
     */
    protected void createElementAttributeTextField(Composite container, String schemaElementPrefix,
            ISchemaAttribute attribute) {
        String name = attribute.getName();
        // We manually create the language field first, for the user's
        // convenience, so check to see whether we have already created it.
        if (name.equals("language") && fLanguageText != null)
            return;
        String basedOn = attribute.getBasedOn();
        String description = stripHTML(attribute.getDescription());
        Object value = attribute.getValue();
        String valueStr = (value == null) ? "" : value.toString();
        boolean isRequired = (attribute.getUse() == ISchemaAttribute.REQUIRED);
        String upName = upperCaseFirst(name);
        WizardPageField field = new WizardPageField(schemaElementPrefix, name, upName, valueStr,
                attribute.getKind(), isRequired, description);
        Text text = createLabelTextBrowse(container, field, basedOn);
        if (name.equals("language") || name.equals("Language")) {
            fLanguageText = text;
            addProjectListener();
        } else if (name.equals("class")) {
            fQualClassText = text;
            // SMS 9 Oct 2007: why not add language listener here?
            addLanguageListener();
        }
        text.setData(field);
        fFields.add(field);
    }

    protected void addLanguageListener() {
        if (fLanguageText != null) {
            // System.out.println("IMPWizardPage.addLanguageListener:  adding listener");
            fLanguageText.addModifyListener(new ModifyListener() {
                public void modifyText(ModifyEvent e) {
                    // System.out.println("IMPWizardPage:languageModifyListener:  got modify event");
                    setClassByLanguage();
                    setIDByLanguage();
                    setNameByLanguage();
                }
            });
        } else {
            WizardPlugin.getInstance()
                    .writeErrorMsg("IMPWizardPage.addLanguageListener(): no language text field?");
        }
    }

    protected void addProjectListener() {
        if (fProjectText != null) {
            // System.out.println("IMPWizardPage.addProjectListener:  adding listener");
            ProjectTextModifyListener ptml = new ProjectTextModifyListener();
            fProjectText.addModifyListener(ptml);
        } else {
            WizardPlugin.getInstance().writeErrorMsg("IMPWizardPage.addProjectListener(): no project text field?");
        }
    }

    // /////////////////////
    private void createFileBrowseButton(Composite container, WizardPageField field, Text text) {
        Button button = new Button(container, SWT.PUSH);
        button.setText("Browse...");
        button.setData(text);
        button.addSelectionListener(new FileBrowseSelectionAdapter(/* container, */field));
        if (field != null)
            field.fButton = button;
    }

    /**
     * Creates controls that are to appear by default above controls that are
     * created by wizard-specific attributes. By default we want to put the
     * language field at (or near) the top, since it's generally important and
     * since other fields may have default values set based on language.
     * 
     * Derived classes may override.
     * 
     * @param parent
     */
    protected void createFirstControls(Composite parent, String componentID) {
        createLanguageFieldForComponent(parent, componentID);
    }

    protected Text createLabelText(Composite container, WizardPageField field) {
        Widget labelWidget = null;
        String name = field.fAttributeName;
        String description = field.fDescription;
        String value = field.fValue;
        name += ":";
        Label label = new Label(container, SWT.NULL);
        label.setText(name);
        label.setToolTipText(description);
        labelWidget = label;
        label.setBackground(container.getBackground());
        Text text = new Text(container, SWT.BORDER | SWT.SINGLE);
        labelWidget.setData(text);
        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
        gd.horizontalSpan = 2;
        text.setLayoutData(gd);
        text.setText(value);
        if (field != null)
            field.fText = text;
        text.addFocusListener(new FocusDescriptionListener());
        text.setData(field);
        return text;
    }

    protected Combo createLabelCombo(Composite container, WizardPageField field, String[] values) {
        final Label levelLabel = new Label(container, SWT.NULL);
        levelLabel.setText("Analysis level required*:");
        levelLabel.setToolTipText("Specify the level of analysis required as a precondition to this service.");
        levelLabel.setBackground(container.getBackground());
        Combo combo = new Combo(container, SWT.DROP_DOWN | SWT.READ_ONLY);
        for (int i = 0; i < values.length; i++) {
            combo.add(values[i]);
        }
        // Put some whitespace into the layout
        new Label(container, SWT.NULL).setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        // Add a modify listener to at least signal that the field has changed
        // (can't be sure here what the value of the field represents, so
        // can't do anything constructive with that)
        // combo.addModifyListener(new ModifyListener() {
        // public void modifyText(ModifyEvent e) {
        // dialogChanged();
        // }
        // });
        return combo;
    }

    protected Text createLabelTextBrowse(Composite container, WizardPageField field, final String basedOn) {
        Widget labelWidget = null;
        String name = field.fAttributeName;
        String description = field.fDescription;
        String value = field.fValue;
        // BUG Prevents clicking "Finish" if an element is optional but one of
        // its attributes isn't
        boolean required = field.fRequired;
        boolean basedOnSomething = (basedOn != null) && (basedOn.length() > 0 && !basedOn.endsWith("NoBrowse"));
        if (required)
            name += "*";
        name += ":";
        if (basedOnSomething && basedOn.endsWith("ClassBrowse")) {
            labelWidget = createNewClassHyperlink(field, name, "", container);
        } else if (basedOnSomething && !basedOn.endsWith("FileBrowse") && !basedOn.endsWith("PackageBrowse")
                && !basedOn.endsWith("ProjectBrowse")) {
            labelWidget = createNewClassHyperlink(field, name, basedOn, container);
        } else {
            Label label = new Label(container, SWT.NULL);
            label.setText(name);
            label.setToolTipText(description);
            labelWidget = label;
            label.setBackground(container.getBackground());
        }
        Text text = new Text(container, SWT.BORDER | SWT.SINGLE);
        labelWidget.setData(text);
        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
        if (!basedOnSomething)
            gd.horizontalSpan = 2;
        else
            gd.horizontalSpan = 1;
        text.setLayoutData(gd);
        text.setText(value);
        if (basedOnSomething) {
            if (basedOn.endsWith("FileBrowse")) {
                createFileBrowseButton(container, field, text);
            } else if (basedOn.endsWith("FolderBrowse")) {
                createFolderBrowseButton(container, field, text);
            } else if (basedOn.endsWith(".java")) {
                createClassBrowseButton(container, field, text);
            } else if (basedOn.endsWith("PackageBrowse")) {
                createPackageBrowseButton(container, field, text);
            } else if (basedOn.endsWith("ClassBrowse")) {
                createClassBrowseButton(container, field, text);
            } else {
                // Assume that it's a Java type
                createClassBrowseButton(container, field, text);
            }
        }
        if (field != null)
            field.fText = text;
        text.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                Text text = (Text) e.widget;
                WizardPageField field = (WizardPageField) text.getData();
                field.fValue = text.getText();
                if (field.fAttributeName.equals("language")) {
                    sLanguage = field.fValue;
                }
                dialogChanged();
            }
        });
        text.addFocusListener(new FocusDescriptionListener());
        return text;
    }

    protected Text createLabelTextFileBrowse(Composite container, WizardPageField field) {
        Widget labelWidget = null;
        String name = field.fAttributeName; // TODO - Why not use the "label"
        // field of "field"?
        String description = field.fDescription;
        String value = field.fValue;
        // BUG Prevents clicking "Finish" if an element is optional but one of
        // its attributes isn't
        boolean required = field.fRequired;
        if (required)
            name += "*";
        name += ":";
        Label label = new Label(container, SWT.NULL);
        label.setText(name);
        label.setToolTipText(description);
        labelWidget = label;
        label.setBackground(container.getBackground());
        Text text = new Text(container, SWT.BORDER | SWT.SINGLE);
        labelWidget.setData(text);
        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
        gd.horizontalSpan = 1;
        text.setLayoutData(gd);
        text.setText(value);
        createFileBrowseButton(container, field, text);
        if (field != null)
            field.fText = text;
        text.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                Text text = (Text) e.widget;
                WizardPageField field = (WizardPageField) text.getData();
                field.fValue = text.getText();
                if (field.fAttributeName.equals("language")) {
                    sLanguage = field.fValue;
                }
                dialogChanged();
            }
        });
        text.addFocusListener(new FocusDescriptionListener());
        return text;
    }

    protected Text createLabelTextPackageBrowse(Composite container, WizardPageField field) {
        Widget labelWidget = null;
        String name = field.fAttributeName;
        String description = field.fDescription;
        String value = field.fValue;
        // BUG Prevents clicking "Finish" if an element is optional but one of
        // its attributes isn't
        boolean required = field.fRequired;
        if (required)
            name += "*";
        name += ":";
        Label label = new Label(container, SWT.NULL);
        label.setText(name);
        label.setToolTipText(description);
        labelWidget = label;
        label.setBackground(container.getBackground());
        Text text = new Text(container, SWT.BORDER | SWT.SINGLE);
        labelWidget.setData(text);
        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
        gd.horizontalSpan = 1;
        text.setLayoutData(gd);
        text.setText(value);
        createPackageBrowseButton(container, field, text);
        if (field != null)
            field.fText = text;
        text.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                Text text = (Text) e.widget;
                WizardPageField field = (WizardPageField) text.getData();
                field.fValue = text.getText();
                if (field.fAttributeName.equals("language")) {
                    sLanguage = field.fValue;
                }
                dialogChanged();
            }
        });
        text.addFocusListener(new FocusDescriptionListener());
        return text;
    }

    /**
     * Create the language field for a wizard page for a component of the IDE
     * under construction. The component may or may not be an extension of an
     * extension point and so may or may not have a corresponding extension
     * point schema id. The component id is a generalization of the schema id
     * that can be used with both extension and non-extension components.
     * 
     * SMS 13 Nov 2007: Field is created in a disabled state, on the theory that
     * most IMP wizards will be run with reference to a particular project and
     * that most projects will uniquely determine a language during most stages
     * of IDE construction. Thus, there is usually no reason to allow the IDE
     * developer to set the language field independently.
     * 
     * May be overridden by derived types of wizard page. One particular reason
     * to override is to have the language be enabled, as when the language is
     * first defined for a project.
     * 
     * @param parent The page in which the field will reside
     * @param componentID The id of the component (extension or otherwise) to
     *            which the page and field are dedicated
     */
    protected void createLanguageFieldForComponent(Composite parent, String componentID) {
        WizardPageField languageField = new WizardPageField(componentID, "language", "Language", "", 0, true,
                "Language for which to create " + componentID);
        fLanguageText = createLabelTextBrowse(parent, languageField, null);
        fLanguageText.setData(languageField);
        if (fProjectText != null && fProjectText.getText().length() > 0) {
            if (fProject == null) {
                fProject = ResourcesPlugin.getWorkspace().getRoot().getProject(fProjectText.getText());
            }
            String langName = ExtensionPointUtils.discoverLanguageForProject(fProject);
            if (langName != null) {
                fLanguageText.setEnabled(false);
            }
        }
        fFields.add(languageField);
        // Listen to changes in value of language field in order to
        // reset dependent fields
        fLanguageText.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                Text text = (Text) e.widget;
                WizardPageField field = (WizardPageField) text.getData();
                field.fValue = text.getText();
                sLanguage = field.fValue;
                dialogChanged();
            }
        });
        // SMS 9 Oct 2007
        // Listen to changes in the value of the project field in order to
        // reset the language field
        if (fProjectText != null) {
            // System.out.println("IMPWizardPage.createLanguageField...:  fProjectText != null, adding listener");
            fProjectText.addModifyListener(new ModifyListener() {
                public void modifyText(ModifyEvent e) {
                    discoverProjectLanguage();
                }
            });
        } else {
            WizardPlugin.getInstance().writeErrorMsg("IMPWizardPage.createLanguageField(): no project text field?");
        }
    }

    protected Widget createNewClassHyperlink(WizardPageField field, String name, final String basedOn,
            Composite container) {
        Widget labelWidget;
        FormToolkit toolkit = new FormToolkit(Display.getDefault());
        Hyperlink link = toolkit.createHyperlink(container, name, SWT.NULL);
        link.setBackground(container.getBackground());
        // SMS 7 Mar 2007
        // At one point it was useful to make this a separately named class;
        // the reason for that no longer pertains, but it didn't seem worthwhile
        // to turn this back into an anonymous class
        class NewClassHyperlinkAdapter extends HyperlinkAdapter {
            public void linkActivated(HyperlinkEvent e) {
                Text text = (Text) e.widget.getData();
                try {
                    if (getProjectNameFromField() == null)
                        MessageDialog.openError(null, "IMP Wizard", "Please select a project first");
                    else {
                        // BUG Should pick up info from wizard page, rather than
                        // using defaults.
                        // SMS 2 Mar 2008: we generally do that now, but the
                        // wizard page doesn't necessarily
                        // have relevant values; these links may sometimes
                        // amount to a way of filling in default
                        // values
                        String superClassName = "";
                        String interfaceName = "";
                        if (basedOn == null || basedOn.length() == 0) {
                            superClassName = getWizardSpecificSuperclass();
                            interfaceName = getWizardSpecificInterface();
                        } else {
                            String basedOnQualName = basedOn;
                            String basedOnTypeName = basedOn.substring(basedOnQualName.lastIndexOf('.') + 1);
                            IJavaProject javaProject = JavaCore.create(getProjectOfRecord());
                            IType basedOnType = javaProject.findType(basedOnQualName);
                            boolean isInterface = false;
                            if (basedOnType != null) {
                                isInterface = basedOnType.isInterface();
                            }
                            if (isInterface) {
                                // Assign the interface name
                                interfaceName = basedOnQualName;
                                // Attempt to determine a superclass name
                                // First contrive a service name based on the
                                // interface name
                                String serviceName = null;
                                if (basedOnTypeName.startsWith("I")
                                        && Character.isUpperCase(basedOnTypeName.charAt(1))) { // Assume
                                    // that
                                    // the
                                    // interface
                                    // name
                                    // begins
                                    // with
                                    // an
                                    // "I"
                                    // that
                                    // won't
                                    // be
                                    // found
                                    // in the service name
                                    serviceName = basedOnTypeName.substring(1);
                                } else {
                                    // Just use the basedOnTypeName
                                    serviceName = basedOnTypeName;
                                }
                                // Now look for a base class with a name that
                                // includes that service name
                                Bundle irb = Platform.getBundle("org.eclipse.imp.runtime");
                                if (irb != null) {
                                    Enumeration entries = irb.getEntryPaths("/src/org/eclipse/imp/services/base/");
                                    // Look for class names that includes to the
                                    // service name; might be
                                    // more than one, so will make a best guess
                                    // at the correct one
                                    String entry = null;
                                    String className = null;
                                    // Get candidate class names
                                    List<String> candidateNames = new ArrayList<String>();
                                    while (entries.hasMoreElements()) {
                                        entry = (String) entries.nextElement();
                                        int lastIndexOfSlash = entry.lastIndexOf("/");
                                        int classNameStart = lastIndexOfSlash > 0 ? lastIndexOfSlash + 1 : 0;
                                        className = entry.substring(classNameStart);
                                        if (className.indexOf(serviceName) > -1)
                                            candidateNames.add(className);
                                    }
                                    // Select best candidate class name, based
                                    // on length
                                    className = null;
                                    for (String s : candidateNames) {
                                        if (className == null) {
                                            className = s;
                                            continue;
                                        }
                                        if (s.length() < className.length())
                                            className = s;
                                    }
                                    // Build qualified superclass name
                                    if (className != null) {
                                        String pakageName = "org.eclipse.imp.services.base.";
                                        int indexOfDot = className.indexOf('.');
                                        if (indexOfDot > 0)
                                            superClassName = pakageName + className.substring(0, indexOfDot);
                                        else
                                            superClassName = pakageName + className;
                                    }
                                }
                            } else {
                                // The basedOnQualName is the superclass name
                                // and there is no interface
                                superClassName = basedOnQualName;
                                interfaceName = "";
                            }
                        }
                        // openClassDialog
                        openClassDialog(fComponentID, interfaceName, superClassName, text);
                    }
                } catch (Exception ee) {
                    ErrorHandler.reportError("Could not open dialog to find type", true, ee);
                }
            }
        }
        NewClassHyperlinkAdapter listener = new NewClassHyperlinkAdapter();
        link.addHyperlinkListener(listener);
        link.setToolTipText(field.fDescription);
        labelWidget = link;
        if (field != null)
            field.fLink = link;
        return labelWidget;
    }

    /*
     * Methods to allow an IMP wizard to provide superclass and interface names
     * to the New Class Wizard (e.g., in the event that these aren't available
     * from an extension-point schema)
     */
    protected String getWizardSpecificSuperclass() {
        return "";
    }

    protected String getWizardSpecificInterface() {
        return "";
    }

    protected WizardDialog openClassDialog(String componentID, String interfaceQualName, String superClassName,
            Text text) {
        NewClassCreationWizard wizard = new NewClassCreationWizard();
        wizard.init(Workbench.getInstance(), null);
        WizardDialog dialog = new WizardDialog(null, wizard);
        dialog.create();
        NewClassWizardPage page = (NewClassWizardPage) wizard.getPages()[0];
        if (text == null || text.getText().length() == 0) {
            dialog = getDialogWithEmptyClassName(text, dialog, page);
        } else {
            dialog = getDialogWithClassName(componentID, interfaceQualName, superClassName, text, dialog, page);
        }
        if (dialog == null)
            return null;
        SWTUtil.setDialogSize(dialog, 400, 500);
        if (dialog.open() == WizardDialog.OK) {
            String name = page.getTypeName();
            String pkg = page.getPackageText();
            if (pkg.length() > 0)
                name = pkg + '.' + name;
            text.setText(name);
            fPackageName = pkg;
        }
        return dialog;
    }

    protected WizardDialog getDialogWithEmptyClassName(Text text, WizardDialog dialog, NewClassWizardPage page) {
        return dialog;
    }

    protected WizardDialog getDialogWithClassName(String componentID, String interfaceQualName,
            String superClassName, Text text, WizardDialog dialog, NewClassWizardPage page) {
        try {
            String intfName = interfaceQualName.substring(interfaceQualName.lastIndexOf('.') + 1);
            IJavaProject javaProject = JavaCore.create(getProjectOfRecord());
            if (javaProject == null) {
                ErrorHandler.reportError("Java project is null", true);
                return null;
            }
            // RMF 7/5/2005 - If the project doesn't yet have the necessary
            // plug-in
            // dependency for this reference to be satisfiable, an error ensues.
            if (interfaceQualName != null && interfaceQualName.length() > 0) {
                if (javaProject.findType(interfaceQualName) == null) {
                    ErrorHandler.reportError("Base interface '" + interfaceQualName
                            + "' does not exist in project's build path; be sure to add the appropriate plugin to the dependencies.",
                            true);
                    return null;
                    // TODO: Do we want to continue from this point, or should
                    // we just throw an exception?
                }
            }
            if (superClassName != null && superClassName.length() > 0) {
                if (javaProject.findType(superClassName) == null) {
                    ErrorHandler.reportError("Base class '" + superClassName
                            + "' does not exist in project's build path; be sure to add the appropriate plugin to the dependencies.",
                            true);
                    return null;
                    // TODO: Do we want to continue from this point, or should
                    // we just throw an exception?
                }
            }
            String givenPackageName = "";
            String givenClassName = "";
            if (text != null && text.getText().length() > 0) {
                givenPackageName = text.getText().substring(0, text.getText().lastIndexOf('.'));
                givenClassName = text.getText().substring(text.getText().lastIndexOf('.') + 1);
            }
            page.setSuperClass(superClassName, true);
            ArrayList<String> interfaces = new ArrayList<String>();
            if (interfaceQualName != null && interfaceQualName.length() > 0) {
                interfaces.add(interfaceQualName);
                page.setSuperInterfaces(interfaces, true);
            }
            String langName = fLanguageText.getText();
            String langClassName = upperCaseFirst(langName);
            String langPackageName = lowerCaseFirst(langName);
            // Compute name of package for new service class
            String servicePackageName = givenPackageName;
            if (servicePackageName == null || servicePackageName.length() == 0) {
                servicePackageName = "org.eclipse.imp."
                        + ((langPackageName == null || langPackageName.length() == 0) ? "" : langPackageName)
                        + componentID.substring(componentID.lastIndexOf('.') + 1);
            }
            // Compute unqualified name of new service class
            String serviceClassName = givenClassName;
            if (serviceClassName == null || serviceClassName.length() == 0) {
                serviceClassName = ((langClassName == null || langClassName.length() == 0) ? "" : langClassName);
                if (intfName.charAt(0) == 'I' && Character.isUpperCase(intfName.charAt(1)))
                    serviceClassName = serviceClassName + intfName.substring(1);
                else
                    serviceClassName = serviceClassName + intfName;
            }
            WizardUtilities.createSubFolders(servicePackageName.replace('.', '\\'), getProjectOfRecord(),
                    new NullProgressMonitor());
            // SMS 2 Mar 2008: Setting of srcFolder could be more sophisticated
            // TODO: set srcFolder with a properly computed value
            IFolder srcFolder = getProjectOfRecord().getFolder("src/");
            IPackageFragmentRoot pkgFragRoot = javaProject.getPackageFragmentRoot(srcFolder);
            IPackageFragment pkgFrag = pkgFragRoot.getPackageFragment(servicePackageName);
            page.setPackageFragmentRoot(pkgFragRoot, true);
            page.setPackageFragment(pkgFrag, true);
            page.setTypeName(serviceClassName, true);
            // SWTUtil.setDialogSize(dialog, 400, 500);
            // if (dialog.open() == WizardDialog.OK) {
            // String name= page.getTypeName();
            // String pkg= page.getPackageText();
            // if (pkg.length() > 0)
            // name= pkg + '.' + name;
            // text.setText(name);
            // fPackageName= pkg;
            // }
            return dialog;
        } catch (Exception e) {
            ErrorHandler.reportError("Could not create class implementing " + interfaceQualName, true, e);
        }
        // return null;
        return dialog;
    }

    private void createPackageBrowseButton(Composite container, WizardPageField field, Text text) {
        Button button = new Button(container, SWT.PUSH);
        button.setText("Browse...");
        button.setData(text);
        final Shell shell = container.getShell();
        button.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                try {
                    IProject project = fProject;
                    if (project == null)
                        project = getProjectBasedOnNameField();
                    if (project == null) {
                        setErrorMessage("Please select a plug-in project to add this extension to");
                        setPageComplete(false);
                        return;
                    }
                    JavaProject javaProject = (JavaProject) JavaCore.create(project);
                    if (javaProject == null)
                        // the project is not configured for Java (has no Java
                        // nature)
                        throw new Exception("createPackageBrowseButton:  unable to open Java project = '"
                                + project.getName() + "' for search scope");
                    SelectionDialog dialog = JavaUI.createPackageDialog(shell, javaProject, 0);
                    dialog.setTitle("Package Browser");
                    if (dialog.open() == PackageSelectionDialog.OK) {
                        Text text = (Text) e.widget.getData();
                        IPackageFragment pack = (org.eclipse.jdt.internal.core.PackageFragment) dialog
                                .getResult()[0];
                        text.setText(pack.getElementName());
                    }
                } catch (Exception ee) {
                    ErrorHandler.reportError("Could not browse package", ee);
                }
            }
        });
        if (field != null)
            field.fButton = button;
    }

    protected void createProjectField(Composite container) {
        Label label = new Label(container, SWT.NULL);
        label.setText("Project*:");
        label.setBackground(container.getBackground());
        label.setToolTipText("Select the plug-in project");
        fProjectText = new Text(container, SWT.BORDER | SWT.SINGLE);
        fProjectText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        // SMS 23 Nov 2007
        // Add a default validator for the project field.
        // Add it here since we've just created the field.
        // Make the default case the most common one we expect
        // (pages that don't require an IDE project will have to override).
        setSelectionValidatorForProjects(getSelectionValidatorForProjects());
        // SMS 9 Oct 2007
        // Here we've just created the project text, so we can't
        // expect that it has any value; to find a value, get the
        // project that is currently selected.
        // Don't validate it here; validation will occur as part
        // of validation of whole page in dialogChanged().
        final IProject project = discoverSelectedProject(); // getProject();
        if (project != null) {
            // Try setting fProject directly rather than waiting for a listener
            fProjectText.setText(project.getName());
            fProject = getProjectBasedOnNameField();
        }
        Button browseButton = new Button(container, SWT.PUSH);
        browseButton.setText("Browse...");
        browseButton.addSelectionListener(new ProjectBrowseSelectionListener(project, true, true));
        fProjectText.addModifyListener(new ProjectTextModifyListener());
        fProjectText.addFocusListener(new FocusAdapter() {
            public void focusGained(FocusEvent e) {
                // Text text = (Text)e.widget;
                if (fDescriptionText != null)
                    fDescriptionText.setText("Select the project to use for this wizard");
            }
        });
    }

    /**
     * Set the name of the "extension" based on the language. "Extension name"
     * is a concept that applies (as you would expect) to components that
     * implement extensions of extension points. We might possibly define an
     * analogous role for generated components that are not based on extension
     * points. In any case, the logic for computing the name can be made
     * independent of the the type of wizard (in that sense) and so for
     * generality it is included at this level of the wizard type hierarchy.
     */
    protected void setNameByLanguage() {
        try {
            WizardPageField langField = getField("language");
            String language = langField.getText();
            if (language.length() == 0)
                return;
            // Give language name an upper-case initial for this purpose
            language = language.substring(0, 1).toUpperCase() + language.substring(1);
            WizardPageField nameField = getField("name");
            if (nameField != null) {
                // SMS 21 Jul 2006
                // setClassIfEmpty() below had provision for fSchema == null
                // but this method did not; I've added it
                // String pointID= fSchema != null ? fSchema.getPointId() :
                // fExtPointID;
                nameField.setText(language + " " + fComponentID);
                // SMS 10 May 2006:
                // Struggling with plural and singular for "builder" classes,
                // ids, names, etc.
                if (fComponentID.endsWith("uilders") || fComponentID.endsWith("olvers")) {
                    nameField.setText(nameField.getText().substring(0, nameField.getText().length() - 1));
                }
            }
        } catch (Exception e) {
            ErrorHandler.reportError("Cannot set name", e);
        }
    }

    /**
     * Set the id of the "extension" based on the language. "Extension id" is a
     * concept that applies (as you would expect) to components that implement
     * extensions of extension points. We might possibly define an analogous
     * role for generated components that are not based on extension points. In
     * any case, the logic for computing the id can be made independent of the
     * the type of wizard (in that sense) and so for generality it is included
     * at this level of the wizard type hierarchy.
     */
    protected void setIDByLanguage() {
        try {
            WizardPageField langField = getField("language");
            String language = langField.getText();
            if (language.length() == 0)
                return;
            String langID = lowerCaseFirst(language);
            WizardPageField idField = getField("id");
            if (idField != null) {
                // SMS 21 Jul 2006
                // setClassIfEmpty() below had provision for fSchema == null
                // but this method did not; I've added it
                // String pointID= fSchema != null ? fSchema.getPointId() :
                // fExtPointID;
                idField.setText(langID + ".imp." + lowerCaseFirst(fComponentID));
                // SMS 10 May 2006:
                // Struggling with plural and singular for "builder" classes,
                // ids, names, etc.
                if (fComponentID.endsWith("uilders") || fComponentID.endsWith("olvers")) {
                    idField.setText(idField.getText().substring(0, idField.getText().length() - 1));
                }
            }
        } catch (Exception e) {
            ErrorHandler.reportError("Cannot set ID", e);
        }
    }

    protected void setClassByLanguage() {
        try {
            WizardPageField langField = getField("language");
            WizardPageField classField = getField("class");
            String language = langField.getText();
            if (language.length() == 0)
                return;
            // SMS 26 Nov 2007 re: bug #296
            String langPkg = language.toLowerCase(); // lowerCaseFirst(language);
            String langClass = upperCaseFirst(language);
            // String pointID= fSchema != null ? fSchema.getPointId() :
            // fComponentID;
            // SMS 21 Jul 2006
            // Above the field pointID is set in such a way as to accommodate
            // fSchema being
            // null, but fSchema was referenced three times below anyway. I've
            // substituted
            // pointID for those references
            fPackageName = langPkg + ".imp." + lowerCaseFirst(fComponentID);
            if (classField != null) {
                classField.setText(fPackageName + "." + langClass + upperCaseFirst(fComponentID));
                // SMS 10 May 2006:
                // Struggling with plural and singular for "builder" classes,
                // ids, names, etc.
                if (fComponentID.endsWith("uilders") || fComponentID.endsWith("olvers")) {
                    classField.setText(classField.getText().substring(0, classField.getText().length() - 1));
                }
            }
        } catch (Exception e) {
            ErrorHandler.reportError("Cannot set class", e);
        }
    }

    /**
     * Directly create a text field for a wizard from given values rather than
     * using an extension schema element or attributes.
     * 
     * @param container The wizard page (or other container) in which the field
     *            will be placed
     * @param fieldCategoryName A name for a larger grouping of fields that
     *            might contain this one (used in place of the schema element
     *            name)
     * @param fieldName A name for the field (used in place of the schema
     *            attribute name)
     * @param description A description of the field (what it's for, how it
     *            should be filled, ...)
     * @param value A value that may be filled into the field by default (may be
     *            null)
     * @param basedOn For fields that represent a Java type, a value (such as
     *            the name of a parent type) used to evaluate or process the
     *            given value
     * @param isRequired Whether the field must be given a value before the
     *            containing wizard can be finished
     */
    public WizardPageField createTextField(Composite container, String fieldCategoryName, String fieldName,
            String description, String value, String basedOn, boolean isRequired) {
        String valueStr = (value == null) ? "" : value;
        String upName = upperCaseFirst(fieldName);
        WizardPageField field = new WizardPageField(fieldCategoryName, fieldName, upName, valueStr,
                IMetaAttribute.STRING, isRequired, description);
        Text text = createLabelTextBrowse(container, field, basedOn);
        // SMS 13 Jun 2007: added test for "Language"
        // SMS 25 Sep 2007: inherited from the original method in
        // ExtensionPointWizardPage
        // on which this one is based; may still be useful
        if (fieldName.equals("language") || fieldName.equals("Language"))
            fLanguageText = text;
        else if (fieldName.equals("class"))
            fQualClassText = text;
        text.setData(field);
        fFields.add(field);
        return field;
    }

    public WizardPageField createLabeledTextFieldWithFileBrowse(Composite container, String fieldCategoryName,
            String fieldName, String description, String value, boolean isRequired) {
        String valueStr = (value == null) ? "" : value;
        String upName = upperCaseFirst(fieldName);
        WizardPageField field = new WizardPageField(fieldCategoryName, fieldName, upName, valueStr,
                IMetaAttribute.STRING, isRequired, description);
        Text text = createLabelTextFileBrowse(container, field);
        // SMS 13 Jun 2007: added test for "Language"
        // SMS 25 Sep 2007: inherited from the original method in
        // ExtensionPointWizardPage
        // on which this one is based; may still be useful
        if (fieldName.equals("language") || fieldName.equals("Language"))
            fLanguageText = text;
        else if (fieldName.equals("class"))
            fQualClassText = text;
        text.setData(field);
        fFields.add(field);
        return field;
    }

    public WizardPageField createLabeledTextFieldWithPackageBrowse(Composite container, String fieldCategoryName,
            String fieldName, String description, String value, boolean isRequired) {
        String valueStr = (value == null) ? "" : value;
        String upName = upperCaseFirst(fieldName);
        WizardPageField field = new WizardPageField(fieldCategoryName, fieldName, upName, valueStr,
                IMetaAttribute.STRING, isRequired, description);
        Text text = createLabelTextPackageBrowse(container, field);
        // SMS 13 Jun 2007: added test for "Language"
        // SMS 25 Sep 2007: inherited from the original method in
        // ExtensionPointWizardPage
        // on which this one is based; may still be useful
        if (fieldName.equals("language") || fieldName.equals("Language"))
            fLanguageText = text;
        else if (fieldName.equals("class"))
            fQualClassText = text;
        text.setData(field);
        fFields.add(field);
        return field;
    }

    String stripHTML(String description) {
        StringBuffer buffer = new StringBuffer(description);
        replace(buffer, "<p>", "");
        replace(buffer, "<ul>", "");
        replace(buffer, "</ul>", "");
        replace(buffer, "<li>", " *  ");
        return buffer.toString();
    }

    void replace(StringBuffer buffer, String s1, String s2) {
        int index = buffer.indexOf(s1);
        while (index != -1) {
            buffer.replace(index, index + s1.length(), s2);
            index = buffer.indexOf(s1);
        }
    }
}