1 /*
   2  * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  * This source code is provided to illustrate the usage of a given feature
  28  * or technique and has been deliberately simplified. Additional steps
  29  * required for a production-quality application, such as security checks,
  30  * input validation and proper error handling, might not be present in
  31  * this sample code.
  32  */
  33 
  34 
  35 package com.sun.tools.example.debug.gui;
  36 
  37 import java.util.*;
  38 
  39 import javax.swing.*;
  40 import javax.swing.tree.*;
  41 import java.awt.*;
  42 import java.awt.event.*;
  43 
  44 import com.sun.jdi.*;
  45 import com.sun.tools.example.debug.event.*;
  46 import com.sun.tools.example.debug.bdi.*;
  47 
  48 public class ClassTreeTool extends JPanel {
  49 
  50     private static final long serialVersionUID = 526178912591739259L;
  51 
  52     private Environment env;
  53 
  54     private ExecutionManager runtime;
  55     private SourceManager sourceManager;
  56     private ClassManager classManager;
  57 
  58     private JTree tree;
  59     private DefaultTreeModel treeModel;
  60     private ClassTreeNode root;
  61 //    private SearchPath sourcePath;
  62 
  63     private CommandInterpreter interpreter;
  64 
  65     private static String HEADING = "CLASSES";
  66 
  67     public ClassTreeTool(Environment env) {
  68 
  69         super(new BorderLayout());
  70 
  71         this.env = env;
  72         this.runtime = env.getExecutionManager();
  73         this.sourceManager = env.getSourceManager();
  74 
  75         this.interpreter = new CommandInterpreter(env);
  76 
  77         root = createClassTree(HEADING);
  78         treeModel = new DefaultTreeModel(root);
  79 
  80         // Create a tree that allows one selection at a time.
  81 
  82         tree = new JTree(treeModel);
  83         tree.setSelectionModel(new SingleLeafTreeSelectionModel());
  84 
  85         /******
  86         // Listen for when the selection changes.
  87         tree.addTreeSelectionListener(new TreeSelectionListener() {
  88             public void valueChanged(TreeSelectionEvent e) {
  89                 ClassTreeNode node = (ClassTreeNode)
  90                     (e.getPath().getLastPathComponent());
  91                 if (node != null) {
  92                     interpreter.executeCommand("view " + node.getReferenceTypeName());
  93                 }
  94             }
  95         });
  96         ******/
  97 
  98         MouseListener ml = new MouseAdapter() {
  99             @Override
 100             public void mouseClicked(MouseEvent e) {
 101                 int selRow = tree.getRowForLocation(e.getX(), e.getY());
 102                 TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
 103                 if(selRow != -1) {
 104                     if(e.getClickCount() == 1) {
 105                         ClassTreeNode node =
 106                             (ClassTreeNode)selPath.getLastPathComponent();
 107                         // If user clicks on leaf, select it, and issue 'view' command.
 108                         if (node.isLeaf()) {
 109                             tree.setSelectionPath(selPath);
 110                             interpreter.executeCommand("view " + node.getReferenceTypeName());
 111                         }
 112                     }
 113                 }
 114             }
 115         };
 116         tree.addMouseListener(ml);
 117 
 118         JScrollPane treeView = new JScrollPane(tree);
 119         add(treeView);
 120 
 121         // Create listener.
 122         ClassTreeToolListener listener = new ClassTreeToolListener();
 123         runtime.addJDIListener(listener);
 124         runtime.addSessionListener(listener);
 125 
 126         //### remove listeners on exit!
 127     }
 128 
 129     private class ClassTreeToolListener extends JDIAdapter
 130                        implements JDIListener, SessionListener {
 131 
 132         // SessionListener
 133 
 134         @Override
 135         public void sessionStart(EventObject e) {
 136             // Get system classes and any others loaded before attaching.
 137             try {
 138                 for (ReferenceType type : runtime.allClasses()) {
 139                     root.addClass(type);
 140                 }
 141             } catch (VMDisconnectedException ee) {
 142                 // VM terminated unexpectedly.
 143             } catch (NoSessionException ee) {
 144                 // Ignore.  Should not happen.
 145             }
 146         }
 147 
 148         @Override
 149         public void sessionInterrupt(EventObject e) {}
 150         @Override
 151         public void sessionContinue(EventObject e) {}
 152 
 153         // JDIListener
 154 
 155         @Override
 156         public void classPrepare(ClassPrepareEventSet e) {
 157             root.addClass(e.getReferenceType());
 158         }
 159 
 160         @Override
 161         public void classUnload(ClassUnloadEventSet e) {
 162             root.removeClass(e.getClassName());
 163         }
 164 
 165         @Override
 166         public void vmDisconnect(VMDisconnectEventSet e) {
 167             // Clear contents of this view.
 168             root = createClassTree(HEADING);
 169             treeModel = new DefaultTreeModel(root);
 170             tree.setModel(treeModel);
 171         }
 172     }
 173 
 174     ClassTreeNode createClassTree(String label) {
 175         return new ClassTreeNode(label, null);
 176     }
 177 
 178     class ClassTreeNode extends DefaultMutableTreeNode {
 179 
 180         private String name;
 181         private ReferenceType refTy;  // null for package
 182 
 183         ClassTreeNode(String name, ReferenceType refTy) {
 184             this.name = name;
 185             this.refTy = refTy;
 186         }
 187 
 188         @Override
 189         public String toString() {
 190             return name;
 191         }
 192 
 193         public ReferenceType getReferenceType() {
 194             return refTy;
 195         }
 196 
 197         public String getReferenceTypeName() {
 198             return refTy.name();
 199         }
 200 
 201         private boolean isPackage() {
 202             return (refTy == null);
 203         }
 204 
 205         @Override
 206         public boolean isLeaf() {
 207             return !isPackage();
 208         }
 209 
 210         public void addClass(ReferenceType refTy) {
 211             addClass(refTy.name(), refTy);
 212         }
 213 
 214         private void addClass(String className, ReferenceType refTy) {
 215             if (className.equals("")) {
 216                 return;
 217             }
 218             int pos = className.indexOf('.');
 219             if (pos < 0) {
 220                 insertNode(className, refTy);
 221             } else {
 222                 String head = className.substring(0, pos);
 223                 String tail = className.substring(pos + 1);
 224                 ClassTreeNode child = insertNode(head, null);
 225                 child.addClass(tail, refTy);
 226             }
 227         }
 228 
 229         private ClassTreeNode insertNode(String name, ReferenceType refTy) {
 230             for (int i = 0; i < getChildCount(); i++) {
 231                 ClassTreeNode child = (ClassTreeNode)getChildAt(i);
 232                 int cmp = name.compareTo(child.toString());
 233                 if (cmp == 0) {
 234                     // like-named node already exists
 235                     return child;
 236                 } else if (cmp < 0) {
 237                     // insert new node before the child
 238                     ClassTreeNode newChild = new ClassTreeNode(name, refTy);
 239                     treeModel.insertNodeInto(newChild, this, i);
 240                     return newChild;
 241                 }
 242             }
 243             // insert new node after last child
 244             ClassTreeNode newChild = new ClassTreeNode(name, refTy);
 245             treeModel.insertNodeInto(newChild, this, getChildCount());
 246             return newChild;
 247         }
 248 
 249         public void removeClass(String className) {
 250             if (className.equals("")) {
 251                 return;
 252             }
 253             int pos = className.indexOf('.');
 254             if (pos < 0) {
 255                 ClassTreeNode child = findNode(className);
 256                 if (!isPackage()) {
 257                     treeModel.removeNodeFromParent(child);
 258                 }
 259             } else {
 260                 String head = className.substring(0, pos);
 261                 String tail = className.substring(pos + 1);
 262                 ClassTreeNode child = findNode(head);
 263                 child.removeClass(tail);
 264                 if (isPackage() && child.getChildCount() < 1) {
 265                     // Prune non-leaf nodes with no children.
 266                     treeModel.removeNodeFromParent(child);
 267                 }
 268             }
 269         }
 270 
 271         private ClassTreeNode findNode(String name) {
 272             for (int i = 0; i < getChildCount(); i++) {
 273                 ClassTreeNode child = (ClassTreeNode)getChildAt(i);
 274                 int cmp = name.compareTo(child.toString());
 275                 if (cmp == 0) {
 276                     return child;
 277                 } else if (cmp > 0) {
 278                     // not found, since children are sorted
 279                     return null;
 280                 }
 281             }
 282             return null;
 283         }
 284 
 285     }
 286 
 287 }