Annotation of java/classes/org/w3c/tools/widgets/TreeBrowser.java, revision 1.15

1.1       abaird      1: // TreeBrowser.java
1.15    ! ylafon      2: // $Id: TreeBrowser.java,v 1.14 2000/08/16 21:37:57 ylafon Exp $ */
1.7       ylafon      3: // Authors: Jean-Michel.Leon@sophia.inria.fr, 
                      4: //          Yves.Lafon@w3.org : 
                      5: //          - Lines, insert/remove, awt 1.1 version
                      6: //          Thierry.Kormann@sophia.inria.fr
                      7: //          - Insert debug, horizontal scrollbar, javadoc, 
                      8: //            selection graphic customization, scrollbar policy, 
                      9: //            lightweight version.
1.1       abaird     10: 
1.7       ylafon     11: package org.w3c.tools.widgets ;
1.1       abaird     12: 
1.14      ylafon     13: import java.awt.Canvas;
                     14: import java.awt.Color;
                     15: import java.awt.Component;
                     16: import java.awt.Dimension;
                     17: import java.awt.FontMetrics;
                     18: import java.awt.Graphics;
                     19: import java.awt.Image;
                     20: import java.awt.Rectangle;
                     21: import java.awt.Scrollbar;
                     22: 
                     23: import java.awt.event.AdjustmentEvent;
                     24: import java.awt.event.AdjustmentListener;
                     25: import java.awt.event.MouseAdapter;
                     26: import java.awt.event.MouseEvent;
                     27: 
                     28: import java.util.Enumeration;
                     29: import java.util.EventObject;
                     30: import java.util.Stack;
                     31: import java.util.Vector;
1.1       abaird     32: 
                     33: /**
                     34:  * The TreeBrowser class.
                     35:  *
                     36:  * This class is a generic framework to browser any hierachical structure.
                     37:  *
1.7       ylafon     38:  * <p>Genericity is obtained through the use of 'handlers': the TreeBrowser
                     39:  * itself does not perform any action in response to user events, but simply
                     40:  * forward them as <b>notifications</b> to <b>handlers</b>. Each item inserted
                     41:  * may have its own handler, but handlers may also (this is the most common
                     42:  * case) be shared between handlers.
1.1       abaird     43:  *
1.7       ylafon     44:  * <p>Any item added in the Tree is displayed with an icon and a label. When a
1.1       abaird     45:  * handler receive a notification on a node, it may change this node, to modify
                     46:  * or update its appearance.
                     47:  *
                     48:  * @author Jean-Michel.Leon@sophia.inria.fr
1.11      ylafon     49:  * @author Yves.Lafon@w3.org
1.7       ylafon     50:  * @author Thierry.Kormann@sophia.inria.fr 
                     51:  */
1.1       abaird     52: public class TreeBrowser extends Canvas implements AdjustmentListener {
1.3       ylafon     53: 
1.7       ylafon     54:     /** 
                     55:      * Specifies that the horizontal/vertical scrollbars should always be shown
                     56:      * regardless of the respective sizes of the TreeBrowser.  
                     57:      */
                     58:     public static final int SCROLLBARS_ALWAYS   = 0; 
                     59:     /** 
                     60:      * Specifies that horizontal/vertical scrollbars should be shown only when
                     61:      * the size of the nodes exceeds the size of the TreeBrowser in the
                     62:      * horizontal/vertical dimension.  
                     63:      */
                     64:     public static final int SCROLLBARS_ASNEEDED = 1;
                     65:     /** 
                     66:      * This policy that lets just one node selected at the same time. 
                     67:      */
1.9       ylafon     68:     public static final int SINGLE = 0;
1.7       ylafon     69:     /** 
                     70:      * The policy that enables a multiple selection of nodes. 
                     71:      */
                     72:     public static final int MULTIPLE = 1;
1.14      ylafon     73: 
1.1       abaird     74:     static final int HMARGIN = 5;
                     75:     static final int VMARGIN = 5;
                     76:     static final int HGAP = 10;
                     77:     static final int DXLEVEL = HGAP*2;
1.14      ylafon     78: 
1.3       ylafon     79:     /**
                     80:      * The inner mouse listener in charge of all the node expansion
                     81:      * selection and execution
                     82:      */
                     83:     private class BrowserMouseListener extends MouseAdapter {
1.7       ylafon     84:        
1.3       ylafon     85:         private void clickAt(TreeNode node, MouseEvent me) {
                     86:            if(node == null) 
                     87:                return;
                     88:            int x = me.getX() - HMARGIN;
                     89:            if(node.handler == null)
                     90:                return;
                     91:            //  node.handler.notifyExpand(this, node);
                     92:            if((x >= node.level*DXLEVEL) &&
                     93:               (x <= node.level*DXLEVEL + DXLEVEL)) {
                     94:                // click on expand/collapse button
                     95:                if(node.children != TreeNode.NOCHILD) {
1.4       ylafon     96:                    node.handler.notifyCollapse(TreeBrowser.this, node);
1.3       ylafon     97:                }
                     98:                else {
1.4       ylafon     99:                    node.handler.notifyExpand(TreeBrowser.this, node);
1.3       ylafon    100:                }
                    101:            }
                    102:            else if(x > node.level*DXLEVEL + HGAP) {
                    103:                // item selection
1.4       ylafon    104:                node.handler.notifySelect(TreeBrowser.this, node);
1.3       ylafon    105:            }
                    106:        }
1.7       ylafon    107:        
1.3       ylafon    108:        /**
                    109:         * Handles events and send notifications ot handlers.
                    110:         * is sent, depending on the node's current state.<br>
                    111:         * on MOUSE_DOWN on a label, a <b>Select</b> notificaiton is sent.<br>
                    112:         * on DOUBLE_CLICK on a label, an <b>Execute</b> notification is sent.
                    113:         */
                    114:         public void mousePressed(MouseEvent me) {
                    115:            int y = me.getY() - VMARGIN;
                    116:            if(me.getClickCount() == 1) {
1.4       ylafon    117:                clickAt(itemAt(y), me);
1.3       ylafon    118:            }
                    119:        }
1.7       ylafon    120:        
1.3       ylafon    121:         public void mouseClicked(MouseEvent me) {
1.9       ylafon    122:            if(me.getClickCount() > 1) {
1.3       ylafon    123:                int y = me.getY() - VMARGIN;
1.4       ylafon    124:                TreeNode node = itemAt(y);
1.3       ylafon    125:                if((node != null) && (node.handler != null)) {
1.4       ylafon    126:                    node.handler.notifyExecute(TreeBrowser.this, node);
1.3       ylafon    127:                }
                    128:            }
                    129:        }
                    130:     }
1.14      ylafon    131: 
1.1       abaird    132:     private Scrollbar vscroll;
                    133:     private Scrollbar hscroll;
1.7       ylafon    134:     private int maxwidth = 0;
                    135:     private int startx = 0;
                    136:     private Color selectColor = new Color(0, 0, 128);
                    137:     private Color selectFontColor = Color.white;
1.13      bmahe     138:     private int scrollbarDisplayPolicy = SCROLLBARS_ASNEEDED;
1.7       ylafon    139:     private boolean hierarchyChanged = true;
1.14      ylafon    140: 
1.1       abaird    141:     protected Vector items;
                    142:     protected Vector selection;
                    143:     protected int topItem = 0;
                    144:     protected int visibleItemCount = 20;
                    145:     protected int selectionPolicy = SINGLE;
                    146:     protected int fontHeight;
1.14      ylafon    147: 
1.1       abaird    148:    /**
                    149:     * Builds a new browser instance
                    150:     *
                    151:     * @param root the root node for this hierarchy
                    152:     * @param label the label that should be displayed for this item
                    153:     * @param handler the handler for this node
                    154:     * @param icon the icon that must be displayed for this item
                    155:     */    
                    156:     public TreeBrowser(Object root, String label,
                    157:                       NodeHandler handler, Image icon) {
                    158:        this();
                    159:        initialize(root, label, handler, icon);
                    160:     }
                    161: 
                    162:     protected TreeBrowser() {
                    163:        selection = new Vector(1, 1);
                    164:        items = new Vector();
                    165:        topItem = 0;
1.4       ylafon    166:        addMouseListener(new BrowserMouseListener());
1.1       abaird    167:     }
                    168: 
                    169:     protected void initialize(Object item,String label,
                    170:                              NodeHandler handler, Image icon) {
                    171:        items.addElement(new TreeNode(item,label, handler, icon, 0));
                    172:     }
                    173: 
1.7       ylafon    174:     public Dimension getPreferredSize() {
                    175:        return new Dimension(200, 400);
                    176:     }
1.1       abaird    177: 
1.7       ylafon    178:     /**
                    179:      * Sets the color of a selected node to the specified color.
                    180:      * @param color the color used to paint a selected node
                    181:      */
                    182:     public void setSelectionFontColor(Color color) {
                    183:        this.selectFontColor = color;
                    184:     }
1.1       abaird    185: 
1.7       ylafon    186:     /**
                    187:      * Sets the background color of a selected node to the specified color.
                    188:      * @param color the color used to paint the background of a selected node
                    189:      */
                    190:     public void setSelectionBackgroudColor(Color color) {
                    191:        this.selectColor = color;
                    192:     }
1.1       abaird    193: 
1.7       ylafon    194:     /**
                    195:      * Sets the scrollbars display policy to the specified policy. The default
                    196:      * is SCROLLBARS_ALWAYS
                    197:      * @param scrollbarDisplayPolicy SCROLLBARS_NEVER | SCROLLBARS_ASNEEDED |
                    198:      * SCROLLBARS_ALWAYS 
                    199:      */
                    200:     public void setScrollbarDisplayPolicy(int scrollbarDisplayPolicy) {
                    201:        this.scrollbarDisplayPolicy = scrollbarDisplayPolicy;
                    202:        hierarchyChanged = false;
1.1       abaird    203:     }
1.14      ylafon    204: 
1.7       ylafon    205:     /**
                    206:      * repaints the View.
                    207:      */
1.1       abaird    208:     public void paint(Graphics g) {
                    209:        fontHeight = g.getFontMetrics().getHeight();
                    210:        int fontAscent = g.getFontMetrics().getAscent();
                    211:        int itemCount = items.size();
                    212:        
1.7       ylafon    213:        Dimension dim = getSize();
                    214:        int myHeight = dim.height-VMARGIN*2;
                    215:        int myWidth = dim.width-HMARGIN*2;
                    216:        
                    217:        g.clipRect(HMARGIN, VMARGIN, myWidth, myHeight);
1.1       abaird    218:        g.translate(HMARGIN, VMARGIN);
1.7       ylafon    219:        
1.1       abaird    220:        int y = 0;
                    221:        int dx, fatherIndex;
                    222:        int level;
1.7       ylafon    223:        
1.1       abaird    224:        Stack indexStack = new Stack();
                    225:        Graphics bg = g.create();
                    226:        bg.setColor(selectColor);
1.7       ylafon    227:        g.setFont(getFont());
1.1       abaird    228:        visibleItemCount = 0;
                    229:        TreeNode node;
                    230:        level = -1;
1.7       ylafon    231:        
                    232:        int labelwidth;
                    233:        if (hierarchyChanged) {
                    234:            maxwidth = 0;
                    235:        }
                    236:        
1.1       abaird    237:        // we push the indexes of the inner levels to speed up things
                    238:        for(int i = 0; i < topItem; i++) {
1.7       ylafon    239:            node = (TreeNode) items.elementAt(i);
                    240:            // hscroll
                    241:            if (hierarchyChanged) {
                    242:                dx = node.level * DXLEVEL;
                    243:                labelwidth = g.getFontMetrics().stringWidth(node.label);
                    244:                maxwidth = Math.max(maxwidth, dx + DXLEVEL + labelwidth);
                    245:            }
                    246:            
1.1       abaird    247:            if(node.level > level) {
                    248:                indexStack.push(new Integer(i-1));
                    249:                level = node.level;
                    250:            }
                    251:            if(node.level < level) {
                    252:                for(int j=node.level; j<level; j++)
                    253:                    indexStack.pop();
                    254:                level = node.level;
                    255:            }
                    256:        }
1.7       ylafon    257:        
                    258:        int nitems = myHeight/fontHeight;
                    259:        int ditems = itemCount - topItem;
                    260:        if (ditems < nitems) {
                    261:            topItem = Math.max(0, topItem-(nitems-ditems));
                    262:        }
1.8       ylafon    263:        if (myWidth >= maxwidth) {
                    264:           startx = 0;
                    265:        } else if (startx+myWidth > maxwidth) {
                    266:           startx = (maxwidth - myWidth);
                    267:        }
1.14      ylafon    268: 
1.8       ylafon    269:        for(int i = topItem; i < itemCount ; i++) {
                    270:           node = (TreeNode) items.elementAt(i);
                    271:           if(node.level > level) {
                    272:               indexStack.push(new Integer(i-1));
                    273:               level = node.level;
                    274:           }
                    275:           if(node.level < level) {
                    276:               for(int j=node.level; j<level; j++)
                    277:                   indexStack.pop();
                    278:               level = node.level;
                    279:           }
1.7       ylafon    280:            
1.8       ylafon    281:           dx = (node.level * DXLEVEL)-startx;
                    282:           if(y <= myHeight) {
                    283:               if(node.selected) {
1.9       ylafon    284:                   bg.fillRect(dx, y-1,
                    285:                               Math.max(myWidth-1, maxwidth-1), fontHeight);
1.8       ylafon    286:                   g.setColor(selectFontColor);
                    287:                   g.drawImage(node.icon, dx, y, this);
                    288:                   g.drawString(node.label, dx + DXLEVEL, y+fontAscent);
                    289:                   g.setColor(getForeground());
                    290:               } else {
                    291:                   g.setColor(getForeground());
                    292:                   g.drawImage(node.icon, dx, y, this);
                    293:                   g.drawString(node.label, dx + DXLEVEL, y+fontAscent);
                    294:               }
1.7       ylafon    295:                
1.8       ylafon    296:               fatherIndex = ((Integer) indexStack.peek()).intValue();
                    297:               if( fatherIndex != -1) { // draw fancy lines
                    298:                   int fi = fatherIndex - topItem;
                    299:                   g.drawLine(dx - HGAP/2 , y + fontHeight/2,
                    300:                              dx - DXLEVEL + HGAP/2, y + fontHeight/2);
1.7       ylafon    301:                    
1.8       ylafon    302:                   if(node.handler.isDirectory(this, node)) {
                    303:                       g.drawRect(dx - DXLEVEL + HGAP/2 -2,
                    304:                                  y + fontHeight/2 - 2,
                    305:                                  4, 4);
                    306:                   }
                    307:                   g.drawLine(dx-DXLEVEL + HGAP/2, y + fontHeight/2, 
                    308:                              dx-DXLEVEL + HGAP/2, (fi+1)*fontHeight - 1);
                    309:               }
                    310:               visibleItemCount++;
                    311:           } else { // draw the lines for invisible nodes.
                    312:               fatherIndex = ((Integer)indexStack.peek()).intValue();
                    313:               if(fatherIndex != -1) {
                    314:                   int fi = fatherIndex - topItem;
                    315:                   if((fi+1)*fontHeight -1 < myHeight)
                    316:                       g.drawLine(dx - DXLEVEL + HGAP/2, myHeight-1,
                    317:                                  dx - DXLEVEL + HGAP/2, (fi+1)*fontHeight-1);
                    318:               }
                    319:           }
                    320:           // hscroll
                    321:           if (hierarchyChanged) {
                    322:               dx = (node.level * DXLEVEL);
                    323:               labelwidth = g.getFontMetrics().stringWidth(node.label);
                    324:               maxwidth = Math.max(maxwidth, dx + DXLEVEL + labelwidth);
                    325:           }
                    326:           y += fontHeight;
                    327:        }
1.7       ylafon    328:        
1.8       ylafon    329:        // hscroll
                    330:        if (hierarchyChanged) {
                    331:           for (int i=itemCount; i < items.size(); ++i) {
                    332:               node = (TreeNode) items.elementAt(i);
                    333:               dx = (node.level * DXLEVEL);
                    334:               labelwidth = g.getFontMetrics().stringWidth(node.label);
                    335:               maxwidth = Math.max(maxwidth, dx + DXLEVEL + labelwidth);
                    336:           }
                    337:        }
                    338:        hierarchyChanged = false;
                    339:        updateScrollbars();
1.1       abaird    340:     }
1.14      ylafon    341: 
1.12      ylafon    342:     /**
                    343:      * this should be private. having it protected is a present
                    344:      * for dummy VM that doesn't know that an inner class can access
                    345:      * private method of its parent class
                    346:      */
1.14      ylafon    347: 
1.12      ylafon    348:     protected TreeNode itemAt(int y) {
1.1       abaird    349:        for(int i = topItem; ((i < items.size()) && (y >0)); i++) {
                    350:            if(y < fontHeight) {
                    351:                return (TreeNode) items.elementAt(i);
                    352:            }
                    353:            y -= fontHeight;
                    354:        }
                    355:        return null;
                    356:     }
1.14      ylafon    357: 
1.7       ylafon    358:     public void update(Graphics pg) {
                    359:         Rectangle r = pg.getClipBounds();
                    360:         Graphics offgc;
                    361:         Image offscreen = null;
                    362:         Dimension d = getSize();
                    363:        
                    364:         // create the offscreen buffer and associated Graphics
                    365:         offscreen = ImageCache.getImage(this, d.width, d.height);
                    366:         offgc = offscreen.getGraphics();
                    367:         if(r != null) {
                    368:             offgc.clipRect(r.x, r.y, r.width, r.height);
                    369:         }
                    370:         // clear the exposed area
                    371:         offgc.setColor(getBackground());
                    372:         offgc.fillRect(0, 0, d.width, d.height);
                    373:         offgc.setColor(getForeground());
                    374:         // do normal redraw
                    375:         paint(offgc);
                    376:         // transfer offscreen to window
                    377:         pg.drawImage(offscreen, 0, 0, this);
1.1       abaird    378: 
1.7       ylafon    379:     }
1.14      ylafon    380: 
1.7       ylafon    381:     /**
                    382:      * Inserts new node.
                    383:      *
                    384:      * @param parent the parent node.
                    385:      * @item the abstract object this node refers to. may be null.
                    386:      * @handler the node handler, that will receive notifications for this node
                    387:      * @label the label displayed in the list.
                    388:      * @icon the icon displayed in the list.
                    389:      */    
1.1       abaird    390:     public void insert(TreeNode parent, Object item, NodeHandler handler,
                    391:                       String label, Image icon) {
                    392:        boolean done;
                    393:        int j;
                    394:        if(parent == null) throw new IllegalArgumentException("null parent");
                    395:        if((handler == null) && (label == null)) {
                    396:            throw new IllegalArgumentException("non-null item required");
                    397:        }
1.7       ylafon    398:        if(handler == null) {
                    399:            handler = parent.handler;
                    400:        }
1.1       abaird    401:        if(label == null) {
                    402:            label = handler.toString();
                    403:        }
                    404:        if(parent.children == TreeNode.NOCHILD) {
                    405:            parent.children = 1;
1.7       ylafon    406:        } else {
1.1       abaird    407:            parent.children += 1;
                    408:        }
                    409:        done = false;
1.7       ylafon    410:        TreeNode node = null;
                    411: 
                    412:        int i = items.indexOf(parent)+parent.children;
                    413:        for (; (i < items.size() && 
                    414:                ((TreeNode) items.elementAt(i)).level > parent.level); 
                    415:            i++) {}
                    416:        items.insertElementAt(node=new TreeNode(item, label, handler, icon,
                    417:                                                parent.level+1), i);
                    418:        // hscroll
                    419:        hierarchyChanged = true;
1.1       abaird    420:     }
1.14      ylafon    421: 
                    422:    
1.7       ylafon    423:     /**
                    424:      * Removes the specified node.
                    425:      * This simply removes a node, without modifying its children if any. USE
                    426:      * WITH CAUTION.
                    427:      * @param node the node to remove
                    428:      */
1.1       abaird    429:     public void remove(TreeNode node) {
1.7       ylafon    430:        int ind = items.indexOf(node);
                    431:        TreeNode t = null;
                    432: 
                    433:        while (ind>=0) {
                    434:            t = (TreeNode) items.elementAt(ind);
1.10      ylafon    435:            if (t.level >= node.level)
1.7       ylafon    436:                ind--;
                    437:            else {
                    438:                t.children--;
                    439:                break;
                    440:            }
                    441:        }
1.10      ylafon    442:        items.removeElement(node);
1.7       ylafon    443:        
1.1       abaird    444:        if(node.selected) {
                    445:            unselect(node);
                    446:        }
1.7       ylafon    447:        // hscroll
                    448:        hierarchyChanged = true;
1.1       abaird    449:     }
1.14      ylafon    450: 
1.1       abaird    451:     /**
1.7       ylafon    452:      * Removes the specified node and its children.
1.5       ylafon    453:      * NOTE: if two threads are doing adds and removes,
                    454:      * this can lead to IndexOutOfBound exception.
                    455:      * You will probably have to use locks to get rid of that problem
1.7       ylafon    456:      * @param node the node to remove
1.1       abaird    457:      */
                    458:     public void removeBranch(TreeNode node) {
                    459:        int ist, iend;
                    460:        
1.7       ylafon    461:        ist  = items.indexOf(node)+1;
1.1       abaird    462:        iend = items.size()-1;
1.7       ylafon    463:        
1.1       abaird    464:        for(int i = ist; i< iend; i++) {
                    465:            if(((TreeNode)items.elementAt(ist)).level > node.level) {
                    466:                remove((TreeNode)items.elementAt(ist));
                    467:            } else
                    468:                break;
                    469:        }
1.7       ylafon    470:        remove(node);
                    471:        // hscroll
                    472:        hierarchyChanged = true;
1.1       abaird    473:     }
1.14      ylafon    474: 
1.7       ylafon    475:     /**
                    476:      * Contracts the representation of the specified node.
                    477:      * removes all the children nodes of 'item'. It is caller's
                    478:      * responsibility to call repaint() afterwards.
                    479:      * @param item the node to contracts
                    480:      */
1.1       abaird    481:     public synchronized void collapse(TreeNode item) {
                    482:        TreeNode node = (TreeNode)item;
                    483:        if(node.children != TreeNode.NOCHILD) {
                    484:            node.children = TreeNode.NOCHILD;
                    485:            for(int j = items.indexOf(item)+1; j <items.size(); /*nothing*/) {
                    486:                TreeNode child = (TreeNode)items.elementAt(j);
                    487:                if(child.level > node.level) {
                    488:                    items.removeElementAt(j);
                    489:                    if(child.selected) {
                    490:                        unselect(child);
                    491:                    }
                    492:                }
                    493:                else {
1.7       ylafon    494:                    // hscroll
                    495:                    hierarchyChanged = true;
1.1       abaird    496:                    // last children reached, exit
                    497:                    return;
                    498:                }
                    499:            }
                    500:        }
                    501:     }
1.14      ylafon    502: 
1.7       ylafon    503:     /**
                    504:      * Sets the selection policy.
                    505:      * @param policy: SINGLE or MULTIPLE
                    506:      */    
1.1       abaird    507:     public void setSelectionPolicy(int policy) {
                    508:        selectionPolicy = policy;
                    509:     }
1.14      ylafon    510: 
1.7       ylafon    511:     /**
                    512:      * Gets the selection policy.
                    513:      */
1.1       abaird    514:     public int getSelectionPolicy() {
                    515:        return selectionPolicy;
                    516:     }
1.14      ylafon    517: 
1.7       ylafon    518:     /**
                    519:      * Selects the specified node.
                    520:      * Selects the given node. If selectionPolicy is SINGLE any previously
                    521:      * selected node is unselected first.  It is caller's responsibility to
                    522:      * call repaint() 
                    523:      * @param node the node to select
                    524:      */
1.1       abaird    525:     public void select(TreeNode node) {
                    526:        if(node == null) return;
                    527:        if(selectionPolicy == SINGLE) {
                    528:            unselectAll();
                    529:        }
                    530:        selection.addElement(node);
                    531:        node.selected = true;
                    532:     }
1.14      ylafon    533: 
1.7       ylafon    534:     /**
                    535:      * Unselects the specified node.
                    536:      * It is caller's responsibility to call repaint()
                    537:      * @param node the node to unselect
                    538:      */  
1.1       abaird    539:     public void unselect(TreeNode node) {
                    540:        if(node == null) return;
                    541:        selection.removeElement(node);
                    542:        node.selected = false;
                    543:     }
1.14      ylafon    544: 
1.7       ylafon    545:     /**
                    546:      * Unselects all selected items.
                    547:      */    
1.1       abaird    548:     public void unselectAll() {
                    549:        for(Enumeration e = selection.elements(); e.hasMoreElements(); ) {
                    550:            TreeNode node = (TreeNode)e.nextElement();
                    551:            node.selected = false;
                    552:        }
                    553:     }
1.14      ylafon    554: 
1.7       ylafon    555:     /**
                    556:      * Returns an Enumeraiton of selected items.
                    557:      */
1.1       abaird    558:     public Enumeration selection() {
                    559:        return selection.elements();
                    560:     }
1.14      ylafon    561: 
1.1       abaird    562:     private void updateScrollbars() {
1.7       ylafon    563:        int max = items.size()+1;
                    564:         if(items.size() > visibleItemCount) {
                    565:            vscroll.setMaximum(max);
                    566:            vscroll.setVisibleAmount(visibleItemCount);
                    567:            vscroll.setVisible(true);
                    568:         } else {
                    569:            vscroll.setValue(0);
                    570:            vscroll.setMaximum(max);
                    571:            vscroll.setVisibleAmount(max);
                    572:            if (scrollbarDisplayPolicy == SCROLLBARS_ASNEEDED) {
                    573:                vscroll.setVisible(false);
1.1       abaird    574:            }
                    575:        }
1.7       ylafon    576: 
                    577:        int myWidth = getSize().width-HMARGIN*2;
                    578:        hscroll.setMaximum(maxwidth);
                    579:        hscroll.setVisibleAmount(myWidth);
                    580:        if (maxwidth > myWidth) {
                    581:            hscroll.setVisible(true);
                    582:        } else {
                    583:            if (scrollbarDisplayPolicy == SCROLLBARS_ASNEEDED) {
                    584:                hscroll.setVisible(false);
                    585:            }
1.1       abaird    586:        }
                    587:     }
                    588: 
1.7       ylafon    589:     /**
                    590:      * Sets 'a' as vertical Scrollbar.
                    591:      * The Browser becomes an AdjustmentListener of this scrollbar.
                    592:      */
1.1       abaird    593:     public void setVerticalScrollbar(Scrollbar a) {
                    594:        vscroll = a;
                    595:        vscroll.addAdjustmentListener(this);
                    596:        vscroll.setMaximum(visibleItemCount);
                    597:        vscroll.setVisibleAmount(visibleItemCount);
                    598:        vscroll.setBlockIncrement(visibleItemCount);
                    599:     }
1.14      ylafon    600: 
1.7       ylafon    601:     /**
                    602:      * Sets 'a' as horizontal Scrollbar.
                    603:      * The Browser becomes an AdjustmentListener of this scrollbar.
                    604:      */
                    605:     public void setHorizontalScrollbar(Scrollbar a) {
                    606:        hscroll = a;
                    607:        hscroll.addAdjustmentListener(this);
                    608:        int myWidth = getSize().width-HMARGIN*2;
                    609:        hscroll.setMaximum(myWidth);
                    610:        hscroll.setVisibleAmount(myWidth);
                    611:        hscroll.setBlockIncrement(20);
                    612:     }
1.14      ylafon    613: 
1.7       ylafon    614:     /**
                    615:      * Updates graphical appearance in response to a scroll.
                    616:      */    
1.1       abaird    617:     public void adjustmentValueChanged(AdjustmentEvent evt) {
1.7       ylafon    618:        if (evt.getSource() == vscroll) {
                    619:            topItem = evt.getValue();
                    620:        } else {
                    621:            startx = evt.getValue();
                    622:        }
1.1       abaird    623:        repaint();
                    624:     }
1.14      ylafon    625: 
1.7       ylafon    626:     /**
                    627:      * Returns the parent node of the specified node.
                    628:      * If 'child' is a valid node belonging to the Tree and has a parent node,
                    629:      * returns its parent. Returns null otherwise.
                    630:      * @param child the child node you want to get its parent
                    631:      */
1.1       abaird    632:     public TreeNode getParent(TreeNode child) {
                    633:        int n = items.indexOf(child);
                    634:        for(int i = n-1; i >= 0; i--) {
                    635:            TreeNode node = (TreeNode)(items.elementAt(i));
                    636:            if(node.level < child.level) {
                    637:                return node;
                    638:            }
                    639:        }
                    640:        return null;
                    641:     }
1.14      ylafon    642: 
1.7       ylafon    643:     /**
                    644:      * Gets the node associated to the specified object, or null if any.
                    645:      * @param obj the object related to a node
                    646:      */
                    647:     public TreeNode getNode(Object obj) {
1.1       abaird    648:        int imax = items.size();
                    649:        for(int i=0; i < imax; i++) {
1.7       ylafon    650:            if(obj.equals(((TreeNode)(items.elementAt(i))).getItem())) 
1.1       abaird    651:                return (TreeNode)(items.elementAt(i));
                    652:        }
                    653:        return null;
                    654:     }
                    655: }
1.14      ylafon    656: 
1.7       ylafon    657: 

Webmaster