All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jaxx.runtime.swing.config.ConfigUIHandler Maven / Gradle / Ivy

There is a newer version: 3.0-alpha-1
Show newest version
package jaxx.runtime.swing.config;

/*
 * #%L
 * JAXX :: Config
 * %%
 * Copyright (C) 2008 - 2014 Code Lutin, Tony Chemit
 * %%
 * This program 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 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */

import jaxx.runtime.JAXXUtil;
import jaxx.runtime.SwingUtil;
import jaxx.runtime.context.JAXXInitialContext;
import jaxx.runtime.swing.config.model.CallBackEntry;
import jaxx.runtime.swing.config.model.CallBackMap;
import jaxx.runtime.swing.config.model.CategoryModel;
import jaxx.runtime.swing.config.model.ConfigUIModel;
import jaxx.runtime.swing.config.model.OptionModel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultSingleSelectionModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import java.awt.Container;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;

import static org.nuiton.i18n.I18n.t;

/**
 * Handler of the {@link ConfigUI} ui.
 *
 * @author Tony Chemit - [email protected]
 * @since 2.5.11
 */
public class ConfigUIHandler {

    public static final Log log = LogFactory.getLog(ConfigUIHandler.class);

    public static final String CALLBACKS_WITH_OPTIONS = "callbacksWithOptions";

    public static final String CALLBACKS = "callbacks";

    public static final String QUIT_ACTION = "quit";

    private final ConfigUI ui;

    /**
     * Set this container if you want to use the ui inside another one (a.k.a not in standalone mode).
     */
    private Container topContainer;


    /**
     * To customize the config call back ui before showning it.
     *
     * @since 2.37
     */
    private ConfigCallBackUICustomizer configCallBackUICustomizer;

    /**
     * To be able to veto a change of a category.
     *
     * @since 2.6
     */
    public static interface ChangeCategoryCallBack {
        boolean canChangeCategory(String categoryName);
    }

    private ChangeCategoryCallBack changeCategoryCallBack;

    public ConfigUIHandler(ConfigUI ui) {
        this.ui = ui;
    }

    public void setChangeCategoryCallBack(ChangeCategoryCallBack changeCategoryCallBack) {
        this.changeCategoryCallBack = changeCategoryCallBack;
    }

    public void initUI(String defaultCategory) {

        ConfigUIModel model = ui.getModel();

        JTabbedPane categories = ui.getCategories();

        categories.setModel(new DefaultSingleSelectionModel() {

            private static final long serialVersionUID = 1L;

            @Override
            public void setSelectedIndex(int index) {
                // check if catgeory can be quit
                boolean canContinue = !isSelected() || canQuitCategory();
                if (canContinue) {
                    // was authorized to leave previous category
                    if (log.isDebugEnabled()) {
                        log.debug("new index : " + index);
                    }
                    String categoryName = ConfigUIHandler.this.ui.getModel().getCategoryName(index);
                    if (changeCategoryCallBack == null || changeCategoryCallBack.canChangeCategory(categoryName)) {
                        // can change category
                        super.setSelectedIndex(index);
                    }
                }
            }
        });

        JButton quitButton = ui.getQuit();

        // prepare quit action
        Action quitAction = createQuitAction();

        String tip = quitButton.getToolTipText();
        quitButton.setAction(quitAction);
        quitButton.setToolTipText(tip);

        // build categories tabs
        for (CategoryModel categoryModel : model) {
            String category = categoryModel.getCategory();
            String categoryLabel = t(categoryModel.getCategoryLabel());
            ConfigCategoryUI p = new ConfigCategoryUI(
                    new JAXXInitialContext().add(ui).add(categoryModel));
            p.getCategoryLabel().setText(categoryLabel);
            p.setName(category);
            categories.addTab(t(category), null, p, categoryLabel);
        }

        model.setCategory(defaultCategory);
        int categoryIndex = model.getCategoryIndex(defaultCategory);
        if (log.isDebugEnabled()) {
            log.debug("index of default category (" + defaultCategory + ")  : "
                      + categoryIndex);
        }
        categories.setSelectedIndex(categoryIndex);
    }

    public void destroy() {
        if (log.isDebugEnabled()) {
            log.debug("destroy ui " + ui.getName());
        }
        JAXXUtil.destroy(ui);
        ui.getModel().destroy();
    }

    public void changeCategory(ChangeEvent e) {
        JPanel p = (JPanel) ui.getCategories().getSelectedComponent();
        if (p == null) {
            // pas de selection
            return;
        }
        ui.getModel().setCategory(p.getName());
        ui.getCategories().invalidate();
    }

    public void displayUI(Frame parentUI, boolean undecorated) {
        JDialog f = new JDialog(parentUI, true);
        f.setTitle(t("config.title"));
        f.add(ui);
        if (parentUI != null) {
            f.setIconImage(parentUI.getIconImage());
        }
        // pour savoir si l'ui est autonome
        ui.getModel().setStandalone(parentUI == null);

        f.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
        f.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                ActionEvent myEvent = new ActionEvent(e.getSource(), 1, QUIT_ACTION);
                ui.getQuit().getAction().actionPerformed(myEvent);
            }
        });
        f.setUndecorated(undecorated);
        JRootPane rootPane = f.getRootPane();
        rootPane.setDefaultButton(ui.getQuit());
        rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
                KeyStroke.getKeyStroke("ESCAPE"), QUIT_ACTION);
        rootPane.getActionMap().put(QUIT_ACTION, ui.getQuit().getAction());
        f.pack();
        SwingUtil.center(parentUI, f);
        f.setVisible(true);
    }

    protected Action createQuitAction() {

        JButton button = ui.getQuit();

        return new AbstractAction(button.getText(),
                                  button.getIcon()) {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                if (!canQuitCategory()) {
                    return;
                }

                Window parentWindow;

                final Container parentContainer;

                if (topContainer == null) {

                    // no top container given, still use the parent frame

                    parentWindow = ui.getParentContainer(Window.class);
                    parentContainer = parentWindow;

                } else {

                    // use only given topContainer
                    parentWindow = null;
                    parentContainer = topContainer;
                }

                ConfigUIModel model = ui.getModel();
                if (!model.isSaved() || model.isStandalone()) {

                    // just quit, no callBack can be apply here
                    closeUI(parentWindow, model);
                    return;
                }

                CallBackMap forSaved = model.getCallBacksForSaved();

                if (forSaved.isEmpty()) {

                    //  just quit, no callBack to call
                    closeUI(parentWindow, model);
                    return;
                }

                forSaved = model.getCallBacksForSaved();

                // init callBackUI

                JAXXInitialContext context = new JAXXInitialContext().
                        add(ui).
                        add(CALLBACKS_WITH_OPTIONS, forSaved).
                        add(CALLBACKS,
                            new ArrayList(forSaved.keySet())).
                        add(new ConfigCallBackUIHandler());

                if (topContainer == null) {

                    // still add parent window (to close ui)
                    context.add("parent", parentWindow);
                }

                ConfigCallBackUI lastUI = new ConfigCallBackUI(context);
                lastUI.init();

                if (configCallBackUICustomizer != null) {
                    configCallBackUICustomizer.customize(lastUI);
                }
                ui.setVisible(false);
                parentContainer.remove(ui);
                parentContainer.add(lastUI);

                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        parentContainer.validate();
                    }
                });
            }
        };
    }

    public void setConfigCallBackUICustomizer(ConfigCallBackUICustomizer configCallBackUICustomizer) {
        this.configCallBackUICustomizer = configCallBackUICustomizer;
    }

    /**
     * To customize config call back ui.
     *
     * @since 2.37
     */
    public interface ConfigCallBackUICustomizer {

        void customize(ConfigCallBackUI callBackUI);
    }


    protected void closeUI(Window parentWindow, ConfigUIModel model) {

        destroy();

        if (parentWindow != null) {

            // close the config ui
            parentWindow.dispose();
        }

        Runnable runnable = model.getCloseAction();
        if (runnable != null) {
            log.info("execute close action");
            runnable.run();
        }
    }

    protected boolean canQuitCategory() {
        boolean canContinue = true;
        ConfigUIModel model = ui.getModel();
        CategoryModel categoryModel = model.getCategoryModel();
        String categoryName = t(categoryModel.getCategory());
        if (!categoryModel.isValid()) {

            // the category is not valid
            // get all the invalid options

            StringBuilder buffer = new StringBuilder();
            buffer.append(t("config.message.quit.invalid.category",
                            categoryName));
            buffer.append('\n');
            for (OptionModel m : categoryModel.getInvalidOptions()) {
                buffer.append("\n- ").append(m.getKey());
            }
            buffer.append('\n');
            int reponse = askUser(t("config.title.need.confirm"),
                                  buffer.toString(),
                                  JOptionPane.ERROR_MESSAGE,
                                  new Object[]{
                                          t("config.choice.continue"),
                                          t("config.choice.cancel")},
                                  0);

            switch (reponse) {
                case JOptionPane.CLOSED_OPTION:
                case 1:
                    canContinue = false;
                    break;
                case 0:
                    if (categoryModel.isModified()) {
                        // wil reset category
                        model.reset();
                    }
                    break;
            }
        } else if (categoryModel.isModified()) {

            // category was modified, ask user if wants to save

            StringBuilder buffer = new StringBuilder();
            buffer.append(t("config.message.quit.valid.and.modified.category",
                            categoryName)).append('\n');
            for (OptionModel m : categoryModel.getModifiedOptions()) {
                buffer.append("\n- ").append(m.getKey());
            }
            buffer.append('\n');

            int reponse = askUser(t("config.title.need.confirm"),
                                  buffer.toString(),
                                  JOptionPane.WARNING_MESSAGE,
                                  new Object[]{
                                          t("config.choice.save"),
                                          t("config.choice.doNotSave"),
                                          t("config.choice.cancel")},
                                  0);

            switch (reponse) {
                case JOptionPane.CLOSED_OPTION:
                case 2:
                    canContinue = false;
                    break;
                case 0:
                    // will save ui
                    model.saveModified();
                    break;
                case 1:
                    // wil reset ui
                    model.reset();
                    break;
            }
        }
        return canContinue;
    }

    public int askUser(String title,
                       String message,
                       int typeMessage,
                       Object[] options,
                       int defaultOption) {

        return JOptionPane.showOptionDialog(
                ui,
                message,
                title,
                JOptionPane.DEFAULT_OPTION,
                typeMessage,
                null,
                options,
                options[defaultOption]
        );
    }

    public void setTopContainer(Container topContainer) {
        this.topContainer = topContainer;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy