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.io.*; 38 import java.util.*; 39 40 import javax.swing.*; 41 import javax.swing.tree.*; 42 import java.awt.*; 43 import java.awt.event.*; 44 45 import com.sun.tools.example.debug.bdi.*; 46 47 public class SourceTreeTool extends JPanel { 48 49 private static final long serialVersionUID = 3336680912107956419L; 50 51 private Environment env; 52 53 private ExecutionManager runtime; 54 private SourceManager sourceManager; 55 private ClassManager classManager; 56 57 private JTree tree; 58 private SourceTreeNode root; 59 private SearchPath sourcePath; 60 private CommandInterpreter interpreter; 61 62 private static String HEADING = "SOURCES"; 63 64 public SourceTreeTool(Environment env) { 65 66 super(new BorderLayout()); 67 68 this.env = env; 69 this.runtime = env.getExecutionManager(); 70 this.sourceManager = env.getSourceManager(); 71 72 this.interpreter = new CommandInterpreter(env); 73 74 sourcePath = sourceManager.getSourcePath(); 75 root = createDirectoryTree(HEADING); 76 77 // Create a tree that allows one selection at a time. 78 tree = new JTree(new DefaultTreeModel(root)); 79 tree.setSelectionModel(new SingleLeafTreeSelectionModel()); 80 81 /****** 82 // Listen for when the selection changes. 83 tree.addTreeSelectionListener(new TreeSelectionListener() { 84 public void valueChanged(TreeSelectionEvent e) { 85 SourceTreeNode node = (SourceTreeNode) 86 (e.getPath().getLastPathComponent()); 87 interpreter.executeCommand("view " + node.getRelativePath()); 88 } 89 }); 90 ******/ 91 92 MouseListener ml = new MouseAdapter() { 93 @Override 94 public void mouseClicked(MouseEvent e) { 95 int selRow = tree.getRowForLocation(e.getX(), e.getY()); 96 TreePath selPath = tree.getPathForLocation(e.getX(), e.getY()); 97 if(selRow != -1) { 98 if(e.getClickCount() == 1) { 99 SourceTreeNode node = 100 (SourceTreeNode)selPath.getLastPathComponent(); 101 // If user clicks on leaf, select it, and issue 'view' command. 102 if (node.isLeaf()) { 103 tree.setSelectionPath(selPath); 104 interpreter.executeCommand("view " + node.getRelativePath()); 105 } 106 } 107 } 108 } 109 }; 110 tree.addMouseListener(ml); 111 112 JScrollPane treeView = new JScrollPane(tree); 113 add(treeView); 114 115 // Create listener for source path changes. 116 117 SourceTreeToolListener listener = new SourceTreeToolListener(); 118 sourceManager.addSourceListener(listener); 119 120 //### remove listeners on exit! 121 } 122 123 private class SourceTreeToolListener implements SourceListener { 124 125 @Override 126 public void sourcepathChanged(SourcepathChangedEvent e) { 127 sourcePath = sourceManager.getSourcePath(); 128 root = createDirectoryTree(HEADING); 129 tree.setModel(new DefaultTreeModel(root)); 130 } 131 132 } 133 134 private static class SourceOrDirectoryFilter implements FilenameFilter { 135 @Override 136 public boolean accept(File dir, String name) { 137 return (name.endsWith(".java") || 138 new File(dir, name).isDirectory()); 139 } 140 } 141 142 private static FilenameFilter filter = new SourceOrDirectoryFilter(); 143 144 SourceTreeNode createDirectoryTree(String label) { 145 try { 146 return new SourceTreeNode(label, null, "", true); 147 } catch (SecurityException e) { 148 env.failure("Cannot access source file or directory"); 149 return null; 150 } 151 } 152 153 154 class SourceTreeNode implements TreeNode { 155 156 private String name; 157 private boolean isDirectory; 158 private SourceTreeNode parent; 159 private SourceTreeNode[] children; 160 private String relativePath; 161 private boolean isExpanded; 162 163 private SourceTreeNode(String label, 164 SourceTreeNode parent, 165 String relativePath, 166 boolean isDirectory) { 167 this.name = label; 168 this.relativePath = relativePath; 169 this.parent = parent; 170 this.isDirectory = isDirectory; 171 } 172 173 @Override 174 public String toString() { 175 return name; 176 } 177 178 public String getRelativePath() { 179 return relativePath; 180 } 181 182 private void expandIfNeeded() { 183 try { 184 if (!isExpanded && isDirectory) { 185 String[] files = sourcePath.children(relativePath, filter); 186 children = new SourceTreeNode[files.length]; 187 for (int i = 0; i < files.length; i++) { 188 String childName = 189 (relativePath.equals("")) 190 ? files[i] 191 : relativePath + File.separator + files[i]; 192 File file = sourcePath.resolve(childName); 193 boolean isDir = (file != null && file.isDirectory()); 194 children[i] = 195 new SourceTreeNode(files[i], this, childName, isDir); 196 } 197 } 198 isExpanded = true; 199 } catch (SecurityException e) { 200 children = null; 201 env.failure("Cannot access source file or directory"); 202 } 203 } 204 205 // -- interface TreeNode -- 206 207 /* 208 * Returns the child <code>TreeNode</code> at index 209 * <code>childIndex</code>. 210 */ 211 @Override 212 public TreeNode getChildAt(int childIndex) { 213 expandIfNeeded(); 214 return children[childIndex]; 215 } 216 217 /** 218 * Returns the number of children <code>TreeNode</code>s the receiver 219 * contains. 220 */ 221 @Override 222 public int getChildCount() { 223 expandIfNeeded(); 224 return children.length; 225 } 226 227 /** 228 * Returns the parent <code>TreeNode</code> of the receiver. 229 */ 230 @Override 231 public TreeNode getParent() { 232 return parent; 233 } 234 235 /** 236 * Returns the index of <code>node</code> in the receivers children. 237 * If the receiver does not contain <code>node</code>, -1 will be 238 * returned. 239 */ 240 @Override 241 public int getIndex(TreeNode node) { 242 expandIfNeeded(); 243 for (int i = 0; i < children.length; i++) { 244 if (children[i] == node) { 245 return i; 246 } 247 } 248 return -1; 249 } 250 251 /** 252 * Returns true if the receiver allows children. 253 */ 254 @Override 255 public boolean getAllowsChildren() { 256 return isDirectory; 257 } 258 259 /** 260 * Returns true if the receiver is a leaf. 261 */ 262 @Override 263 public boolean isLeaf() { 264 expandIfNeeded(); 265 return !isDirectory; 266 } 267 268 /** 269 * Returns the children of the receiver as an Enumeration. 270 */ 271 @Override 272 public Enumeration children() { 273 expandIfNeeded(); 274 return new Enumeration() { 275 int i = 0; 276 @Override 277 public boolean hasMoreElements() { 278 return (i < children.length); 279 } 280 @Override 281 public Object nextElement() throws NoSuchElementException { 282 if (i >= children.length) { 283 throw new NoSuchElementException(); 284 } 285 return children[i++]; 286 } 287 }; 288 } 289 290 } 291 292 }