/* class JComboBox * * Copyright (C) 2001-2003 R M Pitman * * This library 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 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Modified Jul 15, 2003 by Tadpole Computer, Inc. * Modifications Copyright 2003 by Tadpole Computer, Inc. * * Modifications are hereby licensed to all parties at no charge under * the same terms as the original. * * Added the JComboBox(ComboBoxModel) constructor. * Added the removeAllItems method. * Added a stubbed out setEditable method (it would be nice to have editable * ComboBoxes, too. * Fixed color handling to inherit colors from our parent. */ package charvax.swing; import java.util.Enumeration; import java.util.Vector; import charva.awt.Dimension; import charva.awt.EventQueue; import charva.awt.Frame; import charva.awt.Insets; import charva.awt.ItemSelectable; import charva.awt.Point; import charva.awt.Toolkit; import charva.awt.event.AWTEvent; import charva.awt.event.ActionEvent; import charva.awt.event.ActionListener; import charva.awt.event.ItemEvent; import charva.awt.event.ItemListener; import charva.awt.event.KeyEvent; import charva.awt.event.MouseEvent; import charvax.swing.border.LineBorder; import charvax.swing.event.ListSelectionEvent; import charvax.swing.event.ListSelectionListener; /** * The JComboBox component allows the user to select an item from a pop-up * list of choices.<p> * When the combobox is in a non-popped-up state, it looks like a JButton * with a "diamond" character on the right. To make the popup menu appear, * the user positions the cursor over the combobox and presses ENTER.<p> * * When the user selects an item in the popup menu (by positioning the * cursor on it and pressing ENTER), the pop-up menu disappears and * only the selected item is shown. At the same time the JComboBox * posts an ActionEvent onto the system event queue. The "action command" * encapsulated in the ActionEvent is the list item that was selected.<p> * Note that this class provides an "Uneditable" JComboBox only. */ public class JComboBox extends JComponent implements ListSelectionListener, // (an implementation side-effect) ItemSelectable { /** Creates an empty JComboBox. */ public JComboBox() { DefaultComboBoxModel model = new DefaultComboBoxModel(); setModel(model); } /** Creates a JComboBox with the given model. */ public JComboBox(ComboBoxModel model) { setModel(model); } /** Creates a JComboBox that contains the elements in the specified * array. * @param items_ the array of items to display in the combobox */ public JComboBox(Object[] items_) { DefaultComboBoxModel model = new DefaultComboBoxModel(items_); setModel(model); } /** Creates a JComboBox that contains the elements in the specified * Vector. * @param items_ the vector of items to display in the combobox */ public JComboBox(Vector<?> items_) { DefaultComboBoxModel model = new DefaultComboBoxModel(items_); setModel(model); } /** Sets the data model that the JComboBox uses to obtain the list of * items. */ public void setModel(ComboBoxModel model_) { _model = model_; for (int i=0; i<_model.getSize(); i++) { String str = _model.getElementAt(i).toString(); if (str.length() > _columns) _columns = str.length(); } if (super.isDisplayed()) super.repaint(); } /** Add the specified item into the list of items.<p> * * Note that this method works only if the data model is * a MutableComboBoxModel (by default, it is). */ public void addItem(Object item_) { ((MutableComboBoxModel) _model).addElement(item_); if (item_.toString().length() > _columns) _columns = item_.toString().length(); } /** Insert the specified item at the specified index.<p> * * Note that this method works only if the data model is * a MutableComboBoxModel (by default, it is). */ public void insertItemAt(Object item_, int index_) { ((MutableComboBoxModel) _model).insertElementAt(item_, index_); if (item_.toString().length() > _columns) _columns = item_.toString().length(); } /** Remove the item at the specified index. <p> * * Note that this method works only if the data model is * a MutableComboBoxModel (by default, it is). */ public void removeItemAt(int index_) { ((MutableComboBoxModel) _model).removeElementAt(index_); } /** Removes the specified item from the combobox's list. If the * item was not in the list, the list is not changed.<p> * * Note that this method works only if the data model is * a MutableComboBoxModel (by default, it is). */ public void removeItem(Object item_) { ((MutableComboBoxModel) _model).removeElement(item_); } /** Removes all items. * * Note that this method works only if the data model is * a MutableComboBoxModel (by default, it is). */ public void removeAllItems() { while (_model.getSize() > 0) { removeItemAt(0); } } /** Returns the selected item. */ public Object getSelectedItem() { return _model.getSelectedItem(); } /** Sets the selected item in the JComboBox by specifying the * object in the list. */ public void setSelectedItem(Object obj_) { _model.setSelectedItem(obj_); } /** Sets the selected item in the JComboBox by specifying * the index in the list. */ public void setSelectedIndex(int index_) { Object selected = _model.getElementAt(index_); _model.setSelectedItem(selected); } /** * Sets the maximum number of rows that the JComboBox displays. */ public void setMaximumRowCount(int rows_) { _maxRows = rows_; } /** Returns width (including the diamond symbol). */ public int getWidth() { Insets insets = super.getInsets(); return _columns + insets.left + insets.right + 2; } public int getHeight() { Insets insets = super.getInsets(); return 1 + insets.top + insets.bottom; } public Dimension getSize() { return new Dimension(this.getWidth(), this.getHeight()); } public Dimension minimumSize() { return this.getSize(); } /** * Draw the selected item, surrounded by a box. * @param toolkit */ public void draw(Toolkit toolkit) { // Draw the border if it exists super.draw(toolkit); /* Get the absolute origin of this component. */ Point origin = getLocationOnScreen(); Insets insets = super.getInsets(); origin.translate(insets.left, insets.right); int colorpair = getCursesColor(); toolkit.setCursor(origin); String selectedItem = (String) _model.getSelectedItem(); StringBuffer buf = new StringBuffer(); for (int i=0; i<_columns + 1; i++) buf.append(' '); if (selectedItem != null) { buf.replace(1, selectedItem.length()+1, selectedItem); } int attribute = super.isEnabled() ? Toolkit.A_REVERSE : Toolkit.A_NORMAL; toolkit.addString(buf.toString(), attribute, colorpair); toolkit.setCursor(origin.addOffset(_columns + 1, 0)); toolkit.addChar(Toolkit.ACS_DIAMOND, attribute, colorpair); } /** * Register an ItemListener object for this component. */ public void addItemListener(ItemListener il_) { if (_itemListeners == null) _itemListeners = new Vector<ItemListener>(); _itemListeners.add(il_); } public void removeItemListener(ItemListener listener_) { if (_itemListeners == null) return; _itemListeners.remove(listener_); } /** * Invoke all the ItemListener callbacks that may have been registered * for this component. */ protected void fireItemStateChanged(ItemEvent ie_) { if (_itemListeners != null) { for (Enumeration<ItemListener> e = _itemListeners.elements(); e.hasMoreElements(); ) { ItemListener il = (ItemListener) e.nextElement(); il.itemStateChanged(ie_); } } } /** Overrides method in superclass. */ public void processEvent(AWTEvent evt_) { super.processEvent(evt_); if (evt_ instanceof ActionEvent) { fireActionEvent((ActionEvent) evt_); ItemEvent item_event = new ItemEvent(this, this, ItemEvent.SELECTED); fireItemStateChanged(item_event); } } /** * Register an ActionListener object for this component. */ public void addActionListener(ActionListener al_) { if (_actionListeners == null) _actionListeners = new Vector<ActionListener>(); _actionListeners.add(al_); } /** Invoke all the ActionListener callbacks that may have been registered * for this component. */ protected void fireActionEvent(ActionEvent ae_) { if (_actionListeners != null) { for (Enumeration<ActionListener> e = _actionListeners.elements(); e.hasMoreElements(); ) { ActionListener al = (ActionListener) e.nextElement(); al.actionPerformed(ae_); } } } /** * Process KeyEvents that have been generated by this JComboBox component. */ public void processKeyEvent(KeyEvent ke_) { int key = ke_.getKeyCode(); if (key == '\t') { getParent().nextFocus(); return; } else if (key == KeyEvent.VK_BACK_TAB) { getParent().previousFocus(); return; } else if (key == KeyEvent.VK_ENTER) { _activate(); } } /** Process a MouseEvent that was generated by clicking the mouse * on this JComboBox. */ public void processMouseEvent(MouseEvent e_) { // Request focus if this is a MOUSE_PRESSED super.processMouseEvent(e_); if (e_.getButton() == MouseEvent.BUTTON1 && e_.getModifiers() == MouseEvent.MOUSE_CLICKED && this.isFocusTraversable()) { _activate(); } } /** Make the combobox editable. */ public void setEditable(boolean editable) { // implement me } /** Implements the ListSelectionListener interface. */ public void valueChanged(ListSelectionEvent e_) { _popup.hide(); /* Put an ActionEvent onto the system event queue. */ EventQueue evtqueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); Object selectedItem = _popup.getSelectedItem(); if (selectedItem != null) _model.setSelectedItem(selectedItem); evtqueue.postEvent(new ActionEvent( this, _model.getSelectedItem().toString())); } public void requestFocus() { /* Generate the FOCUS_GAINED event. */ super.requestFocus(); /* Get the absolute origin of this component */ Point origin = getLocationOnScreen(); Insets insets = super.getInsets(); Toolkit.getDefaultToolkit().setCursor( origin.addOffset(insets.left, insets.top)); } /** Returns a String representation of this component. */ public String toString() { return "JComboBox location=" + getLocation() + " selectedItem=\"" + getSelectedItem() + "\""; } /** Output a description of this component to stderr. */ public void debug(int level_) { for (int i=0; i<level_; i++) System.err.print(" "); System.err.println(toString()); } private void _activate() { _popup = this.new Popup(this, _model); _popup.setMaximumRowCount(_maxRows); /* Get the absolute origin of this component. */ Point origin = getLocationOnScreen(); _popup.setLocation(origin); _popup.show(); } //==================================================================== // INSTANCE VARIABLES private ComboBoxModel _model; private int _columns = 3; // initial width /** The default value of 0 indicates that there is no limit on the * number of rows to display in the popup menu. */ private int _maxRows = 3; /** * A list of ActionListeners registered for this component. */ protected Vector<ActionListener> _actionListeners = null; /** * A list of ItemListeners registered for this component. */ protected Vector<ItemListener> _itemListeners = null; /** * This is a non-static inner class that implements the popup * window for the JComboBox component. */ private class Popup extends Frame { Popup(JComboBox parent_, ComboBoxModel model_) { _list = new JList(); setBackground(parent_.getBackground()); setForeground(parent_.getForeground()); _scrollpane = new JScrollPane(_list); _scrollpane.setViewportBorder(new LineBorder(getForeground())); // ComboBoxModel is a subclass of ListModel, so this works. _list.setModel(model_); _list.setColumns(_columns); Object selected = model_.getSelectedItem(); int selectedIndex = 0; for (int i=0; i<model_.getSize(); i++) { Object obj = model_.getElementAt(i); if (selected == obj) selectedIndex = i; //String str = obj.toString(); } _list.setSelectedIndex(selectedIndex); /* Ensure we use the add() method inherited from Container * rather than the add() method in the outer class. */ super.add(_scrollpane); _list.addListSelectionListener(parent_); _list.ensureIndexIsVisible(selectedIndex); } Object getSelectedItem() { /* If the user presses ENTER on the list entry that is * already selected, it becomes deselected in the JList; * so that _list.getselectedValue() returns null. The * caller must take this into account and ignore the value. */ return _list.getSelectedValue(); } /** Set the maximum number of rows to be displayed */ void setMaximumRowCount(int rows_) { _list.setVisibleRowCount(rows_); pack(); } private JList _list; private JScrollPane _scrollpane; } // end of nonstatic inner class Popup. private JComboBox.Popup _popup; }