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