KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > languages > studio > TokensBrowserTopComponent


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.studio;
21
22 import java.lang.UnsupportedOperationException JavaDoc;
23 import javax.swing.JTree JavaDoc;
24 import javax.swing.SwingUtilities JavaDoc;
25 import javax.swing.event.TreeSelectionEvent JavaDoc;
26 import javax.swing.event.TreeSelectionListener JavaDoc;
27 import javax.swing.tree.DefaultMutableTreeNode JavaDoc;
28 import javax.swing.tree.DefaultTreeCellRenderer JavaDoc;
29 import javax.swing.tree.TreeNode JavaDoc;
30 import javax.swing.tree.TreePath JavaDoc;
31 import org.netbeans.api.languages.ASTToken;
32 import org.netbeans.api.lexer.Token;
33 import org.netbeans.api.lexer.TokenHierarchy;
34 import org.netbeans.api.lexer.TokenSequence;
35 import org.netbeans.api.lexer.TokenSequence;
36 import org.openide.ErrorManager;
37 import org.openide.cookies.EditorCookie;
38 import org.openide.nodes.Node;
39 import org.openide.util.NbBundle;
40 import org.openide.util.RequestProcessor;
41 import org.openide.windows.TopComponent;
42 import org.openide.windows.WindowManager;
43 import java.util.Enumeration JavaDoc;
44 import javax.swing.event.DocumentEvent JavaDoc;
45 import javax.swing.event.DocumentListener JavaDoc;
46 import javax.swing.text.AbstractDocument JavaDoc;
47 import javax.swing.event.CaretEvent JavaDoc;
48 import javax.swing.event.CaretListener JavaDoc;
49 import java.awt.BorderLayout JavaDoc;
50 import java.awt.Color JavaDoc;
51 import java.awt.Component JavaDoc;
52 import java.awt.event.FocusEvent JavaDoc;
53 import java.awt.event.FocusListener JavaDoc;
54 import java.beans.PropertyChangeEvent JavaDoc;
55 import java.beans.PropertyChangeListener JavaDoc;
56 import java.io.Serializable JavaDoc;
57 import java.lang.ref.WeakReference JavaDoc;
58 import java.util.ConcurrentModificationException JavaDoc;
59 import javax.swing.JEditorPane JavaDoc;
60 import javax.swing.JScrollPane JavaDoc;
61 import javax.swing.tree.DefaultTreeModel JavaDoc;
62
63
64 /**
65  * Top component which displays something.
66  */

67 final class TokensBrowserTopComponent extends TopComponent {
68     
69     private static final String JavaDoc PREFERRED_ID = "TokensBrowserTopComponent";
70     private static final long serialVersionUID = 1L;
71     private static TokensBrowserTopComponent instance;
72     
73     private JTree JavaDoc tree;
74     private Listener JavaDoc listener;
75     private HighlighterSupport highlighting = new HighlighterSupport (Color.yellow);
76     private boolean listen = true;
77     private CaretListener JavaDoc caretListener;
78     private JEditorPane JavaDoc lastPane;
79     private DocumentListener JavaDoc documentListener;
80     private AbstractDocument JavaDoc lastDocument;
81     
82     
83     private TokensBrowserTopComponent () {
84         initComponents ();
85         setLayout (new BorderLayout JavaDoc ());
86         tree = new JTree JavaDoc ();
87         tree.setCellRenderer (new Renderer JavaDoc ());
88         tree.addTreeSelectionListener (new TreeSelectionListener JavaDoc () {
89             public void valueChanged (TreeSelectionEvent JavaDoc e) {
90                 if (!listen) return;
91                 mark ();
92             }
93         });
94         tree.addFocusListener (new FocusListener JavaDoc () {
95             public void focusGained (FocusEvent JavaDoc e) {
96                 mark ();
97             }
98             public void focusLost (FocusEvent JavaDoc e) {
99                 mark ();
100             }
101         });
102         tree.setRootVisible (false);
103         add (new JScrollPane JavaDoc (tree), BorderLayout.CENTER);
104         setName (NbBundle.getMessage (TokensBrowserTopComponent.class, "CTL_TokensBrowserTopComponent"));
105         setToolTipText (NbBundle.getMessage (TokensBrowserTopComponent.class, "HINT_TokensBrowserTopComponent"));
106 // setIcon(Utilities.loadImage(ICON_PATH, true));
107
}
108     
109     /** This method is called from within the constructor to
110      * initialize the form.
111      * WARNING: Do NOT modify this code. The content of this method is
112      * always regenerated by the Form Editor.
113      */

114     // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
115
private void initComponents() {
116
117         org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
118         this.setLayout(layout);
119         layout.setHorizontalGroup(
120             layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
121             .add(0, 400, Short.MAX_VALUE)
122         );
123         layout.setVerticalGroup(
124             layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
125             .add(0, 300, Short.MAX_VALUE)
126         );
127     }// </editor-fold>//GEN-END:initComponents
128

129     
130     // Variables declaration - do not modify//GEN-BEGIN:variables
131
// End of variables declaration//GEN-END:variables
132

133     /**
134      * Gets default instance. Do not use directly: reserved for *.settings files only,
135      * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
136      * To obtain the singleton instance, use {@link findInstance}.
137      */

138     public static synchronized TokensBrowserTopComponent getDefault () {
139         if (instance == null) {
140             instance = new TokensBrowserTopComponent ();
141         }
142         return instance;
143     }
144     
145     /**
146      * Obtain the TokensBrowserTopComponent instance. Never call {@link #getDefault} directly!
147      */

148     public static synchronized TokensBrowserTopComponent findInstance () {
149         TopComponent win = WindowManager.getDefault ().findTopComponent (PREFERRED_ID);
150         if (win == null) {
151             ErrorManager.getDefault ().log (ErrorManager.WARNING, "Cannot find TokensBrowser component. It will not be located properly in the window system.");
152             return getDefault ();
153         }
154         if (win instanceof TokensBrowserTopComponent) {
155             return (TokensBrowserTopComponent)win;
156         }
157         ErrorManager.getDefault ().log (ErrorManager.WARNING, "There seem to be multiple components with the '" + PREFERRED_ID + "' ID. That is a potential source of errors and unexpected behavior.");
158         return getDefault ();
159     }
160     
161     public int getPersistenceType () {
162         return TopComponent.PERSISTENCE_ALWAYS;
163     }
164
165     protected void componentShowing () {
166         refresh ();
167         if (listener == null)
168             listener = new Listener JavaDoc (this);
169     }
170
171     protected void componentHidden () {
172         if (listener != null) {
173             listener.remove ();
174             listener = null;
175         }
176         if (lastPane != null)
177             lastPane.removeCaretListener (caretListener);
178         lastPane = null;
179         if (lastDocument != null)
180             lastDocument.removeDocumentListener (documentListener);
181         lastDocument = null;
182         highlighting.removeHighlight ();
183     }
184     
185     /** replaces this in object stream */
186     public Object JavaDoc writeReplace () {
187         return new ResolvableHelper ();
188     }
189     
190     protected String JavaDoc preferredID () {
191         return PREFERRED_ID;
192     }
193     
194     private void mark () {
195         Node JavaDoc[] ns = TopComponent.getRegistry ().getActivatedNodes ();
196         if (ns.length == 1 && tree.isFocusOwner ()) {
197             EditorCookie editorCookie = (EditorCookie) ns [0].getLookup ().
198                 lookup (EditorCookie.class);
199             if (editorCookie != null) {
200                 THNode t = (THNode) tree.getLastSelectedPathComponent ();
201                 if (t == null) return;
202                 Token token = t.getToken ();
203                 if (token == null) return;
204                 ASTToken stoken = ASTToken.create (
205                     t.getMimeType (),
206                     token.id ().name (),
207                     token.text ().toString (),
208                     t.getOffset ()
209                 );
210                 if (t != null) {
211                     highlighting.highlight (
212                         editorCookie.getDocument (),
213                         stoken
214                     );
215                     return;
216                 }
217             }
218         }
219         highlighting.removeHighlight ();
220     }
221     
222     private JEditorPane JavaDoc getCurrentEditor () {
223         Node JavaDoc[] ns = TopComponent.getRegistry ().getActivatedNodes ();
224         if (ns.length != 1) return null;
225         EditorCookie editorCookie = (EditorCookie) ns [0].getLookup ().
226             lookup (EditorCookie.class);
227         if (editorCookie == null) return null;
228         if (editorCookie.getOpenedPanes () == null) return null;
229         if (editorCookie.getOpenedPanes ().length < 1) return null;
230         return editorCookie.getOpenedPanes () [0];
231     }
232     
233     private AbstractDocument JavaDoc getCurrentDocument () {
234         Node JavaDoc[] ns = TopComponent.getRegistry ().getActivatedNodes ();
235         if (ns.length != 1) return null;
236         EditorCookie editorCookie = (EditorCookie) ns [0].getLookup ().
237             lookup (EditorCookie.class);
238         if (editorCookie == null) return null;
239         if (editorCookie.getOpenedPanes () == null) return null;
240         if (editorCookie.getOpenedPanes ().length < 1) return null;
241         JEditorPane JavaDoc pane = editorCookie.getOpenedPanes () [0];
242         
243         if (caretListener == null)
244             caretListener = new CListener ();
245         if (lastPane != null && lastPane != pane) {
246             lastPane.removeCaretListener (caretListener);
247             lastPane = null;
248         }
249         if (lastPane == null) {
250             pane.addCaretListener (caretListener);
251             lastPane = pane;
252         }
253
254         AbstractDocument JavaDoc doc = (AbstractDocument JavaDoc) editorCookie.getDocument ();
255         if (documentListener == null)
256             documentListener = new CDocumentListener ();
257         if (lastDocument != null && lastDocument != doc) {
258             lastDocument.removeDocumentListener (documentListener);
259             lastDocument = null;
260         }
261         if (lastDocument == null) {
262             doc.addDocumentListener (documentListener);
263             lastDocument = doc;
264         }
265         return doc;
266     }
267     
268     private RequestProcessor.Task task;
269     
270     private void refreshLater () {
271         if (task != null) task.cancel ();
272         task = RequestProcessor.getDefault ().post (
273             new Runnable JavaDoc () {
274                 public void run () {
275                     refresh ();
276                     task = null;
277                 }
278             },
279             1000
280         );
281     }
282     
283     private void refresh () {
284         SwingUtilities.invokeLater(new Runnable JavaDoc() {
285             public void run() {
286                 AbstractDocument JavaDoc doc = getCurrentDocument ();
287                 TokenSequence ts = null;
288                 if (doc != null)
289                     try {
290                         doc.readLock ();
291                         TokenHierarchy tokenHierarchy = TokenHierarchy.get (doc);
292                         if (tokenHierarchy == null) return;
293                         ts = tokenHierarchy.tokenSequence ();
294                     } finally {
295                         doc.readUnlock ();
296                     }
297                 if (ts == null)
298                     tree.setModel (new DefaultTreeModel JavaDoc (new DefaultMutableTreeNode JavaDoc ()));
299                 else
300                     tree.setModel (new DefaultTreeModel JavaDoc (new TSNode (null, ts, null, 0, 0)));
301                 JEditorPane JavaDoc editor = getCurrentEditor ();
302                 if (editor != null) {
303                     int position = getCurrentEditor ().getCaret ().getDot ();
304                     selectPath (position);
305                 }
306             }
307         });
308     }
309     
310     private void selectPath (int offset) {
311         Object JavaDoc root = tree.getModel ().getRoot ();
312         if (!(root instanceof TSNode)) return;
313         listen = false;
314         TSNode n = (TSNode) root;
315         TreePath JavaDoc path = new TreePath JavaDoc (n);
316         path = findPath (path, offset);
317         tree.setSelectionPath (path);
318         tree.scrollPathToVisible (path);
319         listen = true;
320     }
321     
322     private TreePath JavaDoc findPath (TreePath JavaDoc path, int offset) {
323         THNode parent = (THNode) path.getLastPathComponent ();
324         Enumeration JavaDoc en = parent.children ();
325         while (en.hasMoreElements ()) {
326             THNode n = (THNode) en.nextElement ();
327             if (n.getOffset () + n.getToken ().length () > offset) {
328                 if (offset < n.getOffset ())
329                     return path;
330                 if (n.isLeaf ())
331                     return new MPath (path, n);
332                 return findPath (new MPath (path, n), offset);
333             }
334         }
335         return path;
336     }
337     
338     
339     // innerclasses ............................................................
340

341     static interface THNode extends TreeNode JavaDoc {
342         Token getToken ();
343         String JavaDoc getMimeType ();
344         int getOffset ();
345         int getIndex ();
346     }
347     
348     static class MPath extends TreePath JavaDoc {
349         MPath (TreePath JavaDoc path, Object JavaDoc e) {
350             super (path, e);
351         }
352     }
353     
354     static class TSNode implements THNode {
355         
356         private TSNode parent;
357         private TokenSequence ts;
358         private Token token;
359         private int offset;
360         private int index;
361         
362         TSNode (TSNode parent, TokenSequence ts, Token token, int offset, int index) {
363             this.parent = parent;
364             this.ts = ts;
365             this.token = token;
366             this.offset = offset;
367             this.index = index;
368         }
369
370         public TreeNode JavaDoc getChildAt (int index) {
371             ts.moveIndex (index);
372             ts.moveNext ();
373             TokenSequence ts2 = ts.embedded ();
374             if (ts2 != null)
375                 return new TSNode (this, ts2, ts.token (), ts.offset (), ts.index ());
376             return new TNode (this, ts.token (), getMimeType (), index, ts.offset ());
377         }
378
379         public int getChildCount () {
380             return ts.tokenCount ();
381         }
382
383         public TreeNode JavaDoc getParent () {
384             return parent;
385         }
386         
387         public String JavaDoc getMimeType () {
388             return ts.language ().mimeType ();
389         }
390
391         public int getIndex (TreeNode JavaDoc node) {
392             return ((THNode) node).getIndex ();
393         }
394
395         public boolean getAllowsChildren () {
396             return true;
397         }
398
399         public boolean isLeaf () {
400             return false;
401         }
402
403         public Enumeration JavaDoc children () {
404             return new Enumeration JavaDoc() {
405                 private int i = 0;
406                 
407                 public boolean hasMoreElements () {
408                     return i < getChildCount ();
409                 }
410
411                 public Object JavaDoc nextElement() {
412                     return getChildAt (i++);
413                 }
414             };
415         }
416         
417         public Token getToken () {
418             return token;
419         }
420         
421         public int getOffset () {
422             return offset;
423         }
424         
425         public int getIndex () {
426             return index;
427         }
428     }
429     
430     static class TNode implements THNode {
431         
432         private TSNode parent;
433         private Token token;
434         private String JavaDoc mimeType;
435         private int index;
436         private int offset;
437         
438         TNode (TSNode parent, Token token, String JavaDoc mimeType, int index, int offset) {
439             this.parent = parent;
440             this.token = token;
441             this.mimeType = mimeType;
442             this.index = index;
443             this.offset = offset;
444         }
445
446         public TreeNode JavaDoc getChildAt (int index) {
447             throw new UnsupportedOperationException JavaDoc ();
448         }
449
450         public int getChildCount () {
451             throw new UnsupportedOperationException JavaDoc ();
452         }
453
454         public TreeNode JavaDoc getParent() {
455             return parent;
456         }
457
458         public int getIndex (TreeNode JavaDoc node) {
459             throw new UnsupportedOperationException JavaDoc ();
460         }
461
462         public boolean getAllowsChildren () {
463             return false;
464         }
465
466         public boolean isLeaf () {
467             return true;
468         }
469
470         public Enumeration JavaDoc children () {
471             throw new UnsupportedOperationException JavaDoc ();
472         }
473         
474         public Token getToken () {
475             return token;
476         }
477         
478         public String JavaDoc getMimeType () {
479             return mimeType;
480         }
481         
482         public int getOffset () {
483             return offset;
484         }
485         
486         public int getIndex () {
487             return index;
488         }
489     }
490     
491     class CDocumentListener implements DocumentListener JavaDoc {
492         public void insertUpdate (DocumentEvent JavaDoc e) {
493             refreshLater ();
494         }
495
496         public void removeUpdate (DocumentEvent JavaDoc e) {
497             refreshLater ();
498         }
499
500         public void changedUpdate (DocumentEvent JavaDoc e) {
501             refreshLater ();
502         }
503     }
504     
505     class CListener implements CaretListener JavaDoc {
506         public void caretUpdate (CaretEvent JavaDoc e) {
507             int position = e.getDot ();
508             try {
509                 selectPath (position);
510             } catch (ConcurrentModificationException JavaDoc ex) {
511             }
512         }
513     }
514
515     private static class Renderer extends DefaultTreeCellRenderer JavaDoc {
516         
517         private String JavaDoc e (CharSequence JavaDoc t) {
518             StringBuilder JavaDoc sb = new StringBuilder JavaDoc ();
519             int i, k = t.length ();
520             for (i = 0; i < k; i++) {
521                 if (t.charAt (i) == '\t')
522                     sb.append ("\\t");
523                 else
524                 if (t.charAt (i) == '\r')
525                     sb.append ("\\r");
526                 else
527                 if (t.charAt (i) == '\n')
528                     sb.append ("\\n");
529                 else
530                     sb.append (t.charAt (i));
531             }
532             return sb.toString ();
533         }
534         
535         public Component getTreeCellRendererComponent (
536             JTree JavaDoc tree,
537             Object JavaDoc value,
538             boolean sel,
539             boolean expanded,
540             boolean leaf,
541             int row,
542             boolean hasFocus
543         ) {
544             if (!(value instanceof THNode))
545                 return super.getTreeCellRendererComponent (
546                     tree, value, sel, expanded, leaf, row, hasFocus
547                 );
548             THNode node = (THNode) value;
549             Token token = node.getToken ();
550             if (token == null)
551                 return super.getTreeCellRendererComponent (
552                     tree, value, sel, expanded, leaf, row, hasFocus
553                 );
554             StringBuilder JavaDoc sb = new StringBuilder JavaDoc ().
555                 append ('<').
556                 append (node.getOffset ()).
557                 append (",\"").
558                 append (token.id ().name ()).
559                 append (",\"").
560                 append (e (token.text ())).
561                 append ("\">");
562             return super.getTreeCellRendererComponent (
563                 tree, sb.toString (), sel, expanded, leaf, row, hasFocus
564             );
565         }
566     }
567     
568     final static class ResolvableHelper implements Serializable JavaDoc {
569         private static final long serialVersionUID = 1L;
570         public Object JavaDoc readResolve () {
571             return TokensBrowserTopComponent.getDefault ();
572         }
573     }
574     
575     private static class Listener implements PropertyChangeListener JavaDoc {
576         
577         private WeakReference JavaDoc component;
578         
579         
580         Listener (TokensBrowserTopComponent c) {
581             component = new WeakReference JavaDoc (c);
582             TopComponent.getRegistry ().addPropertyChangeListener (this);
583         }
584
585         TokensBrowserTopComponent getComponent () {
586             TokensBrowserTopComponent c = (TokensBrowserTopComponent) component.get ();
587             if (c != null) return c;
588             remove ();
589             return null;
590         }
591         
592         void remove () {
593             TopComponent.getRegistry ().removePropertyChangeListener (this);
594         }
595         
596         public void propertyChange (PropertyChangeEvent JavaDoc evt) {
597             TokensBrowserTopComponent c = getComponent ();
598             if (c == null) return;
599             c.refresh ();
600         }
601     }
602 }
603
Popular Tags