KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > JavaTree


1 /*
2  * JavaTree.java
3  *
4  * Copyright (C) 2002-2003 Peter Graves
5  * $Id: JavaTree.java,v 1.5 2003/11/30 00:05:15 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.j;
23
24 import java.awt.Color JavaDoc;
25 import java.awt.Component JavaDoc;
26 import java.awt.Graphics JavaDoc;
27 import java.awt.Point JavaDoc;
28 import java.awt.event.InputEvent JavaDoc;
29 import java.awt.event.KeyEvent JavaDoc;
30 import java.awt.event.KeyListener JavaDoc;
31 import java.awt.event.MouseEvent JavaDoc;
32 import java.awt.event.MouseListener JavaDoc;
33 import java.util.ArrayList JavaDoc;
34 import java.util.Collections JavaDoc;
35 import java.util.Comparator JavaDoc;
36 import java.util.Enumeration JavaDoc;
37 import java.util.List JavaDoc;
38 import javax.swing.Icon JavaDoc;
39 import javax.swing.JTree JavaDoc;
40 import javax.swing.SwingUtilities JavaDoc;
41 import javax.swing.tree.DefaultMutableTreeNode JavaDoc;
42 import javax.swing.tree.DefaultTreeCellRenderer JavaDoc;
43 import javax.swing.tree.DefaultTreeModel JavaDoc;
44 import javax.swing.tree.TreeModel JavaDoc;
45 import javax.swing.tree.TreePath JavaDoc;
46 import javax.swing.tree.TreeSelectionModel JavaDoc;
47
48 public final class JavaTree extends SidebarTree implements Constants,
49     NavigationComponent, KeyListener JavaDoc, MouseListener JavaDoc
50 {
51     private static final String JavaDoc CAPTION_FIELDS = "Fields";
52     private static final String JavaDoc CAPTION_CONSTRUCTORS = "Constructors";
53     private static final String JavaDoc CAPTION_METHODS = "Methods";
54     private static final String JavaDoc CAPTION_NESTED_CLASSES = "Nested Classes";
55
56     private static final String JavaDoc KEY_ARRANGE_BY_TYPE =
57         "JavaMode.tree.arrangeByType";
58     private static final String JavaDoc 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 JavaDoc 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 JavaDoc)null);
100         this.editor = editor;
101         frame = editor.getFrame();
102         getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
103         setRootVisible(false);
104         setCellRenderer(new TreeCellRenderer JavaDoc());
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 JavaDoc bufferTags = buffer.getTags();
122         if (!force)
123             if (tags != null && tags == bufferTags)
124                 return; // Nothing to do.
125
Runnable JavaDoc r = new Runnable JavaDoc() {
126             public void run()
127             {
128                 refreshInternal(buffer, bufferTags);
129             }
130         };
131         Thread JavaDoc thread = new Thread JavaDoc(r, "JavaTree.refresh()");
132         thread.setDaemon(true);
133         thread.start();
134     }
135
136     private void refreshInternal(Buffer buffer, List JavaDoc bufferTags)
137     {
138         if (bufferTags == null)
139             bufferTags = buffer.getTags(true); // Runs tagger synchronously.
140
if (bufferTags != null) {
141             final TreeModel JavaDoc model =
142                 getDefaultModel(bufferTags, arrangeByType, sort);
143             final List JavaDoc finalBufferTags = bufferTags;
144             Runnable JavaDoc completionRunnable = new Runnable JavaDoc() {
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     // Never returns null!
160
private static TreeModel JavaDoc getDefaultModel(List JavaDoc bufferTags,
161         boolean arrangeByType, boolean sort)
162     {
163         DefaultMutableTreeNode JavaDoc rootNode = new DefaultMutableTreeNode JavaDoc();
164         List JavaDoc 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 JavaDoc parentNode =
177                     findParentNodeForTag(tag, rootNode);
178                 addNode(parentNode, tag, arrangeByType);
179             }
180         }
181         return new DefaultTreeModel JavaDoc(rootNode);
182     }
183
184     // Doesn't modify passed-in list.
185
private static List JavaDoc sort(List JavaDoc list)
186     {
187         List JavaDoc methodsAndFields = new ArrayList JavaDoc();
188         List JavaDoc allTags = new ArrayList JavaDoc();
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 JavaDoc
207     {
208         MethodComparator() {}
209
210         public int compare(Object JavaDoc o1, Object JavaDoc o2)
211         {
212             String JavaDoc s1 = o1.toString();
213             String JavaDoc s2 = o2.toString();
214             return s1.compareTo(s2);
215         }
216     }
217
218     private static DefaultMutableTreeNode JavaDoc findParentNodeForTag(JavaTag tag,
219         DefaultMutableTreeNode JavaDoc rootNode)
220     {
221         JavaClass parent = tag.getParent();
222         if (parent == null)
223             return rootNode;
224         final String JavaDoc parentName = parent.getName();
225         Enumeration JavaDoc nodes = rootNode.breadthFirstEnumeration();
226         while (nodes.hasMoreElements()) {
227             DefaultMutableTreeNode JavaDoc node =
228                 (DefaultMutableTreeNode JavaDoc) nodes.nextElement();
229             Object JavaDoc obj = node.getUserObject();
230             if (obj instanceof JavaTag) {
231                 JavaTag t = (JavaTag) obj;
232                 String JavaDoc 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 JavaDoc 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 JavaDoc model = getModel();
269         if (model == null)
270             return;
271         DefaultMutableTreeNode JavaDoc root = (DefaultMutableTreeNode JavaDoc) 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 JavaDoc node = findNode(root, tag);
279                 if (node != null) {
280                     DefaultMutableTreeNode JavaDoc selectedNode = null;
281                     TreePath JavaDoc oldPath = getSelectionPath();
282                     if (oldPath != null) {
283                         selectedNode =
284                             (DefaultMutableTreeNode JavaDoc) oldPath.getLastPathComponent();
285                     }
286                     if (node != selectedNode)
287                         scrollNodeToCenter(node);
288                     return;
289                 }
290             }
291         }
292         // Otherwise...
293
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 JavaDoc findNode(DefaultMutableTreeNode JavaDoc root,
322         JavaTag tag)
323     {
324         Enumeration JavaDoc nodes = root.depthFirstEnumeration();
325         while (nodes.hasMoreElements()) {
326             DefaultMutableTreeNode JavaDoc node =
327                 (DefaultMutableTreeNode JavaDoc) 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 JavaDoc path = getPathForRow(i);
341             if (path != null) {
342                 DefaultMutableTreeNode JavaDoc node =
343                     (DefaultMutableTreeNode JavaDoc) path.getLastPathComponent();
344                 Object JavaDoc obj = node.getUserObject();
345                 if (obj instanceof String JavaDoc && obj.equals(CAPTION_METHODS)) {
346                     expandRow(i);
347                     break;
348                 }
349             }
350         }
351     }
352
353     public final String JavaDoc getLabelText()
354     {
355         File file = editor.getBuffer().getFile();
356         return file != null ? file.getName() : null;
357     }
358
359     public String JavaDoc getToolTipText(MouseEvent JavaDoc e)
360     {
361         JavaTag t = getJavaTagAtPoint(e.getPoint());
362         return t != null ? t.getToolTipText() : null;
363     }
364
365     private JavaTag getJavaTagAtPoint(Point JavaDoc point)
366     {
367         TreePath JavaDoc treePath = getPathForLocation(point.x, point.y);
368         if (treePath != null) {
369             DefaultMutableTreeNode JavaDoc node =
370                 (DefaultMutableTreeNode JavaDoc) treePath.getLastPathComponent();
371             Object JavaDoc obj = node.getUserObject();
372             if (obj instanceof JavaTag)
373                 return (JavaTag) obj;
374         }
375         return null;
376     }
377
378     public void keyPressed(KeyEvent JavaDoc e)
379     {
380         final int keyCode = e.getKeyCode();
381         final int modifiers = e.getModifiers();
382         switch (keyCode) {
383             // Ignore modifier keystrokes.
384
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 JavaDoc path = getSelectionPath();
392                 if (path != null) {
393                     DefaultMutableTreeNode JavaDoc node =
394                         (DefaultMutableTreeNode JavaDoc) path.getLastPathComponent();
395                     Object JavaDoc 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 JavaDoc e)
425     {
426         e.consume();
427         editor.getDispatcher().setEnabled(true);
428     }
429
430     public void keyTyped(KeyEvent JavaDoc e)
431     {
432         e.consume();
433     }
434
435     protected void processMouseEvent(MouseEvent JavaDoc 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 JavaDoc e) {}
445
446     public void mouseReleased(MouseEvent JavaDoc e) {}
447
448     public void mouseClicked(MouseEvent JavaDoc 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 JavaDoc e) {}
465
466     public void mouseExited(MouseEvent JavaDoc e)
467     {
468         frame.getCurrentEditor().setFocusToDisplay();
469     }
470
471     private static class ClassNode extends DefaultMutableTreeNode JavaDoc
472     {
473         final String JavaDoc className;
474         final boolean arrangeByType;
475
476         DefaultMutableTreeNode JavaDoc fields;
477         DefaultMutableTreeNode JavaDoc constructors;
478         DefaultMutableTreeNode JavaDoc methods;
479         DefaultMutableTreeNode JavaDoc nestedClasses;
480         int index;
481
482         ClassNode(JavaTag tag, boolean arrangeByType)
483         {
484             super(tag);
485             String JavaDoc 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 JavaDoc(CAPTION_FIELDS);
493                 add(fields);
494                 constructors = new DefaultMutableTreeNode JavaDoc(CAPTION_CONSTRUCTORS);
495                 add(constructors);
496                 methods = new DefaultMutableTreeNode JavaDoc(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 JavaDoc(CAPTION_NESTED_CLASSES);
510                         add(nestedClasses);
511                     }
512                     nestedClasses.add(new ClassNode(tag, arrangeByType));
513                     break;
514                 case TAG_EXTENDS:
515                     insert(new DefaultMutableTreeNode JavaDoc(tag), 0);
516                     ++index;
517                     break;
518                 case TAG_IMPLEMENTS:
519                     insert(new DefaultMutableTreeNode JavaDoc(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 JavaDoc(tag));
536         }
537
538         void addConstructor(JavaTag tag)
539         {
540             constructors.add(new DefaultMutableTreeNode JavaDoc(tag));
541         }
542
543         void addMethod(JavaTag tag)
544         {
545             methods.add(new DefaultMutableTreeNode JavaDoc(tag));
546         }
547     }
548
549     private static class TreeCellRenderer extends DefaultTreeCellRenderer JavaDoc
550     {
551         private static Color JavaDoc noFocusSelectionBackground = new Color JavaDoc(208, 208, 208);
552         private static Icon JavaDoc classIcon = Utilities.getIconFromFile("class.png");
553         private static Icon JavaDoc fieldIcon = Utilities.getIconFromFile("field.png");
554         private static Icon JavaDoc constructorIcon = Utilities.getIconFromFile("method.png");
555         private static Icon JavaDoc methodIcon = Utilities.getIconFromFile("method.png");
556
557         private Color JavaDoc oldBackgroundSelectionColor;
558
559         public TreeCellRenderer()
560         {
561             super();
562             oldBackgroundSelectionColor = getBackgroundSelectionColor();
563         }
564
565         public Component JavaDoc getTreeCellRendererComponent(JTree JavaDoc tree, Object JavaDoc 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 JavaDoc) {
580                 Object JavaDoc obj = ((DefaultMutableTreeNode JavaDoc)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 JavaDoc) {
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 JavaDoc g)
600         {
601             Display.setRenderingHints(g);
602             super.paintComponent(g);
603         }
604     }
605 }
606
Popular Tags