org.eclipse.jpt.jaxb.ui.internal.properties.JaxbSchemasPropertiesPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jpt.jaxb.ui.internal.properties.JaxbSchemasPropertiesPage.java

Source

/*******************************************************************************
 * Copyright (c) 2010, 2013 Oracle. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0, which accompanies this distribution
 * and is available at http://www.eclipse.org/legal/epl-v10.html.
 * 
 * Contributors:
 *     Oracle - initial API and implementation
 ******************************************************************************/
package org.eclipse.jpt.jaxb.ui.internal.properties;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EventListener;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.dialogs.TrayDialog;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.jface.window.Window;
import org.eclipse.jpt.common.ui.internal.WorkbenchTools;
import org.eclipse.jpt.common.ui.internal.swt.ColumnAdapter;
import org.eclipse.jpt.common.ui.internal.swt.TableModelAdapter;
import org.eclipse.jpt.common.ui.internal.swt.bind.SWTBindTools;
import org.eclipse.jpt.common.utility.internal.StringTools;
import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
import org.eclipse.jpt.common.utility.internal.iterable.SingleElementIterable;
import org.eclipse.jpt.common.utility.internal.model.AbstractModel;
import org.eclipse.jpt.common.utility.internal.model.value.AspectAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.BufferedModifiablePropertyValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.CollectionPropertyValueModelAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.PropertyAspectAdapter;
import org.eclipse.jpt.common.utility.internal.model.value.SimpleCollectionValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.SortedListValueModelAdapter;
import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
import org.eclipse.jpt.common.utility.model.listener.CollectionChangeListener;
import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener;
import org.eclipse.jpt.common.utility.model.value.CollectionValueModel;
import org.eclipse.jpt.common.utility.model.value.ModifiableCollectionValueModel;
import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
import org.eclipse.jpt.jaxb.core.JaxbProject;
import org.eclipse.jpt.jaxb.core.JaxbProjectManager;
import org.eclipse.jpt.jaxb.core.JaxbWorkspace;
import org.eclipse.jpt.jaxb.core.SchemaEntry;
import org.eclipse.jpt.jaxb.core.xsd.XsdUtil;
import org.eclipse.jpt.jaxb.ui.JaxbWorkbench;
import org.eclipse.jpt.jaxb.ui.JptJaxbUiMessages;
import org.eclipse.jpt.jaxb.ui.internal.wizards.classesgen.SelectFileOrXMLCatalogIdPanel;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.PropertyPage;
import org.eclipse.wst.xsd.contentmodel.internal.XSDImpl;
import org.eclipse.xsd.XSDSchema;

/**
 * Shows the schemas associated with a JAXB project
 */
public class JaxbSchemasPropertiesPage extends PropertyPage {

    private static final int SIZING_SELECTION_PANE_WIDTH = 450;

    private final ResourceManager resourceManager;

    protected final ModifiablePropertyValueModel<IProject> projectModel;

    private final PropertyValueModel<JaxbProject> jaxbProjectModel;

    protected final BufferedModifiablePropertyValueModel.Trigger trigger;

    private final SchemasModel schemasModel;

    private final ModifiableCollectionValueModel<Schema> schemasSelectionModel;

    public JaxbSchemasPropertiesPage() {
        super();
        this.resourceManager = this.buildResourceManager();
        this.projectModel = new SimplePropertyValueModel<IProject>();
        this.jaxbProjectModel = new JaxbProjectModel(this.projectModel);
        this.trigger = new BufferedModifiablePropertyValueModel.Trigger();
        this.schemasModel = new SchemasModel(this.jaxbProjectModel, this.trigger);
        this.schemasSelectionModel = new SimpleCollectionValueModel<Schema>();
        setDescription(JptJaxbUiMessages.SCHEMAS_PAGE_DESCRIPTION);
    }

    private ResourceManager buildResourceManager() {
        return new LocalResourceManager(this.getParentResourceManager());
    }

    private ResourceManager getParentResourceManager() {
        return JFaceResources.getResources();
    }

    protected IProject getProject() {
        return this.projectModel.getValue();
    }

    @Override
    public final void createControl(Composite parent) {
        super.createControl(parent);

        Button revertButton = getDefaultsButton();

        revertButton.setText(JptJaxbUiMessages.SCHEMAS_PAGE_REVERT);

        GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
        Point minButtonSize = revertButton.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
        gd.widthHint = Math.max(convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH), minButtonSize.x);
        revertButton.setLayoutData(gd);

        updateButtons();

        getShell().layout(true, true);
    }

    @Override
    protected final Control createContents(Composite parent) {
        IAdaptable element = getElement();

        IProject project = null;
        if (element instanceof IProject) {
            project = (IProject) element;
        } else {
            project = (IProject) Platform.getAdapterManager().loadAdapter(element, IProject.class.getName());
        }

        this.projectModel.setValue(project);

        Composite pageComponent = new Composite(parent, SWT.NULL);
        GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        pageComponent.setLayout(layout);
        GridData data = new GridData(GridData.FILL_BOTH);
        data.widthHint = SIZING_SELECTION_PANE_WIDTH;
        pageComponent.setLayoutData(data);

        Label schemasLabel = new Label(pageComponent, SWT.LEFT);
        schemasLabel.setText(JptJaxbUiMessages.SCHEMAS_PAGE_SCHEMAS);
        data = new GridData();
        data.horizontalAlignment = GridData.FILL;
        data.horizontalSpan = 2;
        schemasLabel.setLayoutData(data);

        // create the table composite
        Composite tableComposite = new Composite(pageComponent, SWT.NONE);
        data = new GridData(SWT.FILL, SWT.FILL, true, true);
        data.grabExcessHorizontalSpace = true;
        data.grabExcessVerticalSpace = true;
        data.widthHint = SIZING_SELECTION_PANE_WIDTH;
        tableComposite.setLayoutData(data);

        // create the table
        TableViewer schemasTable = new TableViewer(tableComposite, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI);
        TableModelAdapter.adapt(new SortedListValueModelAdapter<Schema>(this.schemasModel),
                this.schemasSelectionModel, schemasTable.getTable(), new SchemaColumnAdapter(),
                new SchemaTableLabelProvider());
        ColumnViewerToolTipSupport.enableFor(schemasTable, ToolTip.NO_RECREATE);
        schemasTable.getTable().setHeaderVisible(true);
        schemasTable.getTable().setToolTipText(null);

        // set the table composite layout (after the table, so that column information is available)
        TableColumnLayout tableLayout = new TableColumnLayout();
        tableLayout.setColumnData(schemasTable.getTable().getColumn(0), new ColumnWeightData(15));
        tableLayout.setColumnData(schemasTable.getTable().getColumn(1), new ColumnWeightData(25));
        tableComposite.setLayout(tableLayout);

        // set the table layout data
        data = new GridData(GridData.FILL_BOTH);
        data.heightHint = schemasTable.getTable().getItemHeight() * 7;
        data.widthHint = 200;
        schemasTable.getTable().setLayoutData(data);

        createButtonGroup(pageComponent);

        Dialog.applyDialogFont(parent);

        return pageComponent;
    }

    protected void createButtonGroup(Composite parent) {
        Composite groupComponent = new Composite(parent, SWT.NULL);
        GridLayout groupLayout = new GridLayout();
        groupLayout.marginWidth = 0;
        groupLayout.marginHeight = 0;
        groupComponent.setLayout(groupLayout);
        GridData data = new GridData();
        data.verticalAlignment = GridData.FILL;
        data.horizontalAlignment = GridData.FILL;
        groupComponent.setLayoutData(data);

        Button addButton = new Button(groupComponent, SWT.PUSH);
        addButton.setText(JptJaxbUiMessages.SCHEMAS_PAGE_ADD_BUTTON_LABEL);
        addButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                addSchema();
            }
        });
        setButtonLayoutData(addButton);

        Button editButton = new Button(groupComponent, SWT.PUSH);
        editButton.setText(JptJaxbUiMessages.SCHEMAS_PAGE_EDIT_BUTTON_LABEL);
        editButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                editSelectedSchema();
            }
        });
        SWTBindTools.controlEnabledState(buildEditEnabledModel(), editButton);
        setButtonLayoutData(editButton);

        Button removeButton = new Button(groupComponent, SWT.PUSH);
        removeButton.setText(JptJaxbUiMessages.SCHEMAS_PAGE_REMOVE_BUTTON_LABEL);
        removeButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                removeSelectedSchemas();
            }
        });
        SWTBindTools.controlEnabledState(buildRemoveEnabledModel(), removeButton);
        setButtonLayoutData(removeButton);
    }

    private void addSchema() {
        // constructs a dialog for editing the new schema namespace and location
        AddEditSchemaDialog dialog = new AddEditSchemaDialog(getShell(), null, this.schemasModel.getAspectValue(),
                this.resourceManager);

        // opens the dialog - just returns if the user cancels it
        if (dialog.open() == Window.CANCEL) {
            return;
        }

        // otherwise, adds the new schema
        Schema schema = this.schemasModel.addSchema(dialog.getNamespace(), dialog.getLocation());

        // select the new schema
        this.schemasSelectionModel.setValues(new SingleElementIterable<Schema>(schema));
    }

    private PropertyValueModel<Boolean> buildEditEnabledModel() {
        return new CollectionPropertyValueModelAdapter<Boolean, Schema>(this.schemasSelectionModel) {
            @Override
            protected Boolean buildValue() {
                return Boolean.valueOf(this.collectionModel.size() == 1);
            }
        };
    }

    private void editSelectedSchema() {
        // constructs a dialog for editing the new schema namespace and location
        final Schema schema = this.schemasSelectionModel.iterator().next();
        AddEditSchemaDialog dialog = new AddEditSchemaDialog(getShell(), schema, this.schemasModel.getAspectValue(),
                this.resourceManager);

        // opens the dialog - just returns if the user cancels it
        if (dialog.open() == Window.CANCEL) {
            return;
        }

        // otherwise, changes the new schema
        schema.setNamespace(dialog.getNamespace());
        schema.setLocation(dialog.getLocation());
    }

    private PropertyValueModel<Boolean> buildRemoveEnabledModel() {
        return new CollectionPropertyValueModelAdapter<Boolean, Schema>(this.schemasSelectionModel) {
            @Override
            protected Boolean buildValue() {
                return Boolean.valueOf(this.collectionModel.size() >= 1);
            }
        };
    }

    private void removeSelectedSchemas() {
        this.schemasModel.removeSchemas(this.schemasSelectionModel);
    }

    private void updateButtons() {
        boolean enableApply = isValid();
        boolean enableRevert = true;

        Button applyButton = getApplyButton();

        if (applyButton != null) {
            applyButton.setEnabled(enableApply);
        }

        Button revertButton = getDefaultsButton();

        if (revertButton != null) {
            revertButton.setEnabled(enableRevert);
        }
    }

    // ********** OK/Revert/Apply behavior **********

    @Override
    public boolean performOk() {
        try {
            // true=fork; false=uncancellable
            this.buildOkProgressMonitorDialog().run(true, false, this.buildOkRunnableWithProgress());
        } catch (InterruptedException ex) {
            // should *not* happen...
            Thread.currentThread().interrupt();
            return false;
        } catch (InvocationTargetException ex) {
            throw new RuntimeException(ex.getTargetException());
        }

        return true;
    }

    private IRunnableContext buildOkProgressMonitorDialog() {
        return new ProgressMonitorDialog(this.getShell());
    }

    private IRunnableWithProgress buildOkRunnableWithProgress() {
        return new IRunnableWithProgress() {
            public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                IWorkspace ws = ResourcesPlugin.getWorkspace();
                try {
                    // the build we execute in #performOk_() locks the workspace root,
                    // so we need to use the workspace root as our scheduling rule here
                    ws.run(buildOkWorkspaceRunnable(), ws.getRoot(), IWorkspace.AVOID_UPDATE, monitor);
                } catch (CoreException ex) {
                    throw new InvocationTargetException(ex);
                }
            }
        };
    }

    /* private */ IWorkspaceRunnable buildOkWorkspaceRunnable() {
        return new IWorkspaceRunnable() {
            public void run(IProgressMonitor monitor) throws CoreException {
                performOk_(monitor);
            }
        };
    }

    void performOk_(IProgressMonitor monitor) throws CoreException {
        if (this.schemasModel.hasChanges()) {
            this.trigger.accept();
            JaxbProjectManager jaxbProjectManager = this.getJaxbProjectManager();
            if (jaxbProjectManager != null) {
                jaxbProjectManager.rebuildJaxbProject(getProject());
            }
            getProject().build(IncrementalProjectBuilder.FULL_BUILD, monitor);
        }
    }

    private JaxbProjectManager getJaxbProjectManager() {
        JaxbWorkspace jaxbWorkspace = this.getJaxbWorkspace();
        return (jaxbWorkspace == null) ? null : jaxbWorkspace.getJaxbProjectManager();
    }

    private JaxbWorkspace getJaxbWorkspace() {
        JaxbWorkbench jaxbWorkbench = this.getJaxbWorkbench();
        return (jaxbWorkbench == null) ? null : jaxbWorkbench.getJaxbWorkspace();
    }

    private JaxbWorkbench getJaxbWorkbench() {
        return WorkbenchTools.getAdapter(JaxbWorkbench.class);
    }

    @Override
    protected void performDefaults() {
        this.trigger.reset();
    }

    @Override
    public void dispose() {
        this.resourceManager.dispose();
        super.dispose();
    }

    static class SchemasModel extends AspectAdapter<JaxbProject, Collection<Schema>>
            implements CollectionValueModel<Schema> {

        /**
         * The collection of schemas
         */
        protected final Collection<Schema> schemas;

        /**
         * This is the trigger that indicates whether the buffered value
         * should be accepted or reset.
         */
        protected final PropertyValueModel<Boolean> triggerHolder;

        /** This listens to the trigger holder. */
        protected final PropertyChangeListener triggerChangeListener;

        SchemasModel(PropertyValueModel<JaxbProject> subjectHolder, PropertyValueModel<Boolean> triggerHolder) {
            super(subjectHolder);
            this.schemas = new ArrayList<Schema>();
            this.triggerHolder = triggerHolder;
            this.triggerChangeListener = buildTriggerChangeListener();
        }

        protected PropertyChangeListener buildTriggerChangeListener() {
            return new PropertyChangeListener() {
                public void propertyChanged(PropertyChangeEvent event) {
                    triggerChanged(event);
                }
            };
        }

        protected Collection<Schema> buildSchemas_() {
            ArrayList<Schema> schemas = new ArrayList<Schema>();
            for (SchemaEntry entry : this.subject.getSchemaLibrary().getSchemaEntries()) {
                schemas.add(new Schema(entry.getNamespace(), entry.getLocation()));
            }
            return schemas;
        }

        public boolean hasChanges() {
            return (this.subject == null) ? false : !this.schemas.equals(buildSchemas_());
        }

        protected void triggerChanged(PropertyChangeEvent event) {
            if (hasChanges()) {
                if (this.subject != null && ((Boolean) event.getNewValue()).booleanValue()) {
                    this.accept();
                } else {
                    this.reset();
                }
            }
        }

        public void accept() {
            List<String> schemaLocations = new Vector<String>();
            for (Schema schema : this.schemas) {
                schemaLocations.add(schema.getLocation());
            }
            this.subject.getSchemaLibrary().setSchemaLocations(schemaLocations);
        }

        public void reset() {
            this.schemas.clear();
            if (this.subject != null) {
                this.schemas.addAll(buildSchemas_());
            }
            fireCollectionChanged(VALUES, getAspectValue());
        }

        public Schema addSchema(String namespace, String location) {
            Schema schema = new Schema(namespace, location);
            addItemToCollection(schema, this.schemas, VALUES);
            return schema;
        }

        public void removeSchemas(Iterable<Schema> schemas) {
            removeItemsFromCollection(schemas, this.schemas, VALUES);
        }

        // ************ AspectAdapter impl ************************************

        @Override
        protected String getListenerAspectName() {
            return VALUES;
        }

        @Override
        protected Class<? extends EventListener> getListenerClass() {
            return CollectionChangeListener.class;
        }

        @Override
        protected boolean hasListeners() {
            return hasAnyCollectionChangeListeners(VALUES);
        }

        @Override
        protected void fireAspectChanged(Collection<Schema> oldValue, Collection<Schema> newValue) {
            this.synchronizeCollection(newValue, new ArrayList<Schema>(oldValue), VALUES);
        }

        @Override
        protected void engageSubject_() {
            this.schemas.addAll(buildSchemas_());
        }

        @Override
        protected void disengageSubject_() {
            this.schemas.clear();
        }

        @Override
        protected void engageModels() {
            super.engageModels();
            this.triggerHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.triggerChangeListener);
        }

        @Override
        protected void disengageModels() {
            this.triggerHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.triggerChangeListener);
            super.disengageModels();
        }

        @Override
        protected Collection<Schema> getAspectValue() {
            return CollectionTools.collection(iterator());
        }

        // ************ CollectionValueModel impl *****************************

        public Iterator<Schema> iterator() {
            return this.schemas.iterator();
        }

        public int size() {
            return this.schemas.size();
        }
    }

    static class Schema extends AbstractModel implements Comparable<Schema> {

        static String locationDisplayString(String location) {
            if (location == null) {
                return StringTools.EMPTY_STRING;
            }

            URI uri = URI.createURI(location);
            if (uri.isPlatformResource()) {
                return uri.toPlatformString(false);
            }

            return location;
        }

        static String namespaceDisplayString(String namespace) {
            if (null == namespace || StringTools.EMPTY_STRING.equals(namespace)) {
                return JptJaxbUiMessages.SCHEMAS_PAGE_NO_NAMESPACE_TEXT;
            }

            return namespace;
        }

        Schema(String namespace, String location) {
            super();
            this.namespace = namespace;
            this.location = location;
        }

        private String namespace;
        final static String NAMESPACE_PROPERTY = "namespace"; //$NON-NLS-1$

        private String location;
        final static String LOCATION_PROPERTY = "location"; //$NON-NLS-1$

        String getNamespace() {
            return this.namespace;
        }

        void setNamespace(String namespace) {
            String old = this.namespace;
            this.namespace = namespace;
            firePropertyChanged(NAMESPACE_PROPERTY, old, namespace);
        }

        String namespaceDisplayString() {
            return namespaceDisplayString(this.namespace);
        }

        String getLocation() {
            return this.location;
        }

        String locationDisplayString() {
            return locationDisplayString(getLocation());
        }

        void setLocation(String location) {
            String old = this.location;
            this.location = location;
            firePropertyChanged(LOCATION_PROPERTY, old, location);
        }

        public int compareTo(Schema o) {
            return this.namespaceDisplayString().compareTo(o.namespaceDisplayString());
        }
    }

    static class SchemaColumnAdapter implements ColumnAdapter<Schema> {

        static final int COLUMN_COUNT = 2;
        static final int NAMESPACE_COLUMN = 0;
        static final int LOCATION_COLUMN = 1;

        public int columnCount() {
            return COLUMN_COUNT;
        }

        public String columnName(int columnIndex) {
            switch (columnIndex) {
            case NAMESPACE_COLUMN:
                return JptJaxbUiMessages.SCHEMAS_PAGE_NAMESPACE_COLUMN_LABEL;
            case LOCATION_COLUMN:
                return JptJaxbUiMessages.SCHEMAS_PAGE_LOCATION_COLUMN_LABEL;
            default:
                return null;
            }
        }

        public ModifiablePropertyValueModel<?>[] cellModels(Schema subject) {
            ModifiablePropertyValueModel<?>[] cellModels = new ModifiablePropertyValueModel<?>[COLUMN_COUNT];
            cellModels[NAMESPACE_COLUMN] = buildNamespaceCellModel(subject);
            cellModels[LOCATION_COLUMN] = buildLocationCellModel(subject);
            return cellModels;
        }

        private ModifiablePropertyValueModel<String> buildNamespaceCellModel(Schema subject) {
            return new PropertyAspectAdapter<Schema, String>(Schema.NAMESPACE_PROPERTY, subject) {
                @Override
                protected String buildValue_() {
                    return this.subject.getNamespace();
                }
            };
        }

        private ModifiablePropertyValueModel<String> buildLocationCellModel(Schema subject) {
            return new PropertyAspectAdapter<Schema, String>(Schema.LOCATION_PROPERTY, subject) {
                @Override
                protected String buildValue_() {
                    return this.subject.getLocation();
                }
            };
        }
    }

    static class SchemaTableLabelProvider extends LabelProvider implements ITableLabelProvider {

        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }

        public String getColumnText(Object element, int columnIndex) {
            switch (columnIndex) {
            case SchemaColumnAdapter.NAMESPACE_COLUMN:
                return ((Schema) element).namespaceDisplayString();
            case SchemaColumnAdapter.LOCATION_COLUMN:
                return ((Schema) element).locationDisplayString();
            default:
                return null;
            }
        }
    }

    static class AddEditSchemaDialog extends TitleAreaDialog {

        private final ResourceManager resourceManager;

        private final Schema currentSchema;

        private String defaultMessage;

        private final ModifiablePropertyValueModel<String> location;

        private final ModifiablePropertyValueModel<String> namespace;

        private XSDSchema resolvedSchema;

        private final Mode mode;

        private final Iterable<Schema> allSchemas;

        public AddEditSchemaDialog(Shell shell, Schema currentSchema, Iterable<Schema> allSchemas,
                ResourceManager resourceManager) {
            super(shell);
            this.resourceManager = resourceManager;
            this.currentSchema = currentSchema;
            this.allSchemas = allSchemas;
            this.location = new SimplePropertyValueModel<String>();
            this.namespace = new SimplePropertyValueModel<String>();

            this.mode = (this.currentSchema == null) ? Mode.ADD : Mode.EDIT;
            if (this.mode == Mode.ADD) {
                this.defaultMessage = JptJaxbUiMessages.SCHEMAS_PAGE_ADD_SCHEMA_MESSAGE;
                this.location.setValue(null);
                this.namespace.setValue(null);
            } else {
                this.defaultMessage = JptJaxbUiMessages.SCHEMAS_PAGE_EDIT_SCHEMA_MESSAGE;
                this.location.setValue(currentSchema.getLocation());
                this.namespace.setValue(currentSchema.getNamespace());
            }
        }

        @Override
        protected void configureShell(Shell newShell) {
            super.configureShell(newShell);
            if (this.mode == Mode.ADD) {
                newShell.setText(JptJaxbUiMessages.SCHEMAS_PAGE_ADD_SCHEMA_DIALOG_TITLE);
            } else {
                newShell.setText(JptJaxbUiMessages.SCHEMAS_PAGE_EDIT_SCHEMA_DIALOG_TITLE);
            }
        }

        @Override
        protected Control createDialogArea(Composite parent) {
            Composite dialogArea = (Composite) super.createDialogArea(parent);

            setMessage(this.defaultMessage);
            if (this.mode == Mode.ADD) {
                setTitle(JptJaxbUiMessages.SCHEMAS_PAGE_ADD_SCHEMA_TITLE);
            } else {
                setTitle(JptJaxbUiMessages.SCHEMAS_PAGE_EDIT_SCHEMA_TITLE);
            }

            Composite composite = new Composite(dialogArea, SWT.NONE);
            composite.setLayout(new GridLayout(3, false));
            composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

            Label locationLabel = new Label(composite, SWT.NULL);
            locationLabel.setText(JptJaxbUiMessages.SCHEMAS_PAGE_LOCATION_LABEL);
            locationLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));

            final Text locationText = new Text(composite, SWT.SINGLE | SWT.BORDER);
            locationText.setText(locationDisplayString());
            locationText.setEditable(false);
            locationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
            this.location.addPropertyChangeListener(PropertyValueModel.VALUE, new PropertyChangeListener() {
                public void propertyChanged(PropertyChangeEvent event) {
                    locationText.setText(locationDisplayString());
                }
            });

            Button browseButton = new Button(composite, SWT.PUSH);
            browseButton.setText(JptJaxbUiMessages.SCHEMAS_PAGE_BROWSE_BUTTON_LABEL);
            browseButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, true, 1, 1));
            browseButton.addSelectionListener(new SelectionListener() {
                public void widgetSelected(SelectionEvent e) {
                    browseForSchemaLocation();
                }

                public void widgetDefaultSelected(SelectionEvent e) {
                    widgetSelected(e);
                }
            });

            Label namespaceLabel = new Label(composite, SWT.NULL);
            namespaceLabel.setText(JptJaxbUiMessages.SCHEMAS_PAGE_NAMESPACE_LABEL);
            namespaceLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));

            final Text namespaceText = new Text(composite, SWT.SINGLE | SWT.BORDER);
            namespaceText.setText(namespaceDisplayString());
            namespaceText.setEditable(false);
            namespaceText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
            this.namespace.addPropertyChangeListener(PropertyValueModel.VALUE, new PropertyChangeListener() {
                public void propertyChanged(PropertyChangeEvent event) {
                    namespaceText.setText(namespaceDisplayString());
                }
            });

            Dialog.applyDialogFont(dialogArea);

            return dialogArea;
        }

        @Override
        public void create() {
            super.create();

            // disable ok button until user does something and then validation takes over
            getButton(IDialogConstants.OK_ID).setEnabled(false);
        }

        @Override
        protected boolean isResizable() {
            return true;
        }

        private void browseForSchemaLocation() {
            SchemaLocationDialog dialog = new SchemaLocationDialog(getShell(), this.resourceManager);

            // opens the dialog - just returns if the user cancels it
            if (dialog.open() == Window.CANCEL) {
                return;
            }

            String location = dialog.getLocation();
            this.location.setValue(location);

            String resolvedUri = XsdUtil.getResolvedUri(location);

            XSDSchema schema = XSDImpl.buildXSDModel(resolvedUri);
            String newNamespace = (schema == null) ? null
                    : ((schema.getTargetNamespace()) == null ? StringTools.EMPTY_STRING
                            : schema.getTargetNamespace());
            this.namespace.setValue(newNamespace);
            this.resolvedSchema = schema;

            validate();
        }

        public String getNamespace() {
            return this.namespace.getValue();
        }

        protected String namespaceDisplayString() {
            return Schema.namespaceDisplayString(getNamespace());
        }

        public String getLocation() {
            return this.location.getValue();
        }

        protected String locationDisplayString() {
            return Schema.locationDisplayString(getLocation());
        }

        private void validate() {
            if (this.resolvedSchema == null) {
                setErrorMessage(JptJaxbUiMessages.SCHEMAS_PAGE_SCHEMA_UNRESOLVED_MESSAGE);
            } else if (isDuplicateNamespace()) {
                setErrorMessage(JptJaxbUiMessages.SCHEMAS_PAGE_DUPLICATE_NAMESPACE_MESSAGE);
            } else if (StringTools.isBlank(this.location.getValue())) {
                setErrorMessage(JptJaxbUiMessages.SCHEMAS_PAGE_NO_LOCATION_MESSAGE);
            } else {
                setErrorMessage(null);
                setMessage(this.defaultMessage);
            }
            getButton(IDialogConstants.OK_ID).setEnabled(getErrorMessage() == null);
        }

        private boolean isDuplicateNamespace() {
            for (Schema schema : this.allSchemas) {
                if ((this.currentSchema != schema) && getNamespace().equals(schema.getNamespace())) {
                    return true;
                }
            }
            return false;
        }

        private enum Mode {
            ADD, EDIT
        }
    }

    static class SchemaLocationDialog extends TrayDialog {

        private final ResourceManager resourceManager;

        private SelectFileOrXMLCatalogIdPanel locationPanel;

        private String location;

        public SchemaLocationDialog(Shell shell, ResourceManager resourceManager) {
            super(shell);
            this.resourceManager = resourceManager;
        }

        @Override
        protected void configureShell(Shell newShell) {
            super.configureShell(newShell);
            newShell.setText(JptJaxbUiMessages.SCHEMAS_PAGE_CHOOSE_LOCATION_TITLE);
        }

        @Override
        protected Control createDialogArea(Composite parent) {
            Composite composite = (Composite) super.createDialogArea(parent);

            this.locationPanel = new SelectFileOrXMLCatalogIdPanel(composite, StructuredSelection.EMPTY,
                    this.resourceManager);
            this.locationPanel.setFilterExtensions(new String[] { ".xsd" }); //$NON-NLS-1$
            this.locationPanel.update();
            this.locationPanel.setVisibleHelper(true);

            return composite;
        }

        @Override
        protected boolean isResizable() {
            return true;
        }

        @Override
        protected void okPressed() {
            IFile file = this.locationPanel.getFile();
            if (file != null) {
                this.location = URI.createPlatformResourceURI(file.getFullPath().toString(), false).toString();
            } else {
                this.location = this.locationPanel.getXMLCatalogId();
            }

            super.okPressed();
        }

        public String getLocation() {
            return this.location;
        }
    }
}