org.mailster.gui.prefs.ConfigurationDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.mailster.gui.prefs.ConfigurationDialog.java

Source

/*******************************************************************************
 * Copyright notice                                                            *
 *                                                                             *
 * Copyright (c) 2005-2006 Feed'n Read Development Team                        *
 * http://sourceforge.net/fnr                                                  *
 *                                                                             *
 * All rights reserved.                                                        *
 *                                                                             *
 * This program and the accompanying materials are made available under the    *
 * terms of the Common Public License v1.0 which accompanies this distribution,*
 * and is available at                                                         *
 * http://www.eclipse.org/legal/cpl-v10.html                                   *
 *                                                                             *
 * A copy is found in the file cpl-v10.html and important notices to the       *
 * license from the team is found in the textfile LICENSE.txt distributed      *
 * in this package.                                                            *
 *                                                                             *
 * This copyright notice MUST APPEAR in all copies of the file.                *
 *                                                                             *
 * Contributors:                                                               *
 *    Feed'n Read - initial API and implementation                             *
 *                  (smachhau@users.sourceforge.net)                           *
 *******************************************************************************/
package org.mailster.gui.prefs;

import java.util.Iterator;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceNode;
import org.eclipse.jface.preference.IPreferencePage;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.preference.PreferenceManager;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.Policy;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.HelpEvent;
import org.eclipse.swt.events.HelpListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
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.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.mailster.gui.Messages;
import org.mailster.gui.SWTHelper;
import org.mailster.gui.prefs.pages.EnclosuresConfigurationPage;
import org.mailster.gui.prefs.pages.GeneralConfigurationPage;
import org.mailster.gui.prefs.pages.LanguageConfigurationPage;
import org.mailster.gui.prefs.pages.POP3ConfigurationPage;
import org.mailster.gui.prefs.pages.ProtocolsConfigurationPage;
import org.mailster.gui.prefs.pages.SMTPConfigurationPage;
import org.mailster.gui.prefs.pages.TrayConfigurationPage;
import org.mailster.gui.prefs.widgets.DialogMessageArea;
import org.mailster.gui.prefs.widgets.ExtendedPreferenceNode;
import org.mailster.gui.utils.DialogUtils;

/**
 * <code>Dialog</code> to manage the application configuration on end-user
 * side.
 * 
 * @author <a href="mailto:smachhau@users.sourceforge.net">Sebastian Machhausen</a>
 *         This file has been used and modified.
 * @author <a href="mailto:doe_wanted@yahoo.fr">Edouard De Oliveira</a>
 */
public class ConfigurationDialog extends PreferenceDialog {
    /**
     * The customized <code>DialogMessageArea</code>
     */
    private DialogMessageArea messageArea;

    /**
     * The last successful <code>IPreferenceNode</code> visited
     */
    private IPreferenceNode lastSuccessfulNode;

    /**
     * Creates a new <code>ConfigurationDialog</code> under the control of the
     * given <code>PreferenceManager</code>.
     * 
     * @param parentShell the parent <code>Shell</code>l
     * @param manager the <code>PreferenceManager</code> which controls this
     *            <code>ConfigurationDialog</code>
     */
    public ConfigurationDialog(Shell parentShell, PreferenceManager manager) {
        super(parentShell, manager);
    }

    public void create() {
        super.create();
        getShell().setSize(getShell().computeSize(540, SWT.DEFAULT, true));
    }

    /**
     * <p>
     * Sets the message for this dialog with an indication of what type of
     * message it is.
     * </p>
     * <p>
     * The valid message types are one of <code>NONE</code>,
     * <code>INFORMATION</code>,<code>WARNING</code>, or
     * <code>ERROR</code>.
     * </p>
     * <p>
     * Note that for backward compatibility, a message of type
     * <code>ERROR</code> is different than an error message (set using
     * <code>setErrorMessage</code>). An error message overrides the current
     * message until the error message is cleared. This method replaces the
     * current message and does not affect the error message.
     * </p>
     * 
     * @param newMessage the message, or <code>null</code> to clear the
     *            message
     * @param newType the message type
     * @see org.eclipse.jface.preference.PreferenceDialog#setMessage(String,
     *      int)
     */
    public void setMessage(String newMessage, int newType) {
        this.messageArea.updateText(newMessage, newType);
    }

    /**
     * Display the given error message. The currently displayed message is saved
     * and will be redisplayed when the error message is set to
     * <code>null</code>.
     * 
     * @param newErrorMessage the errorMessage to display or <code>null</code>
     */
    public void setErrorMessage(String newErrorMessage) {
        if (newErrorMessage == null) {
            this.messageArea.clearErrorMessage();
        } else {
            this.messageArea.updateText(newErrorMessage, IMessageProvider.ERROR);
        }
    }

    /**
     * Updates the message.
     * 
     * @see org.eclipse.jface.preference.IPreferencePageContainer#updateMessage()
     */
    public void updateMessage() {
        String message = null;
        String errorMessage = null;
        boolean showingError = false;
        IPreferencePage currentPage = this.getCurrentPage();

        if (currentPage != null) {
            message = currentPage.getMessage();
            errorMessage = currentPage.getErrorMessage();
        }
        int messageType = IMessageProvider.NONE;
        if (message != null && currentPage instanceof IMessageProvider) {
            messageType = ((IMessageProvider) currentPage).getMessageType();
        }

        if (errorMessage == null) {
            if (showingError) {
                // we were previously showing an error
                showingError = false;
            }
        } else {
            message = errorMessage;
            messageType = IMessageProvider.ERROR;
            if (!showingError) {
                // we were not previously showing an error
                showingError = true;
            }
        }
        this.messageArea.updateText(message, messageType);
    }

    /**
     * Updates the title.
     * 
     * @see org.eclipse.jface.preference.IPreferencePageContainer#updateTitle()
     */
    public void updateTitle() {
        IPreferencePage currentPage = this.getCurrentPage();
        if (currentPage == null) {
            return;
        }
        this.messageArea.showTitle(currentPage.getTitle(), currentPage.getImage());
    }

    /**
     * Updates the buttons.
     * 
     * @see org.eclipse.jface.preference.IPreferencePageContainer#updateButtons()
     */
    public void updateButtons() {
        Button okButton = this.getButton(IDialogConstants.OK_ID);
        okButton.setEnabled(this.isCurrentPageValid());
    }

    /**
     * Add the listeners to the tree viewer.
     * 
     * @param viewer
     * @since 3.1
     */
    protected void addListeners(final TreeViewer viewer) {
        viewer.addPostSelectionChangedListener(new ISelectionChangedListener() {
            private void handleError() {
                try {
                    // remove the listener temporarily so that the events caused
                    // by the error handling dont further cause error handling
                    // to occur.
                    viewer.removePostSelectionChangedListener(this);
                    showPageFlippingAbortError();
                    selectLastVisitedPageAgain();
                    clearLastSelectedNode();
                } finally {

                    viewer.addPostSelectionChangedListener(this);
                }
            }

            public void selectionChanged(SelectionChangedEvent event) {
                Object selection = getSingleSelection(event.getSelection());
                if (selection instanceof IPreferenceNode) {
                    if (!isCurrentPageValid()) {
                        handleError();
                    } else if (!showPage((IPreferenceNode) selection)) {
                        // Page flipping wasn't successful
                        handleError();
                    } else {
                        // Everything went well
                        lastSuccessfulNode = (IPreferenceNode) selection;
                    }
                }
            }
        });
        ((Tree) viewer.getControl()).addSelectionListener(new SelectionAdapter() {
            public void widgetDefaultSelected(final SelectionEvent event) {
                ISelection selection = viewer.getSelection();
                if (selection.isEmpty())
                    return;
                IPreferenceNode singleSelection = getSingleSelection(selection);
                boolean expanded = viewer.getExpandedState(singleSelection);
                viewer.setExpandedState(singleSelection, !expanded);
            }
        });
        // Register help listener on the tree to use context sensitive help
        viewer.getControl().addHelpListener(new HelpListener() {
            public void helpRequested(HelpEvent event) {
                // call perform help on the current page
                if (getCurrentPage() != null) {
                    getCurrentPage().performHelp();
                }
            }
        });
    }

    /**
     * The preference dialog implementation of this <code>Dialog</code>
     * framework method sends <code>performOk</code> to all pages of the
     * preference dialog, then calls <code>handleSave</code> on this dialog to
     * save any state, and then calls <code>close</code> to close this dialog.
     */
    protected void okPressed() {
        SafeRunnable.run(new SafeRunnable() {
            private boolean errorOccurred;

            /**
             * @see org.eclipse.core.runtime.ISafeRunnable#run()
             */
            public void run() {
                // getButton(IDialogConstants.OK_ID).setEnabled(false);
                errorOccurred = false;
                boolean hasFailedOK = false;
                try {
                    PreferenceManager preferenceManager = getPreferenceManager();
                    // Notify all the pages and give them a chance to abort
                    Iterator<?> nodes = preferenceManager.getElements(PreferenceManager.PRE_ORDER).iterator();
                    while (nodes.hasNext()) {
                        IPreferenceNode node = (IPreferenceNode) nodes.next();
                        IPreferencePage page = node.getPage();
                        if (page != null) {
                            if (!page.performOk()) {
                                hasFailedOK = true;
                                return;
                            }
                        }
                    }
                } catch (Exception e) {
                    handleException(e);
                } finally {
                    // Don't bother closing if the OK failed
                    if (hasFailedOK) {
                        return;
                    }
                    if (!errorOccurred) {
                        // Give subclasses the choice to save the state of the
                        // preference pages.
                        handleSave();
                    }

                    close();
                }
            }

            /**
             * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
             */
            public void handleException(Throwable e) {
                errorOccurred = true;
                Policy.getLog().log(new Status(IStatus.ERROR, Policy.JFACE, 0, e.toString(), e));

                clearLastSelectedNode();
                String message = JFaceResources.getString("SafeRunnable.errorMessage"); //$NON-NLS-1$
                MessageDialog.openError(getShell(), JFaceResources.getString("Error"), message); //$NON-NLS-1$
            }
        });
    }

    /**
     * Creates the wizard's title area.
     * 
     * @param parent the SWT parent for the title area composite
     * @return the created title area composite
     */
    protected Composite createTitleArea(Composite parent) {
        /*
         * Create the title area which will contai a title, message, and image.
         */
        int margins = 2;
        Composite titleArea = new Composite(parent, SWT.NONE);
        FormLayout layout = new FormLayout();
        layout.marginHeight = 5;
        layout.marginWidth = margins;
        titleArea.setLayout(layout);

        GridData layoutData = new GridData(GridData.FILL_HORIZONTAL);
        layoutData.verticalAlignment = SWT.TOP;
        titleArea.setLayoutData(layoutData);

        /* Message label */
        this.messageArea = new DialogMessageArea();
        this.messageArea.createContents(titleArea);

        titleArea.addControlListener(new ControlAdapter() {
            /**
             * @see org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse.swt.events.ControlEvent)
             */
            public void controlResized(ControlEvent e) {
                updateMessage();
            }
        });

        final IPropertyChangeListener fontListener = new IPropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent event) {
                if (JFaceResources.BANNER_FONT.equals(event.getProperty()))
                    updateMessage();
                if (JFaceResources.DIALOG_FONT.equals(event.getProperty())) {
                    updateMessage();
                    Font dialogFont = JFaceResources.getDialogFont();
                    updateTreeFont(dialogFont);
                    Control[] children = ((Composite) buttonBar).getChildren();
                    for (int i = 0; i < children.length; i++)
                        children[i].setFont(dialogFont);
                }
            }
        };

        titleArea.addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent event) {
                JFaceResources.getFontRegistry().removeListener(fontListener);
            }
        });
        JFaceResources.getFontRegistry().addListener(fontListener);
        this.messageArea.setTitleLayoutData(this.createMessageAreaData());
        this.messageArea.setMessageLayoutData(this.createMessageAreaData());

        return (titleArea);
    }

    /**
     * Creates the buttons for the embedded hutton bar.
     * 
     * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
     */
    protected void createButtonsForButtonBar(Composite parent) {
        Button okButton = null;
        Button cancelButton = null;

        if (Display.getDefault().getDismissalAlignment() == SWT.LEFT) {
            /* Default dismissal button (OK) has to be on the left side */

            // Create OK Button
            okButton = this.createButton(parent, IDialogConstants.OK_ID, Messages.getString("okButton"), true);

            // Create Cancel Button
            cancelButton = this.createButton(parent, IDialogConstants.CANCEL_ID, Messages.getString("cancelButton"),
                    false);
        } else {
            /* Default dismissal button (OK) has to be on the right side */

            // Create Cancel Button
            cancelButton = this.createButton(parent, IDialogConstants.CANCEL_ID, Messages.getString("cancelButton"),
                    true);

            // Create OK Button
            okButton = this.createButton(parent, IDialogConstants.OK_ID, Messages.getString("okButton"), false);
        }
        // Set Image for OK button and adjust layout
        this.setButtonLayoutData(okButton);

        // Set Image for cancel button and adjust layout
        this.setButtonLayoutData(cancelButton);
    }

    /**
     * Create the <code>Sash</code>with left control on the left. Note that
     * this method assumes <code>GridData</code> for the layout data of the
     * leftControl.
     * 
     * @param composite the <code>Composite</code> to embed the
     *            <code>Sash</code> into
     * @param leftControl the <code>Control</code> at the left side of the
     *            <code>Sash</code>
     * @return Sash the created <code>Sash</code>
     */
    protected Sash createSash(final Composite composite, final Control leftControl) {
        final Sash sash = new Sash(composite, SWT.VERTICAL);
        sash.setLayoutData(new GridData(GridData.FILL_VERTICAL));
        sash.setBackground(composite.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
        sash.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event event) {
                if (event.detail == SWT.DRAG)
                    return;

                int shift = event.x - sash.getBounds().x;
                GridData data = (GridData) leftControl.getLayoutData();
                int newWidthHint = data.widthHint + shift;
                int maxSize = getPageContainer().getSize().x / 2;
                if (newWidthHint > maxSize || newWidthHint < 70) {
                    event.doit = false;
                    return;
                }
                data.widthHint = newWidthHint;
                composite.layout(true);
            }
        });
        return (sash);
    }

    /**
     * Shows the preference page corresponding to the given preference node.
     * Does nothing if that page is already current. This implementation
     * prevents auto resizing.
     * 
     * @param node the preference node, or <code>null</code> if none
     * @return <code>true</code> if the page flip was successful;
     *         <code>false</code> if unsuccessful
     */
    protected boolean showPage(IPreferenceNode node) {
        IPreferencePage currentPage = this.getCurrentPage();
        final Composite pageContainer = this.getPageContainer();

        if (node == null)
            return false;

        // Create the page if nessessary
        if (node.getPage() == null)
            this.createPage(node);

        if (node.getPage() == null)
            return false;

        IPreferencePage newPage = this.getPage(node);
        if (newPage == currentPage)
            return true;

        if (currentPage != null && !currentPage.okToLeave())
            return (false);

        IPreferencePage oldPage = currentPage;
        this.setCurrentPage(newPage);
        currentPage = this.getCurrentPage();
        // Set the new page's container
        currentPage.setContainer(this);

        // Ensure that the page control has been created
        // (this allows lazy page control creation)
        final IPreferencePage curPage = currentPage;
        if (currentPage.getControl() == null) {
            final boolean[] failed = { false };
            SafeRunnable.run(new ISafeRunnable() {
                public void handleException(Throwable e) {
                    failed[0] = true;
                }

                public void run() {
                    createPageControl(curPage, pageContainer);
                }
            });
            if (failed[0])
                return false;
            // the page is responsible for ensuring the created control is
            // accessable via getControl.
            Assert.isNotNull(currentPage.getControl());
        }

        // Force calculation of the page's description label because
        // label can be wrapped.
        final Point[] size = new Point[1];
        final Point failed = new Point(-1, -1);
        SafeRunnable.run(new ISafeRunnable() {
            public void handleException(Throwable e) {
                size[0] = failed;
            }

            public void run() {
                size[0] = curPage.computeSize();
            }
        });
        if (size[0].equals(failed))
            return false;

        // Do we need resizing. Computation not needed if the
        // first page is inserted since computing the dialog's
        // size is done by calling dialog.open().
        // Also prevent auto resize if the user has manually resized
        if (oldPage != null) {
            Rectangle rect = pageContainer.getClientArea();
            Point containerSize = new Point(rect.width, rect.height);
            // Set the size to be sure we use the result of computeSize
            currentPage.setSize(containerSize);
        }
        // Ensure that all other pages are invisible
        // (including ones that triggered an exception during
        // their creation).
        Control[] children = pageContainer.getChildren();
        Control currentControl = currentPage.getControl();
        for (int i = 0; i < children.length; i++) {
            if (children[i] != currentControl)
                children[i].setVisible(false);
        }
        // Make the new page visible
        currentPage.setVisible(true);
        if (oldPage != null)
            oldPage.setVisible(false);

        // update the dialog controls
        this.update();
        return true;
    }

    /**
     * Selects the page determined by <code>lastSuccessfulNode</code> in the
     * page hierarchy.
     */
    private void selectLastVisitedPageAgain() {
        if (lastSuccessfulNode == null) {
            return;
        }
        this.getTreeViewer().setSelection(new StructuredSelection(lastSuccessfulNode));
        this.getCurrentPage().setVisible(true);
    }

    /**
     * Clear the last selected node. This is so that we not chache the last
     * selection in case of an error.
     */
    private void clearLastSelectedNode() {
        this.setSelectedNodePreference(null);
    }

    /**
     * Shows an error indicating that the status of the currently selected page
     * is inavlid and has to be corrected.
     */
    private void showPageFlippingAbortError() {
        this.setErrorMessage(Messages.getString("pageAbortErrorMessage"));
    }

    /**
     * Create the layout data for the message area.
     * 
     * @return FormData for the message area.
     */
    private FormData createMessageAreaData() {
        FormData messageData = new FormData();
        messageData.top = new FormAttachment(0);
        messageData.bottom = new FormAttachment(100);
        messageData.right = new FormAttachment(100);
        messageData.left = new FormAttachment(0);

        return (messageData);
    }

    /**
     * Creates and shows the configuration dialog.
     * 
     * @param shell the shell to attach to
     */
    public static void run(Shell shell) {
        /* Create the preference manager */
        PreferenceManager mgr = new PreferenceManager();
        createPreferenceTree(mgr);

        /* Create and open the ConfigurationDialog */
        ConfigurationDialog dlg = new ConfigurationDialog(shell, mgr);

        dlg.setPreferenceStore(ConfigurationManager.CONFIG_STORE);
        dlg.create();
        dlg.getShell().setText(Messages.getString("configurationDialogTitle"));
        dlg.getShell().setImage(SWTHelper.loadImage("config.gif"));
        Point minSize = new Point(690, 480);
        dlg.getShell().setSize(minSize);
        dlg.setMinimumPageSize(minSize);
        dlg.getShell().setMinimumSize(minSize);
        DialogUtils.centerShellOnParentShell(dlg.getShell());
        dlg.getTreeViewer().expandAll();
        dlg.open();
    }

    /**
     * Creates the preference tree structure.
     * 
     * @param mgr the <code>PreferenceManager</code> that the <code>PreferenceNode</code>s
     * should be embedded in
     */
    private static void createPreferenceTree(PreferenceManager mgr) {
        /* Create the nodes representing the single preference pages */
        ExtendedPreferenceNode generalNode = new ExtendedPreferenceNode(ConfigurationManager.GENERAL_OPTIONS_KEY,
                Messages.getString("generalConfigurationPageTitle"),
                SWTHelper.getImageDescriptor("wizard/generalConfig16.png"),
                GeneralConfigurationPage.class.getName());

        ExtendedPreferenceNode languageNode = new ExtendedPreferenceNode(ConfigurationManager.LANGUAGE_OPTIONS_KEY,
                Messages.getString("languageConfigurationPageTitle"),
                SWTHelper.getImageDescriptor("wizard/languageConfig16.png"),
                LanguageConfigurationPage.class.getName());

        ExtendedPreferenceNode trayNode = new ExtendedPreferenceNode(ConfigurationManager.TRAY_OPTIONS_KEY,
                Messages.getString("trayConfigurationPageTitle"),
                SWTHelper.getImageDescriptor("wizard/trayConfig16.png"), TrayConfigurationPage.class.getName());

        ExtendedPreferenceNode smtpNode = new ExtendedPreferenceNode(ConfigurationManager.SMTP_OPTIONS_KEY,
                Messages.getString("smtpConfigurationPageTitle"),
                SWTHelper.getImageDescriptor("wizard/proxyConfig16.png"), SMTPConfigurationPage.class.getName());

        ExtendedPreferenceNode pop3Node = new ExtendedPreferenceNode(ConfigurationManager.POP3_OPTIONS_KEY,
                Messages.getString("pop3ConfigurationPageTitle"),
                SWTHelper.getImageDescriptor("wizard/proxyConfig16.png"), POP3ConfigurationPage.class.getName());

        ExtendedPreferenceNode connectionNode = new ExtendedPreferenceNode(
                ConfigurationManager.PROTOCOLS_OPTIONS_KEY, Messages.getString("protocolsConfigurationPageTitle"),
                SWTHelper.getImageDescriptor("wizard/connectionConfig16.png"),
                ProtocolsConfigurationPage.class.getName());

        ExtendedPreferenceNode enclosuresNode = new ExtendedPreferenceNode(
                ConfigurationManager.ENCLOSURES_OPTIONS_KEY, Messages.getString("enclosuresConfigurationPageTitle"),
                SWTHelper.getImageDescriptor("wizard/enclosureConfig16.png"),
                EnclosuresConfigurationPage.class.getName());

        /* Add the nodes to the PreferenceManager */
        mgr.addToRoot(generalNode);
        generalNode.add(trayNode);
        generalNode.add(languageNode);

        mgr.addToRoot(enclosuresNode);

        mgr.addToRoot(connectionNode);
        connectionNode.add(smtpNode);
        connectionNode.add(pop3Node);
    }
}