1 19 package org.netbeans.modules.gsf.browser; 20 21 import java.awt.*; 22 import java.io.IOException ; 23 import java.io.Serializable ; 24 import java.util.ArrayList ; 25 import java.util.Enumeration ; 26 import java.util.List ; 27 import java.util.Vector ; 28 import javax.swing.*; 29 import javax.swing.event.CaretEvent ; 30 import javax.swing.event.CaretListener ; 31 import javax.swing.event.TreeSelectionEvent ; 32 import javax.swing.event.TreeSelectionListener ; 33 import javax.swing.text.BadLocationException ; 34 import javax.swing.text.Document ; 35 import javax.swing.tree.DefaultTreeCellRenderer ; 36 import javax.swing.tree.DefaultTreeModel ; 37 import javax.swing.tree.TreeNode ; 38 import javax.swing.tree.TreePath ; 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 69 public class AstViewer extends TopComponent { 70 private static final long serialVersionUID = 1L; 71 private static AstViewer instance; 72 73 74 private static final String PREFERRED_ID = "AstViewer"; 76 private JTree tree; 77 78 private boolean listen = true; 80 private CaretListener caretListener; 81 private JEditorPane lastPane; 82 private ExtSyntaxSupport syntax; 83 84 119 private Document 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 ()); 130 tree.addTreeSelectionListener(new TreeSelectionListener () { 131 public void valueChanged(TreeSelectionEvent 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 } 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 161 public static synchronized AstViewer getDefault() { 162 if (instance == null) { 163 instance = new AstViewer(); 164 } 165 166 return instance; 167 } 168 169 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 refresh(); 207 208 } 213 214 public void componentHidden() { 215 super.componentHidden(); 216 217 } 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 234 public Object writeReplace() { 235 return new ResolvableHelper(); 236 } 237 238 protected String preferredID() { 239 return PREFERRED_ID; 240 } 241 242 public void refresh(FileObject fo, ParserResult result) { 243 if ((result == null) || (result.getAst() == null)) { 244 DefaultTreeModel model = new EmptyTreeModel(); 245 tree.setModel(model); 246 } else { 247 DefaultTreeModel model = new DefaultTreeModel (result.getAst()); 248 tree.setModel(model); 249 } 250 251 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 [] 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 doc = editorCookie.getDocument(); 335 336 if ((doc == null) || !(doc instanceof NbEditorDocument)) { 337 return; 338 } 339 340 String mimeType = (String )doc.getProperty("mimeType"); 341 342 try { 343 Language l = LanguageRegistry.getInstance().getLanguageByMimeType(mimeType); 344 345 if ((l == null) || (l.getParser() == null)) { 346 DefaultTreeModel model = new EmptyTreeModel(); 347 tree.setModel(model); 348 349 return; 350 } 351 352 TreeNode astNode = null; 353 354 DataObject dobj = (DataObject)doc.getProperty(doc.StreamDescriptionProperty); 355 FileObject file = dobj.getPrimaryFile(); 356 357 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 e) { 368 } 369 370 public void exception(Exception e) { 371 } 372 373 public void finished(ParseEvent e) { 374 if (e.getKind() == ParseEvent.Kind.PARSE) { 376 resultHolder[0] = e.getResult(); 377 } 378 } 379 }; 380 381 List <ParserFile> sourceFiles = new ArrayList <ParserFile>(1); 382 sourceFiles.add(new DefaultParserFile(file, null, false)); 383 384 SourceFileReader reader = 385 new SourceFileReader() { 386 public CharSequence read(ParserFile fileObject) 387 throws IOException { 388 try { 389 return doc.getText(0, doc.getLength()); 390 } catch (BadLocationException 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 model = new DefaultTreeModel (astNode); 411 tree.setModel(model); 412 } catch (Exception ex) { 413 ErrorManager.getDefault().notify(ex); 414 } 415 } 416 417 private TreeNode findNode(TreeNode 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 candidate = parent; 424 425 for (int i = 0; i < parent.getChildCount(); i++) { 426 TreeNode child = parent.getChildAt(i); 427 TreeNode found = findNode(child, index); 428 429 if (found != null) { 430 return found; 431 432 } 461 } 462 463 return candidate; 464 } else { 465 TreeNode candidate = null; 466 467 for (int i = 0; i < parent.getChildCount(); i++) { 468 TreeNode child = parent.getChildAt(i); 469 TreeNode 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 root = (TreeNode )tree.getModel().getRoot(); 485 TreeNode closest = findNode(root, position); 486 List <TreeNode > path = new ArrayList <TreeNode >(); 487 488 while (closest != null) { 489 path.add(0, closest); 490 closest = closest.getParent(); 491 } 492 493 try { 494 TreePath treePath = new TreePath (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 ex) { 503 ex.printStackTrace(); 505 } 506 } 507 508 private void selectionChanged() { 509 removeHighlight(); 510 511 if (!tree.hasFocus()) { 512 return; 513 } 514 515 TreePath selPath = tree.getSelectionPath(); 516 517 if (selPath == null) { 518 return; 519 } 520 521 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 { 549 public void caretUpdate(CaretEvent 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 { 560 public Component getTreeCellRendererComponent(JTree tree, Object 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 { 568 private static final long serialVersionUID = 1L; 569 570 public Object readResolve() { 571 return AstViewer.getDefault(); 572 } 573 } 574 575 576 private static TreeNode EMPTY_ROOT = new TreeNode () { 577 public TreeNode getChildAt(int arg0) { 578 throw new UnsupportedOperationException ("Not supported yet."); 579 } 580 581 public int getChildCount() { 582 return 0; 583 } 584 585 public TreeNode getParent() { 586 return null; 587 } 588 589 public int getIndex(TreeNode 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 children() { 602 return new Vector ().elements(); 603 } 604 }; 605 606 private class EmptyTreeModel extends DefaultTreeModel { 607 608 EmptyTreeModel() { 609 super(EMPTY_ROOT); 610 } 611 612 } 613 } 614 | Popular Tags |