1 21 22 package org.armedbear.j; 23 24 import java.awt.Color ; 25 import java.awt.Component ; 26 import java.awt.Graphics ; 27 import java.awt.Point ; 28 import java.awt.event.InputEvent ; 29 import java.awt.event.KeyEvent ; 30 import java.awt.event.KeyListener ; 31 import java.awt.event.MouseEvent ; 32 import java.awt.event.MouseListener ; 33 import java.util.ArrayList ; 34 import java.util.Collections ; 35 import java.util.Comparator ; 36 import java.util.Enumeration ; 37 import java.util.List ; 38 import javax.swing.Icon ; 39 import javax.swing.JTree ; 40 import javax.swing.SwingUtilities ; 41 import javax.swing.tree.DefaultMutableTreeNode ; 42 import javax.swing.tree.DefaultTreeCellRenderer ; 43 import javax.swing.tree.DefaultTreeModel ; 44 import javax.swing.tree.TreeModel ; 45 import javax.swing.tree.TreePath ; 46 import javax.swing.tree.TreeSelectionModel ; 47 48 public final class JavaTree extends SidebarTree implements Constants, 49 NavigationComponent, KeyListener , MouseListener 50 { 51 private static final String CAPTION_FIELDS = "Fields"; 52 private static final String CAPTION_CONSTRUCTORS = "Constructors"; 53 private static final String CAPTION_METHODS = "Methods"; 54 private static final String CAPTION_NESTED_CLASSES = "Nested Classes"; 55 56 private static final String KEY_ARRANGE_BY_TYPE = 57 "JavaMode.tree.arrangeByType"; 58 private static final String KEY_SORT = "JavaMode.tree.sort"; 59 60 private static boolean arrangeByType = 61 Editor.getSessionProperties().getBooleanProperty(KEY_ARRANGE_BY_TYPE, true); 62 private static boolean sort = 63 Editor.getSessionProperties().getBooleanProperty(KEY_SORT, false); 64 65 private final Editor editor; 66 private final Frame frame; 67 private List tags; 68 private boolean arrangedByType; 69 private boolean sorted; 70 71 public static final void setArrangeByType(boolean b) 72 { 73 if (b != arrangeByType) { 74 arrangeByType = b; 75 Editor.getSessionProperties().setBooleanProperty(KEY_ARRANGE_BY_TYPE, b); 76 } 77 } 78 79 public static final boolean getArrangeByType() 80 { 81 return arrangeByType; 82 } 83 84 public static final void setSort(boolean b) 85 { 86 if (b != sort) { 87 sort = b; 88 Editor.getSessionProperties().setBooleanProperty(KEY_SORT, b); 89 } 90 } 91 92 public static final boolean getSort() 93 { 94 return sort; 95 } 96 97 public JavaTree(Editor editor) 98 { 99 super((TreeModel )null); 100 this.editor = editor; 101 frame = editor.getFrame(); 102 getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 103 setRootVisible(false); 104 setCellRenderer(new TreeCellRenderer ()); 105 setFocusTraversalKeysEnabled(false); 106 addKeyListener(this); 107 addMouseListener(this); 108 setToolTipText(""); 109 } 110 111 public void refresh() 112 { 113 boolean force = (arrangedByType != arrangeByType) || 114 (sorted != sort); 115 refresh(force); 116 } 117 118 public void refresh(boolean force) 119 { 120 final Buffer buffer = editor.getBuffer(); 121 final List bufferTags = buffer.getTags(); 122 if (!force) 123 if (tags != null && tags == bufferTags) 124 return; Runnable r = new Runnable () { 126 public void run() 127 { 128 refreshInternal(buffer, bufferTags); 129 } 130 }; 131 Thread thread = new Thread (r, "JavaTree.refresh()"); 132 thread.setDaemon(true); 133 thread.start(); 134 } 135 136 private void refreshInternal(Buffer buffer, List bufferTags) 137 { 138 if (bufferTags == null) 139 bufferTags = buffer.getTags(true); if (bufferTags != null) { 141 final TreeModel model = 142 getDefaultModel(bufferTags, arrangeByType, sort); 143 final List finalBufferTags = bufferTags; 144 Runnable completionRunnable = new Runnable () { 145 public void run() 146 { 147 setModel(model); 148 arrangedByType = arrangeByType; 149 sorted = sort; 150 tags = finalBufferTags; 151 expandRow(0); 152 updatePosition(); 153 } 154 }; 155 SwingUtilities.invokeLater(completionRunnable); 156 } 157 } 158 159 private static TreeModel getDefaultModel(List bufferTags, 161 boolean arrangeByType, boolean sort) 162 { 163 DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode (); 164 List list; 165 if (sort) 166 list = sort(bufferTags); 167 else 168 list = bufferTags; 169 final int size = list.size(); 170 for (int i = 0; i < size; i++) { 171 JavaTag tag = (JavaTag) list.get(i); 172 JavaClass parent = tag.getParent(); 173 if (parent == null) { 174 addNode(rootNode, tag, arrangeByType); 175 } else { 176 DefaultMutableTreeNode parentNode = 177 findParentNodeForTag(tag, rootNode); 178 addNode(parentNode, tag, arrangeByType); 179 } 180 } 181 return new DefaultTreeModel (rootNode); 182 } 183 184 private static List sort(List list) 186 { 187 List methodsAndFields = new ArrayList (); 188 List allTags = new ArrayList (); 189 for (int i = 0; i < list.size(); i++) { 190 JavaTag t = (JavaTag) list.get(i); 191 switch (t.getType()) { 192 case TAG_METHOD: 193 case TAG_FIELD: 194 methodsAndFields.add(t); 195 break; 196 default: 197 allTags.add(t); 198 break; 199 } 200 } 201 Collections.sort(methodsAndFields, new MethodComparator()); 202 allTags.addAll(methodsAndFields); 203 return allTags; 204 } 205 206 private static class MethodComparator implements Comparator 207 { 208 MethodComparator() {} 209 210 public int compare(Object o1, Object o2) 211 { 212 String s1 = o1.toString(); 213 String s2 = o2.toString(); 214 return s1.compareTo(s2); 215 } 216 } 217 218 private static DefaultMutableTreeNode findParentNodeForTag(JavaTag tag, 219 DefaultMutableTreeNode rootNode) 220 { 221 JavaClass parent = tag.getParent(); 222 if (parent == null) 223 return rootNode; 224 final String parentName = parent.getName(); 225 Enumeration nodes = rootNode.breadthFirstEnumeration(); 226 while (nodes.hasMoreElements()) { 227 DefaultMutableTreeNode node = 228 (DefaultMutableTreeNode ) nodes.nextElement(); 229 Object obj = node.getUserObject(); 230 if (obj instanceof JavaTag) { 231 JavaTag t = (JavaTag) obj; 232 String name = t.getName(); 233 switch (t.getType()) { 234 case TAG_CLASS: 235 if (name.startsWith("class ")) 236 name = name.substring(6); 237 if (name.equals(parentName)) 238 return node; 239 break; 240 case TAG_INTERFACE: 241 if (name.startsWith("interface ")) 242 name = name.substring(10); 243 if (name.equals(parentName)) 244 return node; 245 break; 246 default: 247 break; 248 } 249 } 250 } 251 return rootNode; 252 } 253 254 private static void addNode(DefaultMutableTreeNode parentNode, JavaTag tag, 255 boolean arrangeByType) 256 { 257 if (parentNode instanceof ClassNode) { 258 ((ClassNode)parentNode).addTag(tag); 259 } else { 260 final int type = tag.getType(); 261 if (type == TAG_CLASS || type == TAG_INTERFACE) 262 parentNode.add(new ClassNode(tag, arrangeByType)); 263 } 264 } 265 266 public void updatePosition() 267 { 268 TreeModel model = getModel(); 269 if (model == null) 270 return; 271 DefaultMutableTreeNode root = (DefaultMutableTreeNode ) model.getRoot(); 272 if (root == null) 273 return; 274 if (tags != null) { 275 final Position dot = editor.getDotCopy(); 276 JavaTag tag = findTag(dot); 277 if (tag != null) { 278 DefaultMutableTreeNode node = findNode(root, tag); 279 if (node != null) { 280 DefaultMutableTreeNode selectedNode = null; 281 TreePath oldPath = getSelectionPath(); 282 if (oldPath != null) { 283 selectedNode = 284 (DefaultMutableTreeNode ) oldPath.getLastPathComponent(); 285 } 286 if (node != selectedNode) 287 scrollNodeToCenter(node); 288 return; 289 } 290 } 291 } 292 setSelectionRow(0); 294 scrollRowToVisible(0); 295 if (arrangeByType) 296 expandMethods(); 297 } 298 299 private JavaTag findTag(Position dot) 300 { 301 if (dot == null) 302 return null; 303 final Line dotLine = dot.getLine(); 304 JavaTag tag = null; 305 Line lastTagLine = null; 306 final int size = tags.size(); 307 for (int i = 0; i < size; i++) { 308 final JavaTag t = (JavaTag) tags.get(i); 309 if (t.getPosition().isAfter(dot)) { 310 if (t.getLine() == dotLine && t.getLine() != lastTagLine) 311 tag = t; 312 break; 313 } else { 314 tag = t; 315 lastTagLine = t.getLine(); 316 } 317 } 318 return tag; 319 } 320 321 private DefaultMutableTreeNode findNode(DefaultMutableTreeNode root, 322 JavaTag tag) 323 { 324 Enumeration nodes = root.depthFirstEnumeration(); 325 while (nodes.hasMoreElements()) { 326 DefaultMutableTreeNode node = 327 (DefaultMutableTreeNode ) nodes.nextElement(); 328 if (node.getUserObject() instanceof JavaTag) { 329 JavaTag t = (JavaTag) node.getUserObject(); 330 if (t == tag) 331 return node; 332 } 333 } 334 return null; 335 } 336 337 private void expandMethods() 338 { 339 for (int i = 0; i < getRowCount(); i++) { 340 TreePath path = getPathForRow(i); 341 if (path != null) { 342 DefaultMutableTreeNode node = 343 (DefaultMutableTreeNode ) path.getLastPathComponent(); 344 Object obj = node.getUserObject(); 345 if (obj instanceof String && obj.equals(CAPTION_METHODS)) { 346 expandRow(i); 347 break; 348 } 349 } 350 } 351 } 352 353 public final String getLabelText() 354 { 355 File file = editor.getBuffer().getFile(); 356 return file != null ? file.getName() : null; 357 } 358 359 public String getToolTipText(MouseEvent e) 360 { 361 JavaTag t = getJavaTagAtPoint(e.getPoint()); 362 return t != null ? t.getToolTipText() : null; 363 } 364 365 private JavaTag getJavaTagAtPoint(Point point) 366 { 367 TreePath treePath = getPathForLocation(point.x, point.y); 368 if (treePath != null) { 369 DefaultMutableTreeNode node = 370 (DefaultMutableTreeNode ) treePath.getLastPathComponent(); 371 Object obj = node.getUserObject(); 372 if (obj instanceof JavaTag) 373 return (JavaTag) obj; 374 } 375 return null; 376 } 377 378 public void keyPressed(KeyEvent e) 379 { 380 final int keyCode = e.getKeyCode(); 381 final int modifiers = e.getModifiers(); 382 switch (keyCode) { 383 case KeyEvent.VK_SHIFT: 385 case KeyEvent.VK_CONTROL: 386 case KeyEvent.VK_ALT: 387 case KeyEvent.VK_META: 388 return; 389 case KeyEvent.VK_ENTER: { 390 e.consume(); 391 TreePath path = getSelectionPath(); 392 if (path != null) { 393 DefaultMutableTreeNode node = 394 (DefaultMutableTreeNode ) path.getLastPathComponent(); 395 Object obj = node.getUserObject(); 396 if (obj instanceof JavaTag) 397 ((JavaTag)obj).gotoTag(editor); 398 } 399 editor.setFocusToDisplay(); 400 if (modifiers == KeyEvent.ALT_MASK) 401 editor.toggleSidebar(); 402 return; 403 } 404 case KeyEvent.VK_TAB: 405 e.consume(); 406 if (modifiers == 0) { 407 final Sidebar sidebar = editor.getSidebar(); 408 if (sidebar.getBufferList() != null) { 409 updatePosition(); 410 editor.setFocus(sidebar.getBufferList()); 411 } 412 } 413 return; 414 case KeyEvent.VK_ESCAPE: 415 e.consume(); 416 editor.getSidebar().setBuffer(); 417 updatePosition(); 418 editor.setFocusToDisplay(); 419 return; 420 } 421 editor.getDispatcher().setEnabled(false); 422 } 423 424 public void keyReleased(KeyEvent e) 425 { 426 e.consume(); 427 editor.getDispatcher().setEnabled(true); 428 } 429 430 public void keyTyped(KeyEvent e) 431 { 432 e.consume(); 433 } 434 435 protected void processMouseEvent(MouseEvent e) 436 { 437 if (e.isPopupTrigger()) { 438 JavaTreePopupMenu popup = new JavaTreePopupMenu(this); 439 popup.show(this, e.getX(), e.getY()); 440 } else 441 super.processMouseEvent(e); 442 } 443 444 public void mousePressed(MouseEvent e) {} 445 446 public void mouseReleased(MouseEvent e) {} 447 448 public void mouseClicked(MouseEvent e) 449 { 450 LocationBar.cancelInput(); 451 editor.ensureActive(); 452 final int modifiers = e.getModifiers(); 453 if (modifiers != InputEvent.BUTTON1_MASK && modifiers != InputEvent.BUTTON2_MASK) { 454 e.consume(); 455 editor.setFocusToDisplay(); 456 return; 457 } 458 JavaTag t = getJavaTagAtPoint(e.getPoint()); 459 if (t != null) 460 t.gotoTag(editor); 461 editor.setFocusToDisplay(); 462 } 463 464 public void mouseEntered(MouseEvent e) {} 465 466 public void mouseExited(MouseEvent e) 467 { 468 frame.getCurrentEditor().setFocusToDisplay(); 469 } 470 471 private static class ClassNode extends DefaultMutableTreeNode 472 { 473 final String className; 474 final boolean arrangeByType; 475 476 DefaultMutableTreeNode fields; 477 DefaultMutableTreeNode constructors; 478 DefaultMutableTreeNode methods; 479 DefaultMutableTreeNode nestedClasses; 480 int index; 481 482 ClassNode(JavaTag tag, boolean arrangeByType) 483 { 484 super(tag); 485 String s = tag.getName(); 486 if (s.startsWith("class ")) 487 className = s.substring(6); 488 else 489 className = s; 490 this.arrangeByType = arrangeByType; 491 if (arrangeByType) { 492 fields = new DefaultMutableTreeNode (CAPTION_FIELDS); 493 add(fields); 494 constructors = new DefaultMutableTreeNode (CAPTION_CONSTRUCTORS); 495 add(constructors); 496 methods = new DefaultMutableTreeNode (CAPTION_METHODS); 497 add(methods); 498 } else 499 fields = constructors = methods = nestedClasses = this; 500 } 501 502 void addTag(JavaTag tag) 503 { 504 switch (tag.getType()) { 505 case TAG_CLASS: 506 case TAG_INTERFACE: 507 if (nestedClasses == null) { 508 nestedClasses = 509 new DefaultMutableTreeNode (CAPTION_NESTED_CLASSES); 510 add(nestedClasses); 511 } 512 nestedClasses.add(new ClassNode(tag, arrangeByType)); 513 break; 514 case TAG_EXTENDS: 515 insert(new DefaultMutableTreeNode (tag), 0); 516 ++index; 517 break; 518 case TAG_IMPLEMENTS: 519 insert(new DefaultMutableTreeNode (tag), index++); 520 break; 521 case TAG_FIELD: 522 addField(tag); 523 break; 524 default: 525 if (tag.getMethodName().equals(className)) 526 addConstructor(tag); 527 else 528 addMethod(tag); 529 break; 530 } 531 } 532 533 void addField(JavaTag tag) 534 { 535 fields.add(new DefaultMutableTreeNode (tag)); 536 } 537 538 void addConstructor(JavaTag tag) 539 { 540 constructors.add(new DefaultMutableTreeNode (tag)); 541 } 542 543 void addMethod(JavaTag tag) 544 { 545 methods.add(new DefaultMutableTreeNode (tag)); 546 } 547 } 548 549 private static class TreeCellRenderer extends DefaultTreeCellRenderer 550 { 551 private static Color noFocusSelectionBackground = new Color (208, 208, 208); 552 private static Icon classIcon = Utilities.getIconFromFile("class.png"); 553 private static Icon fieldIcon = Utilities.getIconFromFile("field.png"); 554 private static Icon constructorIcon = Utilities.getIconFromFile("method.png"); 555 private static Icon methodIcon = Utilities.getIconFromFile("method.png"); 556 557 private Color oldBackgroundSelectionColor; 558 559 public TreeCellRenderer() 560 { 561 super(); 562 oldBackgroundSelectionColor = getBackgroundSelectionColor(); 563 } 564 565 public Component getTreeCellRendererComponent(JTree tree, Object value, 566 boolean selected, boolean expanded, boolean leaf, int row, 567 boolean hasFocus) 568 { 569 super.getTreeCellRendererComponent(tree, value, selected, expanded, 570 leaf, row, hasFocus); 571 if (selected) 572 super.setForeground(getTextSelectionColor()); 573 else 574 super.setForeground(getTextNonSelectionColor()); 575 if (Editor.getCurrentFrame().getFocusedComponent() == tree) 576 setBackgroundSelectionColor(oldBackgroundSelectionColor); 577 else 578 setBackgroundSelectionColor(noFocusSelectionBackground); 579 if (value instanceof DefaultMutableTreeNode ) { 580 Object obj = ((DefaultMutableTreeNode )value).getUserObject(); 581 if (obj instanceof JavaTag) { 582 JavaTag t = (JavaTag) obj; 583 setIcon(t.getIcon()); 584 setText(t.getSidebarText()); 585 } else if (obj instanceof String ) { 586 if (obj.equals(CAPTION_FIELDS)) 587 setIcon(fieldIcon); 588 else if (obj.equals(CAPTION_CONSTRUCTORS)) 589 setIcon(constructorIcon); 590 else if (obj.equals(CAPTION_METHODS)) 591 setIcon(methodIcon); 592 else if (obj.equals(CAPTION_NESTED_CLASSES)) 593 setIcon(classIcon); 594 } 595 } 596 return this; 597 } 598 599 public void paintComponent(Graphics g) 600 { 601 Display.setRenderingHints(g); 602 super.paintComponent(g); 603 } 604 } 605 } 606 | Popular Tags |