summaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java')
-rw-r--r--libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java792
1 files changed, 792 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java b/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java
new file mode 100644
index 000000000..9ee0a14ba
--- /dev/null
+++ b/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java
@@ -0,0 +1,792 @@
+/* DefaultTreeCellEditor.java --
+ Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.tree;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.EventObject;
+
+import javax.swing.DefaultCellEditor;
+import javax.swing.Icon;
+import javax.swing.JTextField;
+import javax.swing.JTree;
+import javax.swing.SwingUtilities;
+import javax.swing.Timer;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.event.CellEditorListener;
+import javax.swing.event.EventListenerList;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+
+/**
+ * Participates in the tree cell editing.
+ *
+ * @author Andrew Selkirk
+ * @author Audrius Meskauskas
+ */
+public class DefaultTreeCellEditor
+ implements ActionListener, TreeCellEditor, TreeSelectionListener
+{
+ /**
+ * 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.
+ */
+ public EditorContainer()
+ {
+ setLayout(null);
+ }
+
+ /**
+ * This method only exists for API compatibility and is useless as it does
+ * nothing. It got probably introduced by accident.
+ */
+ public void EditorContainer()
+ {
+ // Do nothing here.
+ }
+
+ /**
+ * Overrides Container.paint to paint the node's icon and use the selection
+ * color for the background.
+ *
+ * @param g -
+ * the specified Graphics window
+ */
+ public void paint(Graphics g)
+ {
+ // Paint editing icon.
+ if (editingIcon != null)
+ {
+ // From the previous version, the left margin is taken as half
+ // of the icon width.
+ int y = Math.max(0, (getHeight() - editingIcon.getIconHeight()) / 2);
+ editingIcon.paintIcon(this, g, 0, y);
+ }
+ // Paint border.
+ Color c = getBorderSelectionColor();
+ if (c != null)
+ {
+ g.setColor(c);
+ g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
+ }
+ super.paint(g);
+ }
+
+ /**
+ * Lays out this Container, moving the editor component to the left
+ * (leaving place for the icon).
+ */
+ public void doLayout()
+ {
+ if (editingComponent != null)
+ {
+ editingComponent.getPreferredSize();
+ editingComponent.setBounds(offset, 0, getWidth() - offset,
+ getHeight());
+ }
+ }
+
+ public Dimension getPreferredSize()
+ {
+ Dimension dim;
+ if (editingComponent != null)
+ {
+ dim = editingComponent.getPreferredSize();
+ dim.width += offset + 5;
+ if (renderer != null)
+ {
+ Dimension r = renderer.getPreferredSize();
+ dim.height = Math.max(dim.height, r.height);
+ }
+ if (editingIcon != null)
+ dim.height = Math.max(dim.height, editingIcon.getIconHeight());
+ dim.width = Math.max(100, dim.width);
+ }
+ else
+ dim = new Dimension(0, 0);
+ return dim;
+ }
+ }
+
+ /**
+ * 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;
+
+ /**
+ * The border of the text field.
+ */
+ protected Border border;
+
+ /**
+ * Creates a <code>DefaultTextField</code> object.
+ *
+ * @param aBorder the border to use
+ */
+ public DefaultTextField(Border aBorder)
+ {
+ border = aBorder;
+ }
+
+ /**
+ * Gets the font of this component.
+ * @return this component's font; if a font has not been set for
+ * this component, the font of its parent is returned (if the parent
+ * is not null, otherwise null is returned).
+ */
+ public Font getFont()
+ {
+ Font font = super.getFont();
+ if (font == null)
+ {
+ Component parent = getParent();
+ if (parent != null)
+ return parent.getFont();
+ return null;
+ }
+ return font;
+ }
+
+ /**
+ * Returns the border of the text field.
+ *
+ * @return the border
+ */
+ public Border getBorder()
+ {
+ return border;
+ }
+
+ /**
+ * Overrides JTextField.getPreferredSize to return the preferred size
+ * based on current font, if set, or else use renderer's font.
+ *
+ * @return the Dimension of this textfield.
+ */
+ public Dimension getPreferredSize()
+ {
+ Dimension size = super.getPreferredSize();
+ if (renderer != null && DefaultTreeCellEditor.this.getFont() == null)
+ {
+ size.height = renderer.getPreferredSize().height;
+ }
+ return renderer.getPreferredSize();
+ }
+ }
+
+ private EventListenerList listenerList = new EventListenerList();
+
+ /**
+ * Editor handling the editing.
+ */
+ protected TreeCellEditor realEditor;
+
+ /**
+ * Renderer, used to get border and offsets from.
+ */
+ protected DefaultTreeCellRenderer renderer;
+
+ /**
+ * Editing container, will contain the editorComponent.
+ */
+ protected Container editingContainer;
+
+ /**
+ * Component used in editing, obtained from the editingContainer.
+ */
+ protected transient Component editingComponent;
+
+ /**
+ * As of Java 2 platform v1.4 this field should no longer be used.
+ * If you wish to provide similar behavior you should directly
+ * override isCellEditable.
+ */
+ protected boolean canEdit;
+
+ /**
+ * Used in editing. Indicates x position to place editingComponent.
+ */
+ protected transient int offset;
+
+ /**
+ * JTree instance listening too.
+ */
+ protected transient JTree tree;
+
+ /**
+ * Last path that was selected.
+ */
+ protected transient TreePath lastPath;
+
+ /**
+ * Used before starting the editing session.
+ */
+ protected transient javax.swing.Timer timer;
+
+ /**
+ * Row that was last passed into getTreeCellEditorComponent.
+ */
+ protected transient int lastRow;
+
+ /**
+ * True if the border selection color should be drawn.
+ */
+ protected Color borderSelectionColor;
+
+ /**
+ * Icon to use when editing.
+ */
+ protected transient Icon editingIcon;
+
+ /**
+ * Font to paint with, null indicates font of renderer is to be used.
+ */
+ protected Font font;
+
+ /**
+ * Constructs a DefaultTreeCellEditor object for a JTree using the
+ * specified renderer and a default editor. (Use this constructor
+ * for normal editing.)
+ *
+ * @param tree - a JTree object
+ * @param renderer - a DefaultTreeCellRenderer object
+ */
+ public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer)
+ {
+ this(tree, renderer, null);
+ }
+
+ /**
+ * Constructs a DefaultTreeCellEditor object for a JTree using the specified
+ * renderer and the specified editor. (Use this constructor
+ * for specialized editing.)
+ *
+ * @param tree - a JTree object
+ * @param renderer - a DefaultTreeCellRenderer object
+ * @param editor - a TreeCellEditor object
+ */
+ public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer,
+ TreeCellEditor editor)
+ {
+ this.renderer = renderer;
+ realEditor = editor;
+ if (realEditor == null)
+ realEditor = createTreeCellEditor();
+ editingContainer = createContainer();
+ setTree(tree);
+ Color c = UIManager.getColor("Tree.editorBorderSelectionColor");
+ setBorderSelectionColor(c);
+ }
+
+ /**
+ * writeObject
+ *
+ * @param value0
+ * TODO
+ * @exception IOException
+ * TODO
+ */
+ private void writeObject(ObjectOutputStream value0) throws IOException
+ {
+ // TODO
+ }
+
+ /**
+ * readObject
+ * @param value0 TODO
+ * @exception IOException TODO
+ * @exception ClassNotFoundException TODO
+ */
+ private void readObject(ObjectInputStream value0)
+ throws IOException, ClassNotFoundException
+ {
+ // TODO
+ }
+
+ /**
+ * Sets the color to use for the border.
+ * @param newColor - the new border color
+ */
+ public void setBorderSelectionColor(Color newColor)
+ {
+ this.borderSelectionColor = newColor;
+ }
+
+ /**
+ * Returns the color the border is drawn.
+ * @return Color
+ */
+ public Color getBorderSelectionColor()
+ {
+ return borderSelectionColor;
+ }
+
+ /**
+ * Sets the font to edit with. null indicates the renderers
+ * font should be used. This will NOT override any font you have
+ * set in the editor the receiver was instantied with. If null for
+ * an editor was passed in, a default editor will be created that
+ * will pick up this font.
+ *
+ * @param font - the editing Font
+ */
+ public void setFont(Font font)
+ {
+ if (font != null)
+ this.font = font;
+ else
+ this.font = renderer.getFont();
+ }
+
+ /**
+ * Gets the font used for editing.
+ *
+ * @return the editing font
+ */
+ public Font getFont()
+ {
+ return font;
+ }
+
+ /**
+ * Configures the editor. Passed onto the realEditor.
+ * Sets an initial value for the editor. This will cause
+ * the editor to stopEditing and lose any partially edited value
+ * if the editor is editing when this method is called.
+ * Returns the component that should be added to the client's Component
+ * hierarchy. Once installed in the client's hierarchy this component will
+ * then be able to draw and receive user input.
+ *
+ * @param tree - the JTree that is asking the editor to edit; this parameter can be null
+ * @param value - the value of the cell to be edited
+ * @param isSelected - true is the cell is to be rendered with selection highlighting
+ * @param expanded - true if the node is expanded
+ * @param leaf - true if the node is a leaf node
+ * @param row - the row index of the node being edited
+ *
+ * @return the component for editing
+ */
+ public Component getTreeCellEditorComponent(JTree tree, Object value,
+ boolean isSelected,
+ boolean expanded,
+ boolean leaf, int row)
+ {
+ setTree(tree);
+ lastRow = row;
+ determineOffset(tree, value, isSelected, expanded, leaf, row);
+ if (editingComponent != null)
+ editingContainer.remove(editingComponent);
+
+ editingComponent = realEditor.getTreeCellEditorComponent(tree, value,
+ isSelected,
+ expanded, leaf,
+ row);
+ Font f = getFont();
+ if (f == null)
+ {
+ if (renderer != null)
+ f = renderer.getFont();
+ if (f == null)
+ f = tree.getFont();
+ }
+ editingContainer.setFont(f);
+ prepareForEditing();
+ return editingContainer;
+ }
+
+ /**
+ * Returns the value currently being edited (requests it from the
+ * {@link #realEditor}.
+ *
+ * @return the value currently being edited
+ */
+ public Object getCellEditorValue()
+ {
+ return realEditor.getCellEditorValue();
+ }
+
+ /**
+ * If the realEditor returns true to this message, prepareForEditing
+ * is messaged and true is returned.
+ *
+ * @param event - the event the editor should use to consider whether to
+ * begin editing or not
+ * @return true if editing can be started
+ */
+ public boolean isCellEditable(EventObject event)
+ {
+ boolean ret = false;
+ boolean ed = false;
+ if (event != null)
+ {
+ if (event.getSource() instanceof JTree)
+ {
+ setTree((JTree) event.getSource());
+ if (event instanceof MouseEvent)
+ {
+ MouseEvent me = (MouseEvent) event;
+ TreePath path = tree.getPathForLocation(me.getX(), me.getY());
+ ed = lastPath != null && path != null && lastPath.equals(path);
+ if (path != null)
+ {
+ lastRow = tree.getRowForPath(path);
+ Object val = path.getLastPathComponent();
+ boolean isSelected = tree.isRowSelected(lastRow);
+ boolean isExpanded = tree.isExpanded(path);
+ TreeModel m = tree.getModel();
+ boolean isLeaf = m.isLeaf(val);
+ determineOffset(tree, val, isSelected, isExpanded, isLeaf,
+ lastRow);
+ }
+ }
+ }
+ }
+ if (! realEditor.isCellEditable(event))
+ ret = false;
+ else
+ {
+ if (canEditImmediately(event))
+ ret = true;
+ else if (ed && shouldStartEditingTimer(event))
+ startEditingTimer();
+ else if (timer != null && timer.isRunning())
+ timer.stop();
+ }
+ if (ret)
+ prepareForEditing();
+ return ret;
+
+ }
+
+ /**
+ * Messages the realEditor for the return value.
+ *
+ * @param event -
+ * the event the editor should use to start editing
+ * @return true if the editor would like the editing cell to be selected;
+ * otherwise returns false
+ */
+ public boolean shouldSelectCell(EventObject event)
+ {
+ return true;
+ }
+
+ /**
+ * If the realEditor will allow editing to stop, the realEditor
+ * is removed and true is returned, otherwise false is returned.
+ * @return true if editing was stopped; false otherwise
+ */
+ public boolean stopCellEditing()
+ {
+ boolean ret = false;
+ if (realEditor.stopCellEditing())
+ {
+ finish();
+ ret = true;
+ }
+ return ret;
+ }
+
+ /**
+ * Messages cancelCellEditing to the realEditor and removes it
+ * from this instance.
+ */
+ public void cancelCellEditing()
+ {
+ realEditor.cancelCellEditing();
+ finish();
+ }
+
+ private void finish()
+ {
+ if (editingComponent != null)
+ editingContainer.remove(editingComponent);
+ editingComponent = null;
+ }
+
+ /**
+ * Adds a <code>CellEditorListener</code> object to this editor.
+ *
+ * @param listener
+ * the listener to add
+ */
+ public void addCellEditorListener(CellEditorListener listener)
+ {
+ realEditor.addCellEditorListener(listener);
+ }
+
+ /**
+ * Removes a <code>CellEditorListener</code> object.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeCellEditorListener(CellEditorListener listener)
+ {
+ realEditor.removeCellEditorListener(listener);
+ }
+
+ /**
+ * Returns all added <code>CellEditorListener</code> objects to this editor.
+ *
+ * @return an array of listeners
+ *
+ * @since 1.4
+ */
+ public CellEditorListener[] getCellEditorListeners()
+ {
+ return (CellEditorListener[]) listenerList.getListeners(CellEditorListener.class);
+ }
+
+ /**
+ * Resets lastPath.
+ *
+ * @param e - the event that characterizes the change.
+ */
+ public void valueChanged(TreeSelectionEvent e)
+ {
+ if (tree != null)
+ {
+ if (tree.getSelectionCount() == 1)
+ lastPath = tree.getSelectionPath();
+ else
+ lastPath = null;
+ }
+ // TODO: We really should do the following here, but can't due
+ // to buggy DefaultTreeSelectionModel. This selection model
+ // should only fire if the selection actually changes.
+// if (timer != null)
+// timer.stop();
+ }
+
+ /**
+ * Messaged when the timer fires.
+ *
+ * @param e the event that characterizes the action.
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ if (tree != null && lastPath != null)
+ tree.startEditingAtPath(lastPath);
+ }
+
+ /**
+ * Sets the tree currently editing for. This is needed to add a selection
+ * listener.
+ *
+ * @param newTree -
+ * the new tree to be edited
+ */
+ protected void setTree(JTree newTree)
+ {
+ if (tree != newTree)
+ {
+ if (tree != null)
+ tree.removeTreeSelectionListener(this);
+ tree = newTree;
+ if (tree != null)
+ tree.addTreeSelectionListener(this);
+
+ if (timer != null)
+ timer.stop();
+ }
+ }
+
+ /**
+ * Returns true if event is a MouseEvent and the click count is 1.
+ *
+ * @param event - the event being studied
+ * @return true if editing should start
+ */
+ protected boolean shouldStartEditingTimer(EventObject event)
+ {
+ boolean ret = false;
+ if (event instanceof MouseEvent)
+ {
+ MouseEvent me = (MouseEvent) event;
+ ret = SwingUtilities.isLeftMouseButton(me) && me.getClickCount() == 1
+ && inHitRegion(me.getX(), me.getY());
+ }
+ return ret;
+ }
+
+ /**
+ * Starts the editing timer (if one installed).
+ */
+ protected void startEditingTimer()
+ {
+ if (timer == null)
+ {
+ timer = new Timer(1200, this);
+ timer.setRepeats(false);
+ }
+ timer.start();
+ }
+
+ /**
+ * Returns true if event is null, or it is a MouseEvent with
+ * a click count > 2 and inHitRegion returns true.
+ *
+ * @param event - the event being studied
+ * @return true if event is null, or it is a MouseEvent with
+ * a click count > 2 and inHitRegion returns true
+ */
+ protected boolean canEditImmediately(EventObject event)
+ {
+ if (event == null || !(event instanceof MouseEvent) || (((MouseEvent) event).
+ getClickCount() > 2 && inHitRegion(((MouseEvent) event).getX(),
+ ((MouseEvent) event).getY())))
+ return true;
+ return false;
+ }
+
+ /**
+ * Returns true if the passed in location is a valid mouse location
+ * to start editing from. This is implemented to return false if x is
+ * less than or equal to the width of the icon and icon
+ * gap displayed by the renderer. In other words this returns true if
+ * the user clicks over the text part displayed by the renderer, and
+ * false otherwise.
+ *
+ * @param x - the x-coordinate of the point
+ * @param y - the y-coordinate of the point
+ *
+ * @return true if the passed in location is a valid mouse location
+ */
+ protected boolean inHitRegion(int x, int y)
+ {
+ Rectangle bounds = tree.getPathBounds(lastPath);
+ return bounds.contains(x, y);
+ }
+
+ /**
+ * determineOffset
+ * @param tree -
+ * @param value -
+ * @param isSelected -
+ * @param expanded -
+ * @param leaf -
+ * @param row -
+ */
+ protected void determineOffset(JTree tree, Object value, boolean isSelected,
+ boolean expanded, boolean leaf, int row)
+ {
+ if (renderer != null)
+ {
+ if (leaf)
+ editingIcon = renderer.getLeafIcon();
+ else if (expanded)
+ editingIcon = renderer.getOpenIcon();
+ else
+ editingIcon = renderer.getClosedIcon();
+ if (editingIcon != null)
+ offset = renderer.getIconTextGap() + editingIcon.getIconWidth();
+ else
+ offset = renderer.getIconTextGap();
+ }
+ else
+ {
+ editingIcon = null;
+ offset = 0;
+ }
+ }
+
+ /**
+ * Invoked just before editing is to start. Will add the
+ * editingComponent to the editingContainer.
+ */
+ protected void prepareForEditing()
+ {
+ if (editingComponent != null)
+ editingContainer.add(editingComponent);
+ }
+
+ /**
+ * Creates the container to manage placement of editingComponent.
+ *
+ * @return the container to manage the placement of the editingComponent.
+ */
+ protected Container createContainer()
+ {
+ return new DefaultTreeCellEditor.EditorContainer();
+ }
+
+ /**
+ * This is invoked if a TreeCellEditor is not supplied in the constructor.
+ * It returns a TextField editor.
+ *
+ * @return a new TextField editor
+ */
+ protected TreeCellEditor createTreeCellEditor()
+ {
+ Border border = UIManager.getBorder("Tree.editorBorder");
+ JTextField tf = new DefaultTreeCellEditor.DefaultTextField(border);
+ DefaultCellEditor editor = new DefaultCellEditor(tf);
+ editor.setClickCountToStart(1);
+ realEditor = editor;
+ return editor;
+ }
+}