/* * @(#)CheckBoxTreeCellRenderer.java 8/11/2005 * * Copyright 2002 - 2005 JIDE Software Inc. All rights reserved. */ package com.jidesoft.swing; import javax.swing.*; import javax.swing.border.Border; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreePath; import java.awt.*; import java.awt.event.MouseEvent; import java.io.Serializable; /** * Renderers an item in a tree using JCheckBox. */ public class CheckBoxTreeCellRenderer extends JPanel implements TreeCellRenderer, Serializable { private static final long serialVersionUID = 30207434500313004L; /** * The checkbox that is used to paint the check box in cell renderer */ protected TristateCheckBox _checkBox = null; protected JComponent _emptyBox = null; protected JCheckBox _protoType; /** * The label which appears after the check box. */ protected TreeCellRenderer _actualTreeRenderer; /** * Constructs a default renderer object for an item in a list. */ public CheckBoxTreeCellRenderer() { this(null); } public CheckBoxTreeCellRenderer(TreeCellRenderer renderer) { this(renderer, null); } public CheckBoxTreeCellRenderer(TreeCellRenderer renderer, TristateCheckBox checkBox) { _protoType = new TristateCheckBox(); if (checkBox == null) { _checkBox = createCheckBox(); } else { _checkBox = checkBox; } _emptyBox = (JComponent) Box.createHorizontalStrut(_protoType.getPreferredSize().width); setLayout(new BorderLayout(0, 0)); setOpaque(false); _actualTreeRenderer = renderer; } /** * Create the check box in the cell. * <p/> * By default, it creates a TristateCheckBox and set opaque to false. * * @return the check box instance. */ protected TristateCheckBox createCheckBox() { TristateCheckBox checkBox = new NullTristateCheckBox(); checkBox.setOpaque(false); return checkBox; } public TreeCellRenderer getActualTreeRenderer() { return _actualTreeRenderer; } public void setActualTreeRenderer(TreeCellRenderer actualTreeRenderer) { _actualTreeRenderer = actualTreeRenderer; } public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { removeAll(); // _checkBox.setPreferredSize(new Dimension(_protoType.getPreferredSize().width, 0)); _emptyBox.setPreferredSize(new Dimension(_protoType.getPreferredSize().width, 0)); applyComponentOrientation(tree.getComponentOrientation()); TreePath path = tree.getPathForRow(row); if (path != null && tree instanceof CheckBoxTree) { CheckBoxTreeSelectionModel selectionModel = ((CheckBoxTree) tree).getCheckBoxTreeSelectionModel(); if (selectionModel != null) { boolean enabled = tree.isEnabled() && ((CheckBoxTree) tree).isCheckBoxEnabled() && ((CheckBoxTree) tree).isCheckBoxEnabled(path); if (!enabled && !selected) { if (getBackground() != null) { setForeground(getBackground().darker()); } } _checkBox.setEnabled(enabled); updateCheckBoxState(_checkBox, path, selectionModel); } } if (_actualTreeRenderer != null) { JComponent treeCellRendererComponent = (JComponent) _actualTreeRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); Border border = treeCellRendererComponent.getBorder(); setBorder(border); treeCellRendererComponent.setBorder(BorderFactory.createEmptyBorder()); if (path == null || !(tree instanceof CheckBoxTree) || ((CheckBoxTree) tree).isCheckBoxVisible(path)) { remove(_emptyBox); add(_checkBox, BorderLayout.BEFORE_LINE_BEGINS); } else { remove(_checkBox); add(_emptyBox, BorderLayout.AFTER_LINE_ENDS); // expand the tree node size to be the same as the one with check box. } add(treeCellRendererComponent); // copy the background and foreground for the renderer component setBackground(treeCellRendererComponent.getBackground()); treeCellRendererComponent.setBackground(null); setForeground(treeCellRendererComponent.getForeground()); treeCellRendererComponent.setForeground(null); } return this; } /** * Updates the check box state based on the selection in the selection model. By default, we check if the path is * selected. If yes, we mark the check box as TristateCheckBox.SELECTED. If not, we will check if the path is * partially selected, if yes, we set the check box as null or TristateCheckBox.DONT_CARE to indicate the path is * partially selected. Otherwise, we set it to TristateCheckBox.NOT_SELECTED. * * @param checkBox the TristateCheckBox for the particular tree path. * @param path the tree path. * @param selectionModel the CheckBoxTreeSelectionModel. */ protected void updateCheckBoxState(TristateCheckBox checkBox, TreePath path, CheckBoxTreeSelectionModel selectionModel) { if (selectionModel.isPathSelected(path, selectionModel.isDigIn())) checkBox.setState(TristateCheckBox.STATE_SELECTED); else checkBox.setState(selectionModel.isDigIn() && selectionModel.isPartiallySelected(path) ? TristateCheckBox.STATE_MIXED : TristateCheckBox.STATE_UNSELECTED); } @Override public String getToolTipText(MouseEvent event) { if (_actualTreeRenderer instanceof JComponent) { Point p = event.getPoint(); p.translate(-_checkBox.getWidth(), 0); MouseEvent newEvent = new MouseEvent(((JComponent) _actualTreeRenderer), event.getID(), event.getWhen(), event.getModifiers(), p.x, p.y, event.getClickCount(), event.isPopupTrigger()); String tip = ((JComponent) _actualTreeRenderer).getToolTipText( newEvent); if (tip != null) { return tip; } } return super.getToolTipText(event); } }