1 /*
2  * Copyright (c) 1998, 2015, 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 package javax.swing.tree;
26 
27 import javax.swing.*;
28 import javax.swing.border.*;
29 import javax.swing.event.*;
30 import javax.swing.plaf.FontUIResource;
31 import java.awt.*;
32 import java.awt.event.*;
33 import java.beans.BeanProperty;
34 import java.util.EventObject;
35 
36 /**
37  * A <code>TreeCellEditor</code>. You need to supply an
38  * instance of <code>DefaultTreeCellRenderer</code>
39  * so that the icons can be obtained. You can optionally supply
40  * a <code>TreeCellEditor</code> that will be layed out according
41  * to the icon in the <code>DefaultTreeCellRenderer</code>.
42  * If you do not supply a <code>TreeCellEditor</code>,
43  * a <code>TextField</code> will be used. Editing is started
44  * on a triple mouse click, or after a click, pause, click and
45  * a delay of 1200 milliseconds.
46  *<p>
47  * <strong>Warning:</strong>
48  * Serialized objects of this class will not be compatible with
49  * future Swing releases. The current serialization support is
50  * appropriate for short term storage or RMI between applications running
51  * the same version of Swing.  As of 1.4, support for long term storage
52  * of all JavaBeans&trade;
53  * has been added to the <code>java.beans</code> package.
54  * Please see {@link java.beans.XMLEncoder}.
55  *
56  * @see javax.swing.JTree
57  *
58  * @author Scott Violet
59  */
60 public class DefaultTreeCellEditor implements ActionListener, TreeCellEditor,
61             TreeSelectionListener {
62     /** Editor handling the editing. */
63     protected TreeCellEditor               realEditor;
64 
65     /** Renderer, used to get border and offsets from. */
66     protected DefaultTreeCellRenderer      renderer;
67 
68     /** Editing container, will contain the <code>editorComponent</code>. */
69     protected Container                    editingContainer;
70 
71     /**
72      * Component used in editing, obtained from the
73      * <code>editingContainer</code>.
74      */
75     protected transient Component          editingComponent;
76 
77     /**
78      * As of Java 2 platform v1.4 this field should no longer be used. If
79      * you wish to provide similar behavior you should directly override
80      * <code>isCellEditable</code>.
81      */
82     protected boolean                      canEdit;
83 
84     /**
85      * Used in editing. Indicates x position to place
86      * <code>editingComponent</code>.
87      */
88     protected transient int                offset;
89 
90     /** <code>JTree</code> instance listening too. */
91     protected transient JTree              tree;
92 
93     /** Last path that was selected. */
94     protected transient TreePath           lastPath;
95 
96     /** Used before starting the editing session. */
97     protected transient Timer              timer;
98 
99     /**
100      * Row that was last passed into
101      * <code>getTreeCellEditorComponent</code>.
102      */
103     protected transient int                lastRow;
104 
105     /** True if the border selection color should be drawn. */
106     protected Color                        borderSelectionColor;
107 
108     /** Icon to use when editing. */
109     protected transient Icon               editingIcon;
110 
111     /**
112      * Font to paint with, <code>null</code> indicates
113      * font of renderer is to be used.
114      */
115     protected Font                         font;
116 
117 
118     /**
119      * Constructs a <code>DefaultTreeCellEditor</code>
120      * object for a JTree using the specified renderer and
121      * a default editor. (Use this constructor for normal editing.)
122      *
123      * @param tree      a <code>JTree</code> object
124      * @param renderer  a <code>DefaultTreeCellRenderer</code> object
125      */
DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer)126     public DefaultTreeCellEditor(JTree tree,
127                                  DefaultTreeCellRenderer renderer) {
128         this(tree, renderer, null);
129     }
130 
131     /**
132      * Constructs a <code>DefaultTreeCellEditor</code>
133      * object for a <code>JTree</code> using the
134      * specified renderer and the specified editor. (Use this constructor
135      * for specialized editing.)
136      *
137      * @param tree      a <code>JTree</code> object
138      * @param renderer  a <code>DefaultTreeCellRenderer</code> object
139      * @param editor    a <code>TreeCellEditor</code> object
140      */
DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer, TreeCellEditor editor)141     public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer,
142                                  TreeCellEditor editor) {
143         this.renderer = renderer;
144         realEditor = editor;
145         if(realEditor == null)
146             realEditor = createTreeCellEditor();
147         editingContainer = createContainer();
148         setTree(tree);
149         setBorderSelectionColor(UIManager.getColor
150                                 ("Tree.editorBorderSelectionColor"));
151     }
152 
153     /**
154       * Sets the color to use for the border.
155       * @param newColor the new border color
156       */
setBorderSelectionColor(Color newColor)157     public void setBorderSelectionColor(Color newColor) {
158         borderSelectionColor = newColor;
159     }
160 
161     /**
162       * Returns the color the border is drawn.
163       * @return the border selection color
164       */
getBorderSelectionColor()165     public Color getBorderSelectionColor() {
166         return borderSelectionColor;
167     }
168 
169     /**
170      * Sets the font to edit with. <code>null</code> indicates
171      * the renderers font should be used. This will NOT
172      * override any font you have set in the editor
173      * the receiver was instantiated with. If <code>null</code>
174      * for an editor was passed in a default editor will be
175      * created that will pick up this font.
176      *
177      * @param font  the editing <code>Font</code>
178      * @see #getFont
179      */
setFont(Font font)180     public void setFont(Font font) {
181         this.font = font;
182     }
183 
184     /**
185      * Gets the font used for editing.
186      *
187      * @return the editing <code>Font</code>
188      * @see #setFont
189      */
getFont()190     public Font getFont() {
191         return font;
192     }
193 
194     //
195     // TreeCellEditor
196     //
197 
198     /**
199      * Configures the editor.  Passed onto the <code>realEditor</code>.
200      */
getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row)201     public Component getTreeCellEditorComponent(JTree tree, Object value,
202                                                 boolean isSelected,
203                                                 boolean expanded,
204                                                 boolean leaf, int row) {
205         setTree(tree);
206         lastRow = row;
207         determineOffset(tree, value, isSelected, expanded, leaf, row);
208 
209         if (editingComponent != null) {
210             editingContainer.remove(editingComponent);
211         }
212         editingComponent = realEditor.getTreeCellEditorComponent(tree, value,
213                                         isSelected, expanded,leaf, row);
214 
215 
216         // this is kept for backwards compatibility but isn't really needed
217         // with the current BasicTreeUI implementation.
218         TreePath        newPath = tree.getPathForRow(row);
219 
220         canEdit = (lastPath != null && newPath != null &&
221                    lastPath.equals(newPath));
222 
223         Font            font = getFont();
224 
225         if(font == null) {
226             if(renderer != null)
227                 font = renderer.getFont();
228             if(font == null)
229                 font = tree.getFont();
230         }
231         editingContainer.setFont(font);
232         prepareForEditing();
233         return editingContainer;
234     }
235 
236     /**
237      * Returns the value currently being edited.
238      * @return the value currently being edited
239      */
getCellEditorValue()240     public Object getCellEditorValue() {
241         return realEditor.getCellEditorValue();
242     }
243 
244     /**
245      * If the <code>realEditor</code> returns true to this
246      * message, <code>prepareForEditing</code>
247      * is messaged and true is returned.
248      */
isCellEditable(EventObject event)249     public boolean isCellEditable(EventObject event) {
250         boolean            retValue = false;
251         boolean            editable = false;
252 
253         if (event != null) {
254             if (event.getSource() instanceof JTree) {
255                 setTree((JTree)event.getSource());
256                 if (event instanceof MouseEvent) {
257                     TreePath path = tree.getPathForLocation(
258                                          ((MouseEvent)event).getX(),
259                                          ((MouseEvent)event).getY());
260                     editable = (lastPath != null && path != null &&
261                                lastPath.equals(path));
262                     if (path!=null) {
263                         lastRow = tree.getRowForPath(path);
264                         Object value = path.getLastPathComponent();
265                         boolean isSelected = tree.isRowSelected(lastRow);
266                         boolean expanded = tree.isExpanded(path);
267                         TreeModel treeModel = tree.getModel();
268                         boolean leaf = treeModel.isLeaf(value);
269                         determineOffset(tree, value, isSelected,
270                                         expanded, leaf, lastRow);
271                     }
272                 }
273             }
274         }
275         if(!realEditor.isCellEditable(event))
276             return false;
277         if(canEditImmediately(event))
278             retValue = true;
279         else if(editable && shouldStartEditingTimer(event)) {
280             startEditingTimer();
281         }
282         else if(timer != null && timer.isRunning())
283             timer.stop();
284         if(retValue)
285             prepareForEditing();
286         return retValue;
287     }
288 
289     /**
290      * Messages the <code>realEditor</code> for the return value.
291      */
shouldSelectCell(EventObject event)292     public boolean shouldSelectCell(EventObject event) {
293         return realEditor.shouldSelectCell(event);
294     }
295 
296     /**
297      * If the <code>realEditor</code> will allow editing to stop,
298      * the <code>realEditor</code> is removed and true is returned,
299      * otherwise false is returned.
300      */
stopCellEditing()301     public boolean stopCellEditing() {
302         if(realEditor.stopCellEditing()) {
303             cleanupAfterEditing();
304             return true;
305         }
306         return false;
307     }
308 
309     /**
310      * Messages <code>cancelCellEditing</code> to the
311      * <code>realEditor</code> and removes it from this instance.
312      */
cancelCellEditing()313     public void cancelCellEditing() {
314         realEditor.cancelCellEditing();
315         cleanupAfterEditing();
316     }
317 
318     /**
319      * Adds the <code>CellEditorListener</code>.
320      * @param l the listener to be added
321      */
addCellEditorListener(CellEditorListener l)322     public void addCellEditorListener(CellEditorListener l) {
323         realEditor.addCellEditorListener(l);
324     }
325 
326     /**
327       * Removes the previously added <code>CellEditorListener</code>.
328       * @param l the listener to be removed
329       */
removeCellEditorListener(CellEditorListener l)330     public void removeCellEditorListener(CellEditorListener l) {
331         realEditor.removeCellEditorListener(l);
332     }
333 
334     /**
335      * Returns an array of all the <code>CellEditorListener</code>s added
336      * to this DefaultTreeCellEditor with addCellEditorListener().
337      *
338      * @return all of the <code>CellEditorListener</code>s added or an empty
339      *         array if no listeners have been added
340      * @since 1.4
341      */
getCellEditorListeners()342     public CellEditorListener[] getCellEditorListeners() {
343         return ((DefaultCellEditor)realEditor).getCellEditorListeners();
344     }
345 
346     //
347     // TreeSelectionListener
348     //
349 
350     /**
351      * Resets <code>lastPath</code>.
352      */
valueChanged(TreeSelectionEvent e)353     public void valueChanged(TreeSelectionEvent e) {
354         if(tree != null) {
355             if(tree.getSelectionCount() == 1)
356                 lastPath = tree.getSelectionPath();
357             else
358                 lastPath = null;
359         }
360         if(timer != null) {
361             timer.stop();
362         }
363     }
364 
365     //
366     // ActionListener (for Timer).
367     //
368 
369     /**
370      * Messaged when the timer fires, this will start the editing
371      * session.
372      */
actionPerformed(ActionEvent e)373     public void actionPerformed(ActionEvent e) {
374         if(tree != null && lastPath != null) {
375             tree.startEditingAtPath(lastPath);
376         }
377     }
378 
379     //
380     // Local methods
381     //
382 
383     /**
384      * Sets the tree currently editing for. This is needed to add
385      * a selection listener.
386      * @param newTree the new tree to be edited
387      */
setTree(JTree newTree)388     protected void setTree(JTree newTree) {
389         if(tree != newTree) {
390             if(tree != null)
391                 tree.removeTreeSelectionListener(this);
392             tree = newTree;
393             if(tree != null)
394                 tree.addTreeSelectionListener(this);
395             if(timer != null) {
396                 timer.stop();
397             }
398         }
399     }
400 
401     /**
402      * Returns true if <code>event</code> is a <code>MouseEvent</code>
403      * and the click count is 1.
404      *
405      * @param event the event being studied
406      * @return whether {@code event} should starts the editing timer
407      */
shouldStartEditingTimer(EventObject event)408     protected boolean shouldStartEditingTimer(EventObject event) {
409         if((event instanceof MouseEvent) &&
410             SwingUtilities.isLeftMouseButton((MouseEvent)event)) {
411             MouseEvent        me = (MouseEvent)event;
412 
413             return (me.getClickCount() == 1 &&
414                     inHitRegion(me.getX(), me.getY()));
415         }
416         return false;
417     }
418 
419     /**
420      * Starts the editing timer.
421      */
startEditingTimer()422     protected void startEditingTimer() {
423         if(timer == null) {
424             timer = new Timer(1200, this);
425             timer.setRepeats(false);
426         }
427         timer.start();
428     }
429 
430     /**
431      * Returns true if <code>event</code> is <code>null</code>,
432      * or it is a <code>MouseEvent</code> with a click count &gt; 2
433      * and <code>inHitRegion</code> returns true.
434      *
435      * @param event the event being studied
436      * @return whether editing can be started for the given {@code event}
437      */
canEditImmediately(EventObject event)438     protected boolean canEditImmediately(EventObject event) {
439         if((event instanceof MouseEvent) &&
440            SwingUtilities.isLeftMouseButton((MouseEvent)event)) {
441             MouseEvent       me = (MouseEvent)event;
442 
443             return ((me.getClickCount() > 2) &&
444                     inHitRegion(me.getX(), me.getY()));
445         }
446         return (event == null);
447     }
448 
449     /**
450      * Returns true if the passed in location is a valid mouse location
451      * to start editing from. This is implemented to return false if
452      * <code>x</code> is &lt;= the width of the icon and icon gap displayed
453      * by the renderer. In other words this returns true if the user
454      * clicks over the text part displayed by the renderer, and false
455      * otherwise.
456      * @param x the x-coordinate of the point
457      * @param y the y-coordinate of the point
458      * @return true if the passed in location is a valid mouse location
459      */
inHitRegion(int x, int y)460     protected boolean inHitRegion(int x, int y) {
461         if(lastRow != -1 && tree != null) {
462             Rectangle bounds = tree.getRowBounds(lastRow);
463             ComponentOrientation treeOrientation = tree.getComponentOrientation();
464 
465             if ( treeOrientation.isLeftToRight() ) {
466                 if (bounds != null && x <= (bounds.x + offset) &&
467                     offset < (bounds.width - 5)) {
468                     return false;
469                 }
470             } else if ( bounds != null &&
471                         ( x >= (bounds.x+bounds.width-offset+5) ||
472                           x <= (bounds.x + 5) ) &&
473                         offset < (bounds.width - 5) ) {
474                 return false;
475             }
476         }
477         return true;
478     }
479 
480     /**
481      * Determine the offset.
482      * @param tree      a <code>JTree</code> object
483      * @param value a value
484      * @param isSelected selection status
485      * @param expanded expansion status
486      * @param leaf leaf status
487      * @param row current row
488      */
determineOffset(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row)489     protected void determineOffset(JTree tree, Object value,
490                                    boolean isSelected, boolean expanded,
491                                    boolean leaf, int row) {
492         if(renderer != null) {
493             if(leaf)
494                 editingIcon = renderer.getLeafIcon();
495             else if(expanded)
496                 editingIcon = renderer.getOpenIcon();
497             else
498                 editingIcon = renderer.getClosedIcon();
499             if(editingIcon != null)
500                 offset = renderer.getIconTextGap() +
501                          editingIcon.getIconWidth();
502             else
503                 offset = renderer.getIconTextGap();
504         }
505         else {
506             editingIcon = null;
507             offset = 0;
508         }
509     }
510 
511     /**
512      * Invoked just before editing is to start. Will add the
513      * <code>editingComponent</code> to the
514      * <code>editingContainer</code>.
515      */
prepareForEditing()516     protected void prepareForEditing() {
517         if (editingComponent != null) {
518             editingContainer.add(editingComponent);
519         }
520     }
521 
522     /**
523      * Creates the container to manage placement of
524      * <code>editingComponent</code>.
525      *
526      * @return new Container object
527      */
createContainer()528     protected Container createContainer() {
529         return new EditorContainer();
530     }
531 
532     /**
533      * This is invoked if a <code>TreeCellEditor</code>
534      * is not supplied in the constructor.
535      * It returns a <code>TextField</code> editor.
536      * @return a new <code>TextField</code> editor
537      */
createTreeCellEditor()538     protected TreeCellEditor createTreeCellEditor() {
539         Border              aBorder = UIManager.getBorder("Tree.editorBorder");
540         @SuppressWarnings("serial") // Safe: outer class is non-serializable
541         DefaultCellEditor   editor = new DefaultCellEditor
542             (new DefaultTextField(aBorder)) {
543             public boolean shouldSelectCell(EventObject event) {
544                 boolean retValue = super.shouldSelectCell(event);
545                 return retValue;
546             }
547         };
548 
549         // One click to edit.
550         editor.setClickCountToStart(1);
551         return editor;
552     }
553 
554     /**
555      * Cleans up any state after editing has completed. Removes the
556      * <code>editingComponent</code> the <code>editingContainer</code>.
557      */
cleanupAfterEditing()558     private void cleanupAfterEditing() {
559         if (editingComponent != null) {
560             editingContainer.remove(editingComponent);
561         }
562         editingComponent = null;
563     }
564 
565     /**
566      * <code>TextField</code> used when no editor is supplied.
567      * This textfield locks into the border it is constructed with.
568      * It also prefers its parents font over its font. And if the
569      * renderer is not <code>null</code> and no font
570      * has been specified the preferred height is that of the renderer.
571      */
572     @SuppressWarnings("serial") // Safe: outer class is non-serializable
573     public class DefaultTextField extends JTextField {
574         /** Border to use. */
575         protected Border         border;
576 
577         /**
578          * Constructs a
579          * <code>DefaultTreeCellEditor.DefaultTextField</code> object.
580          *
581          * @param border  a <code>Border</code> object
582          * @since 1.4
583          */
DefaultTextField(Border border)584         public DefaultTextField(Border border) {
585             setBorder(border);
586         }
587 
588         /**
589          * Sets the border of this component.<p>
590          * This is a bound property.
591          *
592          * @param border the border to be rendered for this component
593          * @see Border
594          * @see CompoundBorder
595          */
596         @BeanProperty(preferred = true, visualUpdate = true, description
597                 = "The component's border.")
setBorder(Border border)598         public void setBorder(Border border) {
599             super.setBorder(border);
600             this.border = border;
601         }
602 
603         /**
604          * Overrides <code>JComponent.getBorder</code> to
605          * returns the current border.
606          */
getBorder()607         public Border getBorder() {
608             return border;
609         }
610 
611         // implements java.awt.MenuContainer
getFont()612         public Font getFont() {
613             Font     font = super.getFont();
614 
615             // Prefer the parent containers font if our font is a
616             // FontUIResource
617             if(font instanceof FontUIResource) {
618                 Container     parent = getParent();
619 
620                 if(parent != null && parent.getFont() != null)
621                     font = parent.getFont();
622             }
623             return font;
624         }
625 
626         /**
627          * Overrides <code>JTextField.getPreferredSize</code> to
628          * return the preferred size based on current font, if set,
629          * or else use renderer's font.
630          * @return a <code>Dimension</code> object containing
631          *   the preferred size
632          */
getPreferredSize()633         public Dimension getPreferredSize() {
634             Dimension      size = super.getPreferredSize();
635 
636             // If not font has been set, prefer the renderers height.
637             if(renderer != null &&
638                DefaultTreeCellEditor.this.getFont() == null) {
639                 Dimension     rSize = renderer.getPreferredSize();
640 
641                 size.height = rSize.height;
642             }
643             return size;
644         }
645     }
646 
647 
648     /**
649      * Container responsible for placing the <code>editingComponent</code>.
650      */
651     @SuppressWarnings("serial") // Safe: outer class is non-serializable
652     public class EditorContainer extends Container {
653         /**
654          * Constructs an <code>EditorContainer</code> object.
655          */
EditorContainer()656         public EditorContainer() {
657             setLayout(null);
658         }
659 
660         // This should not be used. It will be removed when new API is
661         // allowed.
662         /**
663          * Do not use.
664          */
EditorContainer()665         public void EditorContainer() {
666             setLayout(null);
667         }
668 
669         /**
670          * Overrides <code>Container.paint</code> to paint the node's
671          * icon and use the selection color for the background.
672          */
paint(Graphics g)673         public void paint(Graphics g) {
674             int width = getWidth();
675             int height = getHeight();
676 
677             // Then the icon.
678             if(editingIcon != null) {
679                 int yLoc = calculateIconY(editingIcon);
680 
681                 if (getComponentOrientation().isLeftToRight()) {
682                     editingIcon.paintIcon(this, g, 0, yLoc);
683                 } else {
684                     editingIcon.paintIcon(
685                             this, g, width - editingIcon.getIconWidth(),
686                             yLoc);
687                 }
688             }
689 
690             // Border selection color
691             Color       background = getBorderSelectionColor();
692             if(background != null) {
693                 g.setColor(background);
694                 g.drawRect(0, 0, width - 1, height - 1);
695             }
696             super.paint(g);
697         }
698 
699         /**
700          * Lays out this <code>Container</code>.  If editing,
701          * the editor will be placed at
702          * <code>offset</code> in the x direction and 0 for y.
703          */
doLayout()704         public void doLayout() {
705             if(editingComponent != null) {
706                 int width = getWidth();
707                 int height = getHeight();
708                 if (getComponentOrientation().isLeftToRight()) {
709                     editingComponent.setBounds(
710                             offset, 0, width - offset, height);
711                 } else {
712                     editingComponent.setBounds(
713                         0, 0, width - offset, height);
714                 }
715             }
716         }
717 
718         /**
719          * Calculate the y location for the icon.
720          */
calculateIconY(Icon icon)721         private int calculateIconY(Icon icon) {
722             // To make sure the icon position matches that of the
723             // renderer, use the same algorithm as JLabel
724             // (SwingUtilities.layoutCompoundLabel).
725             int iconHeight = icon.getIconHeight();
726             int textHeight = editingComponent.getFontMetrics(
727                 editingComponent.getFont()).getHeight();
728             int textY = iconHeight / 2 - textHeight / 2;
729             int totalY = Math.min(0, textY);
730             int totalHeight = Math.max(iconHeight, textY + textHeight) -
731                 totalY;
732             return getHeight() / 2 - (totalY + (totalHeight / 2));
733         }
734 
735         /**
736          * Returns the preferred size for the <code>Container</code>.
737          * This will be at least preferred size of the editor plus
738          * <code>offset</code>.
739          * @return a <code>Dimension</code> containing the preferred
740          *   size for the <code>Container</code>; if
741          *   <code>editingComponent</code> is <code>null</code> the
742          *   <code>Dimension</code> returned is 0, 0
743          */
getPreferredSize()744         public Dimension getPreferredSize() {
745             if(editingComponent != null) {
746                 Dimension         pSize = editingComponent.getPreferredSize();
747 
748                 pSize.width += offset + 5;
749 
750                 Dimension         rSize = (renderer != null) ?
751                                           renderer.getPreferredSize() : null;
752 
753                 if(rSize != null)
754                     pSize.height = Math.max(pSize.height, rSize.height);
755                 if(editingIcon != null)
756                     pSize.height = Math.max(pSize.height,
757                                             editingIcon.getIconHeight());
758 
759                 // Make sure width is at least 100.
760                 pSize.width = Math.max(pSize.width, 100);
761                 return pSize;
762             }
763             return new Dimension(0, 0);
764         }
765     }
766 }
767