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

org.nuiton.jaxx.runtime.swing.JAXXComboBox Maven / Gradle / Ivy

There is a newer version: 3.1.5
Show newest version
/*
 * #%L
 * JAXX :: Runtime
 * %%
 * Copyright (C) 2008 - 2024 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.runtime.swing;

import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JList;
import javax.swing.ListModel;
import java.awt.Component;
import java.awt.event.ItemEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class JAXXComboBox extends JComboBox {

    private static final long serialVersionUID = 1L;

    public class JAXXComboBoxModel extends AbstractListModel implements ComboBoxModel {

        private final List items;

        private Object selectedItem;

        private static final long serialVersionUID = -8940733376638766414L;

        public JAXXComboBoxModel(List items) {
            this.items = items;

            PropertyChangeListener listener = e -> {
                if (e.getPropertyName().equals(Item.SELECTED_PROPERTY)) {
                    Item item = (Item) e.getSource();
                    int itemIndex = JAXXComboBoxModel.this.items.indexOf(item);
                    // TODO: fix cut-and-pasting badness
                    int[] oldSelection = new int[]{getSelectedIndex()};
                    int[] newSelection;
                    int index = -1;
                    for (int i = 0; i < oldSelection.length; i++) {
                        if (oldSelection[i] == itemIndex) {
                            index = i;
                            break;
                        }
                    }
                    if (item.isSelected()) {
                        if (index != -1) // it was already selected
                        {
                            return;
                        }
                        newSelection = new int[oldSelection.length + 1];
                        System.arraycopy(oldSelection, 0, newSelection, 0, oldSelection.length);
                        newSelection[newSelection.length - 1] = itemIndex;
                    } else {
                        if (index == -1) // it already wasn't selected
                        {
                            return;
                        }
                        newSelection = new int[oldSelection.length - 1];
                        System.arraycopy(oldSelection, 0, newSelection, 0, index);
                        System.arraycopy(oldSelection, index + 1, newSelection, index, oldSelection.length - 1 - index);
                    }
                    if (newSelection.length > 0) {
                        setSelectedIndex(newSelection[0]);
                    }
                } else {
                    // TODO: more cut-and-pasting badness
                    for (int i = 0; i < getSize(); i++) {
                        if (getElementAt(i) == ((Item) e.getSource()).getValue()) {
                            fireContentsChanged(JAXXComboBoxModel.this, i, i);
                            if (getSelectedIndex() == i) {
                                fireItemStateChanged(new ItemEvent(JAXXComboBox.this, ItemEvent.ITEM_STATE_CHANGED, getElementAt(i), ItemEvent.DESELECTED));
                            }
                            return;
                        }
                    }
                }
            };
            for (Item item : items) {
                item.addPropertyChangeListener(listener);
            }
        }

        public List getItems() {
            return items;
        }

        @Override
        public Object getElementAt(int i) {
            return items.get(i).getValue();
        }

        @Override
        public int getSize() {
            return items.size();
        }

        @Override
        public Object getSelectedItem() {
            return selectedItem;
        }

        @Override
        public void setSelectedItem(Object selectedItem) {
            if (this.selectedItem != null && !this.selectedItem.equals(selectedItem) ||
                    this.selectedItem == null && selectedItem != null) {
                this.selectedItem = selectedItem;
                fireContentsChanged(this, -1, -1);
            }
        }
    }

    public JAXXComboBox() {
        setRenderer(new DefaultListCellRenderer() {

            private static final long serialVersionUID = 1L;

            @Override
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                ListModel model = list.getModel();
                if (model instanceof JAXXComboBoxModel) {
                    List/**/ items = ((JAXXComboBoxModel) model).items;
                    Item item = null;
                    if (index == -1) {
                        for (Object item1 : items) {
                            Item testItem = (Item) item1;
                            if (testItem.getValue() == value) {
                                item = testItem;
                                break;
                            }
                        }
                    } else {
                        item = (Item) items.get(index);
                    }

                    if (item != null) {
                        String label = item.getLabel();
                        if (label != null) {
                            value = label;
                        }
                    }
                }
                return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            }
        });

        addItemListener(e -> {
            ListModel model = getModel();
            if (model instanceof JAXXComboBoxModel) {
                List items = ((JAXXComboBoxModel) model).items;
                for (int i = items.size() - 1; i >= 0; i--) {
                    boolean selected = getSelectedIndex() == i;
                    Item item = items.get(i);
                    if (selected != item.isSelected()) {
                        item.setSelected(selected);
                    }
                }
            }
        });
    }

    /**
     * Fill a combo box model with some datas, and select after all the given object
     *
     * @param data       data ot inject in combo
     * @param select     the object to select in combo after reflling his model
     * @param methodName method to invoke to display data's name
     */
    public void fillComboBox(Collection data, Object select, String methodName) {
        // prepare method to use
        Method m;
        try {
            m = select.getClass().getMethod(methodName);
            m.setAccessible(true);
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("could not find method " + methodName + " on " + select.getClass());
        }

        List items = new ArrayList<>();
        for (Object o : data) {
            boolean selected = o.equals(select);
            try {
                items.add(new Item(o.toString(), (String) m.invoke(o), o, selected));
            } catch (IllegalAccessException | InvocationTargetException e) {
                // shoudl never happen ?
                throw new RuntimeException(e);
            }
        }
        setItems(items);
    }

    // this way we can keep it marked protected and still allow code in this file to call it

    @Override
    protected void fireItemStateChanged(ItemEvent e) {
        super.fireItemStateChanged(e);
    }

    public void setItems(List items) {
        setModel(new JAXXComboBoxModel(items));
        List selectedIndexList = new ArrayList<>();
        for (int i = 0; i < items.size(); i++) {
            if (items.get(i).isSelected()) {
                selectedIndexList.add(i);
            }
        }
        int[] selectedIndices = new int[selectedIndexList.size()];
        for (int i = 0; i < selectedIndexList.size(); i++) {
            selectedIndices[i] = selectedIndexList.get(i);
        }
        if (selectedIndices.length > 0) {
            setSelectedIndex(selectedIndices[0]);
        }
    }

    public List getItems() {
        if (getModel() instanceof JAXXComboBoxModel) {
            return ((JAXXComboBoxModel) getModel()).getItems();
        }
        return null;
    }

    public void setSelectedItem(Item item) {
        //TC-20092004 Anomalie #73 fix npe when want to call with a null
        // value 
        super.setSelectedItem(item == null ? null : item.getValue());
    }

    public Item getSelectedJaxxItem() {
        Object selected = super.getSelectedItem();
        return findItem(selected);
    }

    public Item findItem(Object value) {
        List items = getItems();
        if (items != null) {
            for (Item i : items) {
                if (i.getValue().equals(value)) {
                    return i;
                }
            }
        }
        return null;
    }

    public void addItem(Item item) {
        List items = getItems();
        if (items != null) {
            items.add(item);
            setItems(items);
        }
    }

    public void addAllItems(Collection itemsToAdd) {
        List items = getItems();
        if (items != null) {
            items.addAll(itemsToAdd);
            setItems(items);
        }
    }

    public void removeItem(Item item) {
        List items = getItems();
        if (items != null) {
            items.remove(item);
            setItems(items);
        }
    }

    public void removeAllItems(Collection itemsToRemove) {
        List items = getItems();
        if (items != null) {
            items.removeAll(itemsToRemove);
            setItems(items);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy