This patch should fix the editing support for JTree. After double
clicking on the
tree node, the editing text component appears under right place. It is
possible to
edit text. The node is updated after finishing the session with ENTER.
2006-01-25 Audrius Meskauskas <[EMAIL PROTECTED]>
* javax/swing/DefaultCellEditor.java (getTreeCellEditorComponent):
Rewritten.
* javax/swing/JTree.java (stopEditing, cancelEditing): Return without
action if not editing.
* javax/swing/plaf/basic/BasicTreeUI.java
(CellEditorHandler.editingCancelled): Delegate to cancelEditing.
(CellEditorHandler.editingStopped): Delegate to stopEditing.
(EditorUpdateTimer): Removed.
(TreeAction.actionPerformed): Stop and not cancel the current editing
when starting editing another node.
(editorTimer, newVal): Removed.
(cancelEditing): Do not send the cancel message.
(completeEditing): Obtain the edited value from the editor.
(finish): New method.
(paintRow): Do not paint the editing component here.
(startEditing, stopEditing): Rewritten.
* javax/swing/tree/DefaultTreeCellEditor.java
(DefaultTextField): Added SVUID.
(EditorContainer): Rewritten.
(RealEditorListener): New inner class.
(ICON_TEXT_GAP, TREE_ICON_GAP: New constants).
(constructor): Add cell editor listener. Do not instantiate timer.
(actionPerformed): Return without action.
(cancelCellEditing): Rewritten.
(createTreeCellEditor): Add cell editor listener to the editor.
(getCellEditorValue): Request the value from the realEditor.
(isCellEditable): Removed timer management.
(prepareForEditing): Remove all components befor adding the
editingComponent.
(startEditingTimer): Start only if it is not null.
(stopCellEditing): Rewritten.
(stopEditingTimer): New method.
(valueChanged): Do not configure editing component here.
Index: DefaultCellEditor.java
===================================================================
RCS file: /sources/classpath/classpath/javax/swing/DefaultCellEditor.java,v
retrieving revision 1.19
diff -u -r1.19 DefaultCellEditor.java
--- DefaultCellEditor.java 20 Jan 2006 09:50:20 -0000 1.19
+++ DefaultCellEditor.java 25 Jan 2006 08:44:23 -0000
@@ -521,25 +521,7 @@
boolean expanded, boolean leaf,
int row)
{
- if (editorComponent instanceof JTextField)
- {
- ((JTextField)editorComponent).setText(value.toString());
- delegate = new EditorDelegate();
- ((JTextField)editorComponent).addActionListener(delegate);
- }
- else if (editorComponent instanceof JCheckBox)
- {
- ((JCheckBox)editorComponent).setText(value.toString());
- delegate = new EditorDelegate();
- ((JCheckBox)editorComponent).addActionListener(delegate);
- }
- else if (editorComponent instanceof JComboBox)
- {
- ((JComboBox)editorComponent).setSelectedItem(value.toString());
- delegate = new EditorDelegate();
- ((JComboBox)editorComponent).addActionListener(delegate);
- }
-
+ delegate.setValue(value);
return editorComponent;
} // getTreeCellEditorComponent()
Index: JTree.java
===================================================================
RCS file: /sources/classpath/classpath/javax/swing/JTree.java,v
retrieving revision 1.53
diff -u -r1.53 JTree.java
--- JTree.java 4 Jan 2006 17:02:32 -0000 1.53
+++ JTree.java 25 Jan 2006 08:44:30 -0000
@@ -2497,8 +2497,9 @@
{
TreeUI ui = getUI();
- if (ui != null)
- return ui.stopEditing(this);
+ if (isEditing())
+ if (ui != null)
+ return ui.stopEditing(this);
return false;
}
@@ -2506,9 +2507,10 @@
public void cancelEditing()
{
TreeUI ui = getUI();
-
- if (ui != null)
- ui.cancelEditing(this);
+
+ if (isEditing())
+ if (ui != null)
+ ui.cancelEditing(this);
}
public void startEditingAtPath(TreePath path)
Index: plaf/basic/BasicTreeUI.java
===================================================================
RCS file: /sources/classpath/classpath/javax/swing/plaf/basic/BasicTreeUI.java,v
retrieving revision 1.117
diff -u -r1.117 BasicTreeUI.java
--- plaf/basic/BasicTreeUI.java 9 Jan 2006 18:44:46 -0000 1.117
+++ plaf/basic/BasicTreeUI.java 25 Jan 2006 08:44:38 -0000
@@ -114,6 +114,7 @@
* @see javax.swing.JTree
* @author Lillian Angel ([EMAIL PROTECTED])
* @author Sascha Brawer ([EMAIL PROTECTED])
+ * @author Audrius Meskauskas ([EMAIL PROTECTED])
*/
public class BasicTreeUI extends TreeUI
{
@@ -225,12 +226,6 @@
/** Set to true if the editor has a different size than the renderer. */
protected boolean editorHasDifferentSize;
- /** The action listener for the editor's Timer. */
- Timer editorTimer = new EditorUpdateTimer();
-
- /** The new value of the node after editing. */
- Object newVal;
-
/** The action bound to KeyStrokes. */
TreeAction action;
@@ -796,7 +791,10 @@
public boolean stopEditing(JTree tree)
{
if (isEditing(tree))
- completeEditing(true, false, false);
+ {
+ completeEditing(false, false, true);
+ finish();
+ }
return !isEditing(tree);
}
@@ -807,9 +805,12 @@
* is the tree to cancel the editing session on.
*/
public void cancelEditing(JTree tree)
- {
- if (isEditing(tree))
- completeEditing(false, true, false);
+ {
+ // There is no need to send the cancel message to the editor,
+ // as the cancellation event itself arrives from it. This would
+ // only be necessary when cancelling the editing programatically.
+ completeEditing(false, false, false);
+ finish();
}
/**
@@ -1246,7 +1247,7 @@
protected void pathWasExpanded(TreePath path)
{
validCachedPreferredSize = false;
- tree.repaint();
+ tree.repaint();
}
/**
@@ -1621,7 +1622,14 @@
}
if (messageTree)
- treeModel.valueForPathChanged(tree.getLeadSelectionPath(), newVal);
+ {
+ TreeCellEditor editor = getCellEditor();
+ if (editor != null)
+ {
+ Object value = editor.getCellEditorValue();
+ treeModel.valueForPathChanged(tree.getLeadSelectionPath(), value);
+ }
+ }
}
/**
@@ -1636,44 +1644,46 @@
*/
protected boolean startEditing(TreePath path, MouseEvent event)
{
- int x;
- int y;
- if (event == null)
- {
- Rectangle bounds = getPathBounds(tree, path);
- x = bounds.x;
- y = bounds.y;
- }
- else
- {
- x = event.getX();
- y = event.getY();
- }
-
+ // Force to recalculate the maximal row height.
+ maxHeight = 0;
+
+ // Force to recalculate the cached preferred size.
+ validCachedPreferredSize = false;
+
updateCellEditor();
TreeCellEditor ed = getCellEditor();
+
if (ed != null && ed.shouldSelectCell(event) && ed.isCellEditable(event))
{
+ Rectangle bounds = getPathBounds(tree, path);
+
+ // Extend the right boundary till the tree width.
+ bounds.width = tree.getWidth() - bounds.x;
+
editingPath = path;
editingRow = tree.getRowForPath(editingPath);
- Object val = editingPath.getLastPathComponent();
- cellEditor.addCellEditorListener(cellEditorListener);
+ Object value = editingPath.getLastPathComponent();
+
stopEditingInCompleteEditing = false;
boolean expanded = tree.isExpanded(editingPath);
isEditing = true;
- editingComponent = ed.getTreeCellEditorComponent(tree, val, true,
+ editingComponent = ed.getTreeCellEditorComponent(tree, value, true,
expanded,
isLeaf(editingRow),
editingRow);
- editingComponent.getParent().setVisible(true);
- editingComponent.getParent().validate();
- tree.add(editingComponent.getParent());
- editingComponent.getParent().validate();
- validCachedPreferredSize = false;
+
+ // Remove all previous components (if still present). Only one
+ // container with the editing component inside is allowed in the tree.
+ tree.removeAll();
+
+ // The editing component must be added to its container. We add the
+ // container, not the editing component itself.
+ Component container = editingComponent.getParent();
+ container.setBounds(bounds);
+ tree.add(container);
+ editingComponent.requestFocus();
- ((JTextField) editingComponent).requestFocusInWindow(false);
- editorTimer.start();
return true;
}
return false;
@@ -1922,7 +1932,7 @@
tree.clearSelection();
if (tree.isEditing() && !e.getActionCommand().equals("startEditing"))
- tree.cancelEditing();
+ tree.stopEditing();
tree.scrollPathToVisible(lead);
}
@@ -1957,51 +1967,7 @@
}
}
- /**
- * The timer that updates the editor component.
- */
- private class EditorUpdateTimer extends Timer implements ActionListener
- {
- /**
- * Creates a new EditorUpdateTimer object with a default delay of 0.3
- * seconds.
- */
- public EditorUpdateTimer()
- {
- super(300, null);
- addActionListener(this);
- }
-
- /**
- * Lets the caret blink and repaints the table.
- */
- public void actionPerformed(ActionEvent ev)
- {
- Caret c = ((JTextField) editingComponent).getCaret();
- if (c != null)
- c.setVisible(!c.isVisible());
- tree.repaint();
- }
-
- /**
- * Updates the blink delay according to the current caret.
- */
- public void update()
- {
- stop();
- Caret c = ((JTextField) editingComponent).getCaret();
- if (c != null)
- {
- setDelay(c.getBlinkRate());
- if (((JTextField) editingComponent).isEditable())
- start();
- else
- c.setVisible(false);
- }
- }
- }
-
- /**
+ /**
* Updates the preferred size when scrolling, if necessary.
*/
public class ComponentHandler extends ComponentAdapter implements
@@ -2089,29 +2055,7 @@
*/
public void editingStopped(ChangeEvent e)
{
- editingPath = null;
- editingRow = -1;
- stopEditingInCompleteEditing = false;
- if (editingComponent != null)
- {
- tree.remove(editingComponent.getParent());
- editingComponent = null;
- }
- if (cellEditor != null)
- {
- newVal = ((JTextField) getCellEditor().getCellEditorValue()).getText();
- completeEditing(false, false, true);
- if (cellEditor instanceof DefaultTreeCellEditor)
- tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor);
- cellEditor.removeCellEditorListener(cellEditorListener);
- setCellEditor(null);
- createdCellEditor = false;
- }
- isEditing = false;
- tree.requestFocusInWindow(false);
- editorTimer.stop();
- validCachedPreferredSize = false;
- tree.repaint();
+ stopEditing(tree);
}
/**
@@ -2123,25 +2067,7 @@
*/
public void editingCanceled(ChangeEvent e)
{
- editingPath = null;
- editingRow = -1;
- stopEditingInCompleteEditing = false;
- if (editingComponent != null)
- tree.remove(editingComponent.getParent());
- editingComponent = null;
- if (cellEditor != null)
- {
- if (cellEditor instanceof DefaultTreeCellEditor)
- tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor);
- cellEditor.removeCellEditorListener(cellEditorListener);
- setCellEditor(null);
- createdCellEditor = false;
- }
- tree.requestFocusInWindow(false);
- editorTimer.stop();
- isEditing = false;
- validCachedPreferredSize = false;
- tree.repaint();
+ cancelEditing(tree);
}
}// CellEditorHandler
@@ -2686,7 +2612,7 @@
public class TreeHomeAction extends AbstractAction
{
- /** direction is either home or end */
+ /** The direction, either home or end */
protected int direction;
/**
@@ -2983,7 +2909,7 @@
public void valueChanged(TreeSelectionEvent event)
{
if (tree.isEditing())
- tree.cancelEditing();
+ tree.stopEditing();
}
}// TreeSelectionHandler
@@ -3650,25 +3576,14 @@
if (row != 0)
bounds.x += gap;
bounds.width = preferredSize.width + bounds.x;
- if (editingComponent != null && editingPath != null && isEditing(tree)
- && node.equals(editingPath.getLastPathComponent()))
- {
- rendererPane.paintComponent(g, editingComponent.getParent(), null,
- bounds);
- }
- else
- {
- TreeCellRenderer dtcr = tree.getCellRenderer();
- if (dtcr == null)
- dtcr = createDefaultCellRenderer();
-
- Component c = dtcr.getTreeCellRendererComponent(tree, node,
- selected,
- isExpanded, isLeaf,
- row,
- tree.hasFocus());
- rendererPane.paintComponent(g, c, c.getParent(), bounds);
- }
+ TreeCellRenderer dtcr = tree.getCellRenderer();
+ if (dtcr == null)
+ dtcr = createDefaultCellRenderer();
+
+ Component c = dtcr.getTreeCellRendererComponent(tree, node, selected,
+ isExpanded, isLeaf,
+ row, tree.hasFocus());
+ rendererPane.paintComponent(g, c, c.getParent(), bounds);
}
}
@@ -3801,4 +3716,22 @@
}
return null;
}
+
+ /**
+ * Finish the editing session.
+ */
+ void finish()
+ {
+ editingPath = null;
+ editingRow = -1;
+ stopEditingInCompleteEditing = false;
+ isEditing = false;
+ tree.removeAll();
+ validCachedPreferredSize = false;
+
+ // Repaint the region, where was the editing component.
+ tree.repaint(editingComponent.getParent().getBounds());
+ editingComponent = null;
+ }
+
} // BasicTreeUI
Index: tree/DefaultTreeCellEditor.java
===================================================================
RCS file: /sources/classpath/classpath/javax/swing/tree/DefaultTreeCellEditor.java,v
retrieving revision 1.18
diff -u -r1.18 DefaultTreeCellEditor.java
--- tree/DefaultTreeCellEditor.java 17 Nov 2005 11:49:49 -0000 1.18
+++ tree/DefaultTreeCellEditor.java 25 Jan 2006 08:44:41 -0000
@@ -45,7 +45,6 @@
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
-import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -60,26 +59,46 @@
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
-import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.CellEditorListener;
+import javax.swing.event.ChangeEvent;
import javax.swing.event.EventListenerList;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
/**
- * DefaultTreeCellEditor
+ * Participates in the tree cell editing.
+ *
* @author Andrew Selkirk
+ * @author Audrius Meskauskas
*/
public class DefaultTreeCellEditor
implements ActionListener, TreeCellEditor, TreeSelectionListener
{
/**
- * EditorContainer
+ * The gap between the icon and editing component during editing.
+ */
+ static int ICON_TEXT_GAP = 3;
+
+ /**
+ * The left margin of the editing container (the gap between the tree and
+ * the editing component of the editing icon.
+ */
+ static int TREE_ICON_GAP = ICON_TEXT_GAP;
+
+ /**
+ * This container that appears on the tree during editing session.
+ * It contains the editing component displays various other editor -
+ * specific parts like editing icon.
*/
public class EditorContainer extends Container
{
+ /**
+ * Use v 1.5 serial version UID for interoperability.
+ */
+ static final long serialVersionUID = 6470339600449699810L;
+
/**
* Creates an <code>EditorContainer</code> object.
*/
@@ -96,17 +115,11 @@
{
// Do nothing here.
}
-
- /**
- * Returns the preferred size for the Container.
- *
- * @return Dimension of EditorContainer
- */
- public Dimension getPreferredSize()
+
+ public void setBounds(Rectangle bounds)
{
- Dimension containerSize = super.getPreferredSize();
- containerSize.width += DefaultTreeCellEditor.this.offset;
- return containerSize;
+ super.setBounds(bounds);
+ doLayout();
}
/**
@@ -118,63 +131,68 @@
*/
public void paint(Graphics g)
{
- Rectangle tr = tree.getPathBounds(lastPath);
- if (tr != null)
+ if (editingIcon != null)
{
- Insets i = ((DefaultTextField) editingComponent).getBorder()
- .getBorderInsets(this);
- int textIconGap = 3;
- tr.x -= i.left;
-
- // paints icon
- if (editingIcon != null)
- {
- editingIcon.paintIcon(this, g, tr.x - editingIcon.
- getIconWidth()/2, tr.y + i.top + i.bottom);
- tr.x += editingIcon.getIconWidth()/2 + textIconGap;
- }
-
- tr.width += offset;
-
- // paint background
- g.translate(tr.x, tr.y);
- editingComponent.setSize(new Dimension(tr.width, tr.height));
- editingComponent.paint(g);
- g.translate(-tr.x, -tr.y);
+ // From the previous version, the left margin is taken as half
+ // of the icon width.
+ editingIcon.paintIcon(this, g, TREE_ICON_GAP, 0);
}
super.paint(g);
}
/**
- * Lays out this Container. If editing, the editor will be placed at offset
- * in the x direction and 0 for y.
+ * Lays out this Container, moving the editor component to the left
+ * (leaving place for the icon).
*/
public void doLayout()
{
- if (DefaultTreeCellEditor.this.tree.isEditing())
- setLocation(offset, 0);
- super.doLayout();
+ // The offset of the editing component.
+ int eOffset;
+
+ // Move the component to the left, leaving room for the editing icon:
+ if (editingIcon != null)
+ eOffset = TREE_ICON_GAP + editingIcon.getIconWidth() + ICON_TEXT_GAP;
+ else
+ eOffset = 0;
+
+ Rectangle bounds = getBounds();
+ Component c = getComponent(0);
+ c.setLocation(eOffset, 0);
+
+ // Span the editing component near over all window width.
+ c.setSize(bounds.width - eOffset - TREE_ICON_GAP, bounds.height);
+ /*
+ * @specnote the Sun sets some more narrow editing component width (it is
+ * not documented how does it is calculated). However as our text field is
+ * still not able to auto - scroll horizontally, replicating such strategy
+ * would prevent adding extra characters to the text being edited.
+ */
}
}
/**
- * DefaultTextField
+ * The default text field, used in the editing sessions.
*/
public class DefaultTextField extends JTextField
{
+ /**
+ * Use v 1.5 serial version UID for interoperability.
+ */
+ static final long serialVersionUID = -6629304544265300143L;
+
/**
- * border
+ * The border of the text field.
*/
protected Border border;
/**
* Creates a <code>DefaultTextField</code> object.
*
- * @param border the border to use
+ * @param aBorder the border to use
*/
- public DefaultTextField(Border border)
+ public DefaultTextField(Border aBorder)
{
- this.border = border;
+ border = aBorder;
}
/**
@@ -228,6 +246,31 @@
return renderer.getPreferredSize();
}
}
+
+ /**
+ * Listens for the events from the realEditor.
+ */
+ class RealEditorListener implements CellEditorListener
+ {
+ /**
+ * The method is called when the editing has been cancelled.
+ * @param event unused
+ */
+ public void editingCanceled(ChangeEvent event)
+ {
+ cancelCellEditing();
+ }
+
+ /**
+ * The method is called after completing the editing session.
+ *
+ * @param event unused
+ */
+ public void editingStopped(ChangeEvent event)
+ {
+ stopCellEditing();
+ }
+ }
private EventListenerList listenerList = new EventListenerList();
@@ -334,6 +377,9 @@
if (editor == null)
editor = createTreeCellEditor();
+ else
+ editor.addCellEditorListener(new RealEditorListener());
+
realEditor = editor;
lastPath = tree.getLeadSelectionPath();
@@ -342,7 +388,6 @@
setFont(UIManager.getFont("Tree.font"));
setBorderSelectionColor(UIManager.getColor("Tree.selectionBorderColor"));
editingIcon = renderer.getIcon();
- timer = new javax.swing.Timer(1200, this);
}
/**
@@ -371,7 +416,7 @@
else
renderer.setIcon(renderer.getClosedIcon());
editingIcon = renderer.getIcon();
-
+
editingComponent = getTreeCellEditorComponent(tree, val, true,
expanded, isLeaf, lastRow);
}
@@ -477,13 +522,14 @@
}
/**
- * Returns the value currently being edited.
+ * Returns the value currently being edited (requests it from the
+ * [EMAIL PROTECTED] realEditor}.
*
* @return the value currently being edited
*/
public Object getCellEditorValue()
{
- return editingComponent;
+ return realEditor.getCellEditorValue();
}
/**
@@ -503,12 +549,6 @@
prepareForEditing();
return true;
}
-
- // Cell may not be currently editable, but may need to start timer.
- if (shouldStartEditingTimer(event))
- startEditingTimer();
- else if (timer.isRunning())
- timer.stop();
return false;
}
@@ -532,9 +572,11 @@
*/
public boolean stopCellEditing()
{
- if (editingComponent != null && realEditor.stopCellEditing())
+ if (editingComponent != null)
{
- timer.stop();
+ stopEditingTimer();
+ tree.stopEditing();
+ editingComponent = null;
return true;
}
return false;
@@ -548,15 +590,26 @@
{
if (editingComponent != null)
{
- timer.stop();
- realEditor.cancelCellEditing();
+ tree.cancelEditing();
+ editingComponent = null;
}
+ stopEditingTimer();
+ }
+
+ /**
+ * Stop the editing timer, if it is installed and running.
+ */
+ private void stopEditingTimer()
+ {
+ if (timer != null && timer.isRunning())
+ timer.stop();
}
/**
* Adds a <code>CellEditorListener</code> object to this editor.
- *
- * @param listener the listener to add
+ *
+ * @param listener
+ * the listener to add
*/
public void addCellEditorListener(CellEditorListener listener)
{
@@ -595,21 +648,16 @@
tPath = lastPath;
lastPath = e.getNewLeadSelectionPath();
lastRow = tree.getRowForPath(lastPath);
- configureEditingComponent(tree, renderer, realEditor);
+ stopCellEditing();
}
/**
- * Messaged when the timer fires, this will start the editing session.
+ * Messaged when the timer fires.
*
* @param e the event that characterizes the action.
*/
public void actionPerformed(ActionEvent e)
{
- if (lastPath != null && tPath != null && tPath.equals(lastPath))
- {
- tree.startEditingAtPath(lastPath);
- timer.stop();
- }
}
/**
@@ -639,13 +687,11 @@
}
/**
- * Starts the editing timer.
+ * Starts the editing timer (if one installed).
*/
protected void startEditingTimer()
{
- if (timer == null)
- timer = new javax.swing.Timer(1200, this);
- if (!timer.isRunning())
+ if (timer != null)
timer.start();
}
@@ -713,6 +759,7 @@
*/
protected void prepareForEditing()
{
+ editingContainer.removeAll();
editingContainer.add(editingComponent);
}
@@ -736,6 +783,7 @@
{
realEditor = new DefaultCellEditor(new DefaultTreeCellEditor.DefaultTextField(
UIManager.getBorder("Tree.selectionBorder")));
+ realEditor.addCellEditorListener(new RealEditorListener());
return realEditor;
}
}
_______________________________________________
Classpath-patches mailing list
[email protected]
http://developer.classpath.org/mailman/listinfo/classpath-patches