ac.soton.fmusim.components.ui.dialogs.EventBPortDialog.java Source code

Java tutorial

Introduction

Here is the source code for ac.soton.fmusim.components.ui.dialogs.EventBPortDialog.java

Source

/**
 * Copyright (c) 2013 University of Southampton.
 * 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
 */
package ac.soton.fmusim.components.ui.dialogs;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
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.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.ui.dialogs.SelectionDialog;
import org.eventb.emf.core.machine.Parameter;
import org.eventb.emf.core.machine.Variable;

import ac.soton.fmusim.components.ComponentsFactory;
import ac.soton.fmusim.components.EventBComponent;
import ac.soton.fmusim.components.EventBPort;
import ac.soton.fmusim.components.Port;
import ac.soton.fmusim.components.VariableCausality;
import ac.soton.fmusim.components.VariableType;

/**
 * New EventB port creation dialog.
 * Allows to specify the name and type of the new port,
 * as well as a parameter for provided read/write event.
 * Also provides the basic name validation based on the source
 * component: disallows empty name or the existing port name.
 * 
 * @author vitaly
 *
 */
public class EventBPortDialog extends SelectionDialog {

    private Combo typeCombo;
    private Combo variableCombo;
    private Combo parameterCombo;
    private Spinner precisionSpinner;
    private Set<String> usedNames;
    private Map<String, Variable> variableMap;
    private Map<String, Parameter> parameterMap;
    private DecoratedInputValidator variableValidator;
    private DecoratedInputValidator parameterValidator;
    private boolean variableValid;
    private boolean parameterValid;
    private EventBPort port;
    private VariableCausality causality;

    /**
     * Creates a new Event-B port dialog.
     * 
     * @param parentShell
     * @param component target component of the new port
     * @param causality port variable causality
     * @param event IO event (only for reading input ports, so not required if causality is other that INPUT)
     */
    public EventBPortDialog(Shell parentShell, EventBComponent component, VariableCausality causality,
            List<Variable> variables, List<Parameter> parameters) {
        super(parentShell);

        // build up a set of existing names
        if (component != null) {
            usedNames = new HashSet<String>(component.getInputs().size() + component.getOutputs().size());
            for (Port p : component.getInputs())
                usedNames.add(p.getName());
            for (Port p : component.getOutputs())
                usedNames.add(p.getName());

            this.causality = causality;

            if (variables != null) {
                variableMap = new HashMap<String, Variable>(variables.size());
                for (Variable variable : variables) {
                    variableMap.put(variable.getName(), variable);
                }
            }

            if (parameters != null) {
                parameterMap = new HashMap<String, Parameter>(parameters.size());
                for (Parameter parameter : parameters) {
                    parameterMap.put(parameter.getName(), parameter);
                }
            }
        }
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
     */
    @Override
    protected void configureShell(Shell newShell) {
        super.configureShell(newShell);
        newShell.setText("New Event-B Port");
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected Control createDialogArea(Composite parent) {
        Composite composite = (Composite) super.createDialogArea(parent);
        composite.setLayout(new GridLayout());

        Group plate = new Group(composite, SWT.NONE);
        GridLayout layout = new GridLayout(2, false);
        plate.setLayout(layout);
        plate.setText("Event-B port attributes");

        // variable label and combo
        if (variableMap != null) {
            variableCombo = createCombo(plate, "Variable:", variableMap, new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    validateVariable();
                }
            });
            variableCombo.setToolTipText("Select a machine variable that represents an output signal");
        }

        // event parameter combo
        if (parameterMap != null) {
            parameterCombo = createCombo(plate, "Parameter:", parameterMap, new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    validateParameter();
                }
            });
            parameterCombo.setToolTipText("Select a read event parameter that respresents an input signal");
        }

        // type label and combo
        Label typeLabel = new Label(plate, SWT.NONE);
        typeLabel.setText("Type:");
        typeCombo = new Combo(plate, SWT.DROP_DOWN | SWT.READ_ONLY);
        typeCombo.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
        typeCombo.setToolTipText("Select a type of the signal");
        typeCombo.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                validateType();
            }
        });
        {
            assert VariableType.VALUES.size() > 0;
            String[] items = new String[VariableType.VALUES.size()];
            for (int i = 0; i < VariableType.VALUES.size(); i++) {
                items[i] = VariableType.VALUES.get(i).getName();
            }
            typeCombo.setItems(items);
            typeCombo.select(0);
        }

        // int to real precision spinner/label
        Label precisionLabel = new Label(plate, SWT.NONE);
        precisionLabel.setText("Precision:");
        precisionSpinner = new Spinner(plate, SWT.BORDER);
        precisionSpinner.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
        precisionSpinner
                .setToolTipText("Set a multiplier for converting FMI Real type to Event-B Integer and back");
        precisionSpinner.setMinimum(0);
        precisionSpinner.setMaximum(10);
        precisionSpinner.setSelection(0);
        precisionSpinner.setIncrement(1);

        // validators & initial validation
        createValidators();
        parameterValid = parameterMap == null;
        variableValid = variableMap == null;

        plate.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        return composite;
    }

    /**
     * Creates input validators.
     */
    private void createValidators() {
        if (variableMap != null) {
            variableValidator = new DecoratedInputValidator(DecoratedInputValidator.createDecorator(variableCombo,
                    "Please select variable", FieldDecorationRegistry.DEC_ERROR, false)) {
                @Override
                public String isValidInput(String variable) {
                    if (variable == null || variable.isEmpty())
                        return "Variable cannot be empty";
                    if (usedNames != null && usedNames.contains(variable.trim()))
                        return "Port for this variable already exists";
                    return null;
                }
            };
        }

        if (parameterMap != null) {
            parameterValidator = new DecoratedInputValidator(DecoratedInputValidator.createDecorator(parameterCombo,
                    "Please select event parameter", FieldDecorationRegistry.DEC_ERROR, false)) {
                @Override
                public String isValidInput(String parameter) {
                    if (parameter == null || parameter.isEmpty())
                        return "Parameter cannot be empty";
                    if (usedNames != null && usedNames.contains(parameter.trim()))
                        return "Port for this parameter already exists";
                    return null;
                }
            };
        }
    }

    /**
     * Creates and returns a combo.
     * 
     * @param parent parent
     * @param label label of the combo
     * @param map map of elements to populate combo
     * @param listener combo selection listener
     * @return
     */
    private Combo createCombo(Composite parent, String label, Map<String, ? extends Object> map,
            SelectionListener listener) {
        Label variableLabel = new Label(parent, SWT.NONE);
        variableLabel.setText(label);
        Combo combo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY);
        combo.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
        combo.addSelectionListener(listener);
        {
            String[] items = new String[map.size() + 1];
            int i = 0;
            items[i++] = ""; // empty item
            for (String name : map.keySet())
                items[i++] = name;
            Arrays.sort(items);
            combo.setItems(items);
        }
        return combo;
    }

    @Override
    protected Control createContents(Composite parent) {
        Control contents = super.createContents(parent);
        // only here the buttons are available, so that's where OK can be disabled for initial state
        update();
        return contents;
    }

    /**
     * Validates type.
     */
    protected void validateType() {
        precisionSpinner.setEnabled(VariableType.REAL.getName().equals(typeCombo.getText()));
    }

    /**
     * Validates variable.
     */
    protected void validateVariable() {
        if (variableValidator != null) {
            variableValid = variableValidator.isValid(variableCombo.getText()) == null;
        } else {
            variableValid = true;
        }
        update();
    }

    /**
     * Validates parameter.
     */
    protected void validateParameter() {
        if (parameterValidator != null) {
            parameterValid = parameterValidator.isValid(parameterCombo.getText()) == null;
        } else {
            parameterValid = true;
        }
        update();
    }

    /**
     * Updates the buttons based on validation.
     */
    private void update() {
        boolean valid = true;
        Control button = getButton(IDialogConstants.OK_ID);
        if (button != null) {
            valid &= variableValid;
            valid &= parameterValid;
            button.setEnabled(valid);
        }
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.dialogs.Dialog#okPressed()
     */
    @Override
    protected void okPressed() {
        String typeStr = typeCombo.getItem(typeCombo.getSelectionIndex());

        port = ComponentsFactory.eINSTANCE.createEventBPort();
        port.setType(VariableType.getByName(typeStr));
        port.setCausality(causality);
        port.setRealPrecision(precisionSpinner.getSelection());

        // set variable if defined
        if (variableMap != null) {
            if (variableCombo.getSelectionIndex() > 0) {
                String variableStr = variableCombo.getItem(variableCombo.getSelectionIndex());
                port.setVariable(variableMap.get(variableStr));
            }
        }

        // set parameter if defined
        if (parameterMap != null) {
            if (parameterCombo.getSelectionIndex() > 0) {
                String parameterStr = parameterCombo.getItem(parameterCombo.getSelectionIndex());
                port.setParameter(parameterMap.get(parameterStr));
            }
        }

        // either variable or port has to be present
        assert port.getVariable() != null || port.getParameter() != null;
        if (port.getVariable() != null) {
            port.setName(port.getVariable().getName());
        } else {
            port.setName(port.getParameter().getName());
        }

        super.okPressed();
    }

    /**
     * Returns created EventB port, or null if the dialog was cancelled.
     * 
     * @return the port
     */
    public EventBPort getPort() {
        return port;
    }

    @Override
    public Object[] getResult() {
        return Collections.singleton(getPort()).toArray();
    }

}