com.buildml.eclipse.utils.PackageFilterDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.buildml.eclipse.utils.PackageFilterDialog.java

Source

/*******************************************************************************
 * Copyright (c) 2012 Arapiki Solutions 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
 *
 * Contributors:
 *    "Peter Smith <psmith@arapiki.com>" - initial API and 
 *        implementation and/or initial documentation
 *******************************************************************************/

package com.buildml.eclipse.utils;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Rectangle;
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.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

import com.buildml.eclipse.utils.errors.FatalError;
import com.buildml.model.IBuildStore;
import com.buildml.model.IPackageMemberMgr;
import com.buildml.model.IPackageMgr;
import com.buildml.model.types.PackageSet;

/**
 * A Dialog allowing the user to select (with checkboxes) a subset of all the
 * BuildStore's packages. This class is used in the Eclipse plugin, wherever
 * it's necessary to select a combination of packages.
 * 
 * @author "Peter Smith <psmith@arapiki.com>"
 */
public class PackageFilterDialog extends BmlTitleAreaDialog {

    /*=====================================================================================*
     * FIELDS/TYPES
     *=====================================================================================*/

    /**
     * The input PackageSet that this Dialog will display. This remains unmodified since
     * we create a clone of this object before modifying it.
     */
    private PackageSet pkgSet;

    /**
     * We need one widget for each line of the table.
     */
    private PkgSelectWidget lineWidgets[];

    /** Default width of the dialog box. */
    private int dialogWidth;

    /** Default height of the dialog box. */
    private int dialogHeight;

    /** Should the dialog box show scope names? */
    private boolean showScopes;

    /*=====================================================================================*
     * NESTED CLASS - PkgSelectWidget
     *=====================================================================================*/

    /**
     * A nested class representing a single line in the PackageFilterDialog window.
     * Each PkgSelectWidget contains the package's name, and a checkbox for each of
     * the scopes.
     * 
     * @author "Peter Smith <psmith@arapiki.com>"
     */
    private class PkgSelectWidget extends Composite {

        /*---------------------------------------------------------------------------------*/

        /** Each scope name (except for None) has its own checkbox widget. */
        private Button checkBoxes[] = null;

        /** This ID of the package that this widget represents. */
        int pkgId;

        /*---------------------------------------------------------------------------------*/

        /**
         * Create a new instance of the PkgSelectWidget class.
         * @param parent The PackageFilterDialog composite that this widget is pat of.
         * @param pkgName The name of the package to be displayed.
         */
        public PkgSelectWidget(Composite parent, String pkgName) {
            super(parent, 0);

            final IPackageMgr pkgMgr = pkgSet.getBuildStore().getPackageMgr();
            final IPackageMemberMgr pkgMemberMgr = pkgSet.getBuildStore().getPackageMemberMgr();

            /* get the scope name, and prepare for a checkbox for each */
            checkBoxes = new Button[IPackageMemberMgr.SCOPE_MAX];

            /* we'll use the package's internal ID when accessing the package Set */
            pkgId = pkgMgr.getId(pkgName);

            /* make sure this widget is stretched to the full width of the shell */
            this.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));

            /* 
             * Each line will contain a section for the package name,
             * and a section for each of the scopes (excluding the None scope).
             */
            GridLayout layout = new GridLayout();
            layout.numColumns = 1 + getNumScopes();
            layout.marginHeight = 0;
            setLayout(layout);

            /* The package name takes as much of the left side as possible */
            Label label1 = new Label(this, 0);
            label1.setText(pkgName);
            label1.setLayoutData(new GridData(SWT.LEFT, SWT.NONE, true, false));

            /*
             * On the right side, create a new checkbox button for each scope
             * (except for "None"). We take note of each widget (in the checkBoxes)
             * array so we can set/refresh it later.
             */
            int numScopes = getNumScopes();
            for (int i = 0; i < numScopes; i++) {

                /* the scope check boxes are on the right side */
                final Button newButton = new Button(this, SWT.CHECK);
                if (showScopes) {
                    newButton.setText(pkgMemberMgr.getScopeName(i + 1));
                } else {
                    newButton.setText("Show");
                }
                newButton.setLayoutData(new GridData());

                /*
                 * An an event listener that updates the current state of
                 * the PackageSet whenever a checkbox is selected.
                 */
                newButton.addSelectionListener(new SelectionAdapter() {
                    public void widgetSelected(SelectionEvent e) {
                        Button button = (Button) (e.getSource());
                        String buttonText = button.getText();
                        int scopeId;
                        if (showScopes) {
                            scopeId = pkgMemberMgr.getScopeId(buttonText);
                        } else {
                            scopeId = IPackageMemberMgr.SCOPE_PUBLIC;
                        }
                        if (button.getSelection()) {
                            pkgSet.add(pkgId, scopeId);
                        } else {
                            pkgSet.remove(pkgId, scopeId);
                        }
                    }
                });
                checkBoxes[i] = newButton;
            }

            /* set all the checkboxes to their initial values. */
            refresh();
        }

        /*---------------------------------------------------------------------------------*/

        /**
         * Refresh this widget with update content from the pkgSet.
         */
        public void refresh() {
            int numScopes = getNumScopes();
            for (int i = 0; i != numScopes; i++) {
                Button thisCheck = checkBoxes[i];
                if (showScopes) {
                    thisCheck.setSelection(pkgSet.isMember(pkgId, i + 1));
                } else {
                    thisCheck.setSelection(pkgSet.isMember(pkgId, IPackageMemberMgr.SCOPE_PUBLIC));
                }
            }
        }

        /*---------------------------------------------------------------------------------*/

        /**
         * @return The number of scope names that should be displayed (e.g. "Public" and 
         * "Private"), or just "Show".
         */
        private int getNumScopes() {
            if (showScopes) {
                return IPackageMemberMgr.SCOPE_MAX;
            } else {
                return 1;
            }
        }

        /*---------------------------------------------------------------------------------*/
    }

    /*=====================================================================================*
     * CONSTRUCTOR
     *=====================================================================================*/

    /**
     * Create a new PackageFilterDialog object, with the specified set of packages
     * shown as being selected.
     * @param initialPkgs The packages that will initially be selected.
     * @param showScopes True if our dialog box should show the package scope names (public
     *    and private), or just allow the whole package to be selected.
     */
    public PackageFilterDialog(PackageSet initialPkgs, boolean showScopes) {
        super(new Shell(), 0, 0, 0, 0.5);

        this.showScopes = showScopes;

        /* 
         * Make a copy of the PackageSet, so we can mess with it as much as we like
         * without disturbing the original copy (if the user hits "Cancel", we want the
         * original to be untouched).
         */
        try {
            pkgSet = (PackageSet) initialPkgs.clone();
        } catch (CloneNotSupportedException e) {
            throw new FatalError("Cloning not supported on PackageSet objects");
        }
    }

    /*=====================================================================================*
     * PUBLIC METHODS
     *=====================================================================================*/

    /**
     * @return The PackageSet representing the current combination
     * of components/scopes that are selected in the dialog.
     */
    public PackageSet getPackageSet() {
        return pkgSet;
    }

    /*-------------------------------------------------------------------------------------*/

    /* (non-Javadoc)
     * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected Control createDialogArea(Composite parent) {

        final IPackageMgr pkgMgr = pkgSet.getBuildStore().getPackageMgr();

        setTitle("Select the packages you wish to view:");
        setHelpAvailable(false);

        /* create and format the top-level composite of this dialog */
        Composite composite = (Composite) super.createDialogArea(parent);

        /* 
         * Add a box containing all the packages, and their selectable state. We put
         * everything inside a ScrolledComposite, so that the scrollbar is managed for us.
         */
        ScrolledComposite scrolledComposite = new ScrolledComposite(composite, SWT.BORDER | SWT.V_SCROLL);
        scrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        scrolledComposite.setLayout(new GridLayout());
        scrolledComposite.setAlwaysShowScrollBars(true);

        /* Add another composite (within the ScrolledComposite) that will contain the list of package names */
        Composite listComposite = new Composite(scrolledComposite, SWT.NONE);
        listComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        GridLayout layout = new GridLayout();
        layout.numColumns = 1;
        listComposite.setLayout(layout);

        /* Add a new line for each package name */
        String packageNames[] = pkgMgr.getPackages();
        lineWidgets = new PkgSelectWidget[packageNames.length];
        for (int i = 0; i != packageNames.length; i++) {
            String pkgName = packageNames[i];
            lineWidgets[i] = new PkgSelectWidget(listComposite, pkgName);
        }

        /* tell the ScrolledComposite what it's managing, and how big it should be. */
        scrolledComposite.setContent(listComposite);
        scrolledComposite.setExpandHorizontal(true);
        scrolledComposite.setMinWidth(0);
        listComposite.setSize(listComposite.computeSize(dialogWidth, SWT.DEFAULT));
        return composite;
    }

    /*-------------------------------------------------------------------------------------*/

    /*
     * (non-Javadoc)
     * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        /* add the standard buttons */
        super.createButtonsForButtonBar(parent);

        createButton(parent, IDialogConstants.SELECT_ALL_ID, "Select All", false);
        createButton(parent, IDialogConstants.DESELECT_ALL_ID, "Deselect All", false);
    }

    /*-------------------------------------------------------------------------------------*/

    /* 
     * (non-Javadoc)
     * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
     */
    @Override
    protected void configureShell(Shell newShell) {
        super.configureShell(newShell);

        /* centre the dialog in the middle of the screen */
        Rectangle parentBounds = Display.getCurrent().getBounds();
        dialogHeight = parentBounds.height / 2;
        dialogWidth = parentBounds.width / 4;
        newShell.setBounds(parentBounds.width / 2 - (dialogWidth / 2), parentBounds.height / 2 - (dialogHeight / 2),
                dialogWidth, dialogHeight);
        newShell.setText("Select Packages to View");
    }

    /*-------------------------------------------------------------------------------------*/

    /* 
     * (non-Javadoc)
     * @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int)
     */
    @Override
    protected void buttonPressed(int buttonId) {
        /* handle standard buttons */
        super.buttonPressed(buttonId);

        /*
         * Handle the "Select all" or "Deselect All" buttons.
         */
        if ((buttonId == IDialogConstants.SELECT_ALL_ID) || (buttonId == IDialogConstants.DESELECT_ALL_ID)) {

            /* 
             * Create a new (replacement) PackageSet with no content, but
             * a default of false (deselect all) or true (select all).
             */
            IBuildStore bs = pkgSet.getBuildStore();
            pkgSet = new PackageSet(bs);
            if (buttonId == IDialogConstants.SELECT_ALL_ID) {
                pkgSet.setDefault(true);
            }

            /*
             * Refresh all the widgets, using this new PackageSet.
             */
            for (int i = 0; i < lineWidgets.length; i++) {
                lineWidgets[i].refresh();
            }
        }
    }

    /*-------------------------------------------------------------------------------------*/
}