package net.vhati.modmanager.ui.tree;
import java.awt.BorderLayout;
import java.awt.Component;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import net.vhati.modmanager.ui.tree.ChecklistTreePathFilter;
import net.vhati.modmanager.ui.tree.ChecklistTreeSelectionModel;
import net.vhati.modmanager.ui.tree.TristateCheckBox;
import net.vhati.modmanager.ui.tree.TristateButtonModel.TristateState;
/**
* A cell renderer that augments an existing renderer with a checkbox.
*/
public class ChecklistTreeCellRenderer extends JPanel implements TreeCellRenderer {
protected ChecklistTreeSelectionModel selectionModel;
protected ChecklistTreePathFilter checklistFilter;
protected TreeCellRenderer delegate;
protected TristateCheckBox checkbox = new TristateCheckBox();
protected int checkMaxX = 0;
/**
* Constructor.
*
* @param delegate a traditional TreeCellRenderer
* @param selectionModel a model to query for checkbox states
* @param checklistFilter a TreePath filter, or null to always show a checkbox
*/
public ChecklistTreeCellRenderer( TreeCellRenderer delegate, ChecklistTreeSelectionModel selectionModel, ChecklistTreePathFilter checklistFilter ) {
super();
this.delegate = delegate;
this.selectionModel = selectionModel;
this.checklistFilter = checklistFilter;
this.setLayout( new BorderLayout() );
this.setOpaque( false );
checkbox.setOpaque( false );
checkMaxX = checkbox.getPreferredSize().width;
}
@Override
public Component getTreeCellRendererComponent( JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus ) {
this.removeAll();
checkbox.setState( TristateState.DESELECTED );
Component delegateComp = delegate.getTreeCellRendererComponent( tree, value, sel, expanded, leaf, row, hasFocus );
TreePath path = tree.getPathForRow( row );
if ( path != null ) {
if ( selectionModel.isPathSelected( path, selectionModel.isDigged() ) ) {
checkbox.setState( TristateState.SELECTED );
} else {
checkbox.setState( ( selectionModel.isDigged() && selectionModel.isPartiallySelected( path ) ) ? TristateState.INDETERMINATE : TristateState.DESELECTED );
}
}
checkbox.setVisible( path == null || checklistFilter == null || checklistFilter.isSelectable( path ) );
checkbox.setEnabled( tree.isEnabled() );
this.add( checkbox, BorderLayout.WEST );
this.add( delegateComp, BorderLayout.CENTER );
return this;
}
public void setDelegate( TreeCellRenderer delegate ) {
this.delegate = delegate;
}
public TreeCellRenderer getDelegate() {
return delegate;
}
/**
* Returns the checkbox's right edge (in the renderer component's coordinate space).
*
* Values less than that can be interpreted as within the checkbox's bounds.
* X=0 is the renderer component's left edge.
*/
public int getCheckboxMaxX() {
return checkMaxX;
}
}