com.google.eclipse.mechanic.plugin.ui.BaseOutputDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.google.eclipse.mechanic.plugin.ui.BaseOutputDialog.java

Source

/*******************************************************************************
 * Copyright (C) 2010, Google Inc.
 *
 * 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 com.google.eclipse.mechanic.plugin.ui;

import java.io.File;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Set;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
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.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.eclipse.mechanic.internal.TaskType;
import com.google.eclipse.mechanic.plugin.core.MechanicPlugin;

/**
 * The dialog to obtain properties for outputting a task file.
 */
public abstract class BaseOutputDialog extends Dialog {

    enum Component {
        TITLE, DESCRIPTION, TASK_TYPE
    }

    private final String extension;
    private boolean willVerifyOverwrite = true;
    private Set<Component> components;

    private Text titleText;
    private Text descriptionText;
    private Combo taskTypeCombo;
    private Text savedLocationText;

    /**
     * Create an output dialog for the given shell.
     * 
     * @param parentShell the shell to create this dialog in.
     * @param extension the file type extension.
     * @param components the set of task parameter components to show.
     * If empty, show all components.
     */
    public BaseOutputDialog(Shell parentShell, String extension, Component... components) {
        super(parentShell);
        this.extension = extension;
        if (components.length == 0) {
            this.components = EnumSet.allOf(Component.class);
        } else {
            this.components = EnumSet.noneOf(Component.class);
            this.components.addAll(Arrays.asList(components));
        }
    }

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

    // TODO: zorzella says: I don't think this overload is doing anything at all.
    // I refactored it to stop growing upon every invocation, but the whole bit
    // about "new Point(p.x, p.y * 3 / 2);" which, on face value, seems like an
    // attempt to make the dialog taller than its otherwise default, seems to
    // simply be having no effect.
    @Override
    protected Point getInitialSize() {
        // We check if the dialog has been resized by the user...
        if (getDialogBoundsSettings() == null) {
            // ... if not, we create a dialog twice the default size
            Point p = super.getInitialSize();
            return new Point(p.x, p.y * 3 / 2);
        } else {
            // ... if it has been resized, we use that size, otherwise
            // every time we open the dialog it grows...
            return super.getInitialSize();
        }
        // ... there probably is a much better way of doing this, btw.
    }

    @Override
    protected IDialogSettings getDialogBoundsSettings() {
        String dialogSettingsSection = getDialogSettingsSection();
        if (dialogSettingsSection == null) {
            return null;
        }
        IDialogSettings settings = MechanicPlugin.getDefault().getDialogSettings();
        IDialogSettings section = settings.getSection(dialogSettingsSection);
        if (section == null)
            section = settings.addNewSection(dialogSettingsSection);
        return section;
    }

    /**
     * Override to describe the dialog settings section.
     */
    protected String getDialogSettingsSection() {
        return null;
    }

    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        super.createButtonsForButtonBar(parent);

        // Initial values for the dialog aren't valid, so set the button to 
        // be disabled initially
        getButton(IDialogConstants.OK_ID).setEnabled(false);
    }

    @Override
    protected void configureShell(Shell shell) {
        super.configureShell(shell);
    }

    protected void createLabel(Composite parent, String text) {
        Label titleLabel = new Label(parent, SWT.BEGINNING);
        titleLabel.setText(text);
    }

    private final ModifyListener validateOnChange = new ModifyListener() {
        public void modifyText(ModifyEvent e) {
            validate();
        }
    };

    protected Text createTextBox(Composite parent) {
        Text text = new Text(parent, SWT.SINGLE | SWT.BORDER);
        text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
        text.addModifyListener(validateOnChange);
        return text;
    }

    @Override
    protected Control createDialogArea(Composite parent) {
        final Composite container = (Composite) super.createDialogArea(parent);
        GridLayout layout = new GridLayout(3, false);
        container.setLayout(layout);

        if (components.contains(Component.TITLE)) {
            createLabel(container, "Title:");
            titleText = createTextBox(container);
            titleText.setEnabled(components.contains(Component.TITLE));
        }

        if (components.contains(Component.DESCRIPTION)) {
            createLabel(container, "Description:");
            descriptionText = createTextBox(container);
            descriptionText.setEnabled(components.contains(Component.DESCRIPTION));
        }

        if (components.contains(Component.TASK_TYPE)) {
            createLabel(container, "Task Type:");
            taskTypeCombo = new Combo(container, SWT.DROP_DOWN | SWT.READ_ONLY);
            // Ensuring the order hasn't changed, as we rely on that.
            Preconditions.checkState(TaskType.values()[0] == TaskType.LASTMOD);
            taskTypeCombo.setItems(new String[] { "Last Mod", "Reconcile" });
            taskTypeCombo.select(0);
            taskTypeCombo.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false, 2, 1));
            taskTypeCombo.addModifyListener(validateOnChange);
            taskTypeCombo.setEnabled(components.contains(Component.TASK_TYPE));
        }

        // Add saved file location
        createLabel(container, "Saved File Location:");
        savedLocationText = createTextBox(container);
        savedLocationText.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                willVerifyOverwrite = true;
                validate();
            }
        });

        // TODO: this button belongs in the same line as the textBox above
        Button browseButton = new Button(container, SWT.PUSH);
        browseButton.setText("Browse...");
        browseButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
        browseButton.addSelectionListener(new SelectionListener() {
            public void widgetSelected(SelectionEvent e) {
                doFileDialog();
                validate();
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                doFileDialog();
                validate();
            }

            private void doFileDialog() {
                FileDialog fd = new FileDialog(container.getShell(), SWT.SAVE);
                String location = getLocation();
                if (location != null && location.trim().length() > 0) {
                    fd.setFileName(location);
                }
                fd.setOverwrite(true);
                fd.setFilterExtensions(new String[] { "*." + extension });
                String file = fd.open();
                if (file != null) {
                    savedLocationText.setText(file);
                }
                willVerifyOverwrite = false; // Should override the listener on the text box
            }
        });

        addChildConfiguration(container);

        return container;
    }

    protected void addChildConfiguration(Composite parent) {
    }

    protected void validate() {
        Button b = this.getButton(IDialogConstants.OK_ID);
        // Can be null when called from createDailogArea. Honestly if someone refactors this,
        // remove this mistake.
        if (b != null) {
            boolean valid = isValid();
            b.setEnabled(valid);
        }
    }

    @Override
    protected Control createContents(Composite parent) {
        Control result = super.createContents(parent);
        // TODO: there's probably a better way of doing this.
        // Validate upon constructing the dialog, so as to enable to "Ok" button
        // if appropriate. This can't be done in the createDailogArea because the
        // OK button is created in super after that method returns.
        validate();
        return result;
    }

    /**
     * Return true if the dialog is valid.
     */
    protected boolean isValid() {
        if (components.contains(Component.TITLE) && getTitle().length() == 0) {
            return false;
        }

        if (components.contains(Component.DESCRIPTION) && getDescription().length() == 0) {
            return false;
        }

        if (getLocation().length() == 0) {
            return false;
        }

        File destFile = new File(getLocation());

        if (destFile.exists()) {
            if (!destFile.isFile()) {
                return false;
            }

            if (!destFile.canWrite()) {
                return false;
            }
        }

        File parentDir = destFile.getParentFile();

        if (parentDir == null) {
            return false;
        }

        if (!parentDir.exists()) {
            return false;
        }

        if (!parentDir.isDirectory()) {
            return false;
        }

        return parentDir.canWrite(); // Can we create a file in this directory?
    }

    protected IPath getValidOutputLocation() {
        IPath destinationLocation = new Path(getLocation());

        if (!Strings.isNullOrEmpty(extension)) {

            String fileExtension = destinationLocation.getFileExtension();
            if (!extension.equals(fileExtension)) {
                String message = String.format("The file \"%s\" does not have a .%s extension. Add it?",
                        destinationLocation, extension);
                if (MessageDialog.openQuestion(this.getShell(), "Add ." + extension + " to filename?", message)) {
                    destinationLocation = destinationLocation.addFileExtension(extension);
                    willVerifyOverwrite = true;
                }
            }
        }
        // If the user picked a file via the dialog and that file exists, then they've already been 
        // asked if the file should be overwritten, and we shouldn't ask again. If not, then we need 
        // to check if the file exists and, if so, ask them now.
        if (willVerifyOverwrite) {
            if (destinationLocation.toFile().exists()) {
                String message = String.format("The file \"%s\" will be overwritten. Is this OK?",
                        destinationLocation);
                if (!MessageDialog.openQuestion(this.getShell(), "Overwrite?", message)) {
                    return null;
                }
            }
        }
        return destinationLocation;
    }

    public String getTitle() {
        return titleText.getText();
    }

    public void setTitle(String text) {
        titleText.setText(text);
    }

    public String getDescription() {
        return descriptionText.getText();
    }

    public void setDescription(String text) {
        descriptionText.setText(text);
        validate();
    }

    /**
     * Get task type provided by the user. Only valid after the dialog has been
     * created.
     */
    public TaskType getTaskType() {
        return TaskType.values()[taskTypeCombo.getSelectionIndex()];
    }

    public void setTaskType(TaskType taskType) {
        taskTypeCombo.select(Arrays.asList(TaskType.values()).indexOf(taskType));
    }

    public String getLocation() {
        return savedLocationText.getText();
    }

    public void setLocation(String text) {
        savedLocationText.setText(text);
        validate();
    }
}