/*
* Copyright 2007-2010 Enrico Boldrini, Lorenzo Bigagli This file is part of
* CheckboxTree. CheckboxTree is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. CheckboxTree is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with CheckboxTree; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
package it.cnr.imaa.essi.lablib.gui.checkboxtree;
import it.cnr.imaa.essi.lablib.gui.checkboxtree.QuadristateButtonModel.State;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.plaf.ColorUIResource;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreePath;
/**
* A renderer for the CheckboxTree. This implementation decorates a
* DefaultTreeCellRenderer (i.e. a JLabel) with a checkbox, by adding a
* QuadristateCheckbox to the former onto a JPanel. Both can be overridden by
* subclasses. Note that double-clicking the label/icon of this renderer does
* not toggle the checkbox.
*
* @author boldrini
* @author bigagli
*/
public class DefaultCheckboxTreeCellRenderer extends JPanel implements CheckboxTreeCellRenderer {
private static final long serialVersionUID = 1L;
/**
* Loads an ImageIcon from the file iconFile, searching it in the classpath.
*/
protected static ImageIcon loadIcon(String iconFile) {
try {
return new ImageIcon(DefaultCheckboxTreeCellRenderer.class.getClassLoader().getResource(iconFile));
} catch (NullPointerException npe) {
// did not find the resource
return null;
}
}
protected QuadristateCheckbox checkBox = new QuadristateCheckbox();
protected DefaultTreeCellRenderer label = new DefaultTreeCellRenderer();
// @Override
// public void doLayout() {
// Dimension d_check = this.checkBox.getPreferredSize();
// Dimension d_label = this.label.getPreferredSize();
// int y_check = 0;
// int y_label = 0;
// if (d_check.height < d_label.height) {
// y_check = (d_label.height - d_check.height) / 2;
// } else {
// y_label = (d_check.height - d_label.height) / 2;
// }
// this.checkBox.setLocation(0, y_check);
// this.checkBox.setBounds(0, y_check, d_check.width, d_check.height);
// this.label.setLocation(d_check.width, y_label);
// this.label.setBounds(d_check.width, y_label, d_label.width,
// d_label.height);
// }
public DefaultCheckboxTreeCellRenderer() {
/* this method was as follows (see ticket #6):
* this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
* add(this.checkBox);
* add(this.label);
* this.checkBox.setBackground(UIManager.getColor("Tree.textBackground"));
* this.setBackground(UIManager.getColor("Tree.textBackground"));
*/
// CHECK: a user suggested BorderLayout appears to work better than FlowLayout with most L&Fs
this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
this.setOpaque(false);
add(this.checkBox);
add(this.label);
/*
* label.setOpaque(false); seems not work...
*/
this.label.setBackgroundNonSelectionColor(new Color(0, 0, 0, 0));
}
@Override
public Dimension getPreferredSize() {
Dimension d_check = this.checkBox.getPreferredSize();
Dimension d_label = this.label.getPreferredSize();
return new Dimension(d_check.width + d_label.width, (d_check.height < d_label.height ? d_label.height : d_check.height));
}
/**
* Decorates this renderer based on the passed in components.
*/
@Override
public Component getTreeCellRendererComponent(JTree tree, Object object,
boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
/*
* most of the rendering is delegated to the wrapped
* DefaultTreeCellRenderer, the rest depends on the TreeCheckingModel
*/
this.label.getTreeCellRendererComponent(tree, object, selected, expanded, leaf, row, hasFocus);
if (tree instanceof CheckboxTree) {
TreePath path = tree.getPathForRow(row);
TreeCheckingModel checkingModel = ((CheckboxTree) tree).getCheckingModel();
this.checkBox.setEnabled(checkingModel.isPathEnabled(path) && tree.isEnabled());
boolean checked = checkingModel.isPathChecked(path);
boolean greyed = checkingModel.isPathGreyed(path);
if (checked && !greyed) {
this.checkBox.setState(State.CHECKED);
}
if (!checked && greyed) {
this.checkBox.setState(State.GREY_UNCHECKED);
}
if (checked && greyed) {
this.checkBox.setState(State.GREY_CHECKED);
}
if (!checked && !greyed) {
this.checkBox.setState(State.UNCHECKED);
}
}
return this;
}
/**
* Checks if the (x,y) coordinates are on the Checkbox.
* @return boolean
* @param x
* @param y
*/
@Override
public boolean isOnHotspot(int x, int y) {
return this.checkBox.contains(x, y);
}
@Override
public void setBackground(Color color) {
if (color instanceof ColorUIResource)
color = null;
super.setBackground(color);
}
/**
* Sets the icon used to represent non-leaf nodes that are not expanded.
*/
public void setClosedIcon(Icon newIcon) {
this.label.setClosedIcon(newIcon);
}
/**
* Sets the icon used to represent leaf nodes.
*/
public void setLeafIcon(Icon newIcon) {
this.label.setLeafIcon(newIcon);
}
/**
* Sets the icon used to represent non-leaf nodes that are expanded.
*/
public void setOpenIcon(Icon newIcon) {
this.label.setOpenIcon(newIcon);
}
}