com.legstar.eclipse.plugin.schemagen.wizards.MainWizardPage.java Source code

Java tutorial

Introduction

Here is the source code for com.legstar.eclipse.plugin.schemagen.wizards.MainWizardPage.java

Source

/*******************************************************************************
 * Copyright (c) 2010 LegSem.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     LegSem - initial API and implementation
 ******************************************************************************/
package com.legstar.eclipse.plugin.schemagen.wizards;

import java.io.File;
import java.util.Properties;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
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.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Text;
import org.osgi.service.prefs.BackingStoreException;

import com.legstar.codegen.CodeGenMakeException;
import com.legstar.codegen.models.SourceToXsdCobolModel;
import com.legstar.eclipse.plugin.common.wizards.AbstractWizardPage;
import com.legstar.eclipse.plugin.common.wizards.AbstractWizardRunnable;
import com.legstar.eclipse.plugin.schemagen.Activator;
import com.legstar.eclipse.plugin.schemagen.Messages;
import com.legstar.eclipse.plugin.schemagen.preferences.PreferenceConstants;

/**
 * This is the first XSD generation wizard page. This is where the user
 * selects the type of source he would like to start from and determines
 * the target location and parameters for the XSD.
 * 
 */
public class MainWizardPage extends AbstractToXsdWizardPage {

    /** Selection of available source types. */
    private Combo _sourceTypeCombo;

    /** Destination container. */
    private Text _targetContainerText;

    /** Destination file name. */
    private Text _targetXSDFileNameText;

    /** Whether the XSD file should be overwritten if it already exist. */
    private boolean _overwriteAllowed = true;

    /** Target XML schema namespace. */
    private Text _targetNamespaceText;

    /** The field values that are permanent. */
    private CommonModel _model;

    /**
     * Will be true is user explicitly modified the namespace. This means we
     * should refrain from trying to generate it automatically.
     */
    private boolean _xsdNamespaceUserChanged;

    /**
     * Constructs the main wizard page.
     * 
     * @param initialSelection the workbench current selection
     */
    public MainWizardPage(final IStructuredSelection initialSelection) {
        super(initialSelection, "MainWizardPage", Messages.main_wizard_page_title,
                Messages.main_wizard_page_description);
    }

    /** {@inheritDoc} */
    @Override
    public void createExtendedControls(final Composite container) {
        Group groupSource = createGroup(container, Messages.source_type_group_label);
        _sourceTypeCombo = createComboFromItemsArray(groupSource, new String[] { Messages.cobol_source_type_text,
                Messages.xsd_source_type_text, Messages.java_source_type_text });

        Group groupTarget = createGroup(container, Messages.target_group_label);

        createLabel(groupTarget, Messages.container_label);
        _targetContainerText = createText(groupTarget);

        createBrowseForContainerButton(groupTarget, Messages.container_selection_label, _targetContainerText);

        createLabel(groupTarget, Messages.xsd_file_name_label);
        _targetXSDFileNameText = createText(groupTarget);
        _targetXSDFileNameText.setFocus();

        createOverwriteAllowedCheckButton(groupTarget, Messages.overwrite_button_label);

        createLabel(groupTarget, Messages.namespace_label);
        _targetNamespaceText = createText(groupTarget, 2);

    }

    /** {@inheritDoc} */
    public void initContents() {
        IProject project = initTargetContainer();

        // Whatever project was identified, tell the wizard so that other pages
        // know about it
        setProject(project);

        loadGenModel();
        createListeners();
    }

    /**
     * Initialize widgets from the Model.
     */
    public void loadGenModel() {
        if (getProject() != null) {
            _model = new CommonModel(loadProperties(getProjectPreferences()));
        } else {
            _model = new CommonModel();
        }

        if (_model.getTargetXsdFileName() != null && _model.getTargetXsdFileName().length() > 0) {
            _targetXSDFileNameText.setText(_model.getTargetXsdFileName());
        } else {
            _targetXSDFileNameText.setText(".xsd");
        }

        if (_model.getNamespace() != null && _model.getNamespace().length() > 0) {
            _targetNamespaceText.setText(_model.getNamespace());
        } else {
            _targetNamespaceText.setText(getDefaultNamespace());
        }

        if (_targetNamespaceText.getText().equals(getDefaultNamespace())) {
            _xsdNamespaceUserChanged = false;
        } else {
            _xsdNamespaceUserChanged = true;
        }

    }

    /** {@inheritDoc} */
    public void initProjectContent() {
        loadGenModel();
        getWizard().getCobolToXsdWizardPage().initProjectContent();
        getWizard().getJavaToXsdWizardPage().initProjectContent();
        getWizard().getXsdToXsdWizardPage().initProjectContent();
    }

    /**
     * Makes sure we start listening on widget changes only after they are
     * initialized.
     */
    public void createListeners() {
        _targetContainerText.addModifyListener(new ModifyListener() {
            public void modifyText(final ModifyEvent e) {
                dialogChanged();
            }
        });
        _targetXSDFileNameText.addModifyListener(new ModifyListener() {
            public void modifyText(final ModifyEvent e) {
                dialogChanged();
            }
        });
        _targetXSDFileNameText.addModifyListener(new ModifyListener() {
            public void modifyText(final ModifyEvent e) {
                autoFill();
            }
        });
        _targetNamespaceText.addModifyListener(new ModifyListener() {
            public void modifyText(final ModifyEvent e) {
                dialogChanged();
            }
        });

        // Detects user modifications to the namespace (as opposed to
        // modifications due to autofill)
        _targetNamespaceText.addFocusListener(new FocusListener() {

            String initialValue;

            public void focusGained(final FocusEvent e) {
                initialValue = ((Text) e.widget).getText();
            }

            public void focusLost(final FocusEvent e) {
                String newValue = ((Text) e.widget).getText();
                if (!_xsdNamespaceUserChanged) {
                    _xsdNamespaceUserChanged = !newValue.equals(initialValue);
                }

            }

        });
    }

    /**
     * Set the initial value of the target container field.
     * <p/>
     * If a project is selected in the workspace, then it is considered to be
     * the initial value.
     * <p/>
     * If no project is selected, we attempt to recover the last container used
     * from the default preferences.
     * <p/>
     * We are only interested in the project so if a lower level element is
     * selected we get the first segment of its path.
     * <p/>
     * Since we can't process multiple selections, we deal with the first one
     * only.
     * 
     * @return the selected project in the workbench or null if none is selected
     */
    protected IProject initTargetContainer() {
        IProject project = null;
        if (getInitialSelection() != null && !getInitialSelection().isEmpty()
                && getInitialSelection() instanceof TreeSelection) {

            Object obj = ((TreeSelection) getInitialSelection()).getPaths()[0].getFirstSegment();
            if (obj instanceof IProject) {
                project = (IProject) obj;
            } else if (obj instanceof IJavaProject) {
                project = ((IJavaProject) obj).getProject();
            }
        }
        if (project == null) {
            String lastContainerPath = getDefaultPreferences().getString(PreferenceConstants.LAST_TARGET_CONTAINER);
            if (lastContainerPath.length() > 0) {
                // Make sure it still exist in the workbench
                project = AbstractWizardRunnable.getProject(lastContainerPath);
                if (project != null && project.isOpen()) {
                    _targetContainerText.setText(lastContainerPath);
                } else {
                    project = null;
                }
            }
        } else {
            _targetContainerText.setText(project.getFullPath().toOSString());
        }

        return project;
    }

    /**
     * Create a default namespace using the preferred prefix and the XSD file
     * name.
     * 
     * @return the value used to initialize the text widget
     */
    private String getDefaultNamespace() {
        return getDefaultNamespacePrefix() + getXsdSimpleFileName();
    }

    /**
     * The default namespace prefix comes from the LegStar general preferences.
     * 
     * @return a default prefix terminated with slash
     */
    protected String getDefaultNamespacePrefix() {
        IPreferenceStore store = getDefaultPreferences();
        String str = store.getString(PreferenceConstants.XSD_NAMESPACE_PREFIX);
        if (str != null && str.length() != 0) {
            str = setSeparatorChar(str, '/');
            return str;
        }
        return "";
    }

    /**
     * If the input string is empty or null, return an empty string.
     * If the input string already ends with the segments separator char, return
     * the input string unchanged.
     * Otherwise, append a final segments separator character and return the
     * resulting string.
     * 
     * @param str input string
     * @param c the segments separator character
     * @return the input string with final continuation character
     */
    private String setSeparatorChar(final String str, final char c) {
        if (str == null || str.length() == 0) {
            return "";
        }
        if (str.charAt(str.length() - 1) == c) {
            return str;
        }
        return str + c;
    }

    /**
     * When user types in an xsd name, we can generally infer an appropriate
     * namespace unless the user has taken control of
     * these fields already.
     * Only the last segment of the xsd file name, excluding the extension,
     * contributes to other field values.
     */
    private void autoFill() {
        String str = getXsdSimpleFileName();
        if (!_xsdNamespaceUserChanged) {
            _targetNamespaceText.setText(getDefaultNamespacePrefix() + str);
        }
    }

    /**
     * @return the last segment of the xsd file name without an extension
     */
    private String getXsdSimpleFileName() {
        IPath path = new Path(_targetXSDFileNameText.getText()).removeFileExtension();
        if (path.lastSegment() == null) {
            return "";
        }
        return path.lastSegment();
    }

    /**
     * Adds a check button that reflects its state in an associated boolean
     * variable.
     * 
     * @param container parent composite
     * @param text the button text
     * @return a check button
     */
    private Button createOverwriteAllowedCheckButton(final Composite container, final String text) {
        final Button button = new Button(container, SWT.CHECK);
        button.setText(text);
        button.setSelection(isOverwriteAllowed());
        button.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(final SelectionEvent e) {
                setOverwriteAllowed(!isOverwriteAllowed());
                dialogChanged();
            }
        });
        return button;
    }

    /** {@inheritDoc} */
    @Override
    public void dialogChanged() {

        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();

        /* Target container should not be empty */
        String targetContainer = getTargetContainer();
        if (targetContainer.length() == 0) {
            updateStatus(Messages.no_target_container_msg);
            return;
        }

        /* Target container must exist and be a valid container */
        IResource containerResource = root.findMember(new Path(targetContainer));
        if (containerResource == null || !containerResource.exists()
                || !(containerResource instanceof IContainer)) {
            updateStatus(Messages.invalid_target_container_msg);
            return;
        }

        /* Make sure we have a valid project. */
        IProject project = containerResource.getProject();
        if (project == null || !project.isOpen()) {
            updateStatus(Messages.invalid_target_container_msg);
            return;
        }

        /*
         * If this is a different project than the one we had before, ignore
         * other changes to this page. We also offer a chance to the next
         * pages to initialize their project-dependent content
         */
        if (project != getProject()) {
            setProject(project);
            initProjectContent();
        }

        /* Target XML schema file name must not be empty */
        if (getXsdSimpleFileName().length() == 0) {
            updateStatus(Messages.no_target_xsd_file_name_msg);
            return;
        }

        String fileName = getTargetXSDFileName();
        /*
         * If overwrite is prohibited, then XML schema file must not exist in
         * target container
         */
        if (!isOverwriteAllowed()) {
            IResource fileResource = root.findMember(new Path(targetContainer).append(fileName));
            if (fileResource != null && fileResource.exists()) {
                updateStatus(Messages.already_exists_target_xsd_file_msg);
                return;
            }
        }

        updateStatus(null);
        updateGenModel();
    }

    /**
     * Update the model with UI field values.
     */
    protected void updateGenModel() {
        _model.setTargetXsdFileName(getValueFromText(_targetXSDFileNameText));
        _model.setNamespace(getValueFromText(_targetNamespaceText));
    }

    /**
     * Store the selected values in the default scoped preference store.
     */
    public void storeDefaultPreferences() {
        getDefaultPreferences().setValue(PreferenceConstants.LAST_TARGET_CONTAINER, getTargetContainer());
    }

    /**
     * The next page depends on the source type selected. {@inheritDoc}
     * 
     * @see org.eclipse.jface.wizard.WizardPage#getNextPage()
     */
    public IWizardPage getNextPage() {
        AbstractWizardPage nextPage = null;
        switch (getSelectedSource()) {
        case 0:
            nextPage = getWizard().getCobolToXsdWizardPage();
            break;
        case 1:
            nextPage = getWizard().getXsdToXsdWizardPage();
            ((XsdToXsdWizardPage) nextPage).setNewTargetNamespace(getTargetNamespace());
            break;
        case 2:
            nextPage = getWizard().getJavaToXsdWizardPage();
            break;
        default:
            break;
        }
        return nextPage;
    }

    /**
     * Returns the zero-relative index of the item which is currently selected
     * in the receiver's list, or -1 if no item is selected.
     * 
     * @return the source type that was selected on the first page.
     */
    public int getSelectedSource() {
        return _sourceTypeCombo.getSelectionIndex();
    }

    /**
     * @return true if the XSD file should be overwritten if it already exist
     */
    public boolean isOverwriteAllowed() {
        return _overwriteAllowed;
    }

    /**
     * @param overwriteAllowed true if the XSD file should be overwritten if it
     *            already exist
     */
    public void setOverwriteAllowed(final boolean overwriteAllowed) {
        _overwriteAllowed = overwriteAllowed;
    }

    /**
     * @return the destination container text
     */
    public String getTargetContainer() {
        return _targetContainerText.getText();
    }

    /**
     * @param destinationContainer the destination container text to set
     */
    public void setDestinationContainer(final String destinationContainer) {
        _targetContainerText.setText(destinationContainer);
    }

    /**
     * @return the target XML Schema file name
     */
    public String getTargetXSDFileName() {
        return _targetXSDFileNameText.getText();
    }

    /**
     * @param targetXSDFileName the target XML Schema file name to set
     */
    public void setTargetXSDFileName(final String targetXSDFileName) {
        _targetXSDFileNameText.setText(targetXSDFileName);
    }

    /**
     * @return the Target XML schema namespace. Returns null if namespace is
     *         spaces
     */
    public String getTargetNamespace() {
        if (_targetNamespaceText.getText().trim().length() == 0) {
            return null;
        }
        return _targetNamespaceText.getText();
    }

    /**
     * @param targetNamespace the Target XML schema namespace to set
     */
    public void setTargetNamespace(final String targetNamespace) {
        _targetNamespaceText.setText(targetNamespace);
    }

    /**
     * @return the default scope preferences
     */
    public IPreferenceStore getDefaultPreferences() {
        return getWizard().getDefaultPreferences();
    }

    /**
     * @return the project scope preferences
     */
    public IEclipsePreferences getProjectPreferences() {
        return getWizard().getProjectPreferences();
    }

    /**
     * Create a properties file from preferences content.
     * <p/>
     * In case we cannot recover the previous values, just log an error.
     * 
     * @param preferences an Eclipse preference store
     * @return a properties file
     */
    public Properties loadProperties(final IEclipsePreferences preferences) {
        try {
            return getWizard().loadProperties(preferences);
        } catch (BackingStoreException e) {
            logCoreException(e, Activator.PLUGIN_ID);
            return new Properties();
        }
    }

    /**
     * This wizard page is common to various translators (COBOL to XSD, XSD to
     * XSD, Java to XSD). So we don't necessarily know which one the user will
     * end up selecting. Here we define the minimal model that is common to all
     * translators so we can store/load previous values.
     * 
     */
    protected class CommonModel extends SourceToXsdCobolModel {

        /**
         * A no-Arg constructor.
         */
        public CommonModel() {
        }

        /**
         * Construct from a properties file.
         * 
         * @param props the property file
         */
        public CommonModel(final Properties props) {
            super(props);
        }

        /** {@inheritDoc} */
        public void generateBuild(final File arg0) throws CodeGenMakeException {
        }

    }

    /**
     * @return the set of properties that need to be persisted
     */
    public Properties getPersistProperties() {
        return _model.toProperties();
    }

}