/******************************************************************************* * 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.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JCheckBox; import javax.swing.JTree; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.border.Border; /** * Make the cell look like a check box. */ public class CheckBoxTreeCellRenderer implements TreeCellEditorAdapter.Renderer { /** the component used to paint the cell */ private JCheckBox checkBox; /** this is set to true when the renderer is used by an editor */ protected boolean editing = false; /** the listener to be notified on an immediate edit */ protected TreeCellEditorAdapter.ImmediateEditListener immediateEditListener; /** various borders (LTR = left-to-right; RTL = right-to-left */ private static final Border NO_FOCUS_BORDER_LTR = BorderFactory.createEmptyBorder(2, 2, 2, 3); private static final Border NO_FOCUS_BORDER_RTL = BorderFactory.createEmptyBorder(2, 3, 2, 2); private static final Border INNER_FOCUS_BORDER_LTR = BorderFactory.createEmptyBorder(1, 1, 1, 2); private static final Border INNER_FOCUS_BORDER_RTL = BorderFactory.createEmptyBorder(1, 2, 1, 1); // ********** constructors/initialization ********** /** * Construct a cell renderer with no label or icon. */ public CheckBoxTreeCellRenderer() { super(); this.initialize(); } /** * Construct a cell renderer with the specified text and icon, * either of which may be null. */ public CheckBoxTreeCellRenderer(String text, Icon icon) { this(); this.setText(text); this.setIcon(icon); } /** * Construct a cell renderer with the specified text. */ public CheckBoxTreeCellRenderer(String text) { this(text, null); } /** * Construct a cell renderer with the specified icon. */ public CheckBoxTreeCellRenderer(Icon icon) { this(null, icon); } protected void initialize() { this.checkBox = this.buildCheckBox(); // by default, check boxes do not paint their borders this.checkBox.setBorderPainted(true); // this setting is recommended for check boxes inside of trees and tables this.checkBox.setBorderPaintedFlat(true); } protected JCheckBox buildCheckBox() { JCheckBox cb = new JCheckBox(); cb.addActionListener(this.buildActionListener()); return cb; } private ActionListener buildActionListener() { return new ActionListener() { public void actionPerformed(ActionEvent e) { if (CheckBoxTreeCellRenderer.this.immediateEditListener != null) { CheckBoxTreeCellRenderer.this.immediateEditListener.immediateEdit(); } } }; } /** * 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.checkBox.setHorizontalAlignment(SwingConstants.LEADING); this.checkBox.setComponentOrientation(tree.getComponentOrientation()); this.checkBox.setFont(tree.getFont()); this.checkBox.setEnabled(tree.isEnabled()); this.checkBox.setForeground(this.foregroundColor(tree, value, selected, expanded, leaf, row, hasFocus)); this.checkBox.setBackground(this.backgroundColor(tree, value, selected, expanded, leaf, row, hasFocus)); // once the colors are set, calculate opaque setting this.checkBox.setOpaque(this.cellIsOpaqueIn(tree, value, selected, expanded, leaf, row, hasFocus)); this.checkBox.setBorder(this.border(tree, value, selected, expanded, leaf, row, hasFocus)); this.setValue(value); return this.checkBox; } /** * 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"); } /** * Return the cell's border. * The border is 2 pixels on each side, except the "trailing" edge, * which is 3 pixels. */ protected Border border(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { return hasFocus ? BorderFactory.createCompoundBorder(this.outerFocusBorder(), this.innerFocusBorder()) : this.noFocusBorder(); } /** * Return the cell's inner focus border, which is padding * between the check box and the visible focus border. * Make the trailing edge a pixel wider than the other sides. */ protected Border innerFocusBorder() { return this.checkBox.getComponentOrientation().isLeftToRight() ? INNER_FOCUS_BORDER_LTR : INNER_FOCUS_BORDER_RTL; } /** * Return the cell's outer focus border, * which is a single-pixel line border. */ protected Border outerFocusBorder() { return this.editing ? // there is no way to tell, from the parms passed in, whether we are editing (?) UIManager.getBorder("Tree.editorBorder") : BorderFactory.createLineBorder(UIManager.getColor("Tree.selectionBorderColor"), 1); } /** * Return the cell's no focus border. * Make the trailing edge a pixel wider than the other sides. */ protected Border noFocusBorder() { return this.checkBox.getComponentOrientation().isLeftToRight() ? NO_FOCUS_BORDER_LTR : NO_FOCUS_BORDER_RTL; } /** * 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.checkBox.getBackground(); Color treeBackground = tree.getBackground(); return ! (tree.isOpaque() && cellBackground.equals(treeBackground)); } /** * Set the check box's value. */ protected void setValue(Object value) { this.checkBox.setSelected(((Boolean) value).booleanValue()); } // ********** TreeCellEditorAdapter.Renderer implementation ********** /** * @see TreeCellEditorAdapter#getValue() */ public Object getValue() { return Boolean.valueOf(this.checkBox.isSelected()); } /** * @see TreeCellEditorAdapter#setImmediateEditListener(TreeCellEditorAdapter.ImmediateEditListener listener) */ public void setImmediateEditListener(TreeCellEditorAdapter.ImmediateEditListener listener) { this.immediateEditListener = listener; } // ********** public API ********** /** * Set the check box's text; which by default is blank. */ public void setText(String text) { this.checkBox.setText(text); } /** * Set the check box's icon; which by default is not present. */ public void setIcon(Icon icon) { this.checkBox.setIcon(icon); } /** * Return the renderer's preferred height. This allows you * to set the tree's row height to something the check box * will look good in.... */ public int getPreferredHeight() { // add in space for the border top and bottom return (int) this.checkBox.getPreferredSize().getHeight() + 4; } // ********** API used by the cell editor ********** protected void addActionListener(ActionListener listener) { this.checkBox.addActionListener(listener); } }