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

org.nuiton.jaxx.widgets.select.BeanListHeaderHandler Maven / Gradle / Ivy

There is a newer version: 3.0.0-RC-12
Show newest version
/*
 * #%L
 * JAXX :: Widgets Select
 * %%
 * Copyright (C) 2008 - 2017 Code Lutin, Ultreia.io
 * %%
 * 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%
 */

package org.nuiton.jaxx.widgets.select;

import org.apache.commons.collections.primitives.ArrayIntList;
import org.apache.commons.collections.primitives.IntList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.decorator.DecoratorUtil;
import org.nuiton.decorator.JXPathDecorator;
import org.nuiton.decorator.MultiJXPathDecorator;
import org.nuiton.jaxx.runtime.spi.UIHandler;
import org.nuiton.jaxx.runtime.swing.JAXXButtonGroup;
import org.nuiton.jaxx.runtime.swing.renderer.DecoratorListCellRenderer;

import javax.swing.DefaultListModel;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JPopupMenu;
import javax.swing.ListModel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.Vector;

/**
 * Le handler d'un {@link BeanListHeader}.
 *
 * Note: ce handler n'est pas stateless et n'est donc pas partageable entre
 * plusieurs ui.
 *
 * @param  le type des objet contenus dans le modèle du composant.
 * @author Tony Chemit - [email protected]
 * @see BeanListHeader
 * @since 2.2
 */
public class BeanListHeaderHandler implements PropertyChangeListener, UIHandler> {

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

    protected BeanListHeader ui;

    /** the decorator of data */
    protected MultiJXPathDecorator decorator;

    /** flag to mark when handler was init (it can be init only once). */
    protected boolean init;

    private I18nLabelsBuilder i18nLabelBuilder;

    public void setI18nLabelBuilder(I18nLabelsBuilder i18nLabelBuilder) {
        this.i18nLabelBuilder = i18nLabelBuilder;
    }

    private final BeanUIUtil.PopupHandler popupHandler = new BeanUIUtil.PopupHandler() {

        @Override
        public I18nLabelsBuilder getI18nLabelsBuilder() {

            if (i18nLabelBuilder==null) {
                i18nLabelBuilder = new I18nLabelsBuilder(ui.getBeanType());
            }
            return i18nLabelBuilder;
        }

        @Override
        public JPopupMenu getPopup() {
            return ui.getPopup();
        }

        @Override
        public JComponent getInvoker() {
            return ui.getChangeDecorator();
        }
    };

    /**
     * Initialise le handler de l'ui
     *
     * @param decorator le decorateur a utiliser
     * @param data      la liste des données a gérer
     */
    public void init(JXPathDecorator decorator, List data) {

        if (init) {
            throw new IllegalStateException("can not init the handler twice");
        }
        init = true;

        if (decorator == null) {
            throw new NullPointerException("decorator can not be null (for type " + ui.getBeanType() + ")");
        }

        // list could have changed and the complex binding is not registred...
        ui.removeDataBinding(BeanListHeader.BINDING_RESET_SELECTION_ENABLED);
        ui.applyDataBinding(BeanListHeader.BINDING_RESET_SELECTION_ENABLED);

        JAXXButtonGroup indexes = ui.getIndexes();

        this.decorator = BeanUIUtil.createDecorator(decorator);

        // init combobox renderer base on given decorator
        ui.getList().setCellRenderer(new DecoratorListCellRenderer<>(this.decorator));

        // build popup
        popupHandler.preparePopup(ui.getSelectedToolTipText(),
                                  ui.getNotSelectedToolTipText(),
                                  ui.getI18nPrefix(),
                                  ui.getPopupTitleText(),
                                  indexes,
                                  ui.getPopupSeparator(),
                                  ui.getPopupLabel(),
                                  ui.getSortUp(),
                                  ui.getSortDown(),
                                  this.decorator);

        ui.addPropertyChangeListener(this);

        // set datas
        ui.setData(data);

        // select sort button
        indexes.setSelectedButton(ui.getIndex());
    }

    /** Toggle the popup visible state. */
    public void togglePopup() {
        popupHandler.togglePopup();
    }

    /**
     * Modifie l'index du décorateur
     *
     * @param oldValue l'ancienne valeur
     * @param newValue la nouvelle valeur
     */
    protected void setIndex(Integer oldValue, Integer newValue) {
        if (newValue == null || newValue.equals(oldValue)) {
            return;
        }
        if (log.isDebugEnabled()) {
            log.debug("check state : <" + oldValue + " to " + newValue + ">");
        }
        updateUI(newValue, ui.isReverseSort());
    }

    /**
     * Modifie l'index du décorateur
     *
     * @param oldValue l'ancienne valeur
     * @param newValue la nouvelle valeur
     */

    protected void setSortOrder(Boolean oldValue, Boolean newValue) {

        if (newValue == null || newValue.equals(oldValue)) {
            return;
        }
        if (log.isDebugEnabled()) {
            log.debug("check state : <" + oldValue + " to " + newValue + ">");
        }

        updateUI(ui.getIndex(), newValue);
    }

    @SuppressWarnings({"unchecked"})
    protected void updateUI(int index, boolean reverseSort) {

        // change decorator context
        decorator.setContextIndex(index);

        String expression = decorator.getExpression();
        if (log.isDebugEnabled()) {
            log.debug("will use expression (index = " + index + ") : " +
                              expression);
        }

        // get the current selection in list
        List selection = ui.getList().getSelectedValuesList();

        List datas = ui.getData();
        try {

            // Sort data with the decorator jxpath tokens.
            DecoratorUtil.sort(decorator,
                               datas,
                               index,
                               reverseSort);
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
        }

        ui.getList().setValueIsAdjusting(true);
        try {

            // reload the model
            ListModel listModel = ui.getList().getModel();

            if (listModel instanceof DefaultListModel) {
                DefaultListModel model = (DefaultListModel) listModel;
                model.removeAllElements();
                for (O data : datas) {
                    model.addElement(data);
                }

            } else {

                ui.getList().setListData(new Vector<>(datas));
            }

            // re-apply selection
            if (selection.size() > 0) {

                // re compute selection (the new data could not contains some
                // previously selected items)
                IntList newSelection = new ArrayIntList();
                for (O o : selection) {
                    if (datas.contains(o)) {

                        newSelection.add(datas.indexOf(o));
                    }
                }

                if (!newSelection.isEmpty()) {

                    // there is still a selection to re-apply
                    int[] ints = newSelection.toArray(new int[newSelection.size()]);
                    newSelection.clear();
                    ui.getList().setSelectedIndices(ints);
                }
            }

        } finally {
            ui.getList().setValueIsAdjusting(false);
        }

        ui.getList().requestFocus();
    }

    public MultiJXPathDecorator getDecorator() {
        return decorator;
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        String propertyName = evt.getPropertyName();

        if (BeanListHeader.PROPERTY_INDEX.equals(propertyName)) {

            // decorator index has changed, force reload of data in ui
            setIndex((Integer) evt.getOldValue(),
                     (Integer) evt.getNewValue());
            return;
        }

        if (BeanListHeader.PROPERTY_REVERSE_SORT.equals(propertyName)) {

            // sort order has changed, force reload of data in ui
            setSortOrder((Boolean) evt.getOldValue(),
                         (Boolean) evt.getNewValue());
            return;
        }

        if (BeanListHeader.PROPERTY_DATA.equals(propertyName)) {

            // list has changed, force reload of index
            setIndex(-1, ui.getIndex());
        }

        if (BeanListHeader.PROPERTY_LIST.equals(propertyName)) {

            // ui list has changed, replace  binding            
            ui.removeDataBinding(BeanListHeader.BINDING_RESET_SELECTION_ENABLED);
            ui.applyDataBinding(BeanListHeader.BINDING_RESET_SELECTION_ENABLED);
        }
    }

    public O getSelectedValue() {
        JList list = ui.getList();
        return list == null ? null : list.getSelectedValue();
    }

    @Override
    public void beforeInit(BeanListHeader ui) {
        this.ui = ui;
    }

    @Override
    public void afterInit(BeanListHeader ui) {

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy