package com.onaro.util.jfc; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.MissingResourceException; import java.util.ResourceBundle; import javax.swing.DefaultListCellRenderer; import javax.swing.Icon; import javax.swing.JComboBox; import javax.swing.JList; import com.onaro.commons.util.IResourceCommonProperties; import com.onaro.util.InvalidConfigException; /** * A combo-box who's items are instance of {@link OptionEntry} which are built * on top of resorce-bundle properties. * Extends {@link JComboBox} to fix the size problem that makes it occupy * all the free space in the toolbar. Also register a custom renderer that displays * an icon at the pull-down button.

* Selection changes are handeled so when an item is selected, it notifies the selected * element. An element may reject the seletion such as when the "cancel" is pressed in * the "custom-time" filter. */ public class AdvancedComboBox extends OnaroComboBox { private static final long serialVersionUID = 1L; /** * Keeps track of the selected entry. Used to restore selection if an * entry rejected its selection. */ OptionEntry selected; /** * Initialize the combo-box, register the renderer and a selection handler * that manage option activation. The box will not be resizable. * * @param bundle locale-dependent resources for loading the caption's icon * @param resourceName icon's resource name * @param items the list's options */ public AdvancedComboBox(ResourceBundle bundle, String resourceName, Object items[]) { super(items); initialize(bundle, resourceName); } /** * Initialize the combo-box, register the renderer and a selection handler * that manage option activation. *

* The box will not be resizable. It will be as wide as the widest item string * up to the specified maximum width. The drop-down list will be as wide as * necessary to show all the item strings. * * @param bundle locale-dependent resources for loading the caption's icon * @param resourceName icon's resource name * @param maxWidth maximum allowed width of the box * @param items the list's options */ public AdvancedComboBox(ResourceBundle bundle, String resourceName, int maxWidth, Object items[]) { super(maxWidth, items); initialize(bundle, resourceName); } private void initialize (ResourceBundle bundle, String resourceName) { setRenderer(new AdvancedComboListRenderer(bundle, resourceName)); try { setToolTipText(bundle.getString(resourceName + ".tooltip")); //$NON-NLS-1$ } catch (MissingResourceException e) { } selected = (OptionEntry) getSelectedItem(); /** * Registers a listener that when an option is selected, notify its * element. The element may reject this selection, in which case the * previous one is restored. */ addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @SuppressWarnings("unchecked") JComboBox cb = (JComboBox) e.getSource(); OptionEntry entry = (OptionEntry) cb.getSelectedItem(); if (entry == null) { return; } if (entry.setSelected()) { selected = entry; } else { cb.setSelectedItem(selected); } } }); } /** * * A base class for all the options in the combo-box. It provides the basic * rendering properties as well as the interface for selecting an entry * and for restoring selection. */ public static abstract class OptionEntry { /** * The option's name that is displayed in the como box. */ String name; /** * Used when restoring selection to access the preferences. */ String resourceName; /** * The option's tooltip. */ String toolTip; /** * Initialize this entry, reading its name and tooltip from the resorces. * * @param bundle locale-dependant resources * @param resourceName resource group name from which the name and tooltip * are read * @throws InvalidConfigException if some resources were missing */ public OptionEntry(ResourceBundle bundle, String resourceName) { this.resourceName = resourceName; IResourceCommonProperties props = ResourceCommonPropertiesFactory.create(bundle, resourceName); name = props.getName(); toolTip = props.getShortDescription(); } public OptionEntry(String resourceName, String name, String toolTip) { this.resourceName = resourceName; this.name = name; this.toolTip = toolTip; } /** * Gets this optoin's name. * * @return the option's name */ public String getName() { return name; } /** * Gets the name to display on the combo-box's caption if this is the * selected option. * * @return the text to display if this is the selected option */ public String getSelectedName() { return getName(); } /** * Gets the name of the resource this element is using. * * @return the name of this element's resource */ public String getResourceName() { return resourceName; } /** * Notified this option that it had been selected. The option may reject * this selection. * * @return true if the selection is accepted */ public abstract boolean setSelected(); /** * Gets this option's tooltip. * * @return this option's tooltip */ public String getToolTip() { return toolTip; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final OptionEntry other = (OptionEntry) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (resourceName == null) { if (other.resourceName != null) return false; } else if (!resourceName.equals(other.resourceName)) return false; if (toolTip == null) { if (other.toolTip != null) return false; } else if (!toolTip.equals(other.toolTip)) return false; return true; } } /** * A combo-box renderer for {@link OptionEntry} that allows for adding * an icon to the selected optoin and is using the entry's interface to get * the text to display in the drop-down list and on the caption. */ class AdvancedComboListRenderer extends DefaultListCellRenderer { private static final long serialVersionUID = 1L; // Prefix added to value strings to make them more readable when there is no icon. private static final String VALUE_PREFIX = " "; //$NON-NLS-1$ /** * The icon that is displayed left to the selected option in the combo-box's * caption. */ Icon icon; /** * Gets from the resource-bundle the icon to display in the caption. * * @param bundle locale-dependant resources * @param resourceName the name of resource to get the icon by * @throws InvalidConfigException if failed to get the icon name of file */ public AdvancedComboListRenderer(ResourceBundle bundle, String resourceName) { try { icon = ResourceCommonPropertiesFactory.getIcon(bundle.getString(resourceName + ".icon")); //$NON-NLS-1$ } catch (MissingResourceException e) { // OK if there is no icon. icon = null; } } /** * Prepare for painting an {@link OptionEntry} option. Get from the * entry the text and tooltip to display. If needs to paint the combo-box's * caption, asks the entry for the "selected" name and setsup the icon. * * @param list The JList we're painting. * @param value The value returned by list.getModel().getElementAt(index). * @param index The cells index. * @param isSelected True if the specified cell was selected. * @param cellHasFocus True if the specified cell has the focus. * @return A component whose paint() method will render the specified value. */ public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { OptionEntry entry = (OptionEntry) value; String valueStr = index == -1 ? entry.getSelectedName() : entry.getName(); // Add a leading space if there is no icon to make the text easier to read. if (icon == null) { valueStr = VALUE_PREFIX + valueStr; } AdvancedComboBox.this.setToolTipText(entry.getToolTip()); super.getListCellRendererComponent(list, valueStr, index, isSelected, cellHasFocus); if (icon != null) { setIcon(index == -1 ? icon : null); } return this; } } }