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