       1 /*
       2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
       3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       4  *
       5  * This code is free software; you can redistribute it and/or modify it
       6  * under the terms of the GNU General Public License version 2 only, as
       7  * published by the Free Software Foundation.  Oracle designates this
       8  * particular file as subject to the "Classpath" exception as provided
       9  * by Oracle in the LICENSE file that accompanied this code.
      10  *
      11  * This code is distributed in the hope that it will be useful, but WITHOUT
      12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14  * version 2 for more details (a copy is included in the LICENSE file that
      15  * accompanied this code).
      16  *
      17  * You should have received a copy of the GNU General Public License version
      18  * 2 along with this work; if not, write to the Free Software Foundation,
      19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      20  *
      21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      22  * or visit www.oracle.com if you need additional information or have any
      23  * questions.
      24  */
      25
      26 package javax.swing;
      27
      28 import java.awt.Component;
      29 import java.awt.event.*;
      30 import java.beans.ConstructorProperties;
      31 import java.lang.Boolean;
      32 import javax.swing.table.*;
      33 import javax.swing.event.*;
      34 import java.util.EventObject;
      35 import javax.swing.tree.*;
      36 import java.io.Serializable;
      37
      38 /**
      39  * The default editor for table and tree cells.
      40  * <p>
      41  * <strong>Warning:</strong>
      42  * Serialized objects of this class will not be compatible with
      43  * future Swing releases. The current serialization support is
      44  * appropriate for short term storage or RMI between applications running
      45  * the same version of Swing.  As of 1.4, support for long term storage
      46  * of all JavaBeans&trade;
      47  * has been added to the <code>java.beans</code> package.
      48  * Please see {@link java.beans.XMLEncoder}.
      49  *
      50  * @author Alan Chung
      51  * @author Philip Milne
      52  * @since 1.2
      53  */
      54 @SuppressWarnings("serial") // Same-version serialization only
      55 public class DefaultCellEditor extends AbstractCellEditor
      56     implements TableCellEditor, TreeCellEditor {
      57
      58 //
      59 //  Instance Variables
      60 //
      61
      62     /** The Swing component being edited. */
      63     protected JComponent editorComponent;
      64     /**
      65      * The delegate class which handles all methods sent from the
      66      * <code>CellEditor</code>.
      67      */
      68     protected EditorDelegate delegate;
      69     /**
      70      * An integer specifying the number of clicks needed to start editing.
      71      * Even if <code>clickCountToStart</code> is defined as zero, it
      72      * will not initiate until a click occurs.
      73      */
      74     protected int clickCountToStart = 1;
      75
      76 //
      77 //  Constructors
      78 //
      79
      80     /**
      81      * Constructs a <code>DefaultCellEditor</code> that uses a text field.
      82      *
      83      * @param textField  a <code>JTextField</code> object
      84      */
      85     @ConstructorProperties({"component"})
      86     public DefaultCellEditor(final JTextField textField) {
      87         editorComponent = textField;
      88         this.clickCountToStart = 2;
      89         delegate = new EditorDelegate() {
      90             public void setValue(Object value) {
      91                 textField.setText((value != null) ? value.toString() : "");
      92             }
      93
      94             public Object getCellEditorValue() {
      95                 return textField.getText();
      96             }
      97         };
      98         textField.addActionListener(delegate);
      99     }
     100
     101     /**
     102      * Constructs a <code>DefaultCellEditor</code> object that uses a check box.
     103      *
     104      * @param checkBox  a <code>JCheckBox</code> object
     105      */
     106     public DefaultCellEditor(final JCheckBox checkBox) {
     107         editorComponent = checkBox;
     108         delegate = new EditorDelegate() {
     109             public void setValue(Object value) {
     110                 boolean selected = false;
     111                 if (value instanceof Boolean) {
     112                     selected = ((Boolean)value).booleanValue();
     113                 }
     114                 else if (value instanceof String) {
     115                     selected = value.equals("true");
     116                 }
     117                 checkBox.setSelected(selected);
     118             }
     119
     120             public Object getCellEditorValue() {
     121                 return Boolean.valueOf(checkBox.isSelected());
     122             }
     123         };
     124         checkBox.addActionListener(delegate);
     125         checkBox.setRequestFocusEnabled(false);
     126     }
     127
     128     /**
     129      * Constructs a <code>DefaultCellEditor</code> object that uses a
     130      * combo box.
     131      * @param <E> the type of the elements of comboBox
     132      * @param comboBox  a <code>JComboBox</code> object
     133      */
     134     @SuppressWarnings("unchecked")
     135     public <E> DefaultCellEditor(final JComboBox<E> comboBox) {
     136         editorComponent = comboBox;
     137         comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
     138         delegate = new EditorDelegate() {
     139             public void setValue(Object value) {
     140                 comboBox.setSelectedItem((E)value);
     141             }
     142
     143             public Object getCellEditorValue() {
     144                 return comboBox.getSelectedItem();
     145             }
     146
     147             public boolean shouldSelectCell(EventObject anEvent) {
     148                 if (anEvent instanceof MouseEvent) {
     149                     MouseEvent e = (MouseEvent)anEvent;
     150                     return e.getID() != MouseEvent.MOUSE_DRAGGED;
     151                 }
     152                 return true;
     153             }
     154             public boolean stopCellEditing() {
     155                 if (comboBox.isEditable()) {
     156                     // Commit edited value.
     157                     comboBox.actionPerformed(new ActionEvent(
     158                                      DefaultCellEditor.this, 0, ""));
     159                 }
     160                 return super.stopCellEditing();
     161             }
     162         };
     163         comboBox.addActionListener(delegate);
     164     }
     165
     166     /**
     167      * Returns a reference to the editor component.
     168      *
     169      * @return the editor <code>Component</code>
     170      */
     171     public Component getComponent() {
     172         return editorComponent;
     173     }
     174
     175 //
     176 //  Modifying
     177 //
     178
     179     /**
     180      * Specifies the number of clicks needed to start editing.
     181      *
     182      * @param count  an int specifying the number of clicks needed to start editing
     183      * @see #getClickCountToStart
     184      */
     185     public void setClickCountToStart(int count) {
     186         clickCountToStart = count;
     187     }
     188
     189     /**
     190      * Returns the number of clicks needed to start editing.
     191      * @return the number of clicks needed to start editing
     192      */
     193     public int getClickCountToStart() {
     194         return clickCountToStart;
     195     }
     196
     197 //
     198 //  Override the implementations of the superclass, forwarding all methods
     199 //  from the CellEditor interface to our delegate.
     200 //
     201
     202     /**
     203      * Forwards the message from the <code>CellEditor</code> to
     204      * the <code>delegate</code>.
     205      * @see EditorDelegate#getCellEditorValue
     206      */
     207     public Object getCellEditorValue() {
     208         return delegate.getCellEditorValue();
     209     }
     210
     211     /**
     212      * Forwards the message from the <code>CellEditor</code> to
     213      * the <code>delegate</code>.
     214      * @see EditorDelegate#isCellEditable(EventObject)
     215      */
     216     public boolean isCellEditable(EventObject anEvent) {
     217         return delegate.isCellEditable(anEvent);
     218     }
     219
     220     /**
     221      * Forwards the message from the <code>CellEditor</code> to
     222      * the <code>delegate</code>.
     223      * @see EditorDelegate#shouldSelectCell(EventObject)
     224      */
     225     public boolean shouldSelectCell(EventObject anEvent) {
     226         return delegate.shouldSelectCell(anEvent);
     227     }
     228
     229     /**
     230      * Forwards the message from the <code>CellEditor</code> to
     231      * the <code>delegate</code>.
     232      * @see EditorDelegate#stopCellEditing
     233      */
     234     public boolean stopCellEditing() {
     235         return delegate.stopCellEditing();
     236     }
     237
     238     /**
     239      * Forwards the message from the <code>CellEditor</code> to
     240      * the <code>delegate</code>.
     241      * @see EditorDelegate#cancelCellEditing
     242      */
     243     public void cancelCellEditing() {
     244         delegate.cancelCellEditing();
     245     }
     246
     247 //
     248 //  Implementing the TreeCellEditor Interface
     249 //
     250
     251     /** Implements the <code>TreeCellEditor</code> interface. */
     252     public Component getTreeCellEditorComponent(JTree tree, Object value,
     253                                                 boolean isSelected,
     254                                                 boolean expanded,
     255                                                 boolean leaf, int row) {
     256         String         stringValue = tree.convertValueToText(value, isSelected,
     257                                             expanded, leaf, row, false);
     258
     259         delegate.setValue(stringValue);
     260         return editorComponent;
     261     }
     262
     263 //
     264 //  Implementing the CellEditor Interface
     265 //
     266     /** Implements the <code>TableCellEditor</code> interface. */
     267     public Component getTableCellEditorComponent(JTable table, Object value,
     268                                                  boolean isSelected,
     269                                                  int row, int column) {
     270         delegate.setValue(value);
     271         if (editorComponent instanceof JCheckBox) {
     272             //in order to avoid a "flashing" effect when clicking a checkbox
     273             //in a table, it is important for the editor to have as a border
     274             //the same border that the renderer has, and have as the background
     275             //the same color as the renderer has. This is primarily only
     276             //needed for JCheckBox since this editor doesn't fill all the
     277             //visual space of the table cell, unlike a text field.
     278             TableCellRenderer renderer = table.getCellRenderer(row, column);
     279             Component c = renderer.getTableCellRendererComponent(table, value,
     280                     isSelected, true, row, column);
     281             if (c != null) {
     282                 editorComponent.setOpaque(true);
     283                 editorComponent.setBackground(c.getBackground());
     284                 if (c instanceof JComponent) {
     285                     editorComponent.setBorder(((JComponent)c).getBorder());
     286                 }
     287             } else {
     288                 editorComponent.setOpaque(false);
     289             }
     290         }
     291         return editorComponent;
     292     }
     293
     294
     295 //
     296 //  Protected EditorDelegate class
     297 //
     298
     299     /**
     300      * The protected <code>EditorDelegate</code> class.
     301      */
     302     protected class EditorDelegate implements ActionListener, ItemListener, Serializable {
     303
     304         /**  The value of this cell. */
     305         protected Object value;
     306
     307        /**
     308         * Returns the value of this cell.
     309         * @return the value of this cell
     310         */
     311         public Object getCellEditorValue() {
     312             return value;
     313         }
     314
     315        /**
     316         * Sets the value of this cell.
     317         * @param value the new value of this cell
     318         */
     319         public void setValue(Object value) {
     320             this.value = value;
     321         }
     322
     323        /**
     324         * Returns true if <code>anEvent</code> is <b>not</b> a
     325         * <code>MouseEvent</code>.  Otherwise, it returns true
     326         * if the necessary number of clicks have occurred, and
     327         * returns false otherwise.
     328         *
     329         * @param   anEvent         the event
     330         * @return  true  if cell is ready for editing, false otherwise
     331         * @see #setClickCountToStart
     332         * @see #shouldSelectCell
     333         */
     334         public boolean isCellEditable(EventObject anEvent) {
     335             if (anEvent instanceof MouseEvent) {
     336                 return ((MouseEvent)anEvent).getClickCount() >= clickCountToStart;
     337             }
     338             return true;
     339         }
     340
     341        /**
     342         * Returns true to indicate that the editing cell may
     343         * be selected.
     344         *
     345         * @param   anEvent         the event
     346         * @return  true
     347         * @see #isCellEditable
     348         */
     349         public boolean shouldSelectCell(EventObject anEvent) {
     350             return true;
     351         }
     352
     353        /**
     354         * Returns true to indicate that editing has begun.
     355         *
     356         * @param anEvent          the event
     357         * @return true to indicate editing has begun
     358         */
     359         public boolean startCellEditing(EventObject anEvent) {
     360             return true;
     361         }
     362
     363        /**
     364         * Stops editing and
     365         * returns true to indicate that editing has stopped.
     366         * This method calls <code>fireEditingStopped</code>.
     367         *
     368         * @return  true
     369         */
     370         public boolean stopCellEditing() {
     371             fireEditingStopped();
     372             return true;
     373         }
     374
     375        /**
     376         * Cancels editing.  This method calls <code>fireEditingCanceled</code>.
     377         */
     378        public void cancelCellEditing() {
     379            fireEditingCanceled();
     380        }
     381
     382        /**
     383         * When an action is performed, editing is ended.
     384         * @param e the action event
     385         * @see #stopCellEditing
     386         */
     387         public void actionPerformed(ActionEvent e) {
     388             DefaultCellEditor.this.stopCellEditing();
     389         }
     390
     391        /**
     392         * When an item's state changes, editing is ended.
     393         * @param e the action event
     394         * @see #stopCellEditing
     395         */
     396         public void itemStateChanged(ItemEvent e) {
     397             DefaultCellEditor.this.stopCellEditing();
     398         }
     399     }
     400
     401 } // End of class JCellEditor