KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > gsf > browser > AstViewer


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 package org.netbeans.modules.gsf.browser;
20
21 import java.awt.*;
22 import java.io.IOException JavaDoc;
23 import java.io.Serializable JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Enumeration JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Vector JavaDoc;
28 import javax.swing.*;
29 import javax.swing.event.CaretEvent JavaDoc;
30 import javax.swing.event.CaretListener JavaDoc;
31 import javax.swing.event.TreeSelectionEvent JavaDoc;
32 import javax.swing.event.TreeSelectionListener JavaDoc;
33 import javax.swing.text.BadLocationException JavaDoc;
34 import javax.swing.text.Document JavaDoc;
35 import javax.swing.tree.DefaultTreeCellRenderer JavaDoc;
36 import javax.swing.tree.DefaultTreeModel JavaDoc;
37 import javax.swing.tree.TreeNode JavaDoc;
38 import javax.swing.tree.TreePath JavaDoc;
39 import org.netbeans.api.gsf.Error;
40 import org.netbeans.api.gsf.ParseEvent;
41 import org.netbeans.api.gsf.ParseListener;
42 import org.netbeans.api.gsf.Parser;
43 import org.netbeans.api.gsf.ParserFile;
44 import org.netbeans.api.gsf.ParserResult;
45 import org.netbeans.api.gsf.SourceFileReader;
46 import org.netbeans.editor.ext.ExtSyntaxSupport;
47 import org.netbeans.modules.editor.NbEditorDocument;
48 import org.netbeans.modules.gsf.Language;
49 import org.netbeans.modules.gsf.LanguageRegistry;
50 import org.netbeans.spi.gsf.DefaultParserFile;
51 import org.openide.ErrorManager;
52 import org.openide.cookies.EditorCookie;
53 import org.openide.filesystems.FileObject;
54 import org.openide.loaders.DataObject;
55 import org.openide.loaders.DataObjectNotFoundException;
56 import org.openide.nodes.Node;
57 import org.openide.util.NbBundle;
58 import org.openide.windows.TopComponent;
59 import org.openide.windows.TopComponent;
60 import org.openide.windows.WindowManager;
61
62
63 /**
64  * This class is based on ASTBrowserTopComponent in the Schliemann prototype by Jan Jancura
65  *
66  * @author Jan Jancura
67  * @author Tor Norbye
68  */

69 public class AstViewer extends TopComponent {
70     private static final long serialVersionUID = 1L;
71     private static AstViewer instance;
72
73     /** path to the icon used by the component and its open action */
74     // static final String ICON_PATH = "SET/PATH/TO/ICON/HERE";
75
private static final String JavaDoc PREFERRED_ID = "AstViewer";
76     private JTree tree;
77
78     // private Listener listener;
79
private boolean listen = true;
80     private CaretListener JavaDoc caretListener;
81     private JEditorPane lastPane;
82     private ExtSyntaxSupport syntax;
83
84     // private static class Listener implements PropertyChangeListener {
85
// private WeakReference component;
86
//
87
// Listener(AstViewer c) {
88
// component = new WeakReference(c);
89
// TopComponent.getRegistry().addPropertyChangeListener(this);
90
// }
91
//
92
// AstViewer getComponent() {
93
// AstViewer c = (AstViewer)component.get();
94
//
95
// if (c != null) {
96
// return c;
97
// }
98
//
99
// remove();
100
//
101
// return null;
102
// }
103
//
104
// void remove() {
105
// TopComponent.getRegistry().removePropertyChangeListener(this);
106
// }
107
//
108
// public void propertyChange(PropertyChangeEvent evt) {
109
// AstViewer c = getComponent();
110
//
111
// if (c == null) {
112
// return;
113
// }
114
//
115
// c.refresh();
116
// }
117
// }
118

119     // highlight selected node in editor ...
120
private Document JavaDoc highlightedDocument = null;
121     private ParserResult.AstTreeNode highlighted = null;
122     private JEditorPane highlightedEditor = null;
123     private NbEditorDocument lastDocument = null;
124
125     private AstViewer() {
126         initComponents();
127         setLayout(new BorderLayout());
128         tree = new JTree();
129         tree.setCellRenderer(new Renderer JavaDoc());
130         tree.addTreeSelectionListener(new TreeSelectionListener JavaDoc() {
131                 public void valueChanged(TreeSelectionEvent JavaDoc e) {
132                     if (!listen) {
133                         return;
134                     }
135
136                     listen = false;
137                     selectionChanged();
138                     listen = true;
139                 }
140             });
141         add(new JScrollPane(tree), BorderLayout.CENTER);
142         setName(NbBundle.getMessage(AstViewer.class, "CTL_AstViewer"));
143
144         //setIcon(Utilities.loadImage(ICON_PATH, true));
145
}
146
147     private void initComponents() {
148         org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
149         this.setLayout(layout);
150         layout.setHorizontalGroup(layout.createParallelGroup(
151                 org.jdesktop.layout.GroupLayout.LEADING).add(0, 400, Short.MAX_VALUE));
152         layout.setVerticalGroup(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
153                                       .add(0, 300, Short.MAX_VALUE));
154     }
155
156     /**
157      * Gets default instance. Do not use directly: reserved for *.settings files only,
158      * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
159      * To obtain the singleton instance, use {@link findInstance}.
160      */

161     public static synchronized AstViewer getDefault() {
162         if (instance == null) {
163             instance = new AstViewer();
164         }
165
166         return instance;
167     }
168
169     /**
170      * Obtain the AstViewer instance. Never call {@link #getDefault} directly!
171      */

172     public static synchronized AstViewer findInstance() {
173         TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
174
175         if (win == null) {
176             ErrorManager.getDefault()
177                         .log(ErrorManager.WARNING,
178                 "Cannot find ASTBrowser component. It will not be located properly in the window system.");
179
180             return getDefault();
181         }
182
183         if (win instanceof AstViewer) {
184             return (AstViewer)win;
185         }
186
187         ErrorManager.getDefault()
188                     .log(ErrorManager.WARNING,
189             "There seem to be multiple components with the '" + PREFERRED_ID +
190             "' ID. That is a potential source of errors and unexpected behavior.");
191
192         return getDefault();
193     }
194
195     public int getPersistenceType() {
196         return TopComponent.PERSISTENCE_ALWAYS;
197     }
198
199     public void componentOpened() {
200     }
201
202     public void componentShowing() {
203         super.componentShowing();
204
205         // TODO add custom code on component opening
206
refresh();
207
208         //
209
// if (listener == null) {
210
// listener = new Listener(this);
211
// }
212
}
213
214     public void componentHidden() {
215         super.componentHidden();
216
217         // TODO add custom code on component closing
218
// if (listener != null) {
219
// listener.remove();
220
// listener = null;
221
// }
222
}
223
224     public void componentClosed() {
225         if (lastPane != null) {
226             lastPane.removeCaretListener(caretListener);
227             lastPane = null;
228             lastDocument = null;
229             org.openide.awt.StatusDisplayer.getDefault().setStatusText("");
230         }
231     }
232
233     /** replaces this in object stream */
234     public Object JavaDoc writeReplace() {
235         return new ResolvableHelper();
236     }
237
238     protected String JavaDoc preferredID() {
239         return PREFERRED_ID;
240     }
241
242     public void refresh(FileObject fo, ParserResult result) {
243         if ((result == null) || (result.getAst() == null)) {
244             DefaultTreeModel JavaDoc model = new EmptyTreeModel();
245             tree.setModel(model);
246         } else {
247             DefaultTreeModel JavaDoc model = new DefaultTreeModel JavaDoc(result.getAst());
248             tree.setModel(model);
249         }
250
251         // Update caret listener
252
DataObject dobj;
253
254         try {
255             dobj = DataObject.find(fo);
256         } catch (DataObjectNotFoundException ex) {
257             return;
258         }
259
260         EditorCookie editorCookie = (EditorCookie)dobj.getCookie(EditorCookie.class);
261
262         if (editorCookie == null) {
263             return;
264         }
265
266         JEditorPane[] panes = editorCookie.getOpenedPanes();
267
268         if ((panes == null) || (panes.length == 0)) {
269             return;
270         }
271
272         JEditorPane pane = panes[0];
273
274         if (caretListener == null) {
275             caretListener = new CListener();
276         }
277
278         if ((lastPane != null) && (lastPane != pane)) {
279             lastPane.removeCaretListener(caretListener);
280             lastPane = null;
281             lastDocument = null;
282         }
283
284         if (lastPane == null) {
285             pane.addCaretListener(caretListener);
286             lastPane = pane;
287             lastDocument = (NbEditorDocument)pane.getDocument();
288         }
289
290         int pos = pane.getCaret().getDot();
291         showPosition(pos);
292     }
293
294     private void refresh() {
295         Node JavaDoc[] ns = TopComponent.getRegistry().getActivatedNodes();
296
297         if (ns.length != 1) {
298             return;
299         }
300
301         DataObject dataObject = (DataObject)ns[0].getLookup().lookup(DataObject.class);
302         EditorCookie editorCookie = (EditorCookie)ns[0].getLookup().lookup(EditorCookie.class);
303
304         if (editorCookie == null) {
305             return;
306         }
307
308         if (editorCookie.getOpenedPanes() == null) {
309             return;
310         }
311
312         if (editorCookie.getOpenedPanes().length < 1) {
313             return;
314         }
315
316         JEditorPane pane = editorCookie.getOpenedPanes()[0];
317
318         if (caretListener == null) {
319             caretListener = new CListener();
320         }
321
322         if ((lastPane != null) && (lastPane != pane)) {
323             lastPane.removeCaretListener(caretListener);
324             lastPane = null;
325             lastDocument = null;
326         }
327
328         if (lastPane == null) {
329             pane.addCaretListener(caretListener);
330             lastPane = pane;
331             lastDocument = (NbEditorDocument)pane.getDocument();
332         }
333
334         final Document JavaDoc doc = editorCookie.getDocument();
335
336         if ((doc == null) || !(doc instanceof NbEditorDocument)) {
337             return;
338         }
339
340         String JavaDoc mimeType = (String JavaDoc)doc.getProperty("mimeType");
341
342         try {
343             Language l = LanguageRegistry.getInstance().getLanguageByMimeType(mimeType);
344
345             if ((l == null) || (l.getParser() == null)) {
346                 DefaultTreeModel JavaDoc model = new EmptyTreeModel();
347                 tree.setModel(model);
348
349                 return;
350             }
351
352             TreeNode JavaDoc astNode = null;
353
354             DataObject dobj = (DataObject)doc.getProperty(doc.StreamDescriptionProperty);
355             FileObject file = dobj.getPrimaryFile();
356
357             //Iterable<? extends ComFile> iterable = l.getParser().parse(file, doc.getText(0, doc.getLength()), errorHandler);
358
//ParserResult result =
359
// l.getParser().parseFiles(file, doc.getText(0, doc.getLength()), errorHandler);
360
Parser parser = l.getParser();
361             final ParserResult[] resultHolder = new ParserResult[1];
362             ParseListener listener =
363                 new ParseListener() {
364                     public void started(ParseEvent e) {
365                     }
366
367                     public void error(Error JavaDoc e) {
368                     }
369
370                     public void exception(Exception JavaDoc e) {
371                     }
372
373                     public void finished(ParseEvent e) {
374                         // TODO - check state
375
if (e.getKind() == ParseEvent.Kind.PARSE) {
376                             resultHolder[0] = e.getResult();
377                         }
378                     }
379                 };
380
381             List JavaDoc<ParserFile> sourceFiles = new ArrayList JavaDoc<ParserFile>(1);
382             sourceFiles.add(new DefaultParserFile(file, null, false));
383
384             SourceFileReader reader =
385                 new SourceFileReader() {
386                     public CharSequence JavaDoc read(ParserFile fileObject)
387                         throws IOException JavaDoc {
388                         try {
389                             return doc.getText(0, doc.getLength());
390                         } catch (BadLocationException JavaDoc ex) {
391                             return "";
392                         }
393                     }
394                 
395                 public int getCaretOffset(ParserFile file) {
396                     return -1;
397                 }
398             };
399
400             parser.parseFiles(sourceFiles, listener, reader);
401
402             ParserResult result = resultHolder[0];
403
404             astNode = result.getAst();
405
406             if (astNode == null) {
407                 return;
408             }
409
410             DefaultTreeModel JavaDoc model = new DefaultTreeModel JavaDoc(astNode);
411             tree.setModel(model);
412         } catch (Exception JavaDoc ex) {
413             ErrorManager.getDefault().notify(ex);
414         }
415     }
416
417     private TreeNode JavaDoc findNode(TreeNode JavaDoc parent, int index) {
418         if (parent instanceof ParserResult.AstTreeNode) {
419             int begin = ((ParserResult.AstTreeNode)parent).getStartOffset();
420             int end = ((ParserResult.AstTreeNode)parent).getEndOffset();
421
422             if ((index >= begin) && (index <= end)) {
423                 TreeNode JavaDoc candidate = parent;
424
425                 for (int i = 0; i < parent.getChildCount(); i++) {
426                     TreeNode JavaDoc child = parent.getChildAt(i);
427                     TreeNode JavaDoc found = findNode(child, index);
428
429                     if (found != null) {
430                         return found;
431
432                         // if (candidate == null) {
433
// candidate = found;
434
// } else {
435
// // See which one is better - further away.
436
// // Another fitness test could be the size of the range...
437
// int depth1 = 0;
438
//
439
// // See which one is better - further away.
440
// // Another fitness test could be the size of the range...
441
// int depth2 = 0;
442
// TreeNode n = candidate;
443
//
444
// while ((n != null) && (n != child)) {
445
// n = n.getParent();
446
// depth1++;
447
// }
448
//
449
// n = found;
450
//
451
// while ((n != null) && (n != child)) {
452
// n = n.getParent();
453
// depth2++;
454
// }
455
//
456
// if (depth2 < depth1) {
457
// candidate = found;
458
// }
459
// }
460
}
461                 }
462
463                 return candidate;
464             } else {
465                 TreeNode JavaDoc candidate = null;
466
467                 for (int i = 0; i < parent.getChildCount(); i++) {
468                     TreeNode JavaDoc child = parent.getChildAt(i);
469                     TreeNode JavaDoc found = findNode(child, index);
470
471                     if (found != null) {
472                         return found;
473                     }
474                 }
475
476                 return null;
477             }
478         } else {
479             return null;
480         }
481     }
482
483     private void showPosition(int position) {
484         TreeNode JavaDoc root = (TreeNode JavaDoc)tree.getModel().getRoot();
485         TreeNode JavaDoc closest = findNode(root, position);
486         List JavaDoc<TreeNode JavaDoc> path = new ArrayList JavaDoc<TreeNode JavaDoc>();
487
488         while (closest != null) {
489             path.add(0, closest);
490             closest = closest.getParent();
491         }
492
493         try {
494             TreePath JavaDoc treePath = new TreePath JavaDoc(path.toArray());
495             listen = false;
496             tree.setSelectionPath(treePath);
497             tree.expandPath(treePath);
498             tree.scrollPathToVisible(treePath);
499             org.openide.awt.StatusDisplayer.getDefault()
500                                            .setStatusText("Caret position : " + position);
501             listen = true;
502         } catch (Exception JavaDoc ex) {
503             // XXX TODO debug
504
ex.printStackTrace();
505         }
506     }
507
508     private void selectionChanged() {
509         removeHighlight();
510
511         if (!tree.hasFocus()) {
512             return;
513         }
514
515         TreePath JavaDoc selPath = tree.getSelectionPath();
516
517         if (selPath == null) {
518             return;
519         }
520
521         //NavigatorNode node = (NavigatorNode) selPath.getLastPathComponent ();
522
ParserResult.AstTreeNode node =
523             (ParserResult.AstTreeNode)tree.getLastSelectedPathComponent();
524
525         if (node == null) {
526             return;
527         }
528
529         highlighted = node;
530         HighlightSections.getDefault().setSelectedNode(highlightedDocument = lastDocument, node);
531         lastPane.setCaretPosition(node.getStartOffset());
532         highlightedEditor = lastPane;
533         highlightedEditor.repaint();
534     }
535
536     private void removeHighlight() {
537         if (highlighted == null) {
538             return;
539         }
540
541         HighlightSections.getDefault().setSelectedNode(highlightedDocument, null);
542         highlightedEditor.repaint();
543         highlighted = null;
544         highlightedDocument = null;
545         highlightedEditor = null;
546     }
547
548     class CListener implements CaretListener JavaDoc {
549         public void caretUpdate(CaretEvent JavaDoc e) {
550             if (!listen) {
551                 return;
552             }
553
554             int position = e.getDot();
555             showPosition(position);
556         }
557     }
558
559     private static class Renderer extends DefaultTreeCellRenderer JavaDoc {
560         public Component getTreeCellRendererComponent(JTree tree, Object JavaDoc value, boolean sel,
561             boolean expanded, boolean leaf, int row, boolean hasFocus) {
562             return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row,
563                 hasFocus);
564         }
565     }
566
567     static final class ResolvableHelper implements Serializable JavaDoc {
568         private static final long serialVersionUID = 1L;
569
570         public Object JavaDoc readResolve() {
571             return AstViewer.getDefault();
572         }
573     }
574
575     
576     private static TreeNode JavaDoc EMPTY_ROOT = new TreeNode JavaDoc() {
577         public TreeNode JavaDoc getChildAt(int arg0) {
578             throw new UnsupportedOperationException JavaDoc("Not supported yet.");
579         }
580
581         public int getChildCount() {
582             return 0;
583         }
584
585         public TreeNode JavaDoc getParent() {
586             return null;
587         }
588
589         public int getIndex(TreeNode JavaDoc arg0) {
590             return -1;
591         }
592
593         public boolean getAllowsChildren() {
594             return false;
595         }
596
597         public boolean isLeaf() {
598             return true;
599         }
600
601         public Enumeration JavaDoc children() {
602             return new Vector JavaDoc().elements();
603         }
604     };
605     
606     private class EmptyTreeModel extends DefaultTreeModel JavaDoc {
607         
608         EmptyTreeModel() {
609             super(EMPTY_ROOT);
610         }
611         
612     }
613 }
614
Popular Tags