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