view com.redhat.thermostat.tools.eclipse.plugin/src/com/redhat/thermostat/tools/eclipse/plugin/editor/OptionsWizard.java @ 112:4d5e3d32d681

Add validation to Options UI The wizard itself is still not connected to the validation system since that breaks when the master list is empty.
author Omair Majid <omajid@redhat.com>
date Fri, 28 Feb 2014 12:06:10 -0500
parents fde496a78a98
children d79c9d0a308d
line wrap: on
line source

package com.redhat.thermostat.tools.eclipse.plugin.editor;

import java.util.Objects;

import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.core.databinding.observable.list.IListChangeListener;
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.jface.databinding.viewers.IViewerObservableValue;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider;
import org.eclipse.jface.databinding.viewers.ViewerProperties;
import org.eclipse.jface.databinding.wizard.WizardPageSupport;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Text;

import com.redhat.thermostat.tools.eclipse.plugin.Messages;
import com.redhat.thermostat.tools.eclipse.plugin.model.Command;
import com.redhat.thermostat.tools.eclipse.plugin.model.Option;
import com.redhat.thermostat.tools.eclipse.plugin.model.Options;

/**
 * A {@link Wizard} for editing the command line options for a command.
 * <p>
 * The wizard allows adding/editing and removing options.
 */
public class OptionsWizard extends Wizard {

    private Command commandModel;
    private Options myOptions;

    public OptionsWizard(Command commandModel) {
        setNeedsProgressMonitor(true);

        this.commandModel = commandModel;

        if (commandModel.getOptions() != null) {
            myOptions = new Options(commandModel.getOptions());
        } else {
            myOptions = new Options();
        }
    }

    @Override
    public void addPages() {
        addPage(new CreateOptionsPage());
    }

    @Override
    public boolean performFinish() {
        commandModel.setOptions(myOptions);

        return true;
    }

    class CreateOptionsPage extends WizardPage {

        private DataBindingContext dataBindingContext;
        private ListViewer optionsListViewer;
        private Text longName;
        private Text shortName;
        private Text description;
        private Text argument;
        private Button required;
        private WritableList allOptions;
        private Button add;
        private Button remove;

        public CreateOptionsPage() {
            super("Create Options"); //$NON-NLS-1$
            setTitle(Messages.OptionsWizard_createOptionsPageTitle);
            setDescription(Messages.OptionsWizard_createOptionsPageDescription);
        }

        @Override
        public void createControl(Composite parent) {
            Composite container = new Composite(parent, SWT.NONE);
            container.setLayout(new GridLayout(2, false));

            createMasterArea(container);
            createDetailsArea(container);

            initDataBindings();

            createWidgetEnableDisableListeners();

            setControl(container);
        }

        private void createMasterArea(Composite parent) {
            Composite masterList = new Composite(parent, SWT.NONE);
            masterList.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, false, true));

            masterList.setLayout(new GridLayout(2, false));

            List optionsList = new List(masterList, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
            GridData listLayoutData = new GridData(SWT.BEGINNING, SWT.FILL, true, true);
            listLayoutData.widthHint = 150;
            optionsList.setLayoutData(listLayoutData);

            optionsListViewer = new ListViewer(optionsList);

            Composite buttonsComposite = new Composite(masterList, SWT.NONE);
            buttonsComposite.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, true));

            buttonsComposite.setLayout(new GridLayout(1, false));

            add = new Button(buttonsComposite, SWT.PUSH);
            add.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
            add.setText(Messages.OptionsWizard_createOptionsPageAddOption);
            add.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    Option option = new Option();
                    allOptions.add(option);
                    optionsListViewer.setSelection(new StructuredSelection(option), true);
                }
            });

            remove = new Button(buttonsComposite, SWT.PUSH);
            remove.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
            remove.setText(Messages.OptionsWizard_createOptionsPageRemoveOption);
            remove.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    IStructuredSelection selection = (IStructuredSelection) optionsListViewer.getSelection();
                    Option selectedOption = (Option) Objects.requireNonNull(selection.getFirstElement());
                    allOptions.remove(selectedOption);
                }
            });
        }

        private void createDetailsArea(Composite parent) {
            Composite details = new Composite(parent, SWT.NONE);
            details.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

            details.setLayout(new GridLayout(2, false));

            Label longNameLabel = new Label(details, SWT.NONE);
            longNameLabel.setLayoutData(new GridData(SWT.END, SWT.BEGINNING, false, false));
            longNameLabel.setText(Messages.OptionsWizard_createOptionsPageLongNameLabel);
            longName = new Text(details, SWT.NONE);
            longName.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

            Label shortNameLabel = new Label(details, SWT.NONE);
            shortNameLabel.setLayoutData(new GridData(SWT.END, SWT.BEGINNING, false, false));
            shortNameLabel.setText(Messages.OptionsWizard_createOptionsPageShortNameLabel);
            shortName = new Text(details, SWT.NONE);
            shortName.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

            Label descriptionLabel = new Label(details, SWT.NONE);
            descriptionLabel.setLayoutData(new GridData(SWT.END, SWT.BEGINNING, false, false));
            descriptionLabel.setText(Messages.OptionsWizard_createOptionsPageDescriptionLabel);
            description = new Text(details, SWT.NONE);
            description.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

            Label argumentLabel = new Label(details, SWT.NONE);
            argumentLabel.setLayoutData(new GridData(SWT.END, SWT.BEGINNING, false, false));
            argumentLabel.setText(Messages.OptionsWizard_createOptionsPageArgumentLabel);
            argument = new Text(details, SWT.NONE);
            argument.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

            Label requiredLabel = new Label(details, SWT.NONE);
            requiredLabel.setLayoutData(new GridData(SWT.END, SWT.BEGINNING, false, false));
            requiredLabel.setText(Messages.OptionsWizard_createOptionsPageRequiredLabel);
            required = new Button(details, SWT.CHECK);
            required.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
        }

        private void initDataBindings() {
            dataBindingContext = new DataBindingContext();

            ObservableListContentProvider contentProvider = new ObservableListContentProvider();
            optionsListViewer.setContentProvider(contentProvider);
            IObservableSet knownElements = contentProvider.getKnownElements();
            IObservableMap longNames = BeanProperties.value(Option.class, "longName", String.class).observeDetail(knownElements); //$NON-NLS-1$
            IObservableMap shortNames = BeanProperties.value(Option.class, "shortName", String.class).observeDetail(knownElements); //$NON-NLS-1$

            IObservableMap[] attributeMaps = new IObservableMap[] { longNames, shortNames };
            optionsListViewer.setLabelProvider(new OptionLabelProvider(attributeMaps));

            allOptions = new WritableList(myOptions.getOptions(), Option.class);
            optionsListViewer.setInput(allOptions);

            IViewerObservableValue selectedOption = ViewerProperties.singleSelection().observe(optionsListViewer);

            IObservableValue longNameWidgetValue = WidgetProperties.text(SWT.Modify).observe(longName);
            IObservableValue longNameModelValue = BeanProperties.value(Option.class, "longName").observeDetail(selectedOption); //$NON-NLS-1$
            UpdateValueStrategy longNameWidgetToModelUpdate = new UpdateValueStrategy();
            longNameWidgetToModelUpdate.setBeforeSetValidator(new Validators.NonEmptyStringRequired("Long name can not be empty"));
            Binding longNameBinding = dataBindingContext.bindValue(longNameWidgetValue, longNameModelValue, longNameWidgetToModelUpdate, null);
            ControlDecorationSupport.create(longNameBinding, SWT.TOP | SWT.LEFT);

            IObservableValue shortNameWidgetValue = WidgetProperties.text(SWT.Modify).observe(shortName);
            IObservableValue shortNameModelValue = BeanProperties.value(Option.class, "shortName").observeDetail(selectedOption); //$NON-NLS-1$
            UpdateValueStrategy shortNameWidgetToModelUpdate = new UpdateValueStrategy();
            shortNameWidgetToModelUpdate.setConverter(new Converters.EmptyStringToNullConverter());
            dataBindingContext.bindValue(shortNameWidgetValue, shortNameModelValue,shortNameWidgetToModelUpdate, null);

            IObservableValue descriptionWidgetValue = WidgetProperties.text(SWT.Modify).observe(description);
            IObservableValue descriptionModelValue = BeanProperties.value(Option.class, "description").observeDetail(selectedOption); //$NON-NLS-1$
            UpdateValueStrategy descriptionWidgetToModelUpdate = new UpdateValueStrategy();
            descriptionWidgetToModelUpdate.setBeforeSetValidator(new Validators.NonEmptyStringRequired("Description can not be empty"));
            Binding descriptionBinding = dataBindingContext.bindValue(descriptionWidgetValue, descriptionModelValue, descriptionWidgetToModelUpdate, null);
            ControlDecorationSupport.create(descriptionBinding, SWT.TOP | SWT.LEFT);

            IObservableValue argumentWidgetValue = WidgetProperties.text(SWT.Modify).observe(argument);
            IObservableValue argumentModelValue = BeanProperties.value(Option.class, "argument").observeDetail(selectedOption); //$NON-NLS-1$
            dataBindingContext.bindValue(argumentWidgetValue, argumentModelValue);

            IObservableValue requiredWidgetValue = WidgetProperties.selection().observe(required);
            IObservableValue requiredModelValue = BeanProperties.value(Option.class, "required").observeDetail(selectedOption); //$NON-NLS-1$
            dataBindingContext.bindValue(requiredWidgetValue, requiredModelValue);

            // FIXME enable this after identifying how to deal with null? master data
            // WizardPageSupport.create(this, dataBindingContext);
        }

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

            dataBindingContext.dispose();
        }

        private void createWidgetEnableDisableListeners() {
            IListChangeListener enableDisableRemoveButton = new IListChangeListener() {
                @Override
                public void handleListChange(ListChangeEvent event) {
                    int size = event.getObservableList().size();
                    if (size == 0) {
                        remove.setEnabled(false);
                    } else {
                        remove.setEnabled(true);
                    }
                }
            };
            allOptions.addListChangeListener(enableDisableRemoveButton);
            // invoke manually during initialization to set initial state
            enableDisableRemoveButton.handleListChange(new ListChangeEvent(allOptions, null));

            IListChangeListener enableDisableDataWidgets = new IListChangeListener() {
                @Override
                public void handleListChange(ListChangeEvent event) {
                    int size = event.getObservableList().size();
                    boolean toEnable = true;
                    if (size == 0) {
                        toEnable = false;
                    } else {
                        toEnable = true;
                    }
                    longName.setEnabled(toEnable);
                    shortName.setEnabled(toEnable);
                    description.setEnabled(toEnable);
                    argument.setEnabled(toEnable);
                    required.setEnabled(toEnable);

                }
            };
            allOptions.addListChangeListener(enableDisableDataWidgets);
            // invoke manually during initialization to set initial state
            enableDisableDataWidgets.handleListChange(new ListChangeEvent(allOptions, null));

        }
    }

    // TODO implement a page to organize options into (exclusive) option groups
    class GroupOptionsPage extends WizardPage {

        public GroupOptionsPage() {
            super("Group Options Page"); //$NON-NLS-1$
        }

        @Override
        public void createControl(Composite parent) {
            // TODO Auto-generated method stub
        }

    }

    private static class OptionLabelProvider extends ObservableMapLabelProvider{
        public OptionLabelProvider(IObservableMap[] attributeMaps) {
            super(attributeMaps);
        }

        @Override
        public String getText(Object element) {
            Objects.requireNonNull(element);
            Option option = (Option) element;

            String longOption = null;
            String longName = option.getLongName();
            if (longName != null && !longName.isEmpty()) {
                longOption = "--" + longName; //$NON-NLS-N$
            }

            String shortOption = null;
            String shortName = option.getShortName();
            if (shortName != null && !shortName.isEmpty()) {
                shortOption = "-" + shortName; //$NON-NLS-N$
            }

            String result = null;

            // FIXME does this need to be internationalized?
            if (longOption != null && shortOption != null) {
                result = longOption + ", " + shortOption;
            } else if (longOption != null) {
                result = longOption;
            } else if (shortOption != null) {
                result = shortOption;
            } else {
                result = "[unknown]";
            }

            return result;
        }
    }
}