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  */
  53 @SuppressWarnings("serial") // Same-version serialization only
  54 public class DefaultCellEditor extends AbstractCellEditor
  55     implements TableCellEditor, TreeCellEditor {
  56 
  57 //
  58 //  Instance Variables
  59 //
  60 
  61     /** The Swing component being edited. */
  62     protected JComponent editorComponent;
  63     /**
  64      * The delegate class which handles all methods sent from the
  65      * <code>CellEditor</code>.
  66      */
  67     protected EditorDelegate delegate;
  68     /**
  69      * An integer specifying the number of clicks needed to start editing.
  70      * Even if <code>clickCountToStart</code> is defined as zero, it
  71      * will not initiate until a click occurs.
  72      */
  73     protected int clickCountToStart = 1;
  74 
  75 //
  76 //  Constructors
  77 //
  78 
  79     /**
  80      * Constructs a <code>DefaultCellEditor</code> that uses a text field.
  81      *
  82      * @param textField  a <code>JTextField</code> object
  83      */
  84     @ConstructorProperties({"component"})
  85     public DefaultCellEditor(final JTextField textField) {
  86         editorComponent = textField;
  87         this.clickCountToStart = 2;
  88         delegate = new EditorDelegate() {
  89             public void setValue(Object value) {
  90                 textField.setText((value != null) ? value.toString() : "");
  91             }
  92 
  93             public Object getCellEditorValue() {
  94                 return textField.getText();
  95             }
  96         };
  97         textField.addActionListener(delegate);
  98     }
  99 
 100     /**
 101      * Constructs a <code>DefaultCellEditor</code> object that uses a check box.
 102      *
 103      * @param checkBox  a <code>JCheckBox</code> object
 104      */
 105     public DefaultCellEditor(final JCheckBox checkBox) {
 106         editorComponent = checkBox;
 107         delegate = new EditorDelegate() {
 108             public void setValue(Object value) {
 109                 boolean selected = false;
 110                 if (value instanceof Boolean) {
 111                     selected = ((Boolean)value).booleanValue();
 112                 }
 113                 else if (value instanceof String) {
 114                     selected = value.equals("true");
 115                 }
 116                 checkBox.setSelected(selected);
 117             }
 118 
 119             public Object getCellEditorValue() {
 120                 return Boolean.valueOf(checkBox.isSelected());
 121             }
 122         };
 123         checkBox.addActionListener(delegate);
 124         checkBox.setRequestFocusEnabled(false);
 125     }
 126 
 127     /**
 128      * Constructs a <code>DefaultCellEditor</code> object that uses a
 129      * combo box.
 130      *
 131      * @param comboBox  a <code>JComboBox</code> object
 132      */
 133     public DefaultCellEditor(final JComboBox comboBox) {
 134         editorComponent = comboBox;
 135         comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
 136         delegate = new EditorDelegate() {
 137             public void setValue(Object value) {
 138                 comboBox.setSelectedItem(value);
 139             }
 140 
 141             public Object getCellEditorValue() {
 142                 return comboBox.getSelectedItem();
 143             }
 144 
 145             public boolean shouldSelectCell(EventObject anEvent) {
 146                 if (anEvent instanceof MouseEvent) {
 147                     MouseEvent e = (MouseEvent)anEvent;
 148                     return e.getID() != MouseEvent.MOUSE_DRAGGED;
 149                 }
 150                 return true;
 151             }
 152             public boolean stopCellEditing() {
 153                 if (comboBox.isEditable()) {
 154                     // Commit edited value.
 155                     comboBox.actionPerformed(new ActionEvent(
 156                                      DefaultCellEditor.this, 0, ""));
 157                 }
 158                 return super.stopCellEditing();
 159             }
 160         };
 161         comboBox.addActionListener(delegate);
 162     }
 163 
 164     /**
 165      * Returns a reference to the editor component.
 166      *
 167      * @return the editor <code>Component</code>
 168      */
 169     public Component getComponent() {
 170         return editorComponent;
 171     }
 172 
 173 //
 174 //  Modifying
 175 //
 176 
 177     /**
 178      * Specifies the number of clicks needed to start editing.
 179      *
 180      * @param count  an int specifying the number of clicks needed to start editing
 181      * @see #getClickCountToStart
 182      */
 183     public void setClickCountToStart(int count) {
 184         clickCountToStart = count;
 185     }
 186 
 187     /**
 188      * Returns the number of clicks needed to start editing.
 189      * @return the number of clicks needed to start editing
 190      */
 191     public int getClickCountToStart() {
 192         return clickCountToStart;
 193     }
 194 
 195 //
 196 //  Override the implementations of the superclass, forwarding all methods
 197 //  from the CellEditor interface to our delegate.
 198 //
 199 
 200     /**
 201      * Forwards the message from the <code>CellEditor</code> to
 202      * the <code>delegate</code>.
 203      * @see EditorDelegate#getCellEditorValue
 204      */
 205     public Object getCellEditorValue() {
 206         return delegate.getCellEditorValue();
 207     }
 208 
 209     /**
 210      * Forwards the message from the <code>CellEditor</code> to
 211      * the <code>delegate</code>.
 212      * @see EditorDelegate#isCellEditable(EventObject)
 213      */
 214     public boolean isCellEditable(EventObject anEvent) {
 215         return delegate.isCellEditable(anEvent);
 216     }
 217 
 218     /**
 219      * Forwards the message from the <code>CellEditor</code> to
 220      * the <code>delegate</code>.
 221      * @see EditorDelegate#shouldSelectCell(EventObject)
 222      */
 223     public boolean shouldSelectCell(EventObject anEvent) {
 224         return delegate.shouldSelectCell(anEvent);
 225     }
 226 
 227     /**
 228      * Forwards the message from the <code>CellEditor</code> to
 229      * the <code>delegate</code>.
 230      * @see EditorDelegate#stopCellEditing
 231      */
 232     public boolean stopCellEditing() {
 233         return delegate.stopCellEditing();
 234     }
 235 
 236     /**
 237      * Forwards the message from the <code>CellEditor</code> to
 238      * the <code>delegate</code>.
 239      * @see EditorDelegate#cancelCellEditing
 240      */
 241     public void cancelCellEditing() {
 242         delegate.cancelCellEditing();
 243     }
 244 
 245 //
 246 //  Implementing the TreeCellEditor Interface
 247 //
 248 
 249     /** Implements the <code>TreeCellEditor</code> interface. */
 250     public Component getTreeCellEditorComponent(JTree tree, Object value,
 251                                                 boolean isSelected,
 252                                                 boolean expanded,
 253                                                 boolean leaf, int row) {
 254         String         stringValue = tree.convertValueToText(value, isSelected,
 255                                             expanded, leaf, row, false);
 256 
 257         delegate.setValue(stringValue);
 258         return editorComponent;
 259     }
 260 
 261 //
 262 //  Implementing the CellEditor Interface
 263 //
 264     /** Implements the <code>TableCellEditor</code> interface. */
 265     public Component getTableCellEditorComponent(JTable table, Object value,
 266                                                  boolean isSelected,
 267                                                  int row, int column) {
 268         delegate.setValue(value);
 269         if (editorComponent instanceof JCheckBox) {
 270             //in order to avoid a "flashing" effect when clicking a checkbox
 271             //in a table, it is important for the editor to have as a border
 272             //the same border that the renderer has, and have as the background
 273             //the same color as the renderer has. This is primarily only
 274             //needed for JCheckBox since this editor doesn't fill all the
 275             //visual space of the table cell, unlike a text field.
 276             TableCellRenderer renderer = table.getCellRenderer(row, column);
 277             Component c = renderer.getTableCellRendererComponent(table, value,
 278                     isSelected, true, row, column);
 279             if (c != null) {
 280                 editorComponent.setOpaque(true);
 281                 editorComponent.setBackground(c.getBackground());
 282                 if (c instanceof JComponent) {
 283                     editorComponent.setBorder(((JComponent)c).getBorder());
 284                 }
 285             } else {
 286                 editorComponent.setOpaque(false);
 287             }
 288         }
 289         return editorComponent;
 290     }
 291 
 292 
 293 //
 294 //  Protected EditorDelegate class
 295 //
 296 
 297     /**
 298      * The protected <code>EditorDelegate</code> class.
 299      */
 300     protected class EditorDelegate implements ActionListener, ItemListener, Serializable {
 301 
 302         /**  The value of this cell. */
 303         protected Object value;
 304 
 305        /**
 306         * Returns the value of this cell.
 307         * @return the value of this cell
 308         */
 309         public Object getCellEditorValue() {
 310             return value;
 311         }
 312 
 313        /**
 314         * Sets the value of this cell.
 315         * @param value the new value of this cell
 316         */
 317         public void setValue(Object value) {
 318             this.value = value;
 319         }
 320 
 321        /**
 322         * Returns true if <code>anEvent</code> is <b>not</b> a
 323         * <code>MouseEvent</code>.  Otherwise, it returns true
 324         * if the necessary number of clicks have occurred, and
 325         * returns false otherwise.
 326         *
 327         * @param   anEvent         the event
 328         * @return  true  if cell is ready for editing, false otherwise
 329         * @see #setClickCountToStart
 330         * @see #shouldSelectCell
 331         */
 332         public boolean isCellEditable(EventObject anEvent) {
 333             if (anEvent instanceof MouseEvent) {
 334                 return ((MouseEvent)anEvent).getClickCount() >= clickCountToStart;
 335             }
 336             return true;
 337         }
 338 
 339        /**
 340         * Returns true to indicate that the editing cell may
 341         * be selected.
 342         *
 343         * @param   anEvent         the event
 344         * @return  true
 345         * @see #isCellEditable
 346         */
 347         public boolean shouldSelectCell(EventObject anEvent) {
 348             return true;
 349         }
 350 
 351        /**
 352         * Returns true to indicate that editing has begun.
 353         *
 354         * @param anEvent          the event
 355         */
 356         public boolean startCellEditing(EventObject anEvent) {
 357             return true;
 358         }
 359 
 360        /**
 361         * Stops editing and
 362         * returns true to indicate that editing has stopped.
 363         * This method calls <code>fireEditingStopped</code>.
 364         *
 365         * @return  true
 366         */
 367         public boolean stopCellEditing() {
 368             fireEditingStopped();
 369             return true;
 370         }
 371 
 372        /**
 373         * Cancels editing.  This method calls <code>fireEditingCanceled</code>.
 374         */
 375        public void cancelCellEditing() {
 376            fireEditingCanceled();
 377        }
 378 
 379        /**
 380         * When an action is performed, editing is ended.
 381         * @param e the action event
 382         * @see #stopCellEditing
 383         */
 384         public void actionPerformed(ActionEvent e) {
 385             DefaultCellEditor.this.stopCellEditing();
 386         }
 387 
 388        /**
 389         * When an item's state changes, editing is ended.
 390         * @param e the action event
 391         * @see #stopCellEditing
 392         */
 393         public void itemStateChanged(ItemEvent e) {
 394             DefaultCellEditor.this.stopCellEditing();
 395         }
 396     }
 397 
 398 } // End of class JCellEditor