classpath-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[cp-patches] FYI: Implementing cell editing in JTable.


From: Meskauskas Audrius
Subject: [cp-patches] FYI: Implementing cell editing in JTable.
Date: Mon, 16 Jan 2006 10:15:18 +0100
User-agent: Mozilla Thunderbird 1.0.2 (Windows/20050317)

This patch implements the cell editing in JTable. The editing session can be started by double clicking on the cell and completed by pressing Enter or canceled by pressing ESC. The table is updated and stores the changed value. This can be tested in the table of the Swing demo.

The implementation for the user-defined text editors is till missing.

2006-01-16  Audrius Meskauskas  <address@hidden>

* javax/swing/DefaultCellEditor.java
(delegate): Assign new instance immediately.
(DefaultCellEditor(JTextField textfield)): Require 2 clicks.
(getTableCellEditorComponent): Rewritten.
(prepareAsJTextField):New method (add listener only once).
* javax/swing/JTable.java
(editingCanceled): Rewritten.
(editingStopped ): Rewritten.
(rowAtPoint): Mind row margin.
(getCellRect): Mind row margin.
(getDefaultEditor): Removing JTextComponent border.
(editCellAt): Rewritten.
javax/swing/plaf/basic/BasicTableUI.java (MouseInputHandler):
Activate editing mode by the mouse clicks.
(getMaximumSize): Mind row margin.
(getPreferredSize): Mind row margin.
(TableAction): Added 'stop editing' command.

Index: javax/swing/DefaultCellEditor.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/DefaultCellEditor.java,v
retrieving revision 1.16
diff -u -r1.16 DefaultCellEditor.java
--- javax/swing/DefaultCellEditor.java  19 Oct 2005 15:45:03 -0000      1.16
+++ javax/swing/DefaultCellEditor.java  15 Jan 2006 23:17:36 -0000
@@ -215,9 +215,9 @@
   protected JComponent editorComponent;
 
   /**
-   * delegate
+   * The editor delegate (normally intialised only once).
    */
-  protected EditorDelegate delegate;
+  protected EditorDelegate delegate = new EditorDelegate();
 
   /**
    * clickCountToStart
@@ -232,7 +232,7 @@
   public DefaultCellEditor(JTextField textfield)
   {
     editorComponent = textfield;
-    clickCountToStart = 3;
+    clickCountToStart = 2;
   } // DefaultCellEditor()
 
   /**
@@ -386,13 +386,14 @@
   } // getTreeCellEditorComponent()
 
   /**
-   * getTableCellEditorComponent
+   * Get the cell editor component that will perform the editing session.
+   * If returned once, the same component should be returned again (reused).
    * 
-   * @param table TODO
-   * @param value TODO
-   * @param isSelected TODO
-   * @param row TODO
-   * @param column TODO
+   * @param table the table where the editing is performed
+   * @param value the current value of the table
+   * @param isSelected if true, the cell is currently selected
+   * @param row the row of the cell being edited
+   * @param column the column of the cell being edited
    *
    * @returns Component
    */
@@ -402,24 +403,42 @@
   {
     // NOTE: as specified by Sun, we don't call new() everytime, we return 
     // editorComponent on each call to getTableCellEditorComponent or
-    // getTreeCellEditorComponent.  However, currently JTextFields have a
-    // problem with getting rid of old text, so without calling new() there
-    // are some strange results.  If you edit more than one cell in the table
-    // text from previously edited cells may unexpectedly show up in the 
-    // cell you are currently editing.  This will be fixed automatically
-    // when JTextField is fixed.
+    // getTreeCellEditorComponent.  
     if (editorComponent instanceof JTextField)
-      {
-        ((JTextField)editorComponent).setText(value.toString());
-        delegate = new EditorDelegate();
-        ((JTextField)editorComponent).addActionListener(delegate);
-      }
-    else
-      {
-        // TODO
-      }
+      prepareAsJTextField(value);
     return editorComponent;
   } // getTableCellEditorComponent()
+  
+  /**
+   * Prepare the editorComponent as the text field.
+   * 
+   * @param value the value of the cell before editin.
+   */
+  private void prepareAsJTextField(Object value)
+  {
+    JTextField f = (JTextField) editorComponent;
+    if (value != null)
+      f.setText(value.toString());
+    else
+      // Default null to the empty string.
+      f.setText("");
 
+    // Do not register our listener again and again (resource leak).
+    ActionListener[] l = f.getActionListeners();
+    
+    boolean have = false;
+    for (int i = 0; i < l.length; i++)
+      {
+        // We cannot just remove all listeners as the user listeners 
+        // may be registered.
+        if (l[i]==delegate)
+          {
+            have = true;
+            break;
+          }
+      }
+    if (!have)
+      f.addActionListener(delegate);
+  }
 
 }
Index: javax/swing/JTable.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JTable.java,v
retrieving revision 1.64
diff -u -r1.64 JTable.java
--- javax/swing/JTable.java     17 Dec 2005 00:50:48 -0000      1.64
+++ javax/swing/JTable.java     15 Jan 2006 23:19:04 -0000
@@ -1765,44 +1765,39 @@
   {
     repaint();
   }
-
+  
   public void editingCanceled (ChangeEvent event)
   {
-    if (rowBeingEdited > -1 && columnBeingEdited > -1)
+    if (editorComp!=null)
       {
-        if (getValueAt(rowBeingEdited, columnBeingEdited) instanceof 
JTextField)
-          {
-            remove ((Component)getValueAt(rowBeingEdited, columnBeingEdited));
-            setValueAt(oldCellValue, rowBeingEdited, columnBeingEdited);
-          }
-        rowBeingEdited = -1;
-        columnBeingEdited = -1;
+        remove(editorComp);
+        editorComp = null;
       }
-    editorTimer.stop();
-    editorComp = null;
-    cellEditor = null;
-    requestFocusInWindow(false);
-    repaint();
   }
-
+  
+  /**
+   * Finish the current editing session and update the table with the
+   * new value by calling address@hidden #setValueAt}.
+   * 
+   * @param event the change event
+   */
   public void editingStopped (ChangeEvent event)
   {
-    if (rowBeingEdited > -1 && columnBeingEdited > -1)
+    if (editorComp!=null)
       {
-        if (getValueAt(rowBeingEdited, columnBeingEdited) instanceof 
JTextField)
+        remove(editorComp);
+        if (editorComp instanceof JTextField)
+          {
+            JTextField f = (JTextField) editorComp;
+            setValueAt(f.getText(), rowBeingEdited, columnBeingEdited);        
    
+          }
+        else
           {
-            remove((Component)getValueAt(rowBeingEdited, columnBeingEdited));
-            setValueAt(((JTextField)editorComp).getText(), 
-                       rowBeingEdited, columnBeingEdited);
+            /** TODO FIXME Handle the editor types other than text field. */
           }
-        rowBeingEdited = -1;
-        columnBeingEdited = -1;
+        editorComp = null;
       }
-    editorTimer.stop();
-    editorComp = null;
-    cellEditor = null;
-    requestFocusInWindow(false);
-    repaint();
+    requestFocusInWindow();
   }
 
   public void tableChanged (TableModelEvent event)
@@ -1875,7 +1870,7 @@
     if (point != null)
       {
         int nrows = getRowCount();
-        int height = getRowHeight();
+        int height = getRowHeight() + getRowMargin();
         int y = point.y;
 
         for (int i = 0; i < nrows; ++i)
@@ -1925,7 +1920,7 @@
     if (includeSpacing)
       return new Rectangle(x, y, width, height);
     else
-      return new Rectangle(x, y, width - x_gap, height - y_gap);
+      return new Rectangle(x, y, width - x_gap, height - y_gap);      
   }
 
   public void clearSelection()
@@ -2025,7 +2020,10 @@
     else
       {
        // FIXME: We have at least an editor for Object.class in our defaults.
-        TableCellEditor r = new DefaultCellEditor(new JTextField());
+        // The text field is without the border.
+        JTextField t = new JTextField();
+        t.setBorder(null);
+        TableCellEditor r = new DefaultCellEditor(t);
         defaultEditorsByColumnClass.put(columnClass, r);
         return r;
       }
@@ -3273,15 +3271,36 @@
    */
   public boolean editCellAt (int row, int column)
   {
+    // Complete the previous editing session, if still active.
+    if (isEditing())
+      editingStopped(new ChangeEvent("editingStopped"));
+    
+    // Select the row being edited.
+    getSelectionModel().setSelectionInterval(row, row);
     oldCellValue = getValueAt(row, column);
     setCellEditor(getCellEditor(row, column));
     editorComp = prepareEditor(cellEditor, row, column);
-    cellEditor.addCellEditorListener(this);
     rowBeingEdited = row;
     columnBeingEdited = column;
-    setValueAt(editorComp, row, column);
-    ((JTextField)editorComp).requestFocusInWindow(false);
-    editorTimer.start();
+    
+    if (editorComp instanceof JTextField)
+      {
+        JTextField t = (JTextField) editorComp;
+        Rectangle r = getCellRect(row, column, true);
+        // Place the text field so that it would not touch the table
+        // border.
+        int m = getRowMargin();
+        r.translate(m,m);
+        r.width-=m;
+        t.setBounds(r);
+        add(t);
+        t.requestFocusInWindow(false);
+      }
+    else
+      {
+        /** TODO FIXME editor component type is still resticted to JTextField 
*/
+      }
+    
     return true;
   }
 
Index: javax/swing/plaf/basic/BasicTableUI.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicTableUI.java,v
retrieving revision 1.38
diff -u -r1.38 BasicTableUI.java
--- javax/swing/plaf/basic/BasicTableUI.java    21 Nov 2005 13:18:29 -0000      
1.38
+++ javax/swing/plaf/basic/BasicTableUI.java    15 Jan 2006 23:14:16 -0000
@@ -57,7 +57,9 @@
 
 import javax.swing.AbstractAction;
 import javax.swing.ActionMap;
+import javax.swing.CellEditor;
 import javax.swing.CellRendererPane;
+import javax.swing.DefaultCellEditor;
 import javax.swing.DefaultListSelectionModel;
 import javax.swing.InputMap;
 import javax.swing.JComponent;
@@ -74,6 +76,7 @@
 import javax.swing.plaf.ComponentUI;
 import javax.swing.plaf.InputMapUIResource;
 import javax.swing.plaf.TableUI;
+import javax.swing.table.TableCellEditor;
 import javax.swing.table.TableCellRenderer;
 import javax.swing.table.TableColumn;
 import javax.swing.table.TableColumnModel;
@@ -193,10 +196,31 @@
             colModel.setSelectionInterval(lo_col, hi_col);
         }
     }
-
-    public void mouseClicked(MouseEvent e) 
+    
+    /**
+     * For the double click, start the cell editor.
+     */
+    public void mouseClicked(MouseEvent e)
     {
-      // TODO: What should be done here, if anything?
+      Point p = e.getPoint();
+      int row = table.rowAtPoint(p);
+      int col = table.columnAtPoint(p);
+      if (table.isCellEditable(row, col))
+        {
+          // If the cell editor is the default editor, we request the
+          // number of the required clicks from it. Otherwise,
+          // require two clicks (double click).
+          TableCellEditor editor = table.getCellEditor(row, col);
+          if (editor instanceof DefaultCellEditor)
+            {
+              DefaultCellEditor ce = (DefaultCellEditor) editor;
+              if (e.getClickCount() < ce.getClickCountToStart())
+                return;
+            }
+          else if (e.getClickCount() < 2)
+            return;
+          table.editCellAt(row, col);
+        }
     }
 
     public void mouseDragged(MouseEvent e) 
@@ -354,7 +378,8 @@
       maxTotalColumnWidth += table.getColumnModel().getColumn(i).getMaxWidth();
     if (maxTotalColumnWidth == 0 || table.getRowCount() == 0)
       return null;
-    return new Dimension(maxTotalColumnWidth, 
table.getRowCount()*table.getRowHeight());
+    return new Dimension(maxTotalColumnWidth, table.getRowCount()*
+                         (table.getRowHeight()+table.getRowMargin()));
   }
 
   /**
@@ -380,7 +405,7 @@
   public Dimension getPreferredSize(JComponent comp) 
   {
     int width = table.getColumnModel().getTotalColumnWidth();
-    int height = table.getRowCount() * table.getRowHeight();
+    int height = table.getRowCount() * 
(table.getRowHeight()+table.getRowMargin());
     return new Dimension(width, height);
   }
 
@@ -854,6 +879,10 @@
           rowModel.setAnchorSelectionIndex(rowLead);
           colModel.setAnchorSelectionIndex(colLead);
         }
+      else if (command.equals("stopEditing"))
+        {
+          table.editingStopped(new ChangeEvent(command));
+        }
       else 
         {
           // If we're here that means we bound this TableAction class
@@ -1219,7 +1248,7 @@
     Rectangle clip = gfx.getClipBounds();
     TableColumnModel cols = table.getColumnModel();
 
-    int height = table.getRowHeight();
+    int height = table.getRowHeight() + table.getRowMargin();
     int x0 = 0, y0 = 0;
     int x = x0;
     int y = y0;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]