org.nuiton.jaxx.widgets.select.BeanListHeaderHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaxx-widgets-select Show documentation
Show all versions of jaxx-widgets-select Show documentation
Widgets to select data (using combobox, jlist, doublelist...)
/*
* #%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) {
}
}