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

xdev.ui.XdevComboBox Maven / Gradle / Ivy

There is a newer version: 6.0.2
Show newest version
package xdev.ui;

/*-
 * #%L
 * XDEV Application Framework
 * %%
 * Copyright (C) 2003 - 2020 XDEV Software
 * %%
 * 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 java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Map;

import javax.accessibility.Accessible;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.JComboBox;
import javax.swing.JList;
import javax.swing.JPopupMenu;
import javax.swing.ListCellRenderer;
import javax.swing.MutableComboBoxModel;
import javax.swing.event.ListDataListener;
import javax.swing.plaf.ComboBoxUI;

import xdev.db.Operator;
import xdev.db.sql.Condition;
import xdev.ui.ItemList.Entry;
import xdev.ui.combobox.ComboBoxSupport;
import xdev.util.ObjectUtils;
import xdev.util.StringUtils;
import xdev.vt.VirtualTable;
import xdev.vt.VirtualTable.VirtualTableRow;
import xdev.vt.VirtualTableColumn;


/**
 * The standard combobox in XDEV. Based on {@link JComboBox}.
 *
 * @see JComboBox
 * @see FormularComponent
 * @see ItemListOwner
 * @see XdevFocusCycleComponent
 * @see MasterDetailComponent
 *
 * @author XDEV Software
 *
 * @since 2.0
 */
@BeanSettings(useXdevCustomizer = true)
public class XdevComboBox extends JComboBox
		implements ExtendedList, XdevFocusCycleComponent
{
	private String							preSelectionValue	= null;
	private Color							evenBackground		= null;
	private Color							oddBackground		= null;

	/**
	 * tabIndex is used to store the index for {@link XdevFocusCycleComponent}
	 * functionality.
	 */
	private int								tabIndex			= -1;

	private ComboBoxSupport	support;


	private ComboBoxSupport getSupport()
	{
		if(this.support == null)
		{
			this.support = new ComboBoxSupport(this);
		}

		return this.support;
	}


	/**
	 * Constructs a new {@link XdevComboBox}.
	 *
	 *
	 * @see #XdevComboBox(ItemList)
	 */
	public XdevComboBox()
	{
		this(new ItemList());
	}


	/**
	 * Constructs a {@link XdevComboBox} that is initialized with
	 * {@link ItemList} as the data model.
	 *
	 * @param il
	 *            the {@link ItemList} that provides the displayed and data
	 *            items
	 *
	 * @see #setItemList(ItemList)
	 * @see #setRenderer(javax.swing.ListCellRenderer)
	 */
	public XdevComboBox(final ItemList il)
	{
		super();
		setItemList(il);
		setRenderer(createListCellRenderer());
	}


	/**
	 * Constructs a {@link XdevComboBox} that is initialized with
	 * {@link ComboBoxModel} as the data model.
	 *
	 * @param model
	 *            the {@link ComboBoxModel} with data
	 *
	 * @see #setModel(ComboBoxModel)
	 * @see #setRenderer(javax.swing.ListCellRenderer)
	 */
	public XdevComboBox(final ComboBoxModel model)
	{
		super();
		setModel(model);
		setRenderer(createListCellRenderer());
	}

	{
		addItemListener(new ItemListener()
		{
			Object oldItem = getSelectedItem();


			@Override
			public void itemStateChanged(final ItemEvent e)
			{
				if(e.getStateChange() == ItemEvent.SELECTED)
				{
					final Object item = e.getItem();
					if(isElementSelectable(item))
					{
						this.oldItem = item;
					}
					else
					{
						setSelectedItem(this.oldItem);
					}
				}
			}
		});
	}


	protected boolean isElementSelectable(final Object item)
	{
		if(item instanceof Entry)
		{
			return ((Entry)item).isEnabled();
		}

		return true;
	}


	protected ListCellRenderer createListCellRenderer()
	{
		return new XdevComboBoxListCellRenderer();
	}


	/**
	 * {@inheritDoc}
	 */
	@Override
	public ItemList getItemList()
	{
		return getSupport().getItemList();
	}


	/**
	 * {@inheritDoc}
	 */
	@Override
	@BeanProperty(category = DefaultBeanCategories.DATA)
	public void setItemList(final ItemList itemList)
	{
		setModel(new ItemListModelWrapper(itemList));
	}


	/**
	 * Create a new {@link ItemList} based on the provided {@link ComboBoxModel}
	 * .
	 *
	 * @param model
	 *            The data model
	 *
	 * @return a {@link ItemList}, the data are the model's values and the
	 *         item's are the model's values as {@link String}.
	 */
	public ItemList modelToItemList(final ComboBoxModel model)
	{
		return new ItemList(model);
	}


	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setModel(final VirtualTable vt, final String itemCol, final String dataCol)
	{
		setModel(vt,itemCol,dataCol,false);
	}


	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setModel(final VirtualTable vt, final String itemCol, final String dataCol,
			final boolean queryData)
	{
		setModel(vt,itemCol,dataCol,queryData,false);
	}


	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setModel(final VirtualTable vt, final String itemCol, final String dataCol,
			final boolean queryData, final boolean selectiveQuery)
	{
		if(getItemList() == null)
		{
			setItemList(new ItemList());
		}

		getItemList().setModel(vt,itemCol,dataCol,queryData,selectiveQuery);
		setSelectedItem(null);
	}


	/**
	 * {@inheritDoc}
	 */
	@Override
	public void refresh()
	{
		getSupport().refresh();
	}


	/**
	 * {@inheritDoc}
	 */
	@Override
	public void updateModel(final Condition condition, final Object... params)
	{
		getSupport().updateModel(condition,params);
	}


	/**
	 * {@inheritDoc}
	 */
	@Override
	public void clearModel()
	{
		getSupport().clearModel();
	}


	/**
	 * Sets the value which is displayed before the user selects a value, e.g.
	 * "- Select your country -".
	 *
	 * @param s
	 *            the {@link String} to display in this {@link XdevComboBox}
	 */
	public void setPreSelectionValue(final String s)
	{
		this.preSelectionValue = s;
		repaint();
	}


	/**
	 * Returns the string which is displayed before the user selects a value.
	 *
	 * @return the string which is displayed before the user selects a value.
	 */
	public String getPreSelectionValue()
	{
		return this.preSelectionValue;
	}


	/**
	 * Sets the background {@link Color} of even rows.
	 *
	 * @param evenBackground
	 *            the background of even rows as {@link Color}.
	 */
	public void setEvenBackground(final Color evenBackground)
	{
		this.evenBackground = evenBackground;
	}


	/**
	 * Returns the background {@link Color} of even rows.
	 *
	 * @return the background of even rows as {@link Color}.
	 */
	public Color getEvenBackground()
	{
		return this.evenBackground;
	}


	/**
	 * Sets the background {@link Color} of odd rows.
	 *
	 * @param oddBackground
	 *            the background of odd rows as {@link Color}.
	 */
	public void setOddBackground(final Color oddBackground)
	{
		this.oddBackground = oddBackground;
	}


	/**
	 * Returns the background {@link Color} of odd rows.
	 *
	 * @return the background of odd rows as {@link Color}.
	 */
	public Color getOddBackground()
	{
		return this.oddBackground;
	}


	/**
	 * Verify if a item is selected.
	 *
	 * @return true if a item is selected, otherwise
	 *         false.
	 */
	public boolean isSomethingSelected()
	{
		return getSelectedItem() != null;
	}


	/**
	 * Returns the selected data.
	 *
	 * @return the selected data, if no data is selected null
	 */
	public Object getSelectedData()
	{
		if(getItemList() != null)
		{
			final Entry entry = getSelectedEntry();
			return entry != null ? entry.getData() : null;
		}
		else
		{
			return getSelectedItem();
		}
	}


	/**
	 * Returns the modelindex of the selected item.
	 * 

* For example the index of the selected item in it is {@link VirtualTable}. *

* * @return an integer specifying the currently selected list item, where 0 * specifies the first item in the list; or -1 if no item is * selected or if the currently selected item is not in the list */ public int getSelectedModelIndex() { final int viewIndex = getSupport().getSelectedModelIndex(super.getSelectedIndex()); return viewIndex; } /** * Select the index of the first occurrence of the specified o * in this list. If the {@link ItemList} of this {@link XdevComboBox} does * not contain the o, the selection is canceled. * * @param o * the {@link Object} to select */ public void setSelectedData(final Object o) { getSupport().setSelectedData(o); } private boolean callSuperSetSelectedItem = false; /** * {@inheritDoc} */ @Override public void setSelectedItem(final Object anObject) { ItemList itemList; if(this.callSuperSetSelectedItem || anObject == null || anObject instanceof Entry || (itemList = getItemList()) == null) { super.setSelectedItem(anObject); } else { final int index = itemList.indexOfItem(anObject); if(index == -1) { super.setSelectedItem(null); } else { try { this.callSuperSetSelectedItem = true; super.setSelectedIndex( getSupport().modelToView(itemList.indexOfItem(anObject))); } finally { this.callSuperSetSelectedItem = false; } } } } /** * Selects the item at modelindex anIndex. *

* For example the given index of an item in it is model {@link VirtualTable} * . *

* * @param anIndex * an integer specifying the list item to select, where 0 * specifies the first item in the list and -1 indicates no * selection */ public void setSelectedModelIndex(final int anIndex) { this.getSupport().setSelectedModelIndex(anIndex); } /** * Returns the selected {@link ItemList}-{@link Entry}. * * @return the selected {@link ItemList}-{@link Entry} */ public Entry getSelectedEntry() { return (Entry)getSelectedItem(); } /** * {@inheritDoc} */ @Override public String getFormularName() { return getSupport().getFormularName(); } /** * {@inheritDoc} * * @since 3.1 */ @Override public void setDataField(final String dataField) { getSupport().setDataField(dataField); } /** * {@inheritDoc} * * @since 3.1 */ @Override public String getDataField() { return getSupport().getDataField(); } /** * {@inheritDoc} */ @Override @Deprecated public void setFormularValue(final VirtualTable vt, final int col, final Object value) { getSupport().setFormularValue(vt,col,value); } /** * {@inheritDoc} * * @since 3.2 */ @Override public void setFormularValue(final VirtualTable vt, final Map record) { getSupport().setFormularValue(vt,record); } /** * {@inheritDoc} * * @since 3.2 */ @Override public void setMasterValue(final VirtualTable vt, final Map record) { this.support.setValue(vt,record); } /** * {@inheritDoc} */ @Override public Object getFormularValue() { return getSupport().getFormularValue(); } /** * {@inheritDoc} */ @Override public void saveState() { getSupport().saveState(); } /** * {@inheritDoc} */ @Override public void restoreState() throws IllegalArgumentException { getSupport().restoreState(); } /** * {@inheritDoc} * * @since 3.1 */ @Override public boolean hasStateChanged() { return getSupport().hasStateChanged(); } /** * {@inheritDoc} */ @Override public boolean isMultiSelect() { return getSupport().isMultiSelect(); } /** * {@inheritDoc} */ @Override public boolean verify() { return getSupport().verify(); } /** * {@inheritDoc} * * @since 3.1 */ @Override public void addValidator(final Validator validator) { getSupport().addValidator(validator); } /** * {@inheritDoc} * * @since 3.1 */ @Override public void removeValidator(final Validator validator) { getSupport().removeValidator(validator); } /** * {@inheritDoc} * * @since 3.1 */ @Override public Validator[] getValidators() { return getSupport().getValidators(); } /** * {@inheritDoc} * * @since 3.1 */ @Override public void validateState() throws ValidationException { getSupport().validateState(); } /** * {@inheritDoc} * * @since 3.1 */ @Override public void validateState(final Validation validation) throws ValidationException { getSupport().validateState(validation); } /** * {@inheritDoc} * * @since 3.1 */ @Override public void setFilterOperator(final Operator filterOperator) { getSupport().setFilterOperator(filterOperator); } /** * {@inheritDoc} * * @since 3.1 */ @Override public Operator getFilterOperator() { return getSupport().getFilterOperator(); } /** * {@inheritDoc} * * @since 3.2 */ @Override public void setReadOnly(final boolean readOnly) { this.support.setReadOnly(readOnly); } /** * {@inheritDoc} * * @since 3.2 */ @Override public boolean isReadOnly() { return this.support.isReadOnly(); } /** * {@inheritDoc} * * @since 4.0 */ @Override public void setVirtualTable(final VirtualTable vt) { VirtualTableColumn primaryColumn = vt.getPrimaryColumn(); if(primaryColumn == null) { primaryColumn = vt.getColumnAt(0); } final String itemCol = primaryColumn.getName(); String dataCol = null; final VirtualTableColumn[] primaryKeyColumns = vt.getPrimaryKeyColumns(); if(primaryKeyColumns != null && primaryKeyColumns.length > 0) { final String[] names = VirtualTableColumn.getNamesOf(primaryKeyColumns); dataCol = StringUtils.concat(",",(Object[])names); } setModel(vt,itemCol,dataCol,false); } /** * {@inheritDoc} */ @Override public VirtualTable getVirtualTable() { return getSupport().getVirtualTable(); } /** * {@inheritDoc} */ @Override public VirtualTableRow getSelectedVirtualTableRow() { return getSupport().getSelectedVirtualTableRow(); } /** * Selects the row in the combo box if present. * * @param row * the row to select * @since 3.2 */ public void setSelectedVirtualTableRow(final VirtualTableRow row) { this.support.setSelectedVirtualTableRow(row); } /** * {@inheritDoc} */ @Override public void addValueChangeListener(final ValueChangeListener l) { getSupport().addValueChangeListener(l); } /** * {@inheritDoc} */ @Override public void setDetailHandler(final DetailHandler detailHandler) { getSupport().setDetailHandler(detailHandler); } /** * {@inheritDoc} */ @Override public Dimension getPreferredSize() { final Dimension d = super.getPreferredSize(); if(d.width < 50) { d.width = 150; } return d; } /** * {@inheritDoc} */ @Override public String toString() { final Object o = getSelectedItem(); if(o != null) { return String.valueOf(o); } return UIUtils.toString(this); } /** * {@inheritDoc} */ @Override public int getTabIndex() { return this.tabIndex; } /** * {@inheritDoc} */ @Override public void setTabIndex(final int tabIndex) { if(this.tabIndex != tabIndex) { final int oldValue = this.tabIndex; this.tabIndex = tabIndex; firePropertyChange(TAB_INDEX_PROPERTY,oldValue,tabIndex); } } public static class ItemListModelWrapper implements MutableComboBoxModel, ItemListOwner { private final ItemList itemList; private Object selectedItem; public ItemListModelWrapper(final ItemList itemList) { this.itemList = itemList; if(itemList.size() > 0) { this.selectedItem = itemList.get(0); } } @Override public ItemList getItemList() { return this.itemList; } @Override public void setSelectedItem(final Object o) { if(!ObjectUtils.equals(this.selectedItem,o)) { this.selectedItem = o; this.itemList.fireContentsChanged(-1,-1); } } @Override public Object getSelectedItem() { return this.selectedItem; } @Override public int getSize() { return this.itemList.size(); } @Override public Object getElementAt(final int index) { return this.itemList.get(index); } @Override public void addElement(final Object obj) { this.itemList.add(String.valueOf(obj),obj); } @Override public void insertElementAt(final Object obj, final int index) { this.itemList.add(index,String.valueOf(obj),obj); } @Override public void removeElement(final Object obj) { final int index = this.itemList.indexOfItem(obj); if(index >= 0) { this.itemList.remove(index); } } @Override public void removeElementAt(final int index) { this.itemList.remove(index); } @Override public void addListDataListener(final ListDataListener l) { this.itemList.addListDataListener(l); } @Override public void removeListDataListener(final ListDataListener l) { this.itemList.removeListDataListener(l); } } protected class XdevComboBoxListCellRenderer extends DefaultListCellRenderer { @Override public Component getListCellRendererComponent(final JList list, Object value, final int index, boolean isSelected, final boolean cellHasFocus) { final boolean selectable = isElementSelectable(value); if(isSelected && !selectable) { isSelected = false; } Icon icon = null; if(index == -1 && getSelectedItem() == null && XdevComboBox.this.preSelectionValue != null) { value = XdevComboBox.this.preSelectionValue; } else if(value instanceof Entry) { final Entry entry = (Entry)value; value = entry.getItem(); icon = entry.getIcon(); } super.getListCellRendererComponent(list,value,index,isSelected,cellHasFocus); setIcon(icon); if(!isSelected) { setBackground(index % 2 == 0 ? getEvenBackground() : getOddBackground()); } setEnabled(selectable); return this; } } /** * Workaround for a JDK bug. * * * @see XDEV * Issue * @see SUN * Issue */ private boolean layouting = false; /** * {@inheritDoc} */ @Override public void doLayout() { try { this.layouting = true; super.doLayout(); } finally { this.layouting = false; } } /** * {@inheritDoc} */ @Override public Dimension getSize() { final Dimension d = super.getSize(); if(!this.layouting) { d.width = Math.max(d.width,getPopup().getPreferredSize().width); } return d; } private JPopupMenu getPopup() { final ComboBoxUI ui = getUI(); final int c = ui.getAccessibleChildrenCount(this); for(int i = 0; i < c; i++) { final Accessible a = ui.getAccessibleChild(this,i); if(a instanceof JPopupMenu) { return (JPopupMenu)a; } } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy