KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > languages > features > LanguagesNavigator


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.languages.features;
21
22 import org.netbeans.api.languages.*;
23 import org.netbeans.api.languages.ASTPath;
24 import org.netbeans.api.languages.ParserManager.State;
25 import org.netbeans.modules.languages.Feature;
26 import org.netbeans.modules.languages.Feature;
27 import org.netbeans.spi.navigator.NavigatorPanel;
28 import org.netbeans.api.languages.ASTToken;
29 import org.netbeans.modules.editor.NbEditorDocument;
30 import org.netbeans.modules.languages.Language;
31 import org.netbeans.modules.languages.LanguagesManagerImpl;
32 import org.netbeans.modules.languages.ParserManagerImpl;
33 import org.openide.ErrorManager;
34 import org.openide.cookies.EditorCookie;
35 import org.openide.cookies.LineCookie;
36 import org.openide.nodes.Node;
37 import org.openide.text.Line;
38 import org.openide.text.NbDocument;
39 import org.openide.util.Lookup;
40 import org.openide.util.Utilities;
41 import org.openide.loaders.DataObject;
42 import org.openide.windows.TopComponent;
43 import java.awt.event.FocusEvent JavaDoc;
44 import java.awt.event.FocusListener JavaDoc;
45 import java.beans.PropertyChangeEvent JavaDoc;
46 import java.beans.PropertyChangeListener JavaDoc;
47 import javax.swing.event.CaretEvent JavaDoc;
48 import javax.swing.event.CaretListener JavaDoc;
49 import javax.swing.event.TreeModelListener JavaDoc;
50 import javax.swing.event.TreeSelectionEvent JavaDoc;
51 import javax.swing.event.TreeSelectionListener JavaDoc;
52 import javax.swing.tree.DefaultMutableTreeNode JavaDoc;
53 import javax.swing.tree.DefaultTreeCellRenderer JavaDoc;
54 import javax.swing.tree.DefaultTreeModel JavaDoc;
55 import javax.swing.tree.TreeModel JavaDoc;
56 import javax.swing.*;
57 import javax.swing.text.BadLocationException JavaDoc;
58 import java.awt.*;
59 import java.awt.event.MouseEvent JavaDoc;
60 import java.awt.event.MouseListener JavaDoc;
61 import java.io.IOException JavaDoc;
62 import java.util.*;
63 import java.util.List JavaDoc;
64 import javax.swing.text.AttributeSet JavaDoc;
65 import javax.swing.text.Document JavaDoc;
66 import javax.swing.text.SimpleAttributeSet JavaDoc;
67 import javax.swing.text.StyleConstants JavaDoc;
68 import javax.swing.tree.TreePath JavaDoc;
69
70
71 /**
72  *
73  * @author Jan Jancura
74  */

75 public class LanguagesNavigator implements NavigatorPanel {
76
77     /** holds UI of this panel */
78     private JComponent panelUI;
79     private JTree tree;
80
81     
82     /** Creates a new instance of LanguagesNavigator */
83     public LanguagesNavigator () {
84     }
85
86     public String JavaDoc getDisplayHint () {
87         return "This is Navigator";
88     }
89
90     public String JavaDoc getDisplayName () {
91         return "Navigator";
92     }
93
94     public JComponent getComponent () {
95         if (panelUI == null) {
96             tree = new JTree () {
97                 public String JavaDoc getToolTipText (MouseEvent JavaDoc ev) {
98                     TreePath JavaDoc selPath = tree.getPathForLocation
99                         (ev.getX (), ev.getY ());
100                     if (selPath == null) return null;
101                     Object JavaDoc selObj = selPath.getLastPathComponent ();
102                     if (selObj == null || !(selObj instanceof NavigatorNode))
103                         return null;
104                     NavigatorNode node = (NavigatorNode)selObj;
105                     return node.tooltip;
106                 }
107             };
108             ToolTipManager.sharedInstance ().registerComponent (tree);
109             tree.setRootVisible (false);
110             tree.setShowsRootHandles (true);
111             tree.addMouseListener (new Listener JavaDoc ());
112             tree.addTreeSelectionListener (new TreeSelectionListener JavaDoc () {
113                 public void valueChanged (TreeSelectionEvent JavaDoc e) {
114                     selectionChanged ();
115                 }
116             });
117             tree.addFocusListener (new FocusListener JavaDoc () {
118                 public void focusGained (FocusEvent JavaDoc e) {
119                     selectionChanged ();
120                 }
121                 public void focusLost (FocusEvent JavaDoc e) {
122                     selectionChanged ();
123                 }
124             });
125             panelUI = new JScrollPane (tree);
126         }
127         return panelUI;
128     }
129
130     private PropertyChangeListener JavaDoc topComponentListener;
131     
132     public void panelActivated (Lookup context) {
133         if (topComponentListener == null) {
134             topComponentListener = new PropertyChangeListener JavaDoc () {
135                 public void propertyChange (PropertyChangeEvent JavaDoc evt) {
136                     if (TopComponent.Registry.PROP_ACTIVATED_NODES.equals
137                             (evt.getPropertyName ())
138                     )
139                         refresh ();
140                 }
141             };
142             TopComponent.getRegistry ().addPropertyChangeListener (topComponentListener);
143         }
144         refresh ();
145     }
146     
147     private NbEditorDocument lastDocument = null;
148     private JEditorPane lastEditor = null;
149     private DocumentListener parserListener = null;
150     
151     private void refresh () {
152         SwingUtilities.invokeLater(new Runnable JavaDoc() {
153             public void run() {
154                 // lookup context and listen to result to get notified about context changes
155
Node[] nodes = TopComponent.getRegistry ().getActivatedNodes ();
156                 if (nodes == null) return;
157                 if (nodes.length != 1) return;
158                 DataObject dob = (DataObject) nodes [0].
159                     getLookup ().lookup (DataObject.class);
160                 if (dob == null) return;
161                 EditorCookie ec = (EditorCookie) dob.getCookie (EditorCookie.class);
162                 if (ec == null) return;
163                 LineCookie lc = (LineCookie) dob.getCookie (LineCookie.class);
164                 try {
165                     NbEditorDocument document = (NbEditorDocument) ec.openDocument ();
166                     ASTNode ast = null;
167                     try {
168                         ast = ParserManagerImpl.get (document).getAST ();
169                     } catch (ParseException ex) {
170                         ast = ex.getASTNode ();
171                     }
172                     if (parserListener == null)
173                         parserListener = new DocumentListener ();
174                     if (lastEditor != null)
175                         lastEditor.removeCaretListener (parserListener);
176                     if (ec.getOpenedPanes () != null &&
177                         ec.getOpenedPanes ().length > 0
178                     ) {
179                         lastEditor = ec.getOpenedPanes () [0];
180                         lastEditor.addCaretListener (parserListener);
181                     } else
182                         lastEditor = null;
183                     if (lastDocument != document) {
184                         if (lastDocument != null)
185                             ParserManagerImpl.get (lastDocument).removeListener (parserListener);
186                         if (document != null)
187                             ParserManagerImpl.get (document).addListener (parserListener);
188                         lastDocument = document;
189                     }
190                     List JavaDoc data = new ArrayList ();
191                     getComponent ();
192                     if (ast != null) {
193                         Model JavaDoc model = new Model JavaDoc ();
194                         model.setContext (ast, lc.getLineSet (), document);
195                         tree.setModel (model);
196                     } else {
197                         DefaultMutableTreeNode JavaDoc root = new DefaultMutableTreeNode JavaDoc ();
198                         State state = ParserManagerImpl.get (document).getState ();
199                         if (state == State.PARSING) {
200                             root.add (new DefaultMutableTreeNode JavaDoc ("Parsing ..."));
201                         } else
202                         if (state != State.NOT_PARSED) {
203                             root.add (new DefaultMutableTreeNode JavaDoc ("?!?!"));
204                         }
205                         tree.setModel (new DefaultTreeModel JavaDoc (root));
206                     }
207                     tree.setCellRenderer (new Renderer JavaDoc ());
208
209                     while (tree.getRowCount () < 50) {
210                         int c = tree.getRowCount ();
211                         int i, k = tree.getRowCount ();
212                         for (i = 0; i < k; i++)
213                             tree.expandRow (i);
214                         if (tree.getRowCount () == c) break;
215                     }
216                 } catch (IOException JavaDoc ex) {
217                     ErrorManager.getDefault ().notify (ex);
218                 }
219             }
220         });
221     }
222
223     public void panelDeactivated() {
224         TopComponent.getRegistry ().removePropertyChangeListener (topComponentListener);
225         topComponentListener = null;
226     }
227     
228     public Lookup getLookup () {
229         // go with default activated Node strategy
230
return null;
231     }
232     
233     
234     // other methods ...........................................................
235

236     private static NavigatorNode createNavigatorNode (
237         ASTItem item,
238         List JavaDoc<ASTItem> path,
239         Line.Set lineSet,
240         NbEditorDocument doc
241     ) {
242         ASTPath path2 = ASTPath.create (path);
243         Feature navigator = null;
244         try {
245             Language language = ((LanguagesManagerImpl) LanguagesManager.getDefault ()).
246                 getLanguage (item.getMimeType ());
247             navigator = language.getFeature (Language.NAVIGATOR, path2);
248         } catch (ParseException ex) {
249             return null;
250         }
251         if (navigator == null) return null;
252         Line line = lineSet.getCurrent (
253             NbDocument.findLineNumber (doc, item.getOffset ())
254         );
255         int column = NbDocument.findLineColumn (doc, item.getOffset ());
256         int start = item.getOffset ();
257         int end = item.getEndOffset ();
258         Context context = SyntaxContext.create (doc, path2);
259         String JavaDoc displayName = (String JavaDoc) navigator.getValue ("display_name", context);
260         if (displayName == null)
261             try {
262                 displayName = doc.getText (
263                     start,
264                     end - start
265                 );
266             } catch (BadLocationException JavaDoc ex) {
267             }
268         String JavaDoc tooltip = (String JavaDoc) navigator.getValue ("tooltip", context);
269         String JavaDoc icon = (String JavaDoc) navigator.getValue ("icon", context);
270         if (icon == null)
271             icon = "/org/netbeans/modules/languages/resources/node.gif";
272         boolean isLeaf = navigator.getBoolean ("tooltip", context, false);
273         return new NavigatorNode (
274             item,
275             path,
276             line, column,
277             displayName, tooltip, icon,
278             isLeaf
279         );
280     }
281     
282     private static Map icons = new HashMap ();
283     
284     private static Icon getCIcon (String JavaDoc resourceName) {
285         if (!icons.containsKey (resourceName)) {
286             Image image = Utilities.loadImage (resourceName);
287             if (image == null)
288                 image = Utilities.loadImage (
289                     "/org/netbeans/modules/languages/resources/node.gif"
290                 );
291             icons.put (
292                 resourceName,
293                 new ImageIcon (image)
294             );
295         }
296         return (Icon) icons.get (resourceName);
297     }
298     
299     private void markSelected (int position) {
300         if (!(tree.getModel () instanceof Model JavaDoc)) return;
301         Model JavaDoc model = (Model JavaDoc) tree.getModel ();
302         ASTPath astPath = model.root.findPath (position);
303         if (astPath == null) return;
304         List JavaDoc nodePath = new ArrayList ();
305         NavigatorNode node = (NavigatorNode) model.astToNode.get (model.root);
306         Iterator it = astPath.listIterator ();
307         while (it.hasNext ()) {
308             Object JavaDoc o = it.next ();
309             NavigatorNode nn = (NavigatorNode) model.astToNode.get (o);
310             if (nn == null) continue;
311             nodePath.add (nn);
312             node = nn;
313         }
314         if (nodePath.isEmpty ()) return;
315         TreePath JavaDoc treePath = new TreePath JavaDoc (nodePath.toArray ());
316         tree.setSelectionPath (treePath);
317         tree.scrollPathToVisible (treePath);
318     }
319
320     // highlight selected node in editor ...
321

322     private Document highlightedDocument = null;
323     private Object JavaDoc highlighted = null;
324     private JEditorPane highlightedEditor = null;
325
326     private void selectionChanged () {
327         removeHighlight ();
328         if (!tree.hasFocus ()) return;
329         TreePath JavaDoc selPath = tree.getSelectionPath ();
330         if (selPath == null) return;
331         Object JavaDoc selObj = selPath.getLastPathComponent ();
332         if (selObj == null || !(selObj instanceof NavigatorNode))
333             return;
334         NavigatorNode node = (NavigatorNode)selObj;
335         if (node.line == null) return;
336         node.line.show (Line.SHOW_SHOW, node.column);
337         //S ystem.out.println ("highlight " + lastDocument + " : " + lastEditor);
338
highlighted = node.item;
339         Highlighting.getHighlighting (highlightedDocument = lastDocument).
340             highlight (node.item, getHighlightAS ());
341         DataObject dataObject = (DataObject) node.line.getLookup ().
342             lookup (DataObject.class);
343         EditorCookie ec = (EditorCookie) dataObject.getCookie
344             (EditorCookie.class);
345         highlightedEditor = ec.getOpenedPanes () [0];
346         highlightedEditor.repaint ();
347     }
348     
349     private void removeHighlight () {
350         if (highlighted == null) return;
351         if (highlighted instanceof ASTToken)
352             Highlighting.getHighlighting (highlightedDocument).removeHighlight
353                 ((ASTToken) highlighted);
354         else
355             Highlighting.getHighlighting (highlightedDocument).removeHighlight
356                 ((ASTNode) highlighted);
357         highlightedEditor.repaint ();
358         highlighted = null;
359         highlightedDocument = null;
360         highlightedEditor = null;
361     }
362     
363     private static AttributeSet JavaDoc highlightAS = null;
364     
365     private static AttributeSet JavaDoc getHighlightAS () {
366         if (highlightAS == null) {
367             SimpleAttributeSet JavaDoc as = new SimpleAttributeSet JavaDoc ();
368             as.addAttribute (StyleConstants.Background, Color.yellow); //new Color (230, 230, 230));
369
highlightAS = as;
370         }
371         return highlightAS;
372     }
373     
374     
375     // innerclasses ............................................................
376

377     private static class Model implements TreeModel JavaDoc {
378         
379         private NbEditorDocument doc;
380         private ASTNode root;
381         private Language language;
382         private Line.Set lineSet;
383         
384         private WeakHashMap nodeToNodes = new WeakHashMap ();
385         private WeakHashMap astToNode = new WeakHashMap ();
386         private NavigatorComparator navigatorComparator;
387         
388         
389         public Object JavaDoc getRoot () {
390             if (astToNode.get (root) == null) {
391                 List JavaDoc<ASTItem> path = new ArrayList<ASTItem> ();
392                 path.add (root);
393                 NavigatorNode navigatorNode = new NavigatorNode (
394                     root,
395                     path,
396                     null, 0,
397                     "root", null,
398                     "/org/netbeans/modules/languages/resources/node.gif",
399                     false
400                 );
401                 astToNode.put (root, navigatorNode);
402             }
403             return (NavigatorNode) astToNode.get (root);
404         }
405
406         public Object JavaDoc getChild (Object JavaDoc parent, int index) {
407             return getNavigatorNodes ((NavigatorNode) parent).get (index);
408         }
409
410         public int getChildCount (Object JavaDoc parent) {
411             return getNavigatorNodes ((NavigatorNode) parent).size ();
412         }
413
414         public boolean isLeaf (Object JavaDoc node) {
415             return getNavigatorNodes ((NavigatorNode) node).isEmpty ();
416         }
417
418         public void valueForPathChanged (TreePath JavaDoc path, Object JavaDoc newValue) {
419         }
420
421         public int getIndexOfChild (Object JavaDoc parent, Object JavaDoc child) {
422             return getNavigatorNodes ((NavigatorNode) parent).indexOf (child);
423         }
424
425         public void addTreeModelListener (TreeModelListener JavaDoc l) {
426         }
427
428         public void removeTreeModelListener (TreeModelListener JavaDoc l) {
429         }
430
431         
432         // other methods .......................................................
433

434         void setContext (
435             ASTNode root,
436             Line.Set lineSet,
437             NbEditorDocument doc
438         ) {
439             this.root = root;
440             this.lineSet = lineSet;
441             this.doc = doc;
442         }
443     
444         private List JavaDoc getNavigatorNodes (NavigatorNode n) {
445             List JavaDoc nodes = (List JavaDoc) nodeToNodes.get (n);
446             if (nodes == null) {
447                 if (n.isLeaf)
448                     nodes = Collections.emptyList ();
449                 else {
450                     nodes = getNavigatorNodes (n.item, n.path, new ArrayList ());
451                     try {
452                         Language language = ((LanguagesManagerImpl) LanguagesManager.getDefault ()).getLanguage
453                             (n.item.getMimeType ());
454                         Feature properties = language.getFeature ("PROPERTIES");
455                         if (properties != null &&
456                             properties.getBoolean ("navigator-sort", false)
457                         ) {
458                             if (navigatorComparator == null)
459                                 navigatorComparator = new NavigatorComparator ();
460                             Collections.sort (nodes, navigatorComparator);
461                         }
462                     } catch (ParseException ex) {
463                     }
464                 }
465                 nodeToNodes.put (n, nodes);
466             }
467             return nodes;
468         }
469         
470         private NavigatorNode getNavigatorNode (ASTItem item, List JavaDoc<ASTItem> path) {
471             if (astToNode.get (item) == null) {
472                 NavigatorNode navigatorNode = createNavigatorNode (
473                     item,
474                     path,
475                     lineSet,
476                     doc
477                 );
478                 astToNode.put (item, navigatorNode);
479             }
480             return (NavigatorNode) astToNode.get (item);
481         }
482     
483         private List JavaDoc getNavigatorNodes (ASTItem item, List JavaDoc<ASTItem> path, List JavaDoc nodes) {
484             Iterator<ASTItem> it = item.getChildren ().iterator ();
485             while (it.hasNext ()) {
486                 ASTItem item2 = it.next ();
487                 path.add (item2);
488                 NavigatorNode navigatorNode = getNavigatorNode (item2, path);
489                 if (navigatorNode != null)
490                     nodes.add (navigatorNode);
491                 else
492                     getNavigatorNodes (item2, path, nodes);
493                 path.remove (path.size () - 1);
494             }
495             return nodes;
496         }
497     }
498     
499     static class Renderer extends DefaultTreeCellRenderer JavaDoc {
500
501         public Component getTreeCellRendererComponent (
502             JTree tree, Object JavaDoc value,
503             boolean sel,
504             boolean expanded,
505             boolean leaf, int row,
506             boolean hasFocus
507         ) {
508             JLabel l = (JLabel) super.getTreeCellRendererComponent (
509                 tree, value, sel, expanded, leaf, row, hasFocus
510             );
511
512             if (value instanceof DefaultMutableTreeNode JavaDoc) {
513                 l.setIcon (null);
514                 l.setText ((String JavaDoc) ((DefaultMutableTreeNode JavaDoc) value).getUserObject ());
515                 return l;
516             }
517             NavigatorNode node = (NavigatorNode) value;
518             l.setIcon (getCIcon (node.icon));
519             l.setText (node.displayName);
520             return l;
521         }
522     }
523     
524     
525     static class NavigatorNode {
526
527         Line line;
528         int column;
529         String JavaDoc displayName;
530         String JavaDoc tooltip;
531         String JavaDoc icon;
532         ASTItem item;
533         List JavaDoc<ASTItem> path;
534         boolean isLeaf;
535
536         /** Creates a new instance of NavigatorNode */
537         NavigatorNode (
538             ASTItem item,
539             List JavaDoc<ASTItem> path,
540             Line line,
541             int column,
542             String JavaDoc displayName,
543             String JavaDoc tooltip,
544             String JavaDoc icon,
545             boolean isLeaf
546         ) {
547             this.item = item;
548             this.path = path;
549             this.line = line;
550             this.column = column;
551             this.displayName = displayName;
552             this.tooltip = tooltip;
553             this.icon = icon;
554             this.isLeaf = isLeaf;
555         }
556     }
557     
558     static class NavigatorComparator implements Comparator {
559         public int compare (Object JavaDoc o1, Object JavaDoc o2) {
560             return ((NavigatorNode) o1).displayName.compareToIgnoreCase (
561                 ((NavigatorNode) o2).displayName
562             );
563         }
564     }
565     
566     class Listener implements MouseListener JavaDoc {
567         
568         public void mouseClicked (MouseEvent JavaDoc ev) {
569             if (ev.getClickCount () != 2) return;
570             TreePath JavaDoc selPath = tree.getPathForLocation
571                 (ev.getX (), ev.getY ());
572             if (selPath == null) return;
573             Object JavaDoc selObj = selPath.getLastPathComponent ();
574             if (selObj == null || !(selObj instanceof NavigatorNode))
575                 return;
576             NavigatorNode node = (NavigatorNode)selObj;
577             node.line.show (Line.SHOW_GOTO, node.column);
578         }
579         
580         public void mouseEntered (MouseEvent JavaDoc e) {
581         }
582         public void mouseExited (MouseEvent JavaDoc e) {
583         }
584         public void mousePressed (MouseEvent JavaDoc e) {
585         }
586         public void mouseReleased (MouseEvent JavaDoc e) {
587         }
588     }
589     
590     class DocumentListener implements CaretListener JavaDoc, ParserManagerListener {
591         public void parsed (State state, ASTNode ast) {
592             if (state == State.PARSING) return;
593             refresh ();
594         }
595
596         public void caretUpdate (CaretEvent JavaDoc e) {
597             markSelected (e.getDot ());
598         }
599     }
600 }
601
Popular Tags