       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      *
     132      * @param comboBox  a <code>JComboBox</code> object
     133      */
     134     public DefaultCellEditor(final JComboBox<?> comboBox) {
     135         editorComponent = comboBox;
     136         comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
     137         delegate = new EditorDelegate() {
     138             public void setValue(Object value) {
     139                 comboBox.setSelectedItem(value);
     140             }
     141
     142             public Object getCellEditorValue() {
     143                 return comboBox.getSelectedItem();
     144             }
     145
     146             public boolean shouldSelectCell(EventObject anEvent) {
     147                 if (anEvent instanceof MouseEvent) {
     148                     MouseEvent e = (MouseEvent)anEvent;
     149                     return e.getID() != MouseEvent.MOUSE_DRAGGED;
     150                 }
     151                 return true;
     152             }
     153             public boolean stopCellEditing() {
     154                 if (comboBox.isEditable()) {
     155                     // Commit edited value.
     156                     comboBox.actionPerformed(new ActionEvent(
     157                                      DefaultCellEditor.this, 0, ""));
     158                 }
     159                 return super.stopCellEditing();
     160             }
     161         };
     162         comboBox.addActionListener(delegate);
     163     }
     164
     165     /**
     166      * Returns a reference to the editor component.
     167      *
     168      * @return the editor <code>Component</code>
     169      */
     170     public Component getComponent() {
     171         return editorComponent;
     172     }
     173
     174 //
     175 //  Modifying
     176 //
     177
     178     /**
     179      * Specifies the number of clicks needed to start editing.
     180      *
     181      * @param count  an int specifying the number of clicks needed to start editing
     182      * @see #getClickCountToStart
     183      */
     184     public void setClickCountToStart(int count) {
     185         clickCountToStart = count;
     186     }
     187
     188     /**
     189      * Returns the number of clicks needed to start editing.
     190      * @return the number of clicks needed to start editing
     191      */
     192     public int getClickCountToStart() {
     193         return clickCountToStart;
     194     }
     195
     196 //
     197 //  Override the implementations of the superclass, forwarding all methods
     198 //  from the CellEditor interface to our delegate.
     199 //
     200
     201     /**
     202      * Forwards the message from the <code>CellEditor</code> to
     203      * the <code>delegate</code>.
     204      * @see EditorDelegate#getCellEditorValue
     205      */
     206     public Object getCellEditorValue() {
     207         return delegate.getCellEditorValue();
     208     }
     209
     210     /**
     211      * Forwards the message from the <code>CellEditor</code> to
     212      * the <code>delegate</code>.
     213      * @see EditorDelegate#isCellEditable(EventObject)
     214      */
     215     public boolean isCellEditable(EventObject anEvent) {
     216         return delegate.isCellEditable(anEvent);
     217     }
     218
     219     /**
     220      * Forwards the message from the <code>CellEditor</code> to
     221      * the <code>delegate</code>.
     222      * @see EditorDelegate#shouldSelectCell(EventObject)
     223      */
     224     public boolean shouldSelectCell(EventObject anEvent) {
     225         return delegate.shouldSelectCell(anEvent);
     226     }
     227
     228     /**
     229      * Forwards the message from the <code>CellEditor</code> to
     230      * the <code>delegate</code>.
     231      * @see EditorDelegate#stopCellEditing
     232      */
     233     public boolean stopCellEditing() {
     234         return delegate.stopCellEditing();
     235     }
     236
     237     /**
     238      * Forwards the message from the <code>CellEditor</code> to
     239      * the <code>delegate</code>.
     240      * @see EditorDelegate#cancelCellEditing
     241      */
     242     public void cancelCellEditing() {
     243         delegate.cancelCellEditing();
     244     }
     245
     246 //
     247 //  Implementing the TreeCellEditor Interface
     248 //
     249
     250     /** Implements the <code>TreeCellEditor</code> interface. */
     251     public Component getTreeCellEditorComponent(JTree tree, Object value,
     252                                                 boolean isSelected,
     253                                                 boolean expanded,
     254                                                 boolean leaf, int row) {
     255         String         stringValue = tree.convertValueToText(value, isSelected,
     256                                             expanded, leaf, row, false);
     257
     258         delegate.setValue(stringValue);
     259         return editorComponent;
     260     }
     261
     262 //
     263 //  Implementing the CellEditor Interface
     264 //
     265     /** Implements the <code>TableCellEditor</code> interface. */
     266     public Component getTableCellEditorComponent(JTable table, Object value,
     267                                                  boolean isSelected,
     268                                                  int row, int column) {
     269         delegate.setValue(value);
     270         if (editorComponent instanceof JCheckBox) {
     271             //in order to avoid a "flashing" effect when clicking a checkbox
     272             //in a table, it is important for the editor to have as a border
     273             //the same border that the renderer has, and have as the background
     274             //the same color as the renderer has. This is primarily only
     275             //needed for JCheckBox since this editor doesn't fill all the
     276             //visual space of the table cell, unlike a text field.
     277             TableCellRenderer renderer = table.getCellRenderer(row, column);
     278             Component c = renderer.getTableCellRendererComponent(table, value,
     279                     isSelected, true, row, column);
     280             if (c != null) {
     281                 editorComponent.setOpaque(true);
     282                 editorComponent.setBackground(c.getBackground());
     283                 if (c instanceof JComponent) {
     284                     editorComponent.setBorder(((JComponent)c).getBorder());
     285                 }
     286             } else {
     287                 editorComponent.setOpaque(false);
     288             }
     289         }
     290         return editorComponent;
     291     }
     292
     293
     294 //
     295 //  Protected EditorDelegate class
     296 //
     297
     298     /**
     299      * The protected <code>EditorDelegate</code> class.
     300      */
     301     protected class EditorDelegate implements ActionListener, ItemListener, Serializable {
     302
     303         /**  The value of this cell. */
     304         protected Object value;
     305
     306        /**
     307         * Returns the value of this cell.
     308         * @return the value of this cell
     309         */
     310         public Object getCellEditorValue() {
     311             return value;
     312         }
     313
     314        /**
     315         * Sets the value of this cell.
     316         * @param value the new value of this cell
     317         */
     318         public void setValue(Object value) {
     319             this.value = value;
     320         }
     321
     322        /**
     323         * Returns true if <code>anEvent</code> is <b>not</b> a
     324         * <code>MouseEvent</code>.  Otherwise, it returns true
     325         * if the necessary number of clicks have occurred, and
     326         * returns false otherwise.
     327         *
     328         * @param   anEvent         the event
     329         * @return  true  if cell is ready for editing, false otherwise
     330         * @see #setClickCountToStart
     331         * @see #shouldSelectCell
     332         */
     333         public boolean isCellEditable(EventObject anEvent) {
     334             if (anEvent instanceof MouseEvent) {
     335                 return ((MouseEvent)anEvent).getClickCount() >= clickCountToStart;
     336             }
     337             return true;
     338         }
     339
     340        /**
     341         * Returns true to indicate that the editing cell may
     342         * be selected.
     343         *
     344         * @param   anEvent         the event
     345         * @return  true
     346         * @see #isCellEditable
     347         */
     348         public boolean shouldSelectCell(EventObject anEvent) {
     349             return true;
     350         }
     351
     352        /**
     353         * Returns true to indicate that editing has begun.
     354         *
     355         * @param anEvent          the event
     356         * @return true to indicate editing has begun
     357         */
     358         public boolean startCellEditing(EventObject anEvent) {
     359             return true;
     360         }
     361
     362        /**
     363         * Stops editing and
     364         * returns true to indicate that editing has stopped.
     365         * This method calls <code>fireEditingStopped</code>.
     366         *
     367         * @return  true
     368         */
     369         public boolean stopCellEditing() {
     370             fireEditingStopped();
     371             return true;
     372         }
     373
     374        /**
     375         * Cancels editing.  This method calls <code>fireEditingCanceled</code>.
     376         */
     377        public void cancelCellEditing() {
     378            fireEditingCanceled();
     379        }
     380
     381        /**
     382         * When an action is performed, editing is ended.
     383         * @param e the action event
     384         * @see #stopCellEditing
     385         */
     386         public void actionPerformed(ActionEvent e) {
     387             DefaultCellEditor.this.stopCellEditing();
     388         }
     389
     390        /**
     391         * When an item's state changes, editing is ended.
     392         * @param e the action event
     393         * @see #stopCellEditing
     394         */
     395         public void itemStateChanged(ItemEvent e) {
     396             DefaultCellEditor.this.stopCellEditing();
     397         }
     398     }
     399
     400 } // End of class JCellEditor