/*
* This library is part of OpenCms -
* the Open Source Content Management System
*
* Copyright (c) Alkacon Software GmbH (http://www.alkacon.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* For further information about Alkacon Software GmbH, please see the
* company website: http://www.alkacon.com
*
* For further information about OpenCms, please see the
* project website: http://www.opencms.org
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.opencms.util.ant;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
/**
* A proprietary {@link javax.swing.JTree} utilization for visuals checkbox selection.
* <p>
*
* It displays a tree with:
* <ul>
* <li> Multiple node selection (windos Look and Feel: press STRG) </li>
* <li> Subsequent selection on the UI: it appears that all subnodes of a node are selected too</li>
* <li>{@link javax.swing.tree.TreeSelectionModel#DISCONTIGUOUS_TREE_SELECTION} </li>
* <li> Custom node UI with checkboxes. </li>
* </ul>
*
*/
public class SelectionTree extends JTree {
/**
*
* Custom cell renderer that displays a checkbox.
* <p>
*
* @since 6.1.6
*
*/
class CheckBoxCellRenderer extends DefaultTreeCellRenderer {
/** Generated servial version UID. * */
private static final long serialVersionUID = -4329469376335457482L;
/**
*
* @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 isSelected,
boolean expanded,
boolean leaf,
int row,
boolean focus) {
super.getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, focus);
return new TreeCellUI((DefaultMutableTreeNode)value, selected);
}
}
/**
*
* {@link TreeSelectionListener} that clears the selections on toggeled paths.
* <p>
*
* This is only needed because of the proprietary UI - display of selected subnodes that are not
* selected within the tree model itself.
* <p>
*
* @since 6.1.6
*
*/
class SubsequentSelection implements TreeSelectionListener {
/**
* @see javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event.TreeSelectionEvent)
*/
public void valueChanged(TreeSelectionEvent e) {
// DefaultMutableTreeNode node =
// (DefaultMutableTreeNode)SelectionTree.this.getLastSelectedPathComponent();
// clear the old subselections:
SelectionTree.this.clearToggledPaths();
}
}
/**
*
* Custom component containing the default tree cell component along with a checkbox.
* <p>
*
* @since 6.1.6
*
*/
class TreeCellUI extends JComponent {
/** Generated serial version UID. * */
private static final long serialVersionUID = -1315044645298979088L;
/** The checkbox to use. * */
private JCheckBox m_checkBox;
/**
* Constructor with the corresponding tree node and the selection flag.
* <p>
*
* @param node the corresponding tree node.
*
* @param selected flag that specifies the state of the internal checkbox to show.
*/
public TreeCellUI(DefaultMutableTreeNode node, boolean selected) {
JLabel label = new JLabel();
label.setText(node.getUserObject().toString());
this.m_checkBox = new JCheckBox();
this.m_checkBox.setSelected(selected || this.searchSelected(node));
this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
this.add(this.m_checkBox);
this.add(label);
m_checkBox.setBackground(UIManager.getLookAndFeel().getDefaults().getColor("window"));
// invalidate all subnodes:
}
private boolean searchSelected(DefaultMutableTreeNode node) {
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)SelectionTree.this.getLastSelectedPathComponent();
if (selectedNode == null) {
return false;
}
return (selectedNode.isNodeDescendant(node));
}
}
/** Generated serial version UID. * */
private static final long serialVersionUID = -3627379509871776708L;
/**
* Defcon.
*/
public SelectionTree() {
super();
super.setCellRenderer(new CheckBoxCellRenderer());
this.selectionModel.setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
this.selectionModel.addTreeSelectionListener(new SubsequentSelection());
// this.setShowsRootHandles(false);
}
/**
* For testing purposes.
* <p>
*
* @param args unused command line args.
*/
public static void main(String[] args) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode("root");
DefaultMutableTreeNode a = new DefaultMutableTreeNode("a");
DefaultMutableTreeNode b = new DefaultMutableTreeNode("b");
DefaultMutableTreeNode c = new DefaultMutableTreeNode("c");
DefaultMutableTreeNode a1 = new DefaultMutableTreeNode("1");
DefaultMutableTreeNode a2 = new DefaultMutableTreeNode("2");
DefaultMutableTreeNode a3 = new DefaultMutableTreeNode("3");
DefaultMutableTreeNode b1 = new DefaultMutableTreeNode("1");
DefaultMutableTreeNode b2 = new DefaultMutableTreeNode("2");
DefaultMutableTreeNode b3 = new DefaultMutableTreeNode("3");
DefaultMutableTreeNode c1 = new DefaultMutableTreeNode("1");
DefaultMutableTreeNode c2 = new DefaultMutableTreeNode("2");
DefaultMutableTreeNode c3 = new DefaultMutableTreeNode("3");
node.add(a);
node.add(b);
node.add(c);
a.add(a1);
a.add(a2);
a.add(a3);
b.add(b1);
b.add(b2);
b.add(b3);
c.add(c1);
c.add(c2);
c.add(c3);
JFrame frame = new JFrame("SelectionTree");
SelectionTree tree = new SelectionTree();
tree.setModel(new DefaultTreeModel(node));
frame.getContentPane().add(tree);
frame.setSize(new Dimension(200, 800));
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
frame.setVisible(true);
}
/**
* @see javax.swing.JTree#clearToggledPaths()
*/
public void clearToggledPaths() {
// TODO: Auto-generated method stub
super.clearToggledPaths();
}
/**
*
* @see javax.swing.JTree#removeSelectionPath(javax.swing.tree.TreePath)
*/
public void removeSelectionPath(TreePath path) {
// unselect the current TreeCell:
super.removeSelectionPath(path);
// unselect the TreeCell rendererer checkboxes in subsequent entries:
// this.clearToggledPaths();
}
/**
*
* @see javax.swing.JTree#setCellRenderer(javax.swing.tree.TreeCellRenderer)
*/
public void setCellRenderer(TreeCellRenderer x) {
// nop
}
/**
* @see javax.swing.JTree#setSelectionPath(javax.swing.tree.TreePath)
*/
public void setSelectionPath(TreePath path) {
super.setSelectionPath(path);
this.clearToggledPaths();
}
}