uk.ac.stfc.isis.ibex.ui.configserver.dialogs.SaveConfigDialog.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.stfc.isis.ibex.ui.configserver.dialogs.SaveConfigDialog.java

Source

/*
* This file is part of the ISIS IBEX application.
* Copyright (C) 2012-2015 Science & Technology Facilities Council.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution.
* EXCEPT AS EXPRESSLY SET FORTH IN THE ECLIPSE PUBLIC LICENSE V1.0, THE PROGRAM 
* AND ACCOMPANYING MATERIALS ARE PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES 
* OR CONDITIONS OF ANY KIND.  See the Eclipse Public License v1.0 for more details.
*
* You should have received a copy of the Eclipse Public License v1.0
* along with this program; if not, you can obtain a copy from
* https://www.eclipse.org/org/documents/epl-v10.php or 
* http://opensource.org/licenses/eclipse-1.0.php
*/

package uk.ac.stfc.isis.ibex.ui.configserver.dialogs;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.swt.SWT;
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.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.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;

import uk.ac.stfc.isis.ibex.configserver.Configurations;
import uk.ac.stfc.isis.ibex.validators.BlockServerNameValidator;
import uk.ac.stfc.isis.ibex.validators.SummaryDescriptionValidator;

/**
 * Dialogue for saving a configuration.
 */
@SuppressWarnings("checkstyle:magicnumber")
public class SaveConfigDialog extends TitleAreaDialog {

    /**
     * The text to use when referring to a component.
     */
    private static final String COMPONENT = "Component";

    /**
     * The test to use when referring to a configuration.
     */
    private static final String CONFIGURATION = "Configuration";

    /**
     * Container for the name label.
     */
    private Text txtName;

    /**
     * Container for the description label.
     */
    private Text txtDesc;

    /**
     * Button to save the new object. as a component.
     */
    private Button btnAsComponent;

    /**
     * Name of the new object.
     */
    private String newName = "";

    /**
     * Name of the new object as it currently exists in the text box.
     */
    private String currentName = "";

    /**
     * Description of the new object.
     */
    private String newDesc = "";

    /**
     * Description of the new object as it currently exists in the text box.
     */
    private String currentDesc = "";

    /**
     * Collection of existing configurations.
     */
    private List<String> existingConfigs;

    /**
     * Collection of existing components.
     */
    private List<String> existingComponents;

    /**
     * Is the new object a configuration (or component).
     */
    private boolean isConfig;

    /**
     * Does the new object have components.
     */
    private boolean hasComponents;

    /**
     * Should the new object be saved as a component.
     */
    private boolean asComponent = false;

    /**
     * The name of the current configuration.
     */
    private final String currentConfigName;

    /**
     * Instantiates a new save configuration dialog.
     *
     * @param parent
     *            the parent
     * @param currentName
     *            the original name of the config if editing an existing one,
     *            otherwise blank
     * @param currentDesc
     *            the original description of the config if editing an existing
     *            one, otherwise blank
     * @param existingConfigs
     *            the existing configuration names (so not to duplicate)
     * @param existingComponents
     *            the existing component names (so not to duplicate)
     * @param isConfig
     *            current configuration
     * @param hasComponents
     *            true if this configuration has components; false otherwise
     * @param currentConfigName
     *            The name of the current configuration
     */
    public SaveConfigDialog(Shell parent, String currentName, String currentDesc,
            Collection<String> existingConfigs, Collection<String> existingComponents, boolean isConfig,
            boolean hasComponents, String currentConfigName) {
        super(parent);
        setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
        this.currentName = currentName;
        this.currentDesc = currentDesc;
        this.existingConfigs = new ArrayList<>(existingConfigs);
        this.existingComponents = new ArrayList<>(existingComponents);
        this.isConfig = isConfig;
        this.hasComponents = hasComponents;
        this.currentConfigName = currentConfigName;
    }

    /**
     * @return the new name set in this dialogue
     */
    public String getNewName() {
        return newName;
    }

    /**
     * @return the new description set
     */
    public String getNewDescription() {
        return newDesc;
    }

    /**
     * @return true, if when saved this will be a component; false otherwise
     */
    public boolean willBeComponent() {
        return !isConfig || asComponent;
    }

    @Override
    protected void configureShell(Shell shell) {
        super.configureShell(shell);
        shell.setText(String.format("Save %s As", getTypeName()));
    }

    @Override
    protected Control createDialogArea(Composite parent) {
        setTitle(String.format("Save %s", getTypeName()));
        Composite container = (Composite) super.createDialogArea(parent);
        GridLayout glContainer = new GridLayout(1, false);
        container.setLayout(glContainer);

        Composite composite = new Composite(container, SWT.NONE);
        composite.setLayout(new GridLayout(2, false));
        GridData gdComposite = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
        gdComposite.widthHint = 95;
        composite.setLayoutData(gdComposite);

        Label lblConfigurationName = new Label(composite, SWT.NONE);
        lblConfigurationName.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
        lblConfigurationName.setText("Name:");

        txtName = new Text(composite, SWT.BORDER);
        GridData gdTxtName = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
        gdTxtName.widthHint = 383;
        txtName.setLayoutData(gdTxtName);
        txtName.setBounds(0, 0, 76, 21);

        Label lblConfigurationDesc = new Label(composite, SWT.NONE);
        lblConfigurationDesc.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
        lblConfigurationDesc.setText("Description:");

        txtDesc = new Text(composite, SWT.BORDER);
        GridData gdTxtDesc = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
        gdTxtDesc.widthHint = 383;
        txtDesc.setLayoutData(gdTxtDesc);
        txtDesc.setBounds(0, 0, 76, 21);
        new Label(composite, SWT.NONE);
        new Label(composite, SWT.NONE);

        if (isConfig) {
            btnAsComponent = new Button(composite, SWT.CHECK);
            btnAsComponent.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
            btnAsComponent.setText("Save the configuration as a component");
            btnAsComponent.setVisible(true);

            new Label(composite, SWT.NONE);
            btnAsComponent.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    updateConfigType();
                    update();
                }
            });
        }

        txtName.addModifyListener(new ModifyListener() {
            @Override
            public void modifyText(ModifyEvent arg0) {
                update();
            }
        });

        txtDesc.addModifyListener(new ModifyListener() {
            @Override
            public void modifyText(ModifyEvent arg0) {
                update();
            }
        });

        txtName.setText(currentName);
        txtDesc.setText(currentDesc);

        update();

        return container;
    }

    /**
     * Create contents of the button bar.
     * @param parent
     */
    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        Button button = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
        button.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
            }
        });
        createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);

        // after creating buttons update their state
        update();
    }

    @Override
    protected void okPressed() {
        if (validate(name())) {
            newName = name();
            newDesc = description();
            // Warn about overwriting if already exists
            if (isDuplicate(newName)) {
                boolean userCancelled = askUserWhetherToOverwrite();
                if (userCancelled) {
                    return;
                }
            }
            super.okPressed();
            close();
        }
        // else ignore the click
    }

    /**
     * @return Does the user want to overwrite the current configuration
     */
    private boolean askUserWhetherToOverwrite() {
        MessageBox box = new MessageBox(getShell(), SWT.YES | SWT.NO);
        box.setMessage(String.format("The specified %s name already exists - do you want to replace it? ",
                getTypeName().toLowerCase()));

        //Message boxes return the ID of the button to close, so need to check that value..
        return box.open() != SWT.YES;
    }

    /**
     * @return The name of the object
     */
    private String name() {
        return txtName.getText();
    }

    /**
     * @return The description of the object
     */
    private String description() {
        return txtDesc.getText().trim();
    }

    /**
     * @return The type of the object as a string, either component or
     *         configuration
     */
    private String getTypeName() {
        return willBeComponent() ? COMPONENT : CONFIGURATION;
    }

    /**
     * Update the view by checking whether the name and description are valid.
     */
    private void update() {
        checkInput(name(), description());
    }

    /**
     * Update whether this is a configuration or component and change the title
     * of the dialog accordingly.
     */
    private void updateConfigType() {
        asComponent = btnAsComponent.getSelection();
        setTitle(String.format("Save %s", getTypeName()));
    }

    /**
     * @param canSave The object has valid parameters and can be saved
     */
    private void allowSaving(boolean canSave) {
        Button ok = getButton(IDialogConstants.OK_ID);
        if (ok != null) {
            ok.setEnabled(canSave);
        }
    }

    /**
     * @return The object is a component containing components
     */
    private boolean savingComponentWithComponents() {
        return willBeComponent() && hasComponents;
    }

    /**
     * @param name The config/component name
     * @return Whether an object already exists with this name
     */
    private boolean isDuplicate(final String name) {
        List<String> prexisting = willBeComponent() ? existingComponents : existingConfigs;
        return Iterables.any(prexisting, new Predicate<String>() {
            @Override
            public boolean apply(String existing) {
                return compareIgnoringCase(existing, name);
            }
        });
    }

    /**
     * @param text The text to compare
     * @param other The text to compare against
     * @return Whether the two pieces of text match case-insensitively
     */
    private boolean compareIgnoringCase(String text, String other) {
        return text.toUpperCase().equals(other.toUpperCase());
    }

    /**
     * @param name The proposed name of the object
     * @return Whether the proposed name is valid
     */
    private Boolean validate(String name) {
        //Must start with a letter and contain no spaces   
        return name.matches("^[a-zA-Z][a-zA-Z0-9_]*$");
    }

    /**
     * Check whether the proposed name and description of the object are valid.
     * Add an error message if they aren't, allow saving if they are.
     * 
     * @param name The proposed name of the object
     * @param desc The proposed description of the object
     */
    private void checkInput(String name, String desc) {
        setErrorMessage(null);
        setMessage(null);

        String error = getErrorMessage(name, desc);
        if (error.length() > 0) {
            setErrorMessage(error);
            allowSaving(false);
            return;
        }

        allowSaving(true);
        String warning = getWarningMessage(name);
        if (warning.length() > 0) {
            setMessage(warning);
        }
    }

    /**
     * Get any error messages associated with proposed name/description of the
     * object.
     * 
     * @param name Proposed name of the object
     * @param description Proposed description of the object
     * @return The error message associated with the proposed name and
     *         description
     */
    private String getErrorMessage(String name, String description) {
        if (savingComponentWithComponents()) {
            return "To be saved as a component, the configuration must have no components of its own.";
        }

        if (name.length() == 0) {
            return "Name cannot be blank";
        }

        if (!name.matches("^[a-zA-Z].*")) {
            return "Name must start with a letter";
        }

        if (!name.matches("[a-zA-Z0-9_]*")) {
            return "Name must only contain alphanumeric characters and underscores";
        }

        if (nameMatchesCurrentConfig(name)) {
            return "Name matches the current configuration";
        }

        BlockServerNameValidator configDescritpionRules = Configurations.getInstance()
                .variables().configDescriptionRules.getValue();
        SummaryDescriptionValidator descriptionValidator = new SummaryDescriptionValidator(null,
                configDescritpionRules);
        IStatus status = descriptionValidator.validate(description);
        if (!status.isOK()) {
            return status.getMessage();
        }

        return "";
    }

    /**
     * Get any warning messages associated with proposed name of the object.
     * 
     * @param name Proposed name of the object
     * @return The error message associated with the proposed name
     */
    private String getWarningMessage(String name) {
        if (isDuplicate(name)) {
            return String.format("A %s with this name already exists", getTypeName().toLowerCase());
        }

        return "";
    }

    /**
     * @return The requested name matches that of the current configuration
     */
    private boolean nameMatchesCurrentConfig(String name) {
        return compareIgnoringCase(name, currentConfigName);
    }
}