Package lcmc.common.ui

Source Code of lcmc.common.ui.ConfigDialog

/*
* This file is part of DRBD Management Console by LINBIT HA-Solutions GmbH
* written by Rasto Levrinc.
*
* Copyright (C) 2009, LINBIT HA-Solutions GmbH.
* Copyright (C) 2011-2012, Rastislav Levrinc.
*
* DRBD Management Console is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* DRBD Management Console 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with drbd; see the file COPYING.  If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package lcmc.common.ui;

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import javax.inject.Inject;
import javax.inject.Named;
import javax.swing.AbstractButton;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import lcmc.cluster.ui.widget.Widget;
import lcmc.cluster.ui.widget.WidgetFactory;
import lcmc.common.domain.Application;
import lcmc.common.ui.utils.MyButton;
import lcmc.common.domain.util.Tools;

/**
* An implementation of a dialog with buttons. Ok button is predefined.
* The dialogs should extend this class and overwrite at least
* getDialogTitle(), getDescription(), getInputPane() and nextDialog() methods.
*/
@Named
public abstract class ConfigDialog {
    private static final int INPUT_PANE_HEIGHT = 200;
    private volatile JOptionPane optionPane;
    private JDialog dialogPanel;
    private String pressedButton = "";
    private final Map<String, MyButton> buttonToObjectMap = new HashMap<String, MyButton>();
    private final StringBuilder answerPaneText = new StringBuilder(100);
    private JEditorPane answerPane = null;
    private final Collection<java.awt.Component> disabledComponents = new ArrayList<java.awt.Component>();
    private CountDownLatch dialogGate;
    private JCheckBox skipButton = null;
    private volatile Object optionPaneAnswer;
    private boolean skipButtonShouldBeEnabled = true;
    private final List<JComponent> additionalOptions = new ArrayList<JComponent>();
    @Inject
    private Application application;
    @Inject
    private WidgetFactory widgetFactory;
    private final MyButton[] options = new MyButton[buttons().length];
    @Inject
    private GUIData guiData;

    protected final JDialog getDialogPanel() {
        return dialogPanel;
    }

    final void setDialogPanel(final JDialog dialogPanel) {
        this.dialogPanel = dialogPanel;
    }

    final Point getLocation() {
        return dialogPanel.getLocation();
    }

    protected abstract String getDialogTitle();

    protected abstract String getDescription();

    protected abstract JComponent getInputPane();

    protected final JOptionPane getOptionPane() {
        return optionPane;
    }

    protected final JScrollPane getAnswerPane(final String initialText) {
        answerPane = new JEditorPane(GUIData.MIME_TYPE_TEXT_PLAIN, initialText);
        answerPane.setBackground(Tools.getDefaultColor("ConfigDialog.AnswerPane"));
        answerPane.setForeground(Color.WHITE);
        answerPane.setEditable(false);
        final JScrollPane scrollPane = new JScrollPane(answerPane);
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setMaximumSize(new Dimension(Short.MAX_VALUE, 80));
        scrollPane.setPreferredSize(new Dimension(Short.MAX_VALUE, 80));
        return scrollPane;
    }

    protected final void answerPaneSetText(final String text) {
        application.invokeLater(new Runnable() {
            @Override
            public void run() {
                final int l = answerPaneText.length();
                if (l > 1) {
                    answerPaneText.delete(0, l);
                }
                answerPaneText.append(text);
                answerPane.setText(answerPaneText.toString());
            }
        });
    }

    protected final void answerPaneAddText(final String text) {
        application.invokeLater(new Runnable() {
            @Override
            public void run() {
                answerPaneText.append('\n');
                answerPaneText.append(text);
                answerPaneSetText(answerPaneText.toString());
            }
        });
    }


    protected final void answerPaneSetTextError(final String text) {
        application.invokeLater(new Runnable() {
            @Override
            public void run() {
                answerPane.setForeground(Tools.getDefaultColor("ConfigDialog.AnswerPane.Error"));
                final int l = answerPaneText.length();
                if (l > 1) {
                    answerPaneText.delete(0, l);
                }
                answerPaneText.append(text);
                answerPane.setText(answerPaneText.toString());
            }
        });
    }

    protected final void answerPaneAddTextError(final String text) {
        application.invokeLater(new Runnable() {
            @Override
            public void run() {
                answerPaneText.append('\n');
                answerPaneText.append(text);
                answerPaneSetTextError(answerPaneText.toString());
            }
        });
    }

    /**
     * Creates body of the dialog. You can redefine getDialogTitle(),
     * getDescription(), getInputPane() methods to customize this
     * body.
     */
    protected final JPanel body() {
        final JPanel pane = new JPanel();
        pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS));
        final JEditorPane descPane = new JEditorPane(GUIData.MIME_TYPE_TEXT_HTML,
                                                     "<span style='font:bold italic;font-family:Dialog; font-size:"
                                                     + application.scaled(14)
                                                     + ";'>"
                                                     + getDialogTitle() + "</span><br>"
                                                     + "<span style='font-family:Dialog; font-size:"
                                                     + application.scaled(12)
                                                     + ";'>"
                                                     + getDescription() + "</span>");
        descPane.setSize(300, Integer.MAX_VALUE);

        descPane.setBackground(Tools.getDefaultColor("ConfigDialog.Background"));
        descPane.setEditable(false);
        final JScrollPane descSP = new JScrollPane(descPane);
        descSP.setBorder(null);
        descSP.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
        descSP.setMinimumSize(new Dimension(0, 50));
        pane.add(descSP);
        final JComponent inputPane = getInputPane();
        if (inputPane != null) {
            inputPane.setMinimumSize(new Dimension(Short.MAX_VALUE, INPUT_PANE_HEIGHT));
            inputPane.setBackground(Tools.getDefaultColor("ConfigDialog.Background"));
            inputPane.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
            pane.add(inputPane);
        }
        pane.setBackground(Tools.getDefaultColor("ConfigDialog.Background.Light"));
        return pane;
    }

    protected ImageIcon icon() {
        return Tools.createImageIcon(Tools.getDefault("ConfigDialog.Icon"));
    }

    /**
     * Array of buttons that are used in the dialog. Wrapper function
     * like okButton() should be used instead of simple "Ok", so
     * it can be localized. In TextResources.java file it can be than
     * redifined with ConfigDialog.Ok.
     */
    protected String[] buttons() {
        return new String[]{okButton()};
    }

    /**
     * Returns icons for buttons in the same order as the buttons are defined.
     */
    protected ImageIcon[] getIcons() {
        return new ImageIcon[]{null};
    }

    /** One default button from the buttons() method. */
    protected String defaultButton() {
        return okButton();
    }

    /** Compares pressed button with button that is passed as parameter. */
    public final boolean isPressedButton(final String button) {
        return pressedButton.equals(button);
    }

    /** Set pressed button to the string passed as a parameter. */
    protected final void setPressedButton(final String button) {
        pressedButton = button;
    }

    /** Returns localized string for Ok button. */
    final String okButton() {
        return buttonString("Ok");
    }


    /** Returns localized string of Cancel button. */
    protected String cancelButton() {
        return buttonString("Cancel");
    }

    /**
     * TextResource files contain texts in different languages. Text for every
     * button has to be defined there. If Ok button is used, resource file
     * has to contain ConfigDialog.Ok item.
     */
    protected final String buttonString(final String b) {
        return Tools.getString("Dialog.Dialog." + b);
    }

    /**
     * Returns class of the button, so that it can be enabled or
     * disabled.
     */
    protected final MyButton buttonClass(final String button) {
        return buttonToObjectMap.get(button);
    }

    /** This method is called before the dialog is screated.  */
    protected void initDialogBeforeCreated() {
    }

    /**
     * This method is called before the dialog is shown but it was created.
     * It also disables buttons. They have to be enabled with enableComponents()
     */
    protected void initDialogBeforeVisible() {
    }

    /**
     * This method is called immediatly after the dialog is shown.
     */
    protected void initDialogAfterVisible() {
    }

    /**
     * This method is called during every insert, update and remove events of
     * field that was added with addCheckField(). It does nothing by default.
     */
    protected void checkFields(final Widget field) {
        /* Does nothing by default. */
    }

    /**
     * Add listener to the field. The checkFields(field) will be called on every
     * insert, update and remove event.
     */
    protected final void addCheckField(final Widget field) {
        field.getDocument().addDocumentListener(
                new DocumentListener() {
                    @Override
                    public void insertUpdate(final DocumentEvent e) {
                        final Thread t = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                checkFields(field);
                            }
                        });
                        t.start();
                    }

                    @Override
                    public void removeUpdate(final DocumentEvent e) {
                        final Thread t = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                checkFields(field);
                            }
                        });
                        t.start();
                    }

                    @Override
                    public void changedUpdate(final DocumentEvent e) {
                        final Thread t = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                checkFields(field);
                            }
                        });
                        t.start();
                    }
                });
    }

    /** This method is called after user has pushed the button. */
    protected ConfigDialog checkAnswer() {
        return null;
    }

    /** Returns the width of the dialog. */
    protected int dialogWidth() {
        return Tools.getDefaultInt("ConfigDialog.width");
    }

    /** Returns the height of the dialog. */
    protected int dialogHeight() {
        return Tools.getDefaultInt("ConfigDialog.height");
    }

    /**
     * Returns the message type of the JOptionPane. Default is
     * INFORMATION_MESSAGE.
     */
    protected int getMessageType() {
        return JOptionPane.INFORMATION_MESSAGE;
    }

    /** Whether the skip button is enabled. */
    protected boolean skipButtonEnabled() {
        return false;
    }

    /** Returns the listener for the skip button. */
    protected ItemListener skipButtonListener() {
        return null;
    }

    /** Returns whether skip button is selected. */
    protected final boolean skipButtonIsSelected() {
        return skipButton != null && skipButton.isSelected();
    }

    /** Enable/disable skip button. */
    protected final void skipButtonSetEnabled(final boolean enable) {
        skipButtonShouldBeEnabled = enable;
    }

    /**
     * Shows dialog and wait for answer.
     * Returns next dialog, or null if it there is no next dialog.
     */
    public final ConfigDialog showDialog() {
        /* making non modal dialog */
        dialogGate = new CountDownLatch(1);
        dialogPanel = null; /* TODO: disabled caching because back button
                               wouldn't work with
                               dialogPanel.setContentPane(optionPane) method
                               it would work with optionPane.createDialog...
                               but that causes lockups with old javas and
                               gnome. */
        initDialogBeforeCreated();
        if (dialogPanel == null) {
            final ImageIcon[] icons = getIcons();
            final Collection<JComponent> allOptions = new ArrayList<JComponent>(additionalOptions);
            if (skipButtonEnabled()) {
                skipButton = new JCheckBox(Tools.getString("Dialog.ConfigDialog.SkipButton"));
                skipButton.setEnabled(false);
                skipButton.setBackground(Tools.getDefaultColor("ConfigDialog.Background.Light"));
                skipButton.addItemListener(skipButtonListener());
                allOptions.add(skipButton);
            }
            final String[] buttons = buttons();
            /* populate buttonToObjectMap */
            MyButton defaultButtonClass = null;
            for (int i = 0; i < buttons.length; i++) {
                options[i] = widgetFactory.createButton(buttons[i], icons[i]);
                options[i].setBackgroundColor(Tools.getDefaultColor("ConfigDialog.Button"));
                allOptions.add(options[i]);
                buttonToObjectMap.put(buttons[i], options[i]);
                if (buttons[i].equals(defaultButton())) {
                    defaultButtonClass = options[i];
                }
            }
            /* create option pane */
            final MyButton dbc = defaultButtonClass;
            application.invokeAndWait(new Runnable() {
                @Override
                public void run() {
                    optionPane = new JOptionPane(body(),
                                                 getMessageType(),
                                                 JOptionPane.DEFAULT_OPTION,
                                                 icon(),
                                                 allOptions.toArray(new JComponent[allOptions.size()]),
                                                 dbc);
                    optionPane.setPreferredSize(new Dimension(dialogWidth(), dialogHeight()));
                    optionPane.setMaximumSize(new Dimension(dialogWidth(), dialogHeight()));
                    optionPane.setMinimumSize(new Dimension(dialogWidth(), dialogHeight()));

                    optionPane.setBackground(Tools.getDefaultColor( "ConfigDialog.Background.Dark"));
                    final Container mainFrame = guiData.getMainFrame();
                    if (mainFrame instanceof JApplet) {
                        final JFrame noframe = new JFrame();
                        dialogPanel = new JDialog(noframe);
                        dialogPanel.setContentPane(optionPane);
                    } else {
                        dialogPanel = new JDialog((Frame) mainFrame);
                        dialogPanel.setContentPane(optionPane);
                    }
                    dialogPanel.addWindowListener(new WindowAdapter() {
                        @Override
                        public void windowClosing(final WindowEvent e) {
                            disposeDialog();
                        }
                    });
                    dialogPanel.setModal(false);
                    dialogPanel.setResizable(true);
                }
            });
            /* set location like the previous dialog */
        }
        /* add action listeners */
        final Map<MyButton, OptionPaneActionListener> optionPaneActionListeners =
                                                                     new HashMap<MyButton, OptionPaneActionListener>();
        for (final MyButton o : options) {
            final OptionPaneActionListener ol = new OptionPaneActionListener();
            optionPaneActionListeners.put(o, ol);
            o.addActionListener(ol);
        }

        final PropertyChangeListener propertyChangeListener =
            new PropertyChangeListener() {
                @Override
                public void propertyChange(final PropertyChangeEvent evt) {
                    if (JOptionPane.VALUE_PROPERTY.equals(evt.getPropertyName())
                        && !"uninitializedValue".equals(evt.getNewValue())) {
                        optionPaneAnswer = optionPane.getValue();
                        dialogGate.countDown();
                    }
                }
            };
        optionPane.addPropertyChangeListener(propertyChangeListener);
        initDialogBeforeVisible();
        application.invokeAndWait(new Runnable() {
            @Override
            public void run() {
                dialogPanel.setPreferredSize(new Dimension(dialogWidth(), dialogHeight()));
                dialogPanel.setMaximumSize(new Dimension(dialogWidth(), dialogHeight()));
                dialogPanel.setMinimumSize(new Dimension(dialogWidth(), dialogHeight()));
                dialogPanel.setLocationRelativeTo(guiData.getMainFrame());
                dialogPanel.setVisible(true);
            }
        });
        application.invokeLater(new Runnable() {
            @Override
            public void run() {
                dialogPanel.setLocationRelativeTo(guiData.getMainFrame());
                /* although the location was set before, it is set again as a
                 * workaround for gray dialogs with nothing in it, that appear
                 * in some comination of Java and compiz. */
            }
        });
        initDialogAfterVisible();
        try {
            dialogGate.await();
        } catch (final InterruptedException ignored) {
            Thread.currentThread().interrupt();
        }

        if (optionPaneAnswer instanceof String) {
            setPressedButton((String) optionPaneAnswer);
        } else {
            setPressedButton(cancelButton());
        }
        optionPane.removePropertyChangeListener(propertyChangeListener);
        /* remove action listeners */
        for (final MyButton o : options) {
            o.removeActionListener(optionPaneActionListeners.get(o));
        }
        dialogPanel.dispose();
        return checkAnswer();
    }

    /**
     * Disables array of components and all the buttons. The ones that
     * were enabled are stored in disabledComponents list so that they
     * can be later enabled with call to enableComponents.
     */
    protected final void disableComponents(final java.awt.Component[] components) {
        application.invokeLater(new Runnable() {
            @Override
            public void run() {
                for (final String b : buttons()) {
                    final JComponent option = buttonClass(b);
                    if (option.isEnabled()) {
                        disabledComponents.add(option);
                        option.setEnabled(false);
                    }
                }
                for (final java.awt.Component c : components) {
                    if (c.isEnabled()) {
                        disabledComponents.add(c);
                        c.setEnabled(false);
                    }
                }
            }
        });
    }

    /**
     * Disables all the option buttons. The ones that
     * were enabled are stored in disabledComponents list so that they
     * can be later enabled with call to enableComponents.
     */
    protected final void disableComponents() {
        disableComponents(new JComponent[]{});
    }

    /**
     * Enables components that were disabled with disableComponents, except
     * the ones that are in componentsToDisable array.
     */
    protected void enableComponents(final JComponent[] componentsToDisable) {
        final Collection<java.awt.Component> ctdHash = new HashSet<java.awt.Component>(Arrays.asList(componentsToDisable));
        application.invokeLater(new Runnable() {
            @Override
            public void run() {
                for (final java.awt.Component dc : disabledComponents) {
                    if (!ctdHash.contains(dc)) {
                        dc.setEnabled(true);
                    }
                }
                disabledComponents.clear();
                if (skipButton != null) {
                    skipButton.setEnabled(skipButtonShouldBeEnabled);
                }
            }
        });
    }

    /**
     * Enables components after disableComponents, but they will be really
     * enabled only after enableComponents without arguments is be called.
     */
    protected void enableComponentsLater(final JComponent[] componentsToEnable) {
        Collections.addAll(disabledComponents, componentsToEnable);
    }

    /** Enables components that were disabled with disableComponents. */
    protected void enableComponents() {
        enableComponents(new JComponent[]{});
    }

    /** Is called after dialog was canceled. It does nothing by default. */
    public void cancelDialog() {
        /* Does nothing by default. */
    }

    /** Returns panel with checkbox. */
    protected final JPanel getComponentPanel(final String text, final java.awt.Component component) {
        final JPanel mp = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
        mp.setBackground(Tools.getDefaultColor("ConfigDialog.Background"));
        mp.add(new JLabel(text));
        mp.add(new JLabel(" "));
        mp.add(component);
        mp.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
        return mp;
    }

    /** Close dialog other than pressing button. */
    protected final void disposeDialog() {
        dialogGate.countDown();
    }

    /** Add the compoment to the options. */
    protected final void addToOptions(final JComponent c) {
        additionalOptions.add(c);
    }

    /**
     * Action listener for custom buttons.
     */
    class OptionPaneActionListener implements ActionListener {

        /**
         * Action performered on custom button.
         */
        @Override
        public void actionPerformed(final ActionEvent e) {
            final Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    application.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            optionPane.setValue(((AbstractButton) e.getSource()).getText());
                        }
                    });
                }
            });
            t.start();
        }
    }
}
TOP

Related Classes of lcmc.common.ui.ConfigDialog

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.