Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / javax / swing / tree / DefaultTreeCellEditor.java
blobe28c9261babbe7db59cd6c379181a7ed8d19a1e7
1 /* DefaultTreeCellEditor.java --
2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.tree;
41 import java.awt.Color;
42 import java.awt.Component;
43 import java.awt.Container;
44 import java.awt.Dimension;
45 import java.awt.Font;
46 import java.awt.FontMetrics;
47 import java.awt.Graphics;
48 import java.awt.Rectangle;
49 import java.awt.event.ActionEvent;
50 import java.awt.event.ActionListener;
51 import java.awt.event.MouseEvent;
52 import java.io.IOException;
53 import java.io.ObjectInputStream;
54 import java.io.ObjectOutputStream;
55 import java.util.EventObject;
57 import javax.swing.DefaultCellEditor;
58 import javax.swing.Icon;
59 import javax.swing.JTextField;
60 import javax.swing.JTree;
61 import javax.swing.SwingUtilities;
62 import javax.swing.UIManager;
63 import javax.swing.border.Border;
64 import javax.swing.event.CellEditorListener;
65 import javax.swing.event.ChangeEvent;
66 import javax.swing.event.EventListenerList;
67 import javax.swing.event.TreeSelectionEvent;
68 import javax.swing.event.TreeSelectionListener;
70 /**
71 * Participates in the tree cell editing.
73 * @author Andrew Selkirk
74 * @author Audrius Meskauskas
76 public class DefaultTreeCellEditor
77 implements ActionListener, TreeCellEditor, TreeSelectionListener
79 /**
80 * The gap between the icon and editing component during editing.
82 static int ICON_TEXT_GAP = 3;
84 /**
85 * The left margin of the editing container (the gap between the tree and
86 * the editing component of the editing icon.
88 static int TREE_ICON_GAP = ICON_TEXT_GAP;
90 /**
91 * The number of the fast mouse clicks, required to start the editing
92 * session.
94 static int CLICK_COUNT_TO_START = 3;
96 /**
97 * This container that appears on the tree during editing session.
98 * It contains the editing component displays various other editor -
99 * specific parts like editing icon.
101 public class EditorContainer extends Container
104 * Use v 1.5 serial version UID for interoperability.
106 static final long serialVersionUID = 6470339600449699810L;
109 * Creates an <code>EditorContainer</code> object.
111 public EditorContainer()
113 // Do nothing here.
117 * This method only exists for API compatibility and is useless as it does
118 * nothing. It got probably introduced by accident.
120 public void EditorContainer()
122 // Do nothing here.
125 public void setBounds(Rectangle bounds)
127 super.setBounds(bounds);
128 doLayout();
132 * Overrides Container.paint to paint the node's icon and use the selection
133 * color for the background.
135 * @param g -
136 * the specified Graphics window
138 public void paint(Graphics g)
140 if (editingIcon != null)
142 // From the previous version, the left margin is taken as half
143 // of the icon width.
144 editingIcon.paintIcon(this, g, TREE_ICON_GAP, 0);
146 super.paint(g);
150 * Lays out this Container, moving the editor component to the left
151 * (leaving place for the icon).
153 public void doLayout()
155 // The offset of the editing component.
156 int eOffset;
158 // Move the component to the left, leaving room for the editing icon:
159 if (editingIcon != null)
160 eOffset = TREE_ICON_GAP + editingIcon.getIconWidth() + ICON_TEXT_GAP;
161 else
162 eOffset = 0;
164 Rectangle bounds = getBounds();
165 Component c = getComponent(0);
166 c.setLocation(eOffset, 0);
168 // Span the editing component near over all window width.
169 c.setSize(bounds.width - eOffset - TREE_ICON_GAP, bounds.height);
171 * @specnote the Sun sets some more narrow editing component width (it is
172 * not documented how does it is calculated). However as our text field is
173 * still not able to auto - scroll horizontally, replicating such strategy
174 * would prevent adding extra characters to the text being edited.
180 * The default text field, used in the editing sessions.
182 public class DefaultTextField extends JTextField
185 * Use v 1.5 serial version UID for interoperability.
187 static final long serialVersionUID = -6629304544265300143L;
190 * The border of the text field.
192 protected Border border;
195 * Creates a <code>DefaultTextField</code> object.
197 * @param aBorder the border to use
199 public DefaultTextField(Border aBorder)
201 border = aBorder;
205 * Gets the font of this component.
206 * @return this component's font; if a font has not been set for
207 * this component, the font of its parent is returned (if the parent
208 * is not null, otherwise null is returned).
210 public Font getFont()
212 Font font = super.getFont();
213 if (font == null)
215 Component parent = getParent();
216 if (parent != null)
217 return parent.getFont();
218 return null;
220 return font;
224 * Returns the border of the text field.
226 * @return the border
228 public Border getBorder()
230 return border;
234 * Overrides JTextField.getPreferredSize to return the preferred size
235 * based on current font, if set, or else use renderer's font.
237 * @return the Dimension of this textfield.
239 public Dimension getPreferredSize()
241 String s = getText();
243 Font f = getFont();
245 if (f != null)
247 FontMetrics fm = getToolkit().getFontMetrics(f);
249 return new Dimension(SwingUtilities.computeStringWidth(fm, s),
250 fm.getHeight());
252 return renderer.getPreferredSize();
257 * Listens for the events from the realEditor.
259 class RealEditorListener implements CellEditorListener
262 * The method is called when the editing has been cancelled.
263 * @param event unused
265 public void editingCanceled(ChangeEvent event)
267 cancelCellEditing();
271 * The method is called after completing the editing session.
273 * @param event unused
275 public void editingStopped(ChangeEvent event)
277 stopCellEditing();
281 private EventListenerList listenerList = new EventListenerList();
284 * Editor handling the editing.
286 protected TreeCellEditor realEditor;
289 * Renderer, used to get border and offsets from.
291 protected DefaultTreeCellRenderer renderer;
294 * Editing container, will contain the editorComponent.
296 protected Container editingContainer;
299 * Component used in editing, obtained from the editingContainer.
301 protected transient Component editingComponent;
304 * As of Java 2 platform v1.4 this field should no longer be used.
305 * If you wish to provide similar behavior you should directly
306 * override isCellEditable.
308 protected boolean canEdit;
311 * Used in editing. Indicates x position to place editingComponent.
313 protected transient int offset;
316 * JTree instance listening too.
318 protected transient JTree tree;
321 * Last path that was selected.
323 protected transient TreePath lastPath;
326 * Used before starting the editing session.
328 protected transient javax.swing.Timer timer;
331 * Row that was last passed into getTreeCellEditorComponent.
333 protected transient int lastRow;
336 * True if the border selection color should be drawn.
338 protected Color borderSelectionColor;
341 * Icon to use when editing.
343 protected transient Icon editingIcon;
346 * Font to paint with, null indicates font of renderer is to be used.
348 protected Font font;
351 * Helper field used to save the last path seen while the timer was
352 * running.
354 private TreePath tPath;
357 * Constructs a DefaultTreeCellEditor object for a JTree using the
358 * specified renderer and a default editor. (Use this constructor
359 * for normal editing.)
361 * @param tree - a JTree object
362 * @param renderer - a DefaultTreeCellRenderer object
364 public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer)
366 this(tree, renderer, null);
370 * Constructs a DefaultTreeCellEditor object for a JTree using the specified
371 * renderer and the specified editor. (Use this constructor
372 * for specialized editing.)
374 * @param tree - a JTree object
375 * @param renderer - a DefaultTreeCellRenderer object
376 * @param editor - a TreeCellEditor object
378 public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer,
379 TreeCellEditor editor)
381 setTree(tree);
382 this.renderer = renderer;
384 if (editor == null)
385 editor = createTreeCellEditor();
386 else
387 editor.addCellEditorListener(new RealEditorListener());
389 realEditor = editor;
391 lastPath = tree.getLeadSelectionPath();
392 tree.addTreeSelectionListener(this);
393 editingContainer = createContainer();
394 setFont(UIManager.getFont("Tree.font"));
395 setBorderSelectionColor(UIManager.getColor("Tree.selectionBorderColor"));
396 editingIcon = renderer.getIcon();
400 * Configures the editing component whenever it is null.
402 * @param tree the tree to configure to component for.
403 * @param renderer the renderer used to set up the nodes
404 * @param editor the editor used
406 private void configureEditingComponent(JTree tree,
407 DefaultTreeCellRenderer renderer,
408 TreeCellEditor editor)
410 if (tree != null && lastPath != null)
412 Object val = lastPath.getLastPathComponent();
413 boolean isLeaf = tree.getModel().isLeaf(val);
414 boolean expanded = tree.isExpanded(lastPath);
415 determineOffset(tree, val, true, expanded, isLeaf, lastRow);
417 // set up icon
418 if (isLeaf)
419 renderer.setIcon(renderer.getLeafIcon());
420 else if (expanded)
421 renderer.setIcon(renderer.getOpenIcon());
422 else
423 renderer.setIcon(renderer.getClosedIcon());
424 editingIcon = renderer.getIcon();
426 editingComponent = getTreeCellEditorComponent(tree, val, true,
427 expanded, isLeaf, lastRow);
432 * writeObject
434 * @param value0
435 * TODO
436 * @exception IOException
437 * TODO
439 private void writeObject(ObjectOutputStream value0) throws IOException
441 // TODO
445 * readObject
446 * @param value0 TODO
447 * @exception IOException TODO
448 * @exception ClassNotFoundException TODO
450 private void readObject(ObjectInputStream value0)
451 throws IOException, ClassNotFoundException
453 // TODO
457 * Sets the color to use for the border.
458 * @param newColor - the new border color
460 public void setBorderSelectionColor(Color newColor)
462 this.borderSelectionColor = newColor;
466 * Returns the color the border is drawn.
467 * @return Color
469 public Color getBorderSelectionColor()
471 return borderSelectionColor;
475 * Sets the font to edit with. null indicates the renderers
476 * font should be used. This will NOT override any font you have
477 * set in the editor the receiver was instantied with. If null for
478 * an editor was passed in, a default editor will be created that
479 * will pick up this font.
481 * @param font - the editing Font
483 public void setFont(Font font)
485 if (font != null)
486 this.font = font;
487 else
488 this.font = renderer.getFont();
492 * Gets the font used for editing.
494 * @return the editing font
496 public Font getFont()
498 return font;
502 * Configures the editor. Passed onto the realEditor.
503 * Sets an initial value for the editor. This will cause
504 * the editor to stopEditing and lose any partially edited value
505 * if the editor is editing when this method is called.
506 * Returns the component that should be added to the client's Component
507 * hierarchy. Once installed in the client's hierarchy this component will
508 * then be able to draw and receive user input.
510 * @param tree - the JTree that is asking the editor to edit; this parameter can be null
511 * @param value - the value of the cell to be edited
512 * @param isSelected - true is the cell is to be rendered with selection highlighting
513 * @param expanded - true if the node is expanded
514 * @param leaf - true if the node is a leaf node
515 * @param row - the row index of the node being edited
517 * @return the component for editing
519 public Component getTreeCellEditorComponent(JTree tree, Object value,
520 boolean isSelected, boolean expanded,
521 boolean leaf, int row)
523 if (realEditor == null)
524 realEditor = createTreeCellEditor();
526 return realEditor.getTreeCellEditorComponent(tree, value, isSelected,
527 expanded, leaf, row);
531 * Returns the value currently being edited (requests it from the
532 * {@link realEditor}.
534 * @return the value currently being edited
536 public Object getCellEditorValue()
538 return realEditor.getCellEditorValue();
542 * If the realEditor returns true to this message, prepareForEditing
543 * is messaged and true is returned.
545 * @param event - the event the editor should use to consider whether to begin editing or not
546 * @return true if editing can be started
548 public boolean isCellEditable(EventObject event)
550 if (editingComponent == null)
551 configureEditingComponent(tree, renderer, realEditor);
553 if (editingComponent != null && realEditor.isCellEditable(event))
555 prepareForEditing();
556 return true;
558 return false;
562 * Messages the realEditor for the return value.
564 * @param event -
565 * the event the editor should use to start editing
566 * @return true if the editor would like the editing cell to be selected;
567 * otherwise returns false
569 public boolean shouldSelectCell(EventObject event)
571 return true;
575 * If the realEditor will allow editing to stop, the realEditor
576 * is removed and true is returned, otherwise false is returned.
577 * @return true if editing was stopped; false otherwise
579 public boolean stopCellEditing()
581 if (editingComponent != null)
583 stopEditingTimer();
584 tree.stopEditing();
585 editingComponent = null;
586 return true;
588 return false;
592 * Messages cancelCellEditing to the realEditor and removes it
593 * from this instance.
595 public void cancelCellEditing()
597 if (editingComponent != null)
599 tree.cancelEditing();
600 editingComponent = null;
602 stopEditingTimer();
606 * Stop the editing timer, if it is installed and running.
608 private void stopEditingTimer()
610 if (timer != null && timer.isRunning())
611 timer.stop();
615 * Adds a <code>CellEditorListener</code> object to this editor.
617 * @param listener
618 * the listener to add
620 public void addCellEditorListener(CellEditorListener listener)
622 realEditor.addCellEditorListener(listener);
626 * Removes a <code>CellEditorListener</code> object.
628 * @param listener the listener to remove
630 public void removeCellEditorListener(CellEditorListener listener)
632 realEditor.removeCellEditorListener(listener);
636 * Returns all added <code>CellEditorListener</code> objects to this editor.
638 * @return an array of listeners
640 * @since 1.4
642 public CellEditorListener[] getCellEditorListeners()
644 return (CellEditorListener[]) listenerList.getListeners(CellEditorListener.class);
648 * Resets lastPath.
650 * @param e - the event that characterizes the change.
652 public void valueChanged(TreeSelectionEvent e)
654 tPath = lastPath;
655 lastPath = e.getNewLeadSelectionPath();
656 lastRow = tree.getRowForPath(lastPath);
657 stopCellEditing();
661 * Messaged when the timer fires.
663 * @param e the event that characterizes the action.
665 public void actionPerformed(ActionEvent e)
670 * Sets the tree currently editing for. This is needed to add a selection
671 * listener.
673 * @param newTree -
674 * the new tree to be edited
676 protected void setTree(JTree newTree)
678 tree = newTree;
682 * Returns true if event is a MouseEvent and the click count is 1.
684 * @param event - the event being studied
685 * @return true if editing should start
687 protected boolean shouldStartEditingTimer(EventObject event)
689 if ((event instanceof MouseEvent) &&
690 ((MouseEvent) event).getClickCount() == 1)
691 return true;
692 return false;
696 * Starts the editing timer (if one installed).
698 protected void startEditingTimer()
700 if (timer != null)
701 timer.start();
705 * Returns true if event is null, or it is a MouseEvent with
706 * a click count > 2 and inHitRegion returns true.
708 * @param event - the event being studied
709 * @return true if event is null, or it is a MouseEvent with
710 * a click count > 2 and inHitRegion returns true
712 protected boolean canEditImmediately(EventObject event)
714 if (event == null || !(event instanceof MouseEvent) || (((MouseEvent) event).
715 getClickCount() > 2 && inHitRegion(((MouseEvent) event).getX(),
716 ((MouseEvent) event).getY())))
717 return true;
718 return false;
722 * Returns true if the passed in location is a valid mouse location
723 * to start editing from. This is implemented to return false if x is
724 * less than or equal to the width of the icon and icon
725 * gap displayed by the renderer. In other words this returns true if
726 * the user clicks over the text part displayed by the renderer, and
727 * false otherwise.
729 * @param x - the x-coordinate of the point
730 * @param y - the y-coordinate of the point
732 * @return true if the passed in location is a valid mouse location
734 protected boolean inHitRegion(int x, int y)
736 Rectangle bounds = tree.getPathBounds(lastPath);
738 return bounds.contains(x, y);
742 * determineOffset
743 * @param tree -
744 * @param value -
745 * @param isSelected -
746 * @param expanded -
747 * @param leaf -
748 * @param row -
750 protected void determineOffset(JTree tree, Object value, boolean isSelected,
751 boolean expanded, boolean leaf, int row)
753 renderer.getTreeCellRendererComponent(tree, value, isSelected, expanded,
754 leaf, row, true);
755 Icon c = renderer.getIcon();
756 if (c != null)
757 offset = renderer.getIconTextGap() + c.getIconWidth();
758 else
759 offset = 0;
763 * Invoked just before editing is to start. Will add the
764 * editingComponent to the editingContainer.
766 protected void prepareForEditing()
768 editingContainer.removeAll();
769 editingContainer.add(editingComponent);
773 * Creates the container to manage placement of editingComponent.
775 * @return the container to manage the placement of the editingComponent.
777 protected Container createContainer()
779 return new DefaultTreeCellEditor.EditorContainer();
783 * This is invoked if a TreeCellEditor is not supplied in the constructor.
784 * It returns a TextField editor.
786 * @return a new TextField editor
788 protected TreeCellEditor createTreeCellEditor()
790 DefaultCellEditor editor = new DefaultCellEditor(new DefaultTreeCellEditor.DefaultTextField(
791 UIManager.getBorder("Tree.selectionBorder")));
792 editor.addCellEditorListener(new RealEditorListener());
793 editor.setClickCountToStart(CLICK_COUNT_TO_START);
794 realEditor = editor;
795 return editor;