1 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 ; 44 import java.awt.event.FocusListener ; 45 import java.beans.PropertyChangeEvent ; 46 import java.beans.PropertyChangeListener ; 47 import javax.swing.event.CaretEvent ; 48 import javax.swing.event.CaretListener ; 49 import javax.swing.event.TreeModelListener ; 50 import javax.swing.event.TreeSelectionEvent ; 51 import javax.swing.event.TreeSelectionListener ; 52 import javax.swing.tree.DefaultMutableTreeNode ; 53 import javax.swing.tree.DefaultTreeCellRenderer ; 54 import javax.swing.tree.DefaultTreeModel ; 55 import javax.swing.tree.TreeModel ; 56 import javax.swing.*; 57 import javax.swing.text.BadLocationException ; 58 import java.awt.*; 59 import java.awt.event.MouseEvent ; 60 import java.awt.event.MouseListener ; 61 import java.io.IOException ; 62 import java.util.*; 63 import java.util.List ; 64 import javax.swing.text.AttributeSet ; 65 import javax.swing.text.Document ; 66 import javax.swing.text.SimpleAttributeSet ; 67 import javax.swing.text.StyleConstants ; 68 import javax.swing.tree.TreePath ; 69 70 71 75 public class LanguagesNavigator implements NavigatorPanel { 76 77 78 private JComponent panelUI; 79 private JTree tree; 80 81 82 83 public LanguagesNavigator () { 84 } 85 86 public String getDisplayHint () { 87 return "This is Navigator"; 88 } 89 90 public String getDisplayName () { 91 return "Navigator"; 92 } 93 94 public JComponent getComponent () { 95 if (panelUI == null) { 96 tree = new JTree () { 97 public String getToolTipText (MouseEvent ev) { 98 TreePath selPath = tree.getPathForLocation 99 (ev.getX (), ev.getY ()); 100 if (selPath == null) return null; 101 Object 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 ()); 112 tree.addTreeSelectionListener (new TreeSelectionListener () { 113 public void valueChanged (TreeSelectionEvent e) { 114 selectionChanged (); 115 } 116 }); 117 tree.addFocusListener (new FocusListener () { 118 public void focusGained (FocusEvent e) { 119 selectionChanged (); 120 } 121 public void focusLost (FocusEvent e) { 122 selectionChanged (); 123 } 124 }); 125 panelUI = new JScrollPane (tree); 126 } 127 return panelUI; 128 } 129 130 private PropertyChangeListener topComponentListener; 131 132 public void panelActivated (Lookup context) { 133 if (topComponentListener == null) { 134 topComponentListener = new PropertyChangeListener () { 135 public void propertyChange (PropertyChangeEvent 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 () { 153 public void run() { 154 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 data = new ArrayList (); 191 getComponent (); 192 if (ast != null) { 193 Model model = new Model (); 194 model.setContext (ast, lc.getLineSet (), document); 195 tree.setModel (model); 196 } else { 197 DefaultMutableTreeNode root = new DefaultMutableTreeNode (); 198 State state = ParserManagerImpl.get (document).getState (); 199 if (state == State.PARSING) { 200 root.add (new DefaultMutableTreeNode ("Parsing ...")); 201 } else 202 if (state != State.NOT_PARSED) { 203 root.add (new DefaultMutableTreeNode ("?!?!")); 204 } 205 tree.setModel (new DefaultTreeModel (root)); 206 } 207 tree.setCellRenderer (new Renderer ()); 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 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 return null; 231 } 232 233 234 236 private static NavigatorNode createNavigatorNode ( 237 ASTItem item, 238 List <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 displayName = (String ) navigator.getValue ("display_name", context); 260 if (displayName == null) 261 try { 262 displayName = doc.getText ( 263 start, 264 end - start 265 ); 266 } catch (BadLocationException ex) { 267 } 268 String tooltip = (String ) navigator.getValue ("tooltip", context); 269 String icon = (String ) 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 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 )) return; 301 Model model = (Model ) tree.getModel (); 302 ASTPath astPath = model.root.findPath (position); 303 if (astPath == null) return; 304 List nodePath = new ArrayList (); 305 NavigatorNode node = (NavigatorNode) model.astToNode.get (model.root); 306 Iterator it = astPath.listIterator (); 307 while (it.hasNext ()) { 308 Object 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 treePath = new TreePath (nodePath.toArray ()); 316 tree.setSelectionPath (treePath); 317 tree.scrollPathToVisible (treePath); 318 } 319 320 322 private Document highlightedDocument = null; 323 private Object highlighted = null; 324 private JEditorPane highlightedEditor = null; 325 326 private void selectionChanged () { 327 removeHighlight (); 328 if (!tree.hasFocus ()) return; 329 TreePath selPath = tree.getSelectionPath (); 330 if (selPath == null) return; 331 Object 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 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 highlightAS = null; 364 365 private static AttributeSet getHighlightAS () { 366 if (highlightAS == null) { 367 SimpleAttributeSet as = new SimpleAttributeSet (); 368 as.addAttribute (StyleConstants.Background, Color.yellow); highlightAS = as; 370 } 371 return highlightAS; 372 } 373 374 375 377 private static class Model implements TreeModel { 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 getRoot () { 390 if (astToNode.get (root) == null) { 391 List <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 getChild (Object parent, int index) { 407 return getNavigatorNodes ((NavigatorNode) parent).get (index); 408 } 409 410 public int getChildCount (Object parent) { 411 return getNavigatorNodes ((NavigatorNode) parent).size (); 412 } 413 414 public boolean isLeaf (Object node) { 415 return getNavigatorNodes ((NavigatorNode) node).isEmpty (); 416 } 417 418 public void valueForPathChanged (TreePath path, Object newValue) { 419 } 420 421 public int getIndexOfChild (Object parent, Object child) { 422 return getNavigatorNodes ((NavigatorNode) parent).indexOf (child); 423 } 424 425 public void addTreeModelListener (TreeModelListener l) { 426 } 427 428 public void removeTreeModelListener (TreeModelListener l) { 429 } 430 431 432 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 getNavigatorNodes (NavigatorNode n) { 445 List nodes = (List ) 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 <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 getNavigatorNodes (ASTItem item, List <ASTItem> path, List 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 { 500 501 public Component getTreeCellRendererComponent ( 502 JTree tree, Object 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 ) { 513 l.setIcon (null); 514 l.setText ((String ) ((DefaultMutableTreeNode ) 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 displayName; 530 String tooltip; 531 String icon; 532 ASTItem item; 533 List <ASTItem> path; 534 boolean isLeaf; 535 536 537 NavigatorNode ( 538 ASTItem item, 539 List <ASTItem> path, 540 Line line, 541 int column, 542 String displayName, 543 String tooltip, 544 String 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 o1, Object o2) { 560 return ((NavigatorNode) o1).displayName.compareToIgnoreCase ( 561 ((NavigatorNode) o2).displayName 562 ); 563 } 564 } 565 566 class Listener implements MouseListener { 567 568 public void mouseClicked (MouseEvent ev) { 569 if (ev.getClickCount () != 2) return; 570 TreePath selPath = tree.getPathForLocation 571 (ev.getX (), ev.getY ()); 572 if (selPath == null) return; 573 Object 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 e) { 581 } 582 public void mouseExited (MouseEvent e) { 583 } 584 public void mousePressed (MouseEvent e) { 585 } 586 public void mouseReleased (MouseEvent e) { 587 } 588 } 589 590 class DocumentListener implements CaretListener , ParserManagerListener { 591 public void parsed (State state, ASTNode ast) { 592 if (state == State.PARSING) return; 593 refresh (); 594 } 595 596 public void caretUpdate (CaretEvent e) { 597 markSelected (e.getDot ()); 598 } 599 } 600 } 601 | Popular Tags |