org.nightlabs.eclipse.ui.dialog.ExpandableAreaDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.nightlabs.eclipse.ui.dialog.ExpandableAreaDialog.java

Source

/* *****************************************************************************
 * org.nightlabs.base.ui - NightLabs Eclipse utilities                            *
 * Copyright (C) 2004-2005 NightLabs - http://NightLabs.org                    *
 *                                                                             *
 * This library is free software; you can redistribute it and/or               *
 * modify it under the terms of the GNU Lesser General Public                  *
 * License as published by the Free Software Foundation; either                *
 * version 2.1 of the License, or (at your option) any later version.          *
 *                                                                             *
 * This library is distributed in the hope that it will be useful,             *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of              *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU           *
 * Lesser General Public License for more details.                             *
 *                                                                             *
 * You should have received a copy of the GNU Lesser General Public            *
 * License along with this library; if not, write to the                       *
 *     Free Software Foundation, Inc.,                                         *
 *     51 Franklin St, Fifth Floor,                                            *
 *     Boston, MA  02110-1301  USA                                             *
 *                                                                             *
 * Or get it online :                                                          *
 *     http://www.gnu.org/copyleft/lesser.html                                 *
 *                                                                             *
 *                                                                             *
 ******************************************************************************/

package org.nightlabs.eclipse.ui.dialog;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
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.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.widgets.ExpandableComposite;

/**
 * Defines a Dialog with a "twistie" for toggling the expansion-state of a Composite.
 * This class is ment to be subclassed. You have to
 * define a constructor and override {@link #createStaticArea(Composite)} as well as
 * {@link #createExpandableArea(Composite)} to have your own Composites inside the Dialog.
 * <p>
 * Here is an example:
 * <pre>
 * public class MyExpandableDialog extends ExpandableAreaDialog{
 *   public MyExpandableDialog(Shell parent)
 *   {
 *     super(parent);
 *       setDialogTitle("My Dialog's Title");
 *       setExpandText("Expand Me");
 *   }
 *
 *   protected Composite createStaticArea(Composite parent)
 *   {
 *     Composite staticArea = super.createStaticArea(parent);
 *     new Label(staticArea, SWT.NONE).setText("The static area");
 *     return staticArea;
 *   }
 *         
 *   protected Composite createExpandableArea(Composite parent)
 *   {
 *     Composite expandableArea = super.createExpandableArea(parent);
 *     new Label(expandableArea, SWT.NONE).setText("The expandable area");
 *     return expandableArea;
 *   }
 * }
 * </pre>
 * </p>
 * <p>
 * You can still override methods from {@link org.eclipse.jface.dialogs.Dialog} in order to provide
 * your own ButtonBar. Please do not override createDialogArea or at least return super(parent).
 * </p>
 * <p>
 * If you provide an implementation of {@link #getDialogBoundsSettings()}, the expansion state
 * of the twistie will be saved in the dialog settings.
 * </p>
 * 
 * @author Alexander Bieber
 * @author Marc Klinger - marc[at]nightlabs[dot]de
 * @see org.eclipse.ui.forms.widgets.ExpandableComposite
 * @see org.eclipse.jface.dialogs.Dialog
 */
public abstract class ExpandableAreaDialog extends Dialog {
    /**
     * The dialog settings key name for the expansion state of the twistie.
     */
    private static final String DIALOG_TWISTIE_EXPANSION_STATE = "DIALOG_TWISTIE_EXPANSION_STATE"; //$NON-NLS-1$

    private ExpandableAreaComp dialogAreaComp = null;
    private Composite staticArea = null;
    private Composite expandableArea = null;

    /**
     * Create a new ExpandableAreaDialog instance.
     * @param parent The parent shell
     */
    public ExpandableAreaDialog(Shell parent) {
        super(parent);
    }

    private String expandText = ""; //$NON-NLS-1$

    /**
     * @return the expandText.
     */
    public String getExpandText() {
        return expandText;
    }

    /**
     * @param expandText The expandText to set.
     */
    public void setExpandText(String expandText) {
        this.expandText = expandText;
    }

    /** Do not override this method.
     * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected Control createDialogArea(Composite parent) {
        dialogAreaComp = new ExpandableAreaComp();
        return dialogAreaComp.createComposite(parent, this, expandText);
    }

    /**
     * Override this method to return the Composite you want to be visible in the
     * upper area of the Dialog.
     * @param parent Add your Composite as child of this
     */
    protected Composite createStaticArea(Composite parent) {
        // create a composite with no margins and standard spacing
        Composite composite = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
        layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
        composite.setLayout(layout);
        composite.setLayoutData(new GridData(GridData.FILL_BOTH));
        applyDialogFont(composite);
        return composite;
    }

    /**
     * Override this method to return the Composite you want to be the client of the
     * ExpandableComposite.
     * @param parent Add your Composite as child of this
     */
    protected Composite createExpandableArea(Composite parent) {
        // create a composite with no margins and standard spacing
        Composite composite = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
        layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
        composite.setLayout(layout);
        composite.setLayoutData(new GridData(GridData.FILL_BOTH));
        applyDialogFont(composite);
        return composite;
    }

    /**
     * Returns the expandable area Composite
     * @see #createExpandableArea(Composite)
     */
    public Composite getExpandableArea() {
        return expandableArea;
    }

    /**
     * Returns the static area Composite
     * @see #createStaticArea(Composite)
     */
    public Composite getStaticArea() {
        return staticArea;
    }

    /**
     * Packs, layouts and resizes the Dialog according to
     * its contents and {@link #getMaxWidth()} and
     * {@link #getMaxHeight()}.
     */
    public void doRelayout() {
        if (getShell() != null) {
            getShell().layout();
            getShell().pack();
            Point sizeAfterPack = getShell().getSize();
            Point sizeToSet = new Point(sizeAfterPack.x, sizeAfterPack.y);
            if (sizeAfterPack.x > getMaxWidth())
                sizeToSet.x = getMaxWidth();
            if (sizeAfterPack.y > getMaxHeight())
                sizeToSet.y = getMaxHeight();

            getShell().setSize(sizeToSet.x, sizeToSet.y);
            getShell().layout();
        }
    }

    /**
     * Overrides {@link Dialog#create()} and adds a call to {@link #doRelayout()}
     */
    @Override
    public void create() {
        super.create();
        doRelayout();
    }

    private int maxWidth = -1;
    private int maxHeight = -1;

    /**
     * Returns the maximal Width for the dialog.
     * Default value is the screens width.
     */
    public int getMaxWidth() {
        if (maxWidth > 0) {
            return maxWidth;
        } else
            return Display.getCurrent().getClientArea().width;
    }

    /**
     * Returns the maximal Height for the dialog.
     * Default value is the screens height.
     */
    public int getMaxHeight() {
        if (maxHeight > 0) {
            return maxHeight;
        } else
            return Display.getCurrent().getClientArea().height;
    }

    /**
     * Sets the maximum size for the dialog.
     * @param maxSize
     */
    public void setMaxSize(Point maxSize) {
        setMaxWidth(maxSize.x);
        setMaxHeight(maxSize.y);
    }

    /**
     * Sets the maximum width for the dialog.
     * maxHeight is not affected by this method.
     * @param width
     */
    public void setMaxWidth(int width) {
        this.maxWidth = width;
    }

    /**
     * Sets the maximum height for the dialog.
     * maxWidth is not affected by this method.
     * @param height
     */
    public void setMaxHeight(int height) {
        this.maxHeight = height;
    }

    /**
     * This class is internally used.
     * @author Alexander Bieber
     */
    private class ExpandableAreaComp {

        private Composite expComp = null;

        private Composite getComp() {
            return expComp;
        }

        private ExpandableAreaDialog dialog = null;

        private ExpandableAreaDialog getDialog() {
            return dialog;
        }

        /**
         * Calls {@link ExpandableAreaDialog#createStaticArea(Composite)}, creates an
         * {@link ExpandableComposite} and adds the result of
         * {@link ExpandableAreaDialog#createExpandableArea(Composite)} to it.
         * An anonymous {@link ExpansionAdapter} is added that handles
         * relayouting of the parent Dialog.
         * @param parent
         * @param dialog
         * @param expandText
         */
        public Composite createComposite(Composite parent, ExpandableAreaDialog dialog, String expandText) {
            if (dialog == null)
                throw new IllegalArgumentException(
                        this.getClass().getName() + "#createComposite: Parameter dialog can not be null."); //$NON-NLS-1$
            this.dialog = dialog;
            // create the Composite
            expComp = new Composite(parent, SWT.NONE);
            // LayoutData takes care of layouting within the dialog ...
            GridData myData = new GridData(GridData.FILL_BOTH);
            expComp.setLayoutData(myData);

            // Use a TableWrapLayout for the parent
            GridLayout layout = new GridLayout();
            expComp.setLayout(layout);

            // create the static Composite
            staticArea = createStaticArea(expComp);
            if (staticArea != null) {
                // take care of its layoutData
                GridData gdStatic = new GridData(GridData.FILL_BOTH);
                //            gdStatic.grabExcessHorizontalSpace = true;
                //            gdStatic.horizontalAlignment=GridData.FILL_;
                staticArea.setLayoutData(gdStatic);
            }

            // the ExpandableComposite
            ExpandableComposite expandableComposite = new ExpandableComposite(parent, SWT.NONE,
                    ExpandableComposite.TWISTIE | ExpandableComposite.COMPACT);
            expandableComposite.setText(expandText);
            IDialogSettings settings = getDialogBoundsSettings();
            if (settings != null)
                expandableComposite.setExpanded(settings.getBoolean(DIALOG_TWISTIE_EXPANSION_STATE));
            expandableComposite.addExpansionListener(new ExpansionAdapter() {
                /* (non-Javadoc)
                 * @see org.eclipse.ui.forms.events.ExpansionAdapter#expansionStateChanged(org.eclipse.ui.forms.events.ExpansionEvent)
                 */
                @Override
                public void expansionStateChanged(ExpansionEvent e) {
                    IDialogSettings settings = getDialogBoundsSettings();
                    if (settings != null)
                        settings.put(DIALOG_TWISTIE_EXPANSION_STATE, e.getState());
                    getComp().layout(true);
                    getDialog().doRelayout();
                }
            });
            GridData gd = new GridData(GridData.FILL_BOTH);
            expandableComposite.setLayoutData(gd);

            GridLayout ecLayout = new GridLayout();
            ecLayout.verticalSpacing = 5;
            ecLayout.horizontalSpacing = 5;
            expandableComposite.setLayout(ecLayout);

            // dummyComp wraps the expandable Comp one more time.
            // Workaround, otherwise half of first row in expandableArea
            // visible even when collapsed
            Composite dummyComp = new Composite(expandableComposite, SWT.NONE);
            gd = new GridData(GridData.FILL_BOTH);
            dummyComp.setLayoutData(gd);
            GridLayout gl = new GridLayout();
            dummyComp.setLayout(gl);

            expandableArea = createExpandableArea(dummyComp);
            if (expandableArea != null) {
                // set the LayoutData
                gd = new GridData(GridData.FILL_BOTH);
                expandableArea.setLayoutData(gd);
                // tell the parent to manage this as expandable client
                expandableComposite.setClient(dummyComp);
            }

            return expComp;
        }
    }
}