/*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ package Sirius.navigator.ui.tree; import Sirius.navigator.types.iterator.TreeNodeIterator; import Sirius.navigator.types.iterator.TreeNodeRestriction; import Sirius.navigator.types.treenode.ClassTreeNode; import Sirius.navigator.types.treenode.DefaultMetaTreeNode; import Sirius.navigator.types.treenode.PureTreeNode; import Sirius.navigator.types.treenode.RootTreeNode; import Sirius.navigator.types.treenode.TreeNodeLoader; import Sirius.navigator.ui.widget.IconCheckBox; import Sirius.server.middleware.types.MetaClassNode; import Sirius.server.middleware.types.MetaNode; import Sirius.server.middleware.types.MetaObjectNode; import Sirius.server.middleware.types.Node; import org.apache.log4j.Logger; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import javax.swing.JTree; import javax.swing.UIManager; import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.FontUIResource; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeNode; /** * DOCUMENT ME! * * @version $Revision$, $Date$ */ public final class SearchSelectionTree extends MetaCatalogueTree { //~ Static fields/initializers --------------------------------------------- private static final transient Logger LOG = Logger.getLogger(SearchSelectionTree.class); //~ Constructors ----------------------------------------------------------- /** * Creates a new SearchSelectionTree object. * * @param rootNodes DOCUMENT ME! */ public SearchSelectionTree(final Node[] rootNodes) { this(new RootTreeNode(rootNodes, new SelectionTreeNodeLoader())); } /** * Creates a new SearchSelectionTree object. * * @param rootNode DOCUMENT ME! */ public SearchSelectionTree(final RootTreeNode rootNode) { super(rootNode, false, true, 1); try { if (LOG.isDebugEnabled()) { LOG.warn("Exploring all nodes of search selection tree root node"); // NOI18N } rootNode.exploreAll(); } catch (Exception exp) { LOG.error("cound not explore all nodes of search selection tree root node", exp); // NOI18N } this.setSelectionModel(null); this.setCellRenderer(new CheckBoxTreeCellRenderer()); this.setRowHeight(0); } //~ Methods ---------------------------------------------------------------- /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public ClassTreeNode[] getClassNodes() { final Enumeration enu = ((DefaultMutableTreeNode)this.getModel().getRoot()).breadthFirstEnumeration(); final List<ClassTreeNode> nodes = new ArrayList<ClassTreeNode>(); if (enu == null) { return null; } while (enu.hasMoreElements()) { final DefaultMetaTreeNode tempNode = (DefaultMetaTreeNode)enu.nextElement(); if ((tempNode != null) && tempNode.isClassNode()) { nodes.add((ClassTreeNode)tempNode); } } if (LOG.isDebugEnabled()) { LOG.debug("[SearchSelectionTree] ClassNodes: " + nodes.size()); // NOI18N } return nodes.toArray(new ClassTreeNode[nodes.size()]); } /** * DOCUMENT ME! */ public void deselectAllNodes() { this.clearSelection(); final Enumeration enu = ((DefaultMutableTreeNode)this.getModel().getRoot()).breadthFirstEnumeration(); final TreeNodeIterator iterator = new TreeNodeIterator(enu); while (iterator.hasNext()) { iterator.next().setSelected(false); } this.revalidate(); this.repaint(); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public List<String> getSelectedClassNodeKeys() { if (LOG.isDebugEnabled()) { LOG.debug("getSelectedClassNodeKeys() called"); // NOI18N } final List<String> selectedClassNodeKeys = new ArrayList<String>(); final Enumeration enu = ((DefaultMutableTreeNode)this.getModel().getRoot()).breadthFirstEnumeration(); final TreeNodeIterator iterator = new TreeNodeIterator(enu, new TreeNodeRestriction()); while (iterator.hasNext()) { final DefaultMetaTreeNode node = iterator.next(); if (node.isSelected()) { try { if (LOG.isDebugEnabled()) { LOG.debug("selected class node '" + node.toString() + "' key: " + node.getKey()); // NOI18N } selectedClassNodeKeys.add(node.getKey()); } catch (final Exception exp) { LOG.warn("could not add class node key", exp); // NOI18N } } else if (LOG.isDebugEnabled()) { LOG.debug("ignoring class node '" + node.toString() + "' (not selected)"); // NOI18N } } return selectedClassNodeKeys; } /** * select all class nodes. * * @param classNodeKeys DOCUMENT ME! */ public void setSelectedClassNodeKeys(final List classNodeKeys) { if (LOG.isDebugEnabled()) { LOG.debug("selecting '" + classNodeKeys.size() + "'class nodes"); // NOI18N } this.clearSelection(); final DefaultTreeModel model = (DefaultTreeModel)this.getModel(); final DefaultMetaTreeNode rootNode = (DefaultMetaTreeNode)model.getRoot(); final Enumeration enu = rootNode.breadthFirstEnumeration(); while (enu.hasMoreElements()) { final DefaultMetaTreeNode tempNode = (DefaultMetaTreeNode)enu.nextElement(); tempNode.setSelected(false); final Iterator iterator = classNodeKeys.iterator(); while (iterator.hasNext()) { try { final Object key = iterator.next(); if ((key != null) && (tempNode.getKey() != null) && tempNode.getKey().equals(key)) { if (LOG.isDebugEnabled()) { LOG.debug("selecting class node '" + tempNode + "' (" + key + ")"); // NOI18N } tempNode.setSelected(true); } } catch (final Exception exp) { LOG.warn("could not compare class node key", exp); // NOI18N } } } this.revalidate(); this.repaint(); } //~ Inner Classes ---------------------------------------------------------- /** * ---------------------------------------------------------------------------. * * @version $Revision$, $Date$ */ final class CheckBoxTreeCellRenderer extends IconCheckBox implements TreeCellRenderer { //~ Instance fields ---------------------------------------------------- /** Is the value currently selected. */ protected boolean selected; /** True if has focus. */ protected boolean hasFocus; // Colors /** Color to use for the foreground for selected nodes. */ protected Color textSelectionColor; /** Color to use for the foreground for non-selected nodes. */ protected Color textNonSelectionColor; /** Color to use for the background when a node is selected. */ protected Color backgroundSelectionColor; /** Color to use for the background when the node isn't selected. */ protected Color backgroundNonSelectionColor; /** Color to use for the background when the node isn't selected. */ protected Color borderSelectionColor; /** True if draws focus border around icon as well. */ private boolean drawsFocusBorderAroundIcon; //~ Constructors ------------------------------------------------------- /** * Returns a new instance of DefaultTreeCellRenderer. Alignment is set to left aligned. Icons and text color are * determined from the UIManager. */ public CheckBoxTreeCellRenderer() { setTextSelectionColor(UIManager.getColor("Tree.selectionForeground")); // NOI18N setTextNonSelectionColor(UIManager.getColor("Tree.textForeground")); // NOI18N setBackgroundSelectionColor(UIManager.getColor("Tree.selectionBackground")); // NOI18N setBackgroundNonSelectionColor(UIManager.getColor("Tree.textBackground")); // NOI18N setBorderSelectionColor(UIManager.getColor("Tree.selectionBorderColor")); // NOI18N final Object value = UIManager.get("Tree.drawsFocusBorderAroundIcon"); // NOI18N drawsFocusBorderAroundIcon = ((value != null) && ((Boolean)value).booleanValue()); } //~ Methods ------------------------------------------------------------ /** * Sets the color the text is drawn with when the node is selected. * * @param newColor DOCUMENT ME! */ public void setTextSelectionColor(final Color newColor) { textSelectionColor = newColor; } /** * Returns the color the text is drawn with when the node is selected. * * @return DOCUMENT ME! */ public Color getTextSelectionColor() { return textSelectionColor; } /** * Sets the color the text is drawn with when the node isn't selected. * * @param newColor DOCUMENT ME! */ public void setTextNonSelectionColor(final Color newColor) { textNonSelectionColor = newColor; } /** * Returns the color the text is drawn with when the node isn't selected. * * @return DOCUMENT ME! */ public Color getTextNonSelectionColor() { return textNonSelectionColor; } /** * Sets the color to use for the background if node is selected. * * @param newColor DOCUMENT ME! */ public void setBackgroundSelectionColor(final Color newColor) { backgroundSelectionColor = newColor; } /** * Returns the color to use for the background if node is selected. * * @return DOCUMENT ME! */ public Color getBackgroundSelectionColor() { return backgroundSelectionColor; } /** * Sets the background color to be used for non selected nodes. * * @param newColor DOCUMENT ME! */ public void setBackgroundNonSelectionColor(final Color newColor) { backgroundNonSelectionColor = newColor; } /** * Returns the background color to be used for non selected nodes. * * @return DOCUMENT ME! */ public Color getBackgroundNonSelectionColor() { return backgroundNonSelectionColor; } /** * Sets the color to use for the border. * * @param newColor DOCUMENT ME! */ public void setBorderSelectionColor(final Color newColor) { borderSelectionColor = newColor; } /** * Returns the color the border is drawn. * * @return DOCUMENT ME! */ public Color getBorderSelectionColor() { return borderSelectionColor; } /** * Subclassed to map <code>FontUIResource</code>s to null. If <code>font</code> is null, or a <code> * FontUIResource</code>, this has the effect of letting the font of the JTree show through. On the other hand, * if <code>font</code> is non-null, and not a <code>FontUIResource</code>, the font becomes <code>font</code>. * * @param font DOCUMENT ME! */ @Override public void setFont(Font font) { if (font instanceof FontUIResource) { font = null; } super.setFont(font); } /** * Subclassed to map <code>ColorUIResource</code>s to null. If <code>color</code> is null, or a <code> * ColorUIResource</code>, this has the effect of letting the background color of the JTree show through. On the * other hand, if <code>color</code> is non-null, and not a <code>ColorUIResource</code>, the background becomes * <code>color</code>. * * @param color DOCUMENT ME! */ @Override public void setBackground(Color color) { if (color instanceof ColorUIResource) { color = null; } super.setBackground(color); } /** * Configures the renderer based on the passed in components. The value is set from messaging the tree with * <code>convertValueToText</code>, which ultimately invokes <code>toString</code> on <code>value</code>. The * foreground color is set based on the selection and the icon is set based on on leaf and expanded. * * @param tree DOCUMENT ME! * @param value DOCUMENT ME! * @param sel DOCUMENT ME! * @param expanded DOCUMENT ME! * @param leaf DOCUMENT ME! * @param row DOCUMENT ME! * @param hasFocus DOCUMENT ME! * * @return DOCUMENT ME! */ @Override public Component getTreeCellRendererComponent(final JTree tree, final java.lang.Object value, final boolean sel, final boolean expanded, final boolean leaf, final int row, final boolean hasFocus) { final String stringValue = tree.convertValueToText(value, sel, expanded, leaf, row, hasFocus); this.hasFocus = hasFocus; setText(stringValue); if (sel) { setForeground(getTextSelectionColor()); } else { setForeground(getTextNonSelectionColor()); } if (!tree.isEnabled()) { setEnabled(false); } else { setEnabled(true); } setComponentOrientation(tree.getComponentOrientation()); final DefaultMetaTreeNode treeNode = (DefaultMetaTreeNode)value; this.setSelected(treeNode.isSelected()); this.setEnabled(treeNode.isEnabled()); if (expanded == true) { this.setIcon(treeNode.getOpenIcon()); } else if (leaf == true) { this.setIcon(treeNode.getLeafIcon()); } else { this.setIcon(treeNode.getClosedIcon()); } return this; } } } /** * DOCUMENT ME! * * @version $Revision$, $Date$ */ final class SelectionTreeNodeLoader implements TreeNodeLoader { //~ Static fields/initializers --------------------------------------------- private static final transient Logger LOG = Logger.getLogger(SelectionTreeNodeLoader.class); //~ Methods ---------------------------------------------------------------- @Override public boolean addChildren(final DefaultMetaTreeNode node) throws Exception { return this.addChildren(node, node.getChildren()); } @Override public boolean addChildren(final DefaultMetaTreeNode node, final Node[] children) throws Exception { boolean explored = true; // WaitNode entfernen! node.removeChildren(); if (children == null) { return false; } DefaultMetaTreeNode childNode; for (int i = 0; i < children.length; i++) { if (children[i] instanceof MetaNode) { childNode = new PureTreeNode((MetaNode)children[i]); childNode.setAllowsChildren(checkForChildren(childNode)); childNode.setSelected(node.isSelected()); childNode.setEnabled(!childNode.isLeaf()); node.add(childNode); explored &= children[i].isValid(); if (LOG.isDebugEnabled()) { LOG.debug("[SelectionTreeNodeLoader] PureNode Children added"); // NOI18N } } else if (children[i] instanceof MetaClassNode) { childNode = new ClassTreeNode((MetaClassNode)children[i]); childNode.setAllowsChildren(checkForChildren(childNode)); childNode.setSelected(node.isSelected()); node.add(childNode); explored &= children[i].isValid(); if (LOG.isDebugEnabled()) { LOG.debug("[SelectionTreeNodeLoader] ClassNode Children added"); // NOI18N } } else if (children[i] instanceof MetaObjectNode) { if (LOG.isDebugEnabled()) { LOG.debug("[SelectionTreeNodeLoader] ObjectNodes not allowed here: " + children[i]); // NOI18N } } else { if (LOG.isDebugEnabled()) { LOG.debug("[SelectionTreeNodeLoader] Wrong Node Type: " + children[i]); // NOI18N } throw new Exception("Wrong Node Type: " + children[i]); // NOI18N } if (LOG.isDebugEnabled()) { LOG.debug("[SelectionTreeNodeLoader] Children #" + i + 1 + " added."); // NOI18N } } return explored; } /** * DOCUMENT ME! * * @param node DOCUMENT ME! * * @return DOCUMENT ME! */ protected boolean checkForChildren(final DefaultMetaTreeNode node) { if (LOG.isDebugEnabled()) { LOG.debug("cycle check: '" + node + "'"); // NOI18N } if (!node.isLeaf() && !node.isWaitNode()) { try { final Node[] children = node.getChildren(); if ((children != null) && (children.length > 0)) { final TreeNode[] anchestors = node.getPath(); final ArrayList childrenList = new ArrayList(children.length); for (int i = 0; i < children.length; i++) { boolean recursive = false; if ((children[i] instanceof MetaNode) || (children[i] instanceof MetaClassNode)) { for (int j = i; j < anchestors.length; j++) { if ((((DefaultMetaTreeNode)anchestors[j]).getID() == children[i].getId()) && ((DefaultMetaTreeNode)anchestors[j]).getDomain().equals( children[i].getDomain())) { recursive = true; if (LOG.isDebugEnabled()) { LOG.debug("[SelectionTreeNodeLoader] cycle detected: " + children[i] // NOI18N + " id: " + children[i].getId() + " LocalServerName: " // NOI18N + children[i].getDomain()); } break; } } if (!recursive) { childrenList.add(children[i]); } } else { if (LOG.isDebugEnabled()) { LOG.debug("Node Type not allowed here" + children[i]); // NOI18N } } } } } catch (final Exception exp) { LOG.error( "[SelectionTreeNodeLoader] Exception at checkForChildren(DefaultMetaTreeNode node): " // NOI18N + node, exp); } } return false; } }