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;
}
}
}