Author: pwang
Date: 2009-03-16 15:30:19 -0700 (Mon, 16 Mar 2009)
New Revision: 16288

Added:
   
csplugins/trunk/ucsd/pwang/cyprovision/org.eclipse.equinox.p2.ui2/src/org/eclipse/equinox/internal/provisional/p2/ui2/dialogs/CheckBoxTreeCellRenderer.java
Log:
free software from http://furbelow.sf.net


Added: 
csplugins/trunk/ucsd/pwang/cyprovision/org.eclipse.equinox.p2.ui2/src/org/eclipse/equinox/internal/provisional/p2/ui2/dialogs/CheckBoxTreeCellRenderer.java
===================================================================
--- 
csplugins/trunk/ucsd/pwang/cyprovision/org.eclipse.equinox.p2.ui2/src/org/eclipse/equinox/internal/provisional/p2/ui2/dialogs/CheckBoxTreeCellRenderer.java
 2009-03-16 20:27:27 UTC (rev 16287)
+++ 
csplugins/trunk/ucsd/pwang/cyprovision/org.eclipse.equinox.p2.ui2/src/org/eclipse/equinox/internal/provisional/p2/ui2/dialogs/CheckBoxTreeCellRenderer.java
 2009-03-16 22:30:19 UTC (rev 16288)
@@ -0,0 +1,482 @@
+package org.eclipse.equinox.internal.provisional.p2.ui2.dialogs;
+
+//package furbelow;
+/* Copyright (c) 2006-2007 Timothy Wall, All Rights Reserved
+*
+* 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.
+* <p/>
+* 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.  
+*/
+import java.awt.BasicStroke;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.ComponentOrientation;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import javax.swing.AbstractAction;
+import javax.swing.Icon;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTree;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.TreeCellRenderer;
+import javax.swing.tree.TreePath;
+
+/** Provides checkbox-based selection of tree nodes.  Override the protected
+ * methods to adapt this renderer's behavior to your local tree table flavor.
+ * No change listener notifications are provided.
+ */
+public class CheckBoxTreeCellRenderer implements TreeCellRenderer {
+    
+    public static final int UNCHECKABLE = 0;
+    public static final int FULLCHECKED = 1;
+    public static final int UNCHECKED = 2;
+    public static final int PARTIALCHECKED = 3;
+    
+    private TreeCellRenderer renderer;
+    private JCheckBox checkBox;
+    private Point mouseLocation;
+    private int mouseRow = -1;
+    private int pressedRow = -1;
+    private boolean mouseInCheck;
+    private int state = UNCHECKED;
+    private Set checkedPaths;
+    private JTree tree;
+    private MouseHandler handler;
+
+    /** Create a per-tree instance of the checkbox renderer. */
+    public CheckBoxTreeCellRenderer(JTree tree, TreeCellRenderer original) {
+        this.tree = tree;
+        this.renderer = original;
+        checkedPaths = new HashSet();
+        checkBox = new JCheckBox();
+        checkBox.setOpaque(false);
+        checkBox.setSize(checkBox.getPreferredSize());
+    }
+    
+    protected void installMouseHandler() {
+        if (handler == null) {
+            handler = new MouseHandler();
+            addMouseHandler(handler);
+        }
+    }
+        
+    protected void addMouseHandler(MouseHandler handler) {
+        tree.addMouseListener(handler);
+        tree.addMouseMotionListener(handler);
+    }
+    
+    private void updateMouseLocation(Point newLoc) {
+        if (mouseRow != -1) {
+            repaint(mouseRow);
+        }
+        mouseLocation = newLoc;
+        if (mouseLocation != null) {
+            mouseRow = getRow(newLoc);
+            repaint(mouseRow);
+        }
+        else {
+            mouseRow = -1;
+        }
+        if (mouseRow != -1 && mouseLocation != null) {
+            Point mouseLoc = new Point(mouseLocation);
+            Rectangle r = getRowBounds(mouseRow);
+            if (r != null)
+                mouseLoc.x -= r.x;
+            mouseInCheck = isInCheckBox(mouseLoc);
+        }
+        else {
+            mouseInCheck = false;
+        }
+    }
+
+    protected int getRow(Point p) {
+        return tree.getRowForLocation(p.x, p.y);
+    }
+    
+    protected Rectangle getRowBounds(int row) {
+        return tree.getRowBounds(row);
+    }
+    
+    protected TreePath getPathForRow(int row) {
+        return tree.getPathForRow(row);
+    }
+    
+    protected int getRowForPath(TreePath path) {
+        return tree.getRowForPath(path);
+    }
+    
+    protected void repaint(Rectangle r) {
+        tree.repaint(r);
+    }
+    
+    protected void repaint() {
+        tree.repaint();
+    }
+    
+    private void repaint(int row) {
+        Rectangle r = getRowBounds(row);
+        if (r != null)
+            repaint(r);
+    }
+    
+    public Component getTreeCellRendererComponent(JTree tree, Object value, 
boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+        installMouseHandler();
+        TreePath path = getPathForRow(row);
+        state = UNCHECKABLE; 
+        if (path != null) {
+            if (isChecked(path)) {
+                state = FULLCHECKED;
+            }
+            else if (isPartiallyChecked(path)) {
+                state = PARTIALCHECKED;
+            }
+            else if (isSelectable(path)) {
+                state = UNCHECKED;
+            }
+        }
+        checkBox.setSelected(state == FULLCHECKED);
+        checkBox.getModel().setArmed(mouseRow == row && pressedRow == row && 
mouseInCheck);
+        checkBox.getModel().setPressed(pressedRow == row && mouseInCheck);
+        checkBox.getModel().setRollover(mouseRow == row && mouseInCheck);
+
+        Component c = renderer.getTreeCellRendererComponent(tree, value, 
selected, expanded, leaf, row, hasFocus);
+        checkBox.setForeground(c.getForeground());
+        if (c instanceof JLabel) {
+            JLabel label = (JLabel)c;
+            // Augment the icon to include the checkbox
+            label.setIcon(new CompoundIcon(label.getIcon()));
+        }
+        return c;
+    }
+    
+    private boolean isInCheckBox(Point where) {
+        Insets insets = tree.getInsets();
+        int right = checkBox.getWidth();
+        int left = 0;
+        if (insets != null) {
+            left += insets.left;
+            right += insets.left;
+        }
+        return where.x >= left && where.x < right;
+    }
+
+    public boolean isExplicitlyChecked(TreePath path) {
+        return checkedPaths.contains(path);
+    }
+    
+    /** Returns whether selecting the given path is allowed.  The default
+     * returns true.  You should return false if the given path represents
+     * a placeholder for a node that has not yet loaded, or anything else
+     * that doesn't represent a normal, operable object in the tree.
+     */
+    public boolean isSelectable(TreePath path) {
+        return true;
+    }
+    
+    /** Returns whether the given path is currently checked. */
+    public boolean isChecked(TreePath path) {
+        if (isExplicitlyChecked(path)) {
+            return true;
+        }
+        else {
+            if (path.getParentPath() != null) {
+                return isChecked(path.getParentPath());
+            }
+            else {
+                return false;
+            }
+        }
+    }
+    
+    public boolean isPartiallyChecked(TreePath path) {
+        Object node = path.getLastPathComponent();
+        for (int i = 0; i < tree.getModel().getChildCount(node); i++) {
+            Object child = tree.getModel().getChild(node, i);
+            TreePath childPath = path.pathByAddingChild(child);
+            if (isChecked(childPath) || isPartiallyChecked(childPath)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    private boolean isFullyChecked(TreePath parent) {
+        Object node = parent.getLastPathComponent();
+        for (int i = 0; i < tree.getModel().getChildCount(node); i++) {
+            Object child = tree.getModel().getChild(node, i);
+            TreePath childPath = parent.pathByAddingChild(child);
+            if (!isExplicitlyChecked(childPath)) {
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    public void toggleChecked(int row) {
+        TreePath path = getPathForRow(row);
+        boolean isChecked = isChecked(path);
+        removeDescendants(path);
+        if (!isChecked) {
+            checkedPaths.add(path);
+        }
+        setParent(path);
+        repaint();
+    }
+
+    private void setParent(TreePath path) {
+        TreePath parent = path.getParentPath();
+        if (parent != null) {
+            if (isFullyChecked(parent)) {
+                removeChildren(parent);
+                checkedPaths.add(parent);
+            } else {
+                if (isChecked(parent)) {
+                    checkedPaths.remove(parent);
+                    addChildren(parent);
+                    checkedPaths.remove(path);
+                }
+            }
+            setParent(parent);
+        }
+    }
+    
+    private void addChildren(TreePath parent) {
+        Object node = parent.getLastPathComponent();
+        for (int i = 0; i < tree.getModel().getChildCount(node); i++) {
+            Object child = tree.getModel().getChild(node, i);
+            TreePath path = parent.pathByAddingChild(child);
+            checkedPaths.add(path);
+        }
+    }
+
+    private void removeChildren(TreePath parent) {
+        for (Iterator i = checkedPaths.iterator(); i.hasNext();) {
+            TreePath p = (TreePath) i.next();
+            if (p.getParentPath() != null && parent.equals(p.getParentPath())) 
{
+                i.remove();
+            }
+        }
+    }
+
+    private void removeDescendants(TreePath ancestor) {
+        for (Iterator i = checkedPaths.iterator(); i.hasNext();) {
+            TreePath path = (TreePath) i.next();
+            if (ancestor.isDescendant(path)) {
+                i.remove();
+            }
+        }
+    }
+
+    /** Returns all checked rows. */
+    public int[] getCheckedRows() {
+        TreePath[] paths = getCheckedPaths();
+        int[] rows = new int[checkedPaths.size()];
+        for (int i = 0; i < checkedPaths.size(); i++) {
+            rows[i] = getRowForPath(paths[i]);
+        }
+        Arrays.sort(rows);
+        return rows;
+    }
+    
+    /** Returns all checked paths. */
+    public TreePath[] getCheckedPaths() {
+        return (TreePath[]) checkedPaths.toArray(new 
TreePath[checkedPaths.size()]);
+    }
+    
+    protected class MouseHandler extends MouseAdapter implements 
MouseMotionListener {
+        public void mouseEntered(MouseEvent e) {
+            updateMouseLocation(e.getPoint());
+        }
+        public void mouseExited(MouseEvent e) {
+            updateMouseLocation(null);
+        }
+        public void mouseMoved(MouseEvent e) {
+            updateMouseLocation(e.getPoint());
+        }
+        public void mouseDragged(MouseEvent e) {
+            updateMouseLocation(e.getPoint());
+        }
+        public void mousePressed(MouseEvent e) {
+            pressedRow = e.getModifiersEx() == InputEvent.BUTTON1_DOWN_MASK
+                ? getRow(e.getPoint()) : -1;
+            updateMouseLocation(e.getPoint());
+        }
+        public void mouseReleased(MouseEvent e) {
+            if (pressedRow != -1) {
+                int row = getRow(e.getPoint());
+                if (row == pressedRow) {
+                    Point p = e.getPoint();
+                    Rectangle r = getRowBounds(row);
+                    p.x -= r.x;
+                    if (isInCheckBox(p)) {
+                        toggleChecked(row);
+                    }
+                }
+                pressedRow = -1;
+                updateMouseLocation(e.getPoint());
+            }
+        }
+    }
+    
+    /** Combine a JCheckBox's checkbox with another icon. */
+    private final class CompoundIcon implements Icon {
+        private final Icon icon;
+        private final int w;
+        private final int h;
+
+        private CompoundIcon(Icon icon) {
+            if (icon == null) {
+                icon = new Icon() {
+                    public int getIconHeight() { return 0; }
+                    public int getIconWidth() { return 0; }
+                    public void paintIcon(Component c, Graphics g, int x, int 
y) { }
+                };
+            }
+            this.icon = icon;
+            this.w = icon.getIconWidth();
+            this.h = icon.getIconHeight();
+        }
+
+        public int getIconWidth() {
+            return checkBox.getPreferredSize().width + w;
+        }
+
+        public int getIconHeight() {
+            return Math.max(checkBox.getPreferredSize().height, h);
+        }
+
+        public void paintIcon(Component c, Graphics g, int x, int y) {
+            if (c.getComponentOrientation().isLeftToRight()) {
+                int xoffset = checkBox.getPreferredSize().width;
+                int yoffset = (getIconHeight()-icon.getIconHeight())/2;
+                icon.paintIcon(c, g, x + xoffset, y + yoffset);
+                if (state != UNCHECKABLE) { 
+                    paintCheckBox(g, x, y);
+                }
+            }
+            else {
+                int yoffset = (getIconHeight()-icon.getIconHeight())/2;
+                icon.paintIcon(c, g, x, y + yoffset);
+                if (state != UNCHECKABLE) { 
+                    paintCheckBox(g, x + icon.getIconWidth(), y);
+                }
+            }
+        }
+
+        private void paintCheckBox(Graphics g, int x, int y) {
+            int yoffset;
+            boolean db = checkBox.isDoubleBuffered();
+            checkBox.setDoubleBuffered(false);
+            try {
+                yoffset = 
(getIconHeight()-checkBox.getPreferredSize().height)/2;
+                g = g.create(x, y+yoffset, getIconWidth(), getIconHeight());
+                checkBox.paint(g);
+                if (state == PARTIALCHECKED) {
+                    final int WIDTH = 2;
+                    g.setColor(UIManager.getColor("CheckBox.foreground"));
+                    Graphics2D g2d = (Graphics2D)g;
+                    g2d.setStroke(new BasicStroke(WIDTH, 
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+                    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
RenderingHints.VALUE_ANTIALIAS_ON);
+                    int w = checkBox.getWidth();
+                    int h = checkBox.getHeight();
+                    g.drawLine(w/4+2, h/2-WIDTH/2+1, w/4+w/2-3, h/2-WIDTH/2+1);
+                }
+                g.dispose();
+            }
+            finally {
+                checkBox.setDoubleBuffered(db);
+            }
+        }
+    }
+
+    private static String createText(TreePath[] paths) {
+        if (paths.length == 0) {
+            return "Nothing checked";
+        }
+        String checked = "Checked:\n";
+        for (int i=0;i < paths.length;i++) {
+            checked += paths[i] + "\n";
+        }
+        return checked;
+    }
+    
+    public static void main(String[] args) {
+        try {
+            final String SWITCH = "toggle-componentOrientation";
+            
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+            JFrame frame = new JFrame("Tree with Check Boxes");
+            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+            final JTree tree = new JTree();
+            final CheckBoxTreeCellRenderer r = 
+                new CheckBoxTreeCellRenderer(tree, tree.getCellRenderer()); 
+            tree.setCellRenderer(r);
+            tree.getActionMap().put(SWITCH, new AbstractAction(SWITCH) {
+                public void actionPerformed(ActionEvent e) {
+                    ComponentOrientation o = tree.getComponentOrientation();
+                    if (o.isLeftToRight()) {
+                        o = ComponentOrientation.RIGHT_TO_LEFT;
+                    }
+                    else {
+                        o = ComponentOrientation.LEFT_TO_RIGHT;
+                    }
+                    tree.setComponentOrientation(o);
+                    tree.repaint();
+                }
+            });
+            int mask = 
InputEvent.SHIFT_MASK|Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+            tree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_O, 
mask), SWITCH);
+            
+            final JTextArea text = new 
JTextArea(createText(r.getCheckedPaths()));
+            text.setPreferredSize(new Dimension(200, 100));
+            tree.addMouseListener(new MouseAdapter() {
+                public void mouseReleased(MouseEvent e) {
+                    // Invoke later to ensure all mouse handling is completed
+                    SwingUtilities.invokeLater(new Runnable() { public void 
run() {
+                        text.setText(createText(r.getCheckedPaths()));
+                    }});
+                }
+            });
+            
+            frame.getContentPane().add(new JScrollPane(tree));
+            frame.getContentPane().add(new JScrollPane(text), 
BorderLayout.SOUTH);
+            
+            frame.pack();
+            frame.setSize(300, 350);
+            frame.setVisible(true);
+        }
+        catch(Exception e) {
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+}


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"cytoscape-cvs" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/cytoscape-cvs?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to