com.codesourcery.installer.ui.ChoiceDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.codesourcery.installer.ui.ChoiceDialog.java

Source

/*******************************************************************************
 *  Copyright (c) 2014 Mentor Graphics and others.
 *  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:
 *     Mentor Graphics - initial API and implementation
 *******************************************************************************/
package com.codesourcery.installer.ui;

import java.util.ArrayList;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
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 com.codesourcery.installer.IInstallConsoleProvider;
import com.codesourcery.installer.Installer;
import com.codesourcery.installer.console.ConsoleListPrompter;
import com.codesourcery.internal.installer.IInstallerImages;
import com.codesourcery.installer.ui.InfoButton;
import com.codesourcery.installer.ui.InfoButton.ElementColor;

/**
 * A dialog that displays a list of choices.  This dialog also provides
 * console support.
 */
public class ChoiceDialog extends Dialog implements IInstallConsoleProvider {
    /** Dialog element colors */
    private Color[] colors = new Color[ElementColor.values().length];
    /** Dialog background color */
    private Color backgroundColor;
    /** Prompt foreground color*/
    private Color promptColor;
    /** Dialog title font */
    private Font titleFont;
    /** Choices to display */
    private ArrayList<Option> options = new ArrayList<Option>();
    /** Dialog title */
    private String title;
    /** Dialog title text */
    private String titleText;
    /** Dialog prompt text */
    private String promptText;
    /** Default option or <code>null</code>*/
    private Option defaultOption;
    /** Identifier of currently selected option or <code>null</code>*/
    private String selectedOption;
    /** Console list prompter */
    private ConsoleListPrompter<String> consoleList;
    /** Choice widths */
    private int width = -1;

    /**
     * Constructor
     * 
     * @param parentShell Parent shell or <code>null</code> to use for console
     * @param title Title for dialog
     */
    public ChoiceDialog(Shell parentShell, String title) {
        super(parentShell);
        this.title = title;
        setShellStyle(getShellStyle() | SWT.RESIZE);
    }

    /**
     * Sets the text displayed in the title.
     * 
     * @param titleText Title text or <code>null</code>
     */
    public void setTitleText(String titleText) {
        this.titleText = titleText;
    }

    /**
     * Returns the text displayed in the title.
     * 
     * @return Title text or <code>null</code>
     */
    public String getTitleText() {
        return titleText;
    }

    /**
     * Sets the prompt text.
     * 
     * @param promptText Prompt text
     */
    public void setPromptText(String promptText) {
        this.promptText = promptText;
    }

    /**
     * Returns the prompt text.
     * 
     * @return Prompt text
     */
    public String getPromptText() {
        return promptText;
    }

    /**
     * Sets the maximum width of the dialog.
     * 
     * @param width Width
     */
    public void setWidth(int width) {
        this.width = width;
    }

    /**
     * Returns the maximum width of the dialog.
     * 
     * @return Width
     */
    public int getWidth() {
        return width;
    }

    /**
     * Adds a new option to display on the dialog.
     * 
     * @param id Identifier for the option
     * @param image Image for the option or <code>null</code>
     * @param label Label for the option or <code>null</code>
     * @param description Description for the option or <code>null</code>
     */
    public void addOption(String id, Image image, String label, String description) {
        options.add(new Option(id, image, label, description));
    }

    /**
     * Returns an option.
     * 
     * @param id Option identifier
     * @return Option or <code>null</code>
     */
    private Option getOption(String id) {
        Option foundOption = null;
        for (Option option : options) {
            if (option.getId().equals(id)) {
                foundOption = option;
                break;
            }
        }

        return foundOption;
    }

    /**
     * Sets the default option.
     * 
     * @param id Identifier of option to set as default
     */
    public void setDefaultOption(String id) {
        defaultOption = getOption(id);
    }

    /**
     * Returns the selected option.
     * 
     * @return Option identifier or <code>null</code>
     */
    public String getSelection() {
        return selectedOption;
    }

    @Override
    protected void configureShell(Shell newShell) {
        super.configureShell(newShell);
        // Set dialog icon
        newShell.setImage(Installer.getDefault().getImageRegistry().get(IInstallerImages.TITLE_ICON));
        // Set title
        newShell.setText(title);
    }

    @Override
    protected Control createContents(Composite parent) {
        GridLayout layout;
        GridData data;

        if (width == -1) {
            GC gc = new GC(parent);
            gc.setFont(JFaceResources.getDialogFont());
            FontMetrics fontMetrics = gc.getFontMetrics();
            gc.dispose();
            width = convertHorizontalDLUsToPixels(fontMetrics, 185);
        }

        // Initialize element colors
        initColors();

        // Main area
        Composite area = new Composite(parent, SWT.NONE);
        layout = new GridLayout(1, true);
        layout.marginHeight = 5;
        layout.marginWidth = 0;
        layout.verticalSpacing = 0;
        area.setLayout(layout);
        area.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        // Title text
        if (getTitleText() != null) {
            // Title text font
            FontData fontData = JFaceResources.getDialogFont().getFontData()[0];
            fontData.setHeight(fontData.getHeight() + 2);
            titleFont = new Font(getShell().getDisplay(), fontData);

            // Title text area
            Composite titleArea = new Composite(area, SWT.NONE);
            layout = new GridLayout(1, true);
            titleArea.setLayout(layout);
            titleArea.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

            // Title text label
            Label label = new Label(titleArea, SWT.WRAP);
            data = new GridData(SWT.FILL, SWT.CENTER, true, false);
            data.widthHint = getWidth();
            label.setLayoutData(data);
            label.setText(getTitleText());
            label.setFont(titleFont);

            // Separator
            label = new Label(titleArea, SWT.NONE);
            label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

            // Prompt
            if (getPromptText() != null) {
                label = new Label(titleArea, SWT.WRAP);
                label.setForeground(promptColor);
                data = new GridData(SWT.FILL, SWT.CENTER, true, false);
                data.widthHint = getWidth();
                label.setLayoutData(data);
                label.setText(getPromptText());
                label.setFont(titleFont);
                label.setForeground(promptColor);
            }
        }

        // Add choices
        for (Option option : options) {
            InfoButton button = new InfoButton(area, SWT.RADIO);
            button.setData(option);
            button.setImage(option.getImage());
            button.setText(option.getLabel());
            button.setDescription(option.getDescription());
            data = new GridData(SWT.FILL, SWT.CENTER, true, false);
            data.widthHint = getWidth();
            button.setLayoutData(data);
            // Set label colors
            for (int index = 0; index < colors.length; index++) {
                button.setColor(ElementColor.values()[index], colors[index]);
            }

            // Default option
            if (option.equals(defaultOption)) {
                button.setSelection(true);
                selectedOption = option.getId();
            }

            // Selected option listener
            button.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    InfoButton button = (InfoButton) e.widget;
                    selectedOption = ((Option) button.getData()).getId();
                    updateButtons();
                }
            });
            // Close dialog on option double-click
            button.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseDoubleClick(MouseEvent e) {
                    InfoButton button = (InfoButton) e.widget;
                    selectedOption = ((Option) button.getData()).getId();
                    updateButtons();
                    okPressed();
                }
            });
        }

        applyDialogFont(area);

        // Set dialog background color
        Composite contents = (Composite) super.createContents(parent);
        setBackground(parent, backgroundColor);
        return contents;
    }

    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        super.createButtonsForButtonBar(parent);
        if (getSelection() != null) {
            // Select OK by default
            getButton(IDialogConstants.OK_ID).setFocus();
        } else {
            // Select Cancel by default
            getButton(IDialogConstants.CANCEL_ID).setFocus();
        }
        updateButtons();
    }

    /**
     * Updates the state of buttons.
     */
    private void updateButtons() {
        // Set OK enabled only if an option is selected
        getButton(IDialogConstants.OK_ID).setEnabled(getSelection() != null);
    }

    /**
     * Initializes dialog colors.
     */
    private void initColors() {
        promptColor = new Color(getShell().getDisplay(), new RGB(45, 137, 239));
        // Background
        backgroundColor = getShell().getDisplay().getSystemColor(SWT.COLOR_WHITE);
        Color selectBackground = new Color(getShell().getDisplay(),
                blendRGB(new RGB(45, 137, 239), backgroundColor.getRGB(), 20));
        // Option selection
        colors[ElementColor.selectBackground.ordinal()] = selectBackground;
        // Option hover
        colors[ElementColor.hoverBackground.ordinal()] = new Color(getShell().getDisplay(),
                blendRGB(selectBackground.getRGB(), backgroundColor.getRGB(), 15));
        // Option label
        Color foreground = new Color(getShell().getDisplay(), new RGB(0, 0, 0));
        colors[ElementColor.label.ordinal()] = foreground;
        colors[ElementColor.selectedLabel.ordinal()] = foreground;
        // Option description
        Color descriptionForeground = new Color(getShell().getDisplay(),
                blendRGB(foreground.getRGB(), backgroundColor.getRGB(), 50));
        colors[ElementColor.description.ordinal()] = descriptionForeground;
        colors[ElementColor.selectedDescription.ordinal()] = descriptionForeground;
    }

    @Override
    public boolean close() {
        // Dispose of element colors
        if (colors != null) {
            for (Color color : colors) {
                color.dispose();
            }
            colors = null;
        }
        // Dispose of title color
        if (promptColor != null) {
            promptColor.dispose();
            promptColor = null;
        }
        // Dispose of title font
        if (titleFont != null) {
            titleFont.dispose();
            titleFont = null;
        }
        return super.close();
    }

    /**
     * Blends two RGB values using the provided ratio. 
     * 
     * @param c1 First RGB value
     * @param c2 Second RGB value
     * @param ratio Percentage of the first RGB to blend with 
     * second RGB (0-100)
     * 
     * @return The RGB value of the blended color
     */
    public static RGB blendRGB(RGB c1, RGB c2, int ratio) {
        ratio = Math.max(0, Math.min(255, ratio));

        int r = Math.max(0, Math.min(255, (ratio * c1.red + (100 - ratio) * c2.red) / 100));
        int g = Math.max(0, Math.min(255, (ratio * c1.green + (100 - ratio) * c2.green) / 100));
        int b = Math.max(0, Math.min(255, (ratio * c1.blue + (100 - ratio) * c2.blue) / 100));

        return new RGB(r, g, b);
    }

    @Override
    protected Control createButtonBar(Composite parent) {
        Composite bar = (Composite) super.createButtonBar(parent);
        // Change bar to center on dialog
        bar.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER | GridData.VERTICAL_ALIGN_CENTER));

        return bar;
    }

    /**
     * Sets the background color for a composite and it's children.
     * 
     * @param area Composite
     * @param color Background color
     */
    private void setBackground(Control area, Color color) {
        area.setBackground(color);
        if (area instanceof Composite) {
            Control[] children = ((Composite) area).getChildren();
            for (Control child : children) {
                setBackground(child, color);
            }
        }
    }

    /**
     * Dialog option
     */
    private class Option {
        /** Option identifier */
        private String id;
        /** Image for the option */
        private Image image;
        /** Label for the option */
        private String label;
        /** Description for the label */
        private String description;

        /**
         * Constructor
         * 
         * @param id Option identifier
         * @param image Option image
         * @param label Option label
         * @param description Option description
         */
        public Option(String id, Image image, String label, String description) {
            this.id = id;
            this.image = image;
            this.label = label;
            this.description = description;
        }

        /**
         * Returns the option identifier.
         * 
         * @return Identifier
         */
        public String getId() {
            return id;
        }

        /**
         * Returns the option image.
         * 
         * @return Image
         */
        public Image getImage() {
            return image;
        }

        /**
         * Return the option label.
         * 
         * @return Label
         */
        public String getLabel() {
            return label;
        }

        /**
         * Returns the option description.
         * 
         * @return Description
         */
        public String getDescription() {
            return description;
        }
    }

    @Override
    public String getConsoleResponse(String input) throws IllegalArgumentException {
        String response = null;

        // Initial prompt
        if (input == null) {
            consoleList = new ConsoleListPrompter<String>(getTitleText(), true);

            // Add options
            for (Option option : options) {
                StringBuffer itemName = new StringBuffer();
                if (option.getLabel() != null)
                    itemName.append(option.getLabel());
                if (option.getDescription() != null) {
                    if (itemName.length() > 0)
                        itemName.append(" - ");
                    itemName.append(option.getDescription());
                }
                consoleList.addItem(itemName.toString(), option.getId());
            }
        }
        // Get response
        response = consoleList.getConsoleResponse(input);
        // Handle selection
        if (response == null) {
            ArrayList<String> selection = new ArrayList<String>();
            consoleList.getSelectedData(selection);
            if (selection.size() > 0) {
                selectedOption = selection.get(0);
            }
        }

        return response;
    }
}