/*******************************************************************************
* Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.workbench.uitools.cell;
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.LayoutManager;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.tree.TreeCellRenderer;
/**
* Make the cell look like a component, with an optional label.
* This is useful for components that do not have a label and
* need one when acting as a leaf on a tree, where there are
* no headers like a table.
*
* Subclasses must implement:
* #buildComponent()
* build and return the component to be placed next to the label
* #setValue(Object)
* set value of the component appropriately
*/
public abstract class LabeledTreeCellRenderer implements TreeCellRenderer {
/** the components used to paint the cell */
private JPanel panel;
private JLabel label;
protected JComponent component; // built by concrete subclass
/** this is set to true when the renderer is used by an editor */
protected boolean editing = false;
/** "normal" border */
private static final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1);
// ********** constructors **********
/**
* Construct a cell renderer that will display the specified text and icon
* in the component's label.
*/
public LabeledTreeCellRenderer(String labelText, Icon labelIcon) {
super();
this.initialize(labelText, labelIcon);
}
/**
* Construct a cell renderer that will display the specified text
* in the component's label.
*/
public LabeledTreeCellRenderer(String labelText) {
this(labelText, (Icon) null);
}
/**
* Construct a cell renderer that will display the specified icon
* in the component's label.
*/
public LabeledTreeCellRenderer(Icon labelIcon) {
this((String) null, labelIcon);
}
/**
* Construct a cell renderer that has no (visible) label.
*/
public LabeledTreeCellRenderer() {
this((String) null, (Icon) null);
}
// ********** initialization **********
protected void initialize(String labelText, Icon labelIcon) {
this.panel = this.buildPanel(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
// label
this.label = this.buildLabel(labelText, labelIcon);
constraints.gridx = 0;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 0;
constraints.weighty = 0;
constraints.fill = GridBagConstraints.BOTH;
constraints.anchor = GridBagConstraints.PAGE_START;
constraints.insets = new Insets(0, 0, 0, 5);
this.panel.add(this.label, constraints);
// component
this.component = this.buildComponent();
constraints.gridx = 1;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 1;
constraints.weighty = 0;
constraints.fill = GridBagConstraints.BOTH;
constraints.anchor = GridBagConstraints.PAGE_START;
constraints.insets = new Insets(0, 0, 0, 0);
this.panel.add(this.component, constraints);
}
protected JPanel buildPanel(LayoutManager layoutManager) {
return new JPanel(layoutManager);
}
protected JLabel buildLabel(String labelText, Icon labelIcon) {
return new JLabel(labelText, labelIcon, SwingConstants.LEADING);
}
protected abstract JComponent buildComponent();
/**
* Set whether the renderer is for an editor.
* This will cause a distinctive border to be drawn around the cell
* when it is being edited. It will also cause the component's
* default colors to be restored.
*/
protected void setEditing(boolean editing) {
this.editing = editing;
}
// ********** TreeCellRenderer implementation **********
/**
* @see javax.swing.tree.TreeCellRenderer#getTreeCellRendererComponent(javax.swing.JTree, java.lang.Object, boolean, boolean, boolean, int, boolean)
*/
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
this.setComponentOrientation(tree.getComponentOrientation());
this.setFont(tree.getFont());
this.setEnabled(tree.isEnabled());
this.setForeground(this.foregroundColor(tree, value, selected, expanded, leaf, row, hasFocus));
this.setBackground(this.backgroundColor(tree, value, selected, expanded, leaf, row, hasFocus));
this.panel.setBorder(this.border(tree, value, selected, expanded, leaf, row, hasFocus));
// once the colors are set, calculate opaque setting
this.setOpaque(this.cellIsOpaqueIn(tree, value, selected, expanded, leaf, row, hasFocus));
this.setValue(value);
return this.panel;
}
/**
* Set the orientation for the all the components.
*/
protected void setComponentOrientation(ComponentOrientation o) {
this.panel.setComponentOrientation(o);
this.label.setComponentOrientation(o);
this.component.setComponentOrientation(o);
}
/**
* Set the font for the all the components.
*/
protected void setFont(Font f) {
this.panel.setFont(f);
this.label.setFont(f);
this.component.setFont(f);
}
/**
* Set the enabled state for the all the components.
*/
protected void setEnabled(boolean enabled) {
this.panel.setEnabled(enabled);
this.label.setEnabled(enabled);
this.component.setEnabled(enabled);
}
/**
* Return the cell's foreground color.
*/
protected Color foregroundColor(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (selected) {
if (this.editing) { // there is no way to tell, from the parms passed in, whether we are editing (?)
return UIManager.getColor("Tree.textForeground");
}
return UIManager.getColor("Tree.selectionForeground");
}
return UIManager.getColor("Tree.textForeground");
}
/**
* Return the cell's background color.
*/
protected Color backgroundColor(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (selected) {
if (this.editing) { // there is no way to tell, from the parms passed in, whether we are editing (?)
return UIManager.getColor("Tree.textBackground");
}
return UIManager.getColor("Tree.selectionBackground");
}
return UIManager.getColor("Tree.textBackground");
}
/**
* Set the foreground color for the all the components.
*/
protected void setForeground(Color c) {
this.panel.setForeground(c);
this.label.setForeground(c);
this.component.setForeground(c);
}
/**
* Set the background color for the all the components.
*/
protected void setBackground(Color c) {
this.panel.setBackground(c);
this.label.setBackground(c);
this.component.setBackground(c);
}
/**
* Return the cell's border.
*/
protected Border border(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (hasFocus) {
if (this.editing) { // there is no way to tell, from the parms passed in, whether we are editing (?)
return UIManager.getBorder("Tree.editorBorder");
}
return BorderFactory.createLineBorder(UIManager.getColor("Tree.selectionBorderColor"), 1);
}
return NO_FOCUS_BORDER;
}
/**
* Return whether the cell should be opaque in the tree.
* If the cell's background is the same as the tree's background
* and tree is opaque, we don't need to paint the background -
* the tree will do it.
*/
protected boolean cellIsOpaqueIn(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
Color cellBackground = this.panel.getBackground();
Color treeBackground = tree.getBackground();
return ! (tree.isOpaque() && cellBackground.equals(treeBackground));
}
/**
* Set whether the cell is opaque.
*/
protected void setOpaque(boolean opaque) {
this.panel.setOpaque(opaque);
}
/**
* Set the component's value.
*/
protected abstract void setValue(Object value);
// ********** public API **********
/**
* Set the text displayed by the component's label.
*/
public void setLabelText(String labelText) {
this.label.setText(labelText);
}
/**
* Set the icon displayed by the component's label.
*/
public void setLabelIcon(Icon labelIcon) {
this.label.setIcon(labelIcon);
}
/**
* Return the renderer's preferred height. This allows you
* to set the row height to something the component will look good in....
*/
public int getPreferredHeight() {
// add in space for the border top and bottom
return (int) this.panel.getPreferredSize().getHeight() + 2;
}
public void setPreferredWidth(int width) {
this.panel.setPreferredSize(new Dimension(width, this.panel.getPreferredSize().height));
}
}