1 /* 2 * Copyright (c) 1997, 2020, 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"}) DefaultCellEditor(final JTextField textField)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 */ DefaultCellEditor(final JCheckBox checkBox)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 */ DefaultCellEditor(final JComboBox<?> comboBox)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 */ getComponent()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 */ setClickCountToStart(int count)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 */ getClickCountToStart()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 */ getCellEditorValue()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 */ isCellEditable(EventObject anEvent)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 */ shouldSelectCell(EventObject anEvent)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 */ stopCellEditing()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 */ cancelCellEditing()242 public void cancelCellEditing() { 243 delegate.cancelCellEditing(); 244 } 245 246 // 247 // Implementing the TreeCellEditor Interface 248 // 249 250 /** Implements the <code>TreeCellEditor</code> interface. */ getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row)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. */ getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)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 * Constructs an {@code EditorDelegate}. 308 */ EditorDelegate()309 protected EditorDelegate() {} 310 311 /** 312 * Returns the value of this cell. 313 * @return the value of this cell 314 */ getCellEditorValue()315 public Object getCellEditorValue() { 316 return value; 317 } 318 319 /** 320 * Sets the value of this cell. 321 * @param value the new value of this cell 322 */ setValue(Object value)323 public void setValue(Object value) { 324 this.value = value; 325 } 326 327 /** 328 * Returns true if <code>anEvent</code> is <b>not</b> a 329 * <code>MouseEvent</code>. Otherwise, it returns true 330 * if the necessary number of clicks have occurred, and 331 * returns false otherwise. 332 * 333 * @param anEvent the event 334 * @return true if cell is ready for editing, false otherwise 335 * @see #setClickCountToStart 336 * @see #shouldSelectCell 337 */ isCellEditable(EventObject anEvent)338 public boolean isCellEditable(EventObject anEvent) { 339 if (anEvent instanceof MouseEvent) { 340 return ((MouseEvent)anEvent).getClickCount() >= clickCountToStart; 341 } 342 return true; 343 } 344 345 /** 346 * Returns true to indicate that the editing cell may 347 * be selected. 348 * 349 * @param anEvent the event 350 * @return true 351 * @see #isCellEditable 352 */ shouldSelectCell(EventObject anEvent)353 public boolean shouldSelectCell(EventObject anEvent) { 354 return true; 355 } 356 357 /** 358 * Returns true to indicate that editing has begun. 359 * 360 * @param anEvent the event 361 * @return true to indicate editing has begun 362 */ startCellEditing(EventObject anEvent)363 public boolean startCellEditing(EventObject anEvent) { 364 return true; 365 } 366 367 /** 368 * Stops editing and 369 * returns true to indicate that editing has stopped. 370 * This method calls <code>fireEditingStopped</code>. 371 * 372 * @return true 373 */ stopCellEditing()374 public boolean stopCellEditing() { 375 fireEditingStopped(); 376 return true; 377 } 378 379 /** 380 * Cancels editing. This method calls <code>fireEditingCanceled</code>. 381 */ cancelCellEditing()382 public void cancelCellEditing() { 383 fireEditingCanceled(); 384 } 385 386 /** 387 * When an action is performed, editing is ended. 388 * @param e the action event 389 * @see #stopCellEditing 390 */ actionPerformed(ActionEvent e)391 public void actionPerformed(ActionEvent e) { 392 DefaultCellEditor.this.stopCellEditing(); 393 } 394 395 /** 396 * When an item's state changes, editing is ended. 397 * @param e the action event 398 * @see #stopCellEditing 399 */ itemStateChanged(ItemEvent e)400 public void itemStateChanged(ItemEvent e) { 401 DefaultCellEditor.this.stopCellEditing(); 402 } 403 } 404 405 } // End of class JCellEditor 406