You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
781 lines
25 KiB
781 lines
25 KiB
/*
|
|
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
package javax.swing.tree;
|
|
|
|
import javax.swing.*;
|
|
import javax.swing.border.*;
|
|
import javax.swing.event.*;
|
|
import javax.swing.plaf.FontUIResource;
|
|
import java.awt.*;
|
|
import java.awt.event.*;
|
|
import java.beans.*;
|
|
import java.io.*;
|
|
import java.util.EventObject;
|
|
import java.util.Vector;
|
|
|
|
/**
|
|
* A <code>TreeCellEditor</code>. You need to supply an
|
|
* instance of <code>DefaultTreeCellRenderer</code>
|
|
* so that the icons can be obtained. You can optionally supply
|
|
* a <code>TreeCellEditor</code> that will be layed out according
|
|
* to the icon in the <code>DefaultTreeCellRenderer</code>.
|
|
* If you do not supply a <code>TreeCellEditor</code>,
|
|
* a <code>TextField</code> will be used. Editing is started
|
|
* on a triple mouse click, or after a click, pause, click and
|
|
* a delay of 1200 milliseconds.
|
|
*<p>
|
|
* <strong>Warning:</strong>
|
|
* Serialized objects of this class will not be compatible with
|
|
* future Swing releases. The current serialization support is
|
|
* appropriate for short term storage or RMI between applications running
|
|
* the same version of Swing. As of 1.4, support for long term storage
|
|
* of all JavaBeans™
|
|
* has been added to the <code>java.beans</code> package.
|
|
* Please see {@link java.beans.XMLEncoder}.
|
|
*
|
|
* @see javax.swing.JTree
|
|
*
|
|
* @author Scott Violet
|
|
*/
|
|
public class DefaultTreeCellEditor implements ActionListener, TreeCellEditor,
|
|
TreeSelectionListener {
|
|
/** Editor handling the editing. */
|
|
protected TreeCellEditor realEditor;
|
|
|
|
/** Renderer, used to get border and offsets from. */
|
|
protected DefaultTreeCellRenderer renderer;
|
|
|
|
/** Editing container, will contain the <code>editorComponent</code>. */
|
|
protected Container editingContainer;
|
|
|
|
/**
|
|
* Component used in editing, obtained from the
|
|
* <code>editingContainer</code>.
|
|
*/
|
|
transient protected 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
|
|
* <code>isCellEditable</code>.
|
|
*/
|
|
protected boolean canEdit;
|
|
|
|
/**
|
|
* Used in editing. Indicates x position to place
|
|
* <code>editingComponent</code>.
|
|
*/
|
|
protected transient int offset;
|
|
|
|
/** <code>JTree</code> instance listening too. */
|
|
protected transient JTree tree;
|
|
|
|
/** Last path that was selected. */
|
|
protected transient TreePath lastPath;
|
|
|
|
/** Used before starting the editing session. */
|
|
protected transient Timer timer;
|
|
|
|
/**
|
|
* Row that was last passed into
|
|
* <code>getTreeCellEditorComponent</code>.
|
|
*/
|
|
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, <code>null</code> indicates
|
|
* font of renderer is to be used.
|
|
*/
|
|
protected Font font;
|
|
|
|
|
|
/**
|
|
* Constructs a <code>DefaultTreeCellEditor</code>
|
|
* object for a JTree using the specified renderer and
|
|
* a default editor. (Use this constructor for normal editing.)
|
|
*
|
|
* @param tree a <code>JTree</code> object
|
|
* @param renderer a <code>DefaultTreeCellRenderer</code> object
|
|
*/
|
|
public DefaultTreeCellEditor(JTree tree,
|
|
DefaultTreeCellRenderer renderer) {
|
|
this(tree, renderer, null);
|
|
}
|
|
|
|
/**
|
|
* Constructs a <code>DefaultTreeCellEditor</code>
|
|
* object for a <code>JTree</code> using the
|
|
* specified renderer and the specified editor. (Use this constructor
|
|
* for specialized editing.)
|
|
*
|
|
* @param tree a <code>JTree</code> object
|
|
* @param renderer a <code>DefaultTreeCellRenderer</code> object
|
|
* @param editor a <code>TreeCellEditor</code> object
|
|
*/
|
|
public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer,
|
|
TreeCellEditor editor) {
|
|
this.renderer = renderer;
|
|
realEditor = editor;
|
|
if(realEditor == null)
|
|
realEditor = createTreeCellEditor();
|
|
editingContainer = createContainer();
|
|
setTree(tree);
|
|
setBorderSelectionColor(UIManager.getColor
|
|
("Tree.editorBorderSelectionColor"));
|
|
}
|
|
|
|
/**
|
|
* Sets the color to use for the border.
|
|
* @param newColor the new border color
|
|
*/
|
|
public void setBorderSelectionColor(Color newColor) {
|
|
borderSelectionColor = newColor;
|
|
}
|
|
|
|
/**
|
|
* Returns the color the border is drawn.
|
|
* @return the border selection color
|
|
*/
|
|
public Color getBorderSelectionColor() {
|
|
return borderSelectionColor;
|
|
}
|
|
|
|
/**
|
|
* Sets the font to edit with. <code>null</code> indicates
|
|
* the renderers font should be used. This will NOT
|
|
* override any font you have set in the editor
|
|
* the receiver was instantiated with. If <code>null</code>
|
|
* for an editor was passed in a default editor will be
|
|
* created that will pick up this font.
|
|
*
|
|
* @param font the editing <code>Font</code>
|
|
* @see #getFont
|
|
*/
|
|
public void setFont(Font font) {
|
|
this.font = font;
|
|
}
|
|
|
|
/**
|
|
* Gets the font used for editing.
|
|
*
|
|
* @return the editing <code>Font</code>
|
|
* @see #setFont
|
|
*/
|
|
public Font getFont() {
|
|
return font;
|
|
}
|
|
|
|
//
|
|
// TreeCellEditor
|
|
//
|
|
|
|
/**
|
|
* Configures the editor. Passed onto the <code>realEditor</code>.
|
|
*/
|
|
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);
|
|
|
|
|
|
// this is kept for backwards compatibility but isn't really needed
|
|
// with the current BasicTreeUI implementation.
|
|
TreePath newPath = tree.getPathForRow(row);
|
|
|
|
canEdit = (lastPath != null && newPath != null &&
|
|
lastPath.equals(newPath));
|
|
|
|
Font font = getFont();
|
|
|
|
if(font == null) {
|
|
if(renderer != null)
|
|
font = renderer.getFont();
|
|
if(font == null)
|
|
font = tree.getFont();
|
|
}
|
|
editingContainer.setFont(font);
|
|
prepareForEditing();
|
|
return editingContainer;
|
|
}
|
|
|
|
/**
|
|
* Returns the value currently being edited.
|
|
* @return the value currently being edited
|
|
*/
|
|
public Object getCellEditorValue() {
|
|
return realEditor.getCellEditorValue();
|
|
}
|
|
|
|
/**
|
|
* If the <code>realEditor</code> returns true to this
|
|
* message, <code>prepareForEditing</code>
|
|
* is messaged and true is returned.
|
|
*/
|
|
public boolean isCellEditable(EventObject event) {
|
|
boolean retValue = false;
|
|
boolean editable = false;
|
|
|
|
if (event != null) {
|
|
if (event.getSource() instanceof JTree) {
|
|
setTree((JTree)event.getSource());
|
|
if (event instanceof MouseEvent) {
|
|
TreePath path = tree.getPathForLocation(
|
|
((MouseEvent)event).getX(),
|
|
((MouseEvent)event).getY());
|
|
editable = (lastPath != null && path != null &&
|
|
lastPath.equals(path));
|
|
if (path!=null) {
|
|
lastRow = tree.getRowForPath(path);
|
|
Object value = path.getLastPathComponent();
|
|
boolean isSelected = tree.isRowSelected(lastRow);
|
|
boolean expanded = tree.isExpanded(path);
|
|
TreeModel treeModel = tree.getModel();
|
|
boolean leaf = treeModel.isLeaf(value);
|
|
determineOffset(tree, value, isSelected,
|
|
expanded, leaf, lastRow);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(!realEditor.isCellEditable(event))
|
|
return false;
|
|
if(canEditImmediately(event))
|
|
retValue = true;
|
|
else if(editable && shouldStartEditingTimer(event)) {
|
|
startEditingTimer();
|
|
}
|
|
else if(timer != null && timer.isRunning())
|
|
timer.stop();
|
|
if(retValue)
|
|
prepareForEditing();
|
|
return retValue;
|
|
}
|
|
|
|
/**
|
|
* Messages the <code>realEditor</code> for the return value.
|
|
*/
|
|
public boolean shouldSelectCell(EventObject event) {
|
|
return realEditor.shouldSelectCell(event);
|
|
}
|
|
|
|
/**
|
|
* If the <code>realEditor</code> will allow editing to stop,
|
|
* the <code>realEditor</code> is removed and true is returned,
|
|
* otherwise false is returned.
|
|
*/
|
|
public boolean stopCellEditing() {
|
|
if(realEditor.stopCellEditing()) {
|
|
cleanupAfterEditing();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Messages <code>cancelCellEditing</code> to the
|
|
* <code>realEditor</code> and removes it from this instance.
|
|
*/
|
|
public void cancelCellEditing() {
|
|
realEditor.cancelCellEditing();
|
|
cleanupAfterEditing();
|
|
}
|
|
|
|
/**
|
|
* Adds the <code>CellEditorListener</code>.
|
|
* @param l the listener to be added
|
|
*/
|
|
public void addCellEditorListener(CellEditorListener l) {
|
|
realEditor.addCellEditorListener(l);
|
|
}
|
|
|
|
/**
|
|
* Removes the previously added <code>CellEditorListener</code>.
|
|
* @param l the listener to be removed
|
|
*/
|
|
public void removeCellEditorListener(CellEditorListener l) {
|
|
realEditor.removeCellEditorListener(l);
|
|
}
|
|
|
|
/**
|
|
* Returns an array of all the <code>CellEditorListener</code>s added
|
|
* to this DefaultTreeCellEditor with addCellEditorListener().
|
|
*
|
|
* @return all of the <code>CellEditorListener</code>s added or an empty
|
|
* array if no listeners have been added
|
|
* @since 1.4
|
|
*/
|
|
public CellEditorListener[] getCellEditorListeners() {
|
|
return ((DefaultCellEditor)realEditor).getCellEditorListeners();
|
|
}
|
|
|
|
//
|
|
// TreeSelectionListener
|
|
//
|
|
|
|
/**
|
|
* Resets <code>lastPath</code>.
|
|
*/
|
|
public void valueChanged(TreeSelectionEvent e) {
|
|
if(tree != null) {
|
|
if(tree.getSelectionCount() == 1)
|
|
lastPath = tree.getSelectionPath();
|
|
else
|
|
lastPath = null;
|
|
}
|
|
if(timer != null) {
|
|
timer.stop();
|
|
}
|
|
}
|
|
|
|
//
|
|
// ActionListener (for Timer).
|
|
//
|
|
|
|
/**
|
|
* Messaged when the timer fires, this will start the editing
|
|
* session.
|
|
*/
|
|
public void actionPerformed(ActionEvent e) {
|
|
if(tree != null && lastPath != null) {
|
|
tree.startEditingAtPath(lastPath);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Local methods
|
|
//
|
|
|
|
/**
|
|
* 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 <code>event</code> is a <code>MouseEvent</code>
|
|
* and the click count is 1.
|
|
* @param event the event being studied
|
|
*/
|
|
protected boolean shouldStartEditingTimer(EventObject event) {
|
|
if((event instanceof MouseEvent) &&
|
|
SwingUtilities.isLeftMouseButton((MouseEvent)event)) {
|
|
MouseEvent me = (MouseEvent)event;
|
|
|
|
return (me.getClickCount() == 1 &&
|
|
inHitRegion(me.getX(), me.getY()));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Starts the editing timer.
|
|
*/
|
|
protected void startEditingTimer() {
|
|
if(timer == null) {
|
|
timer = new Timer(1200, this);
|
|
timer.setRepeats(false);
|
|
}
|
|
timer.start();
|
|
}
|
|
|
|
/**
|
|
* Returns true if <code>event</code> is <code>null</code>,
|
|
* or it is a <code>MouseEvent</code> with a click count > 2
|
|
* and <code>inHitRegion</code> returns true.
|
|
* @param event the event being studied
|
|
*/
|
|
protected boolean canEditImmediately(EventObject event) {
|
|
if((event instanceof MouseEvent) &&
|
|
SwingUtilities.isLeftMouseButton((MouseEvent)event)) {
|
|
MouseEvent me = (MouseEvent)event;
|
|
|
|
return ((me.getClickCount() > 2) &&
|
|
inHitRegion(me.getX(), me.getY()));
|
|
}
|
|
return (event == null);
|
|
}
|
|
|
|
/**
|
|
* Returns true if the passed in location is a valid mouse location
|
|
* to start editing from. This is implemented to return false if
|
|
* <code>x</code> is <= 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) {
|
|
if(lastRow != -1 && tree != null) {
|
|
Rectangle bounds = tree.getRowBounds(lastRow);
|
|
ComponentOrientation treeOrientation = tree.getComponentOrientation();
|
|
|
|
if ( treeOrientation.isLeftToRight() ) {
|
|
if (bounds != null && x <= (bounds.x + offset) &&
|
|
offset < (bounds.width - 5)) {
|
|
return false;
|
|
}
|
|
} else if ( bounds != null &&
|
|
( x >= (bounds.x+bounds.width-offset+5) ||
|
|
x <= (bounds.x + 5) ) &&
|
|
offset < (bounds.width - 5) ) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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
|
|
* <code>editingComponent</code> to the
|
|
* <code>editingContainer</code>.
|
|
*/
|
|
protected void prepareForEditing() {
|
|
if (editingComponent != null) {
|
|
editingContainer.add(editingComponent);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates the container to manage placement of
|
|
* <code>editingComponent</code>.
|
|
*/
|
|
protected Container createContainer() {
|
|
return new EditorContainer();
|
|
}
|
|
|
|
/**
|
|
* This is invoked if a <code>TreeCellEditor</code>
|
|
* is not supplied in the constructor.
|
|
* It returns a <code>TextField</code> editor.
|
|
* @return a new <code>TextField</code> editor
|
|
*/
|
|
protected TreeCellEditor createTreeCellEditor() {
|
|
Border aBorder = UIManager.getBorder("Tree.editorBorder");
|
|
DefaultCellEditor editor = new DefaultCellEditor
|
|
(new DefaultTextField(aBorder)) {
|
|
public boolean shouldSelectCell(EventObject event) {
|
|
boolean retValue = super.shouldSelectCell(event);
|
|
return retValue;
|
|
}
|
|
};
|
|
|
|
// One click to edit.
|
|
editor.setClickCountToStart(1);
|
|
return editor;
|
|
}
|
|
|
|
/**
|
|
* Cleans up any state after editing has completed. Removes the
|
|
* <code>editingComponent</code> the <code>editingContainer</code>.
|
|
*/
|
|
private void cleanupAfterEditing() {
|
|
if (editingComponent != null) {
|
|
editingContainer.remove(editingComponent);
|
|
}
|
|
editingComponent = null;
|
|
}
|
|
|
|
// Serialization support.
|
|
private void writeObject(ObjectOutputStream s) throws IOException {
|
|
Vector<Object> values = new Vector<Object>();
|
|
|
|
s.defaultWriteObject();
|
|
// Save the realEditor, if its Serializable.
|
|
if(realEditor != null && realEditor instanceof Serializable) {
|
|
values.addElement("realEditor");
|
|
values.addElement(realEditor);
|
|
}
|
|
s.writeObject(values);
|
|
}
|
|
|
|
private void readObject(ObjectInputStream s)
|
|
throws IOException, ClassNotFoundException {
|
|
s.defaultReadObject();
|
|
|
|
Vector values = (Vector)s.readObject();
|
|
int indexCounter = 0;
|
|
int maxCounter = values.size();
|
|
|
|
if(indexCounter < maxCounter && values.elementAt(indexCounter).
|
|
equals("realEditor")) {
|
|
realEditor = (TreeCellEditor)values.elementAt(++indexCounter);
|
|
indexCounter++;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* <code>TextField</code> used when no editor is supplied.
|
|
* This textfield locks into the border it is constructed with.
|
|
* It also prefers its parents font over its font. And if the
|
|
* renderer is not <code>null</code> and no font
|
|
* has been specified the preferred height is that of the renderer.
|
|
*/
|
|
public class DefaultTextField extends JTextField {
|
|
/** Border to use. */
|
|
protected Border border;
|
|
|
|
/**
|
|
* Constructs a
|
|
* <code>DefaultTreeCellEditor.DefaultTextField</code> object.
|
|
*
|
|
* @param border a <code>Border</code> object
|
|
* @since 1.4
|
|
*/
|
|
public DefaultTextField(Border border) {
|
|
setBorder(border);
|
|
}
|
|
|
|
/**
|
|
* Sets the border of this component.<p>
|
|
* This is a bound property.
|
|
*
|
|
* @param border the border to be rendered for this component
|
|
* @see Border
|
|
* @see CompoundBorder
|
|
* @beaninfo
|
|
* bound: true
|
|
* preferred: true
|
|
* attribute: visualUpdate true
|
|
* description: The component's border.
|
|
*/
|
|
public void setBorder(Border border) {
|
|
super.setBorder(border);
|
|
this.border = border;
|
|
}
|
|
|
|
/**
|
|
* Overrides <code>JComponent.getBorder</code> to
|
|
* returns the current border.
|
|
*/
|
|
public Border getBorder() {
|
|
return border;
|
|
}
|
|
|
|
// implements java.awt.MenuContainer
|
|
public Font getFont() {
|
|
Font font = super.getFont();
|
|
|
|
// Prefer the parent containers font if our font is a
|
|
// FontUIResource
|
|
if(font instanceof FontUIResource) {
|
|
Container parent = getParent();
|
|
|
|
if(parent != null && parent.getFont() != null)
|
|
font = parent.getFont();
|
|
}
|
|
return font;
|
|
}
|
|
|
|
/**
|
|
* Overrides <code>JTextField.getPreferredSize</code> to
|
|
* return the preferred size based on current font, if set,
|
|
* or else use renderer's font.
|
|
* @return a <code>Dimension</code> object containing
|
|
* the preferred size
|
|
*/
|
|
public Dimension getPreferredSize() {
|
|
Dimension size = super.getPreferredSize();
|
|
|
|
// If not font has been set, prefer the renderers height.
|
|
if(renderer != null &&
|
|
DefaultTreeCellEditor.this.getFont() == null) {
|
|
Dimension rSize = renderer.getPreferredSize();
|
|
|
|
size.height = rSize.height;
|
|
}
|
|
return size;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Container responsible for placing the <code>editingComponent</code>.
|
|
*/
|
|
public class EditorContainer extends Container {
|
|
/**
|
|
* Constructs an <code>EditorContainer</code> object.
|
|
*/
|
|
public EditorContainer() {
|
|
setLayout(null);
|
|
}
|
|
|
|
// This should not be used. It will be removed when new API is
|
|
// allowed.
|
|
public void EditorContainer() {
|
|
setLayout(null);
|
|
}
|
|
|
|
/**
|
|
* Overrides <code>Container.paint</code> to paint the node's
|
|
* icon and use the selection color for the background.
|
|
*/
|
|
public void paint(Graphics g) {
|
|
int width = getWidth();
|
|
int height = getHeight();
|
|
|
|
// Then the icon.
|
|
if(editingIcon != null) {
|
|
int yLoc = calculateIconY(editingIcon);
|
|
|
|
if (getComponentOrientation().isLeftToRight()) {
|
|
editingIcon.paintIcon(this, g, 0, yLoc);
|
|
} else {
|
|
editingIcon.paintIcon(
|
|
this, g, width - editingIcon.getIconWidth(),
|
|
yLoc);
|
|
}
|
|
}
|
|
|
|
// Border selection color
|
|
Color background = getBorderSelectionColor();
|
|
if(background != null) {
|
|
g.setColor(background);
|
|
g.drawRect(0, 0, width - 1, height - 1);
|
|
}
|
|
super.paint(g);
|
|
}
|
|
|
|
/**
|
|
* Lays out this <code>Container</code>. If editing,
|
|
* the editor will be placed at
|
|
* <code>offset</code> in the x direction and 0 for y.
|
|
*/
|
|
public void doLayout() {
|
|
if(editingComponent != null) {
|
|
int width = getWidth();
|
|
int height = getHeight();
|
|
if (getComponentOrientation().isLeftToRight()) {
|
|
editingComponent.setBounds(
|
|
offset, 0, width - offset, height);
|
|
} else {
|
|
editingComponent.setBounds(
|
|
0, 0, width - offset, height);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculate the y location for the icon.
|
|
*/
|
|
private int calculateIconY(Icon icon) {
|
|
// To make sure the icon position matches that of the
|
|
// renderer, use the same algorithm as JLabel
|
|
// (SwingUtilities.layoutCompoundLabel).
|
|
int iconHeight = icon.getIconHeight();
|
|
int textHeight = editingComponent.getFontMetrics(
|
|
editingComponent.getFont()).getHeight();
|
|
int textY = iconHeight / 2 - textHeight / 2;
|
|
int totalY = Math.min(0, textY);
|
|
int totalHeight = Math.max(iconHeight, textY + textHeight) -
|
|
totalY;
|
|
return getHeight() / 2 - (totalY + (totalHeight / 2));
|
|
}
|
|
|
|
/**
|
|
* Returns the preferred size for the <code>Container</code>.
|
|
* This will be at least preferred size of the editor plus
|
|
* <code>offset</code>.
|
|
* @return a <code>Dimension</code> containing the preferred
|
|
* size for the <code>Container</code>; if
|
|
* <code>editingComponent</code> is <code>null</code> the
|
|
* <code>Dimension</code> returned is 0, 0
|
|
*/
|
|
public Dimension getPreferredSize() {
|
|
if(editingComponent != null) {
|
|
Dimension pSize = editingComponent.getPreferredSize();
|
|
|
|
pSize.width += offset + 5;
|
|
|
|
Dimension rSize = (renderer != null) ?
|
|
renderer.getPreferredSize() : null;
|
|
|
|
if(rSize != null)
|
|
pSize.height = Math.max(pSize.height, rSize.height);
|
|
if(editingIcon != null)
|
|
pSize.height = Math.max(pSize.height,
|
|
editingIcon.getIconHeight());
|
|
|
|
// Make sure width is at least 100.
|
|
pSize.width = Math.max(pSize.width, 100);
|
|
return pSize;
|
|
}
|
|
return new Dimension(0, 0);
|
|
}
|
|
}
|
|
}
|