001    /*
002     * $Id: ComboBoxCellEditor.java 2370 2007-11-02 14:26:47Z kschaefe $
003     *
004     * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005     * Santa Clara, California 95054, U.S.A. All rights reserved.
006     *
007     * This library is free software; you can redistribute it and/or
008     * modify it under the terms of the GNU Lesser General Public
009     * License as published by the Free Software Foundation; either
010     * version 2.1 of the License, or (at your option) any later version.
011     * 
012     * This library is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     * Lesser General Public License for more details.
016     * 
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this library; if not, write to the Free Software
019     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    package org.jdesktop.swingx.autocomplete;
022    
023    import javax.swing.*;
024    import javax.swing.table.TableCellEditor;
025    import java.awt.event.ActionEvent;
026    import java.awt.event.KeyAdapter;
027    import java.awt.event.KeyEvent;
028    import java.beans.PropertyChangeEvent;
029    import java.beans.PropertyChangeListener;
030    import java.io.Serializable;
031    
032    /**
033     * <p>This is a cell editor that can be used when a combo box (that has been set
034     * up for automatic completion) is to be used in a JTable. The
035     * {@link javax.swing.DefaultCellEditor DefaultCellEditor} won't work in this
036     * case, because each time an item gets selected it stops cell editing and hides
037     * the combo box.
038     * </p>
039     * <p>
040     * Usage example:
041     * </p>
042     * <p>
043     * <pre><code>
044     * JTable table = ...;
045     * JComboBox comboBox = ...;
046     * ...
047     * TableColumn column = table.getColumnModel().getColumn(0);
048     * column.setCellEditor(new ComboBoxCellEditor(comboBox));
049     * </code></pre>
050     * </p>
051     */
052    public class ComboBoxCellEditor extends AbstractCellEditor implements TableCellEditor, Serializable {
053        
054        /** the combo box */
055        private JComboBox comboBox;
056    
057        /**
058         * Creates a new ComboBoxCellEditor.
059         * @param comboBox the comboBox that should be used as the cell editor.
060         */
061        public ComboBoxCellEditor(final JComboBox comboBox) {
062            this.comboBox = comboBox;
063            
064            Handler handler = new Handler();
065            
066            // Don't do this:
067            // this.comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
068            // it probably breaks various things
069            
070            // hitting enter in the combo box should stop cellediting
071            JComponent editorComponent = (JComponent) comboBox.getEditor().getEditorComponent();
072            editorComponent.addKeyListener(handler);
073            // remove the editor's border - the cell itself already has one
074            editorComponent.setBorder(null);
075    
076            // editor component might change (e.g. a look&feel change)
077            // the new editor component needs to be modified then (keyListener, border)
078            comboBox.addPropertyChangeListener(handler);
079        }
080        
081        // ------ Implementing CellEditor ------
082        /**
083         * Returns the value contained in the combo box
084         * @return the value contained in the combo box
085         */
086        public Object getCellEditorValue() {
087            return comboBox.getSelectedItem();
088        }
089        
090        /**
091         * Tells the combo box to stop editing and accept any partially edited value as the value of the combo box.
092         * Always returns true.
093         * @return true
094         */
095        public boolean stopCellEditing() {
096            if (comboBox.isEditable()) {
097                // Notify the combo box that editing has stopped (e.g. User pressed F2)
098                comboBox.actionPerformed(new ActionEvent(this, 0, ""));
099            }
100            fireEditingStopped();
101            return true;
102        }
103        
104        // ------ Implementing TableCellEditor ------
105        /**
106         * Sets an initial value for the combo box.
107         * Returns the combo box that should be added to the client's Component hierarchy.
108         * Once installed in the client's hierarchy this combo box will then be able to draw and receive user input.
109         * @param table the JTable that is asking the editor to edit; can be null
110         * @param value the value of the cell to be edited; null is a valid value
111         * @param isSelected will be ignored
112         * @param row the row of the cell being edited
113         * @param column the column of the cell being edited
114         * @return the combo box for editing
115         */
116        public java.awt.Component getTableCellEditorComponent(javax.swing.JTable table, Object value, boolean isSelected, int row, int column) {
117            comboBox.setSelectedItem(value);
118            return comboBox;
119        }
120        
121        // ------ Implementing TreeCellEditor ------
122    //    public java.awt.Component getTreeCellEditorComponent(javax.swing.JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
123    //        String stringValue = tree.convertValueToText(value, isSelected, expanded, leaf, row, false);
124    //        comboBox.setSelectedItem(stringValue);
125    //        return comboBox;
126    //    }
127        
128        class Handler extends KeyAdapter implements PropertyChangeListener {
129            public void keyPressed(KeyEvent keyEvent) {
130                int keyCode = keyEvent.getKeyCode();
131                if (keyCode==KeyEvent.VK_ENTER) stopCellEditing();
132            }
133            public void propertyChange(PropertyChangeEvent e) {
134                if (e.getPropertyName().equals("editor")) {
135                    ComboBoxEditor editor = comboBox.getEditor();
136                    if (editor!=null && editor.getEditorComponent()!=null) {
137                        JComponent editorComponent = (JComponent) comboBox.getEditor().getEditorComponent();
138                        editorComponent.addKeyListener(this);
139                        editorComponent.setBorder(null);
140                    }
141                }
142            }
143        }
144    }