1 19 20 package org.netbeans.modules.java; 21 22 import java.beans.*; 23 import java.io.*; 24 import java.util.*; 25 import java.lang.ref.Reference ; 26 import java.lang.ref.WeakReference ; 27 28 import javax.swing.event.ChangeListener ; 29 import javax.swing.event.ChangeEvent ; 30 import javax.swing.event.DocumentListener ; 31 import javax.swing.text.BadLocationException ; 32 import javax.swing.text.Segment ; 33 import javax.swing.text.StyledDocument ; 34 35 import org.openide.util.Task; 36 import org.openide.cookies.*; 37 import org.openide.loaders.MultiDataObject; 38 import org.openide.loaders.DataObject; 39 import org.openide.nodes.Node; 40 import org.openide.nodes.CookieSet; 41 import org.openide.src.*; 42 import org.openide.text.*; 43 44 import org.netbeans.modules.java.parser.LangEnvImpl; 45 import org.netbeans.modules.java.parser.JavaParser; 46 import org.netbeans.modules.java.codegen.DocumentBinding; 47 import org.netbeans.modules.java.codegen.TextBinding; 48 49 import org.netbeans.modules.java.bridge.BindingFactory; 50 import org.netbeans.modules.java.bridge.WrapperFactory; 51 import org.netbeans.modules.java.bridge.LangModel; 52 import org.netbeans.modules.java.bridge.ElementOrder; 53 import org.netbeans.modules.java.bridge.ElementImpl; 54 55 import org.netbeans.modules.java.parser.ParsingSupport; 56 import org.netbeans.modules.java.codegen.SourceText; 57 import org.netbeans.modules.java.bridge.DefaultLangModel; 58 59 import org.netbeans.modules.javacore.internalapi.JavaMetamodel; 60 61 62 63 69 class JavaParserGlue implements JavaParser.Env, DocumentBinding.Env, 70 LangModel.Env, SourceCookie.Editor { 71 72 private MultiDataObject.Entry sourceEntry; 73 private JavaDataObject jdo; 74 private DocumentBinding docBinding; 75 private LangEnvImpl envSupport; 76 private ParsingSupport parser; 77 private Map cookieMap; 78 private SiblingListener l; 79 private boolean documentLoaded; 80 private CloneableEditorSupport cloneableEditSupp; 81 private int suspended; 82 private PropertyChangeListener weakPropListener; 83 private boolean editorBound; 84 85 89 public JavaParserGlue(MultiDataObject.Entry en) { 90 this.sourceEntry = en; 91 this.jdo = (JavaDataObject)en.getDataObject(); 92 this.docBinding = new SourceText(this); 93 this.envSupport = new LangEnvImpl(docBinding); 94 this.cookieMap = new WeakHashMap(57); 95 96 DefaultLangModel model = new DefaultLangModel(this, jdo); 97 envSupport.setModel(model); 98 99 parser = new ParsingSupport(this, jdo, docBinding, model, model); 100 l = new SiblingListener(); 101 jdo.addPropertyChangeListener(l); 102 } 103 104 108 public Node.Cookie findCookie(Element el, Class clazz) { 109 Node.Cookie lookup = null; 110 111 if (el == parser.getSource()) 112 return findCookie((SourceElement)el, clazz); 115 if (clazz == OpenCookie.class) { 116 lookup = lookupCookie(el, clazz); 117 if (lookup != null) 118 return lookup; 119 lookup = createOpenCookie(el); 120 } else { 121 return jdo.getCookie(clazz); 122 } 123 return lookup; 124 } 125 126 public void annotateThrowable(Throwable t, String locMessage, boolean user) { 127 Util.annotateThrowable(t, locMessage, user); 128 } 129 130 public void annotateThrowable(Throwable wrapper, Throwable nested) { 131 Util.annotateThrowable(wrapper, nested); 132 } 133 134 public Node.Cookie findCookie(SourceElement src, Class clazz) { 135 return jdo.getCookie(clazz); 136 } 137 138 141 public void cloneableSupportCreated(CloneableEditorSupport supp) { 142 bindEditorSupport(supp); 143 } 144 145 public JavaParser getParser() { 146 return parser; 147 } 148 149 public org.openide.filesystems.FileObject getSourceFile() { 150 return jdo.getPrimaryFile(); 151 } 152 153 public String getSourceName() { 154 return jdo.getPrimaryFile().getNameExt(); 155 } 156 157 160 public InputStream findCompiledClass(String classFQN) { 161 return null; 163 } 164 165 176 public Reader getSourceText() throws IOException { 177 CloneableEditorSupport je = findEditorSupport(); 178 final StyledDocument doc = je.getDocument(); 179 180 if (doc != null) { 181 final Segment s = new javax.swing.text.Segment (); 183 doc.render(new Runnable () { 184 public void run() { 185 try { 186 doc.getText(0, doc.getLength(), s); 187 } catch (BadLocationException ex) { 188 } 190 } 191 }); 192 return new CharArrayReader(s.array, s.offset, s.count); 193 } else { 194 JavaDataLoader.JavaFileEntry en = (JavaDataLoader.JavaFileEntry)sourceEntry; 195 return new JavaEditor.GuardedReader(en.getInputStream(), true, 196 Util.getFileEncoding(en.getFile())); 197 } 198 } 199 200 204 protected OpenCookie createOpenCookie(Element el) { 205 ElementImpl impl = (ElementImpl)el.getCookie(ElementImpl.class); 206 OpenCookie ck = new OpenCookieImpl((TextBinding)impl.getBinding()); 207 return ck; 208 } 209 210 private Node.Cookie lookupCookie(Element el, Class clazz) { 211 synchronized (cookieMap) { 212 Object o = cookieMap.get(el); 213 if (o == null) 214 return null; 215 216 if (o instanceof CookieSet) 217 return ((CookieSet)o).getCookie(clazz); 218 219 if (o.getClass().isAssignableFrom(clazz)) 220 return (Node.Cookie)o; 221 return null; 222 } 223 } 224 225 private TextBinding getBinding(Element el) { 226 ElementImpl impl = (ElementImpl)el.getCookie(ElementImpl.class); 227 if (impl == null) { 228 Element.Impl iimpl = (Element.Impl)el.getCookie(Element.Impl.class); 229 throw new IllegalArgumentException ("Incompatible implementation: " + iimpl); 231 } 232 return (TextBinding)impl.getBinding(); 233 } 234 235 236 238 public CloneableEditorSupport findEditorSupport() { 239 if (this.cloneableEditSupp == null) { 240 bindEditorSupport(jdo.findCloneableEditorSupport()); 241 } 242 return cloneableEditSupp; 243 } 244 245 public void takeLock() throws IOException { 246 jdo.getPrimaryEntry().takeLock(); 247 } 248 249 private synchronized void bindEditorSupport(CloneableEditorSupport supp) { 250 if (!editorBound) { 251 supp.addChangeListener(l); 252 documentLoaded = supp.isDocumentLoaded(); 253 editorBound = true; 254 cloneableEditSupp = supp; 255 if (documentLoaded) 256 l.stateChanged(new ChangeEvent (supp)); 257 } 258 } 259 260 public PositionRef findFreePosition(PositionBounds bounds) { 261 return getJavaEditor().findFreePosition(bounds); 262 } 263 264 private JavaEditor getJavaEditor() { 265 return (JavaEditor)jdo.getCookie(JavaEditor.class); 266 } 267 268 272 public BindingFactory getBindingFactory() { 273 return envSupport.getBindingFactory(); 274 } 275 276 public WrapperFactory getWrapperFactory() { 277 return envSupport.getWrapperFactory(); 278 } 279 280 public void complete(Element scope, int informationKind) { 281 envSupport.complete(scope, informationKind); 282 } 283 284 public Type resolveType(Element context, Type original) { 285 return envSupport.resolveType(context, original); 286 } 287 288 public Identifier resolveTypeIdent(Element context, Identifier original) { 289 return envSupport.resolveTypeIdent(context, original); 290 } 291 292 295 public SourceElement getSource() { 296 return parser.getSource(); 297 } 298 299 302 private class OpenCookieImpl implements OpenCookie, Runnable { 303 TextBinding binding; 304 305 OpenCookieImpl(TextBinding binding) { 306 this.binding = binding; 307 } 308 309 public void open() { 310 org.openide.util.Mutex.EVENT.postReadRequest(this); 313 } 314 315 public void run() { 316 PositionBounds elBounds = binding.getElementRange(true); 317 getJavaEditor().openAt(elBounds.getBegin()); 318 } 319 } 320 321 public StyledDocument getDocument() { 322 return findEditorSupport().getDocument(); 323 } 324 325 public Line.Set getLineSet() { 326 return findEditorSupport().getLineSet(); 327 } 328 329 public javax.swing.JEditorPane [] getOpenedPanes() { 330 return findEditorSupport().getOpenedPanes(); 331 } 332 333 public boolean isModified() { 334 return findEditorSupport().isModified(); 335 } 336 337 public void open() { 338 findEditorSupport().open(); 339 } 340 341 public StyledDocument openDocument() throws IOException { 342 return findEditorSupport().openDocument(); 343 } 344 345 public Task prepareDocument() { 346 return findEditorSupport().prepareDocument(); 347 } 348 349 public void saveDocument() throws IOException { 350 findEditorSupport().saveDocument(); 351 } 352 353 public boolean close() { 354 return findEditorSupport().close(); 355 } 356 357 public void suspendDocumentChanges() { 358 suspended++; 359 } 360 361 public void resumeDocumentChanges() { 362 --suspended; 363 } 364 365 protected boolean isDocumentSuspended() { 366 return suspended > 0; 367 } 368 369 private void dissolve() { 370 suspendDocumentChanges(); 371 jdo.removePropertyChangeListener(l); 372 jdo.suspendSupports(); 374 375 synchronized (this) { 376 if (cloneableEditSupp != null) { 377 cloneableEditSupp.removeChangeListener(l); 378 editorBound = false; 379 StyledDocument d = cloneableEditSupp.getDocument(); 380 if (d != null) 381 d.removeDocumentListener(l); 382 } 383 } 384 parser.invalidate(); 385 } 386 387 private class SiblingListener implements PropertyChangeListener, ChangeListener , 388 DocumentListener { 389 390 private StyledDocument doc; 391 392 public void propertyChange(PropertyChangeEvent p) { 393 String evName = p.getPropertyName(); 394 Object source = p.getSource(); 395 396 if (source == jdo) 397 dataObjectPropertyChange(evName, p); 398 } 399 400 private void dataObjectPropertyChange(String evName, final PropertyChangeEvent p) { 401 if (DataObject.PROP_VALID.equals(evName) && ((Boolean )p.getNewValue()).booleanValue() == false) { 402 dissolve(); 403 } 404 } 405 406 public void stateChanged(ChangeEvent e) { CloneableEditorSupport supp = (CloneableEditorSupport)e.getSource(); 408 StyledDocument d = supp.getDocument(); 409 410 if (d != null) { 411 if (doc == null) { 412 synchronized (this) { 413 doc = d; 414 d.addDocumentListener(this); 415 documentLoaded = true; 416 } 417 } 418 } else { 419 removeDocListener(); 420 } 421 } 422 423 private synchronized void removeDocListener() { 424 if (doc != null) 425 doc.removeDocumentListener(this); 426 doc = null; 427 documentLoaded = false; 428 } 429 430 public void removeUpdate(javax.swing.event.DocumentEvent p1) { 431 documentChanged(); 432 } 433 434 public void changedUpdate(javax.swing.event.DocumentEvent p1) { 435 } 437 438 public void insertUpdate(javax.swing.event.DocumentEvent p1) { 439 documentChanged(); 440 } 441 442 private void documentChanged() { 443 if (!isDocumentSuspended()) { 444 parser.sourceChanged(-1, -1); 445 JavaMetamodel.getManager().addModified(jdo.getPrimaryFile()); 446 getJavaEditor().restartTimer(false); 447 } 448 } 449 } 450 451 private Map swingElementMap; 452 453 public org.openide.src.Element findElement(int offset) { 455 javax.swing.text.Element swingEl = sourceToText(getSource()); 456 457 while (swingEl != null) { 458 if (swingEl.isLeaf()) { 459 return ((TextElement)swingEl).getSourceElement(); 460 } 461 int elIndex = swingEl.getElementIndex(offset); 462 if (elIndex == -1) 463 return ((TextElement)swingEl).getSourceElement(); 464 swingEl = swingEl.getElement(elIndex); 465 } 466 return null; 467 468 } 469 470 public org.openide.src.Element textToSource(javax.swing.text.Element element) throws NoSuchElementException { 471 if (!(element instanceof TextElement)) { 472 throw new NoSuchElementException(); 473 } 474 TextElement el = (TextElement)element; 475 return el.getSourceElement(); 476 } 477 478 481 public javax.swing.text.Element sourceToText(org.openide.src.Element element) { 482 javax.swing.text.Document d; 483 try { 484 d = findEditorSupport().openDocument(); 485 } catch (IOException ex) { 486 IllegalStateException x = new IllegalStateException ("Could not load document"); org.openide.ErrorManager.getDefault().annotate(x, ex); 488 throw x; 489 } 490 if (swingElementMap == null) { 491 synchronized (this) { 492 if (swingElementMap == null) 493 swingElementMap = new WeakHashMap(75); 494 } 495 } 496 Reference r = (Reference )swingElementMap.get(element); 497 javax.swing.text.Element e = r == null ? null : (javax.swing.text.Element )r.get(); 498 if (e == null) { 499 e = new TextElement(element); 500 synchronized (this) { 501 swingElementMap.put(element, new WeakReference (e)); 502 } 503 } 504 return e; 505 } 506 507 private static final Element[] NO_CHILDREN = new Element[0]; 508 509 private class TextElement implements TextBinding.ExElement { 510 private Element myElement; 511 private org.netbeans.jmi.javamodel.Element refObject; 512 513 public TextElement(Element element) { 514 myElement = element; 515 ElementImpl impl = (ElementImpl) myElement.getCookie(ElementImpl.class); 516 if (impl != null) { 517 refObject = (org.netbeans.jmi.javamodel.Element)impl.getJavaElement (); 518 } 519 } 520 521 private PositionBounds getBounds() { 522 try { 523 JavaMetamodel manager=JavaMetamodel.getManager(); 524 return manager.getElementPosition(refObject, true); 525 } catch (javax.jmi.reflect.InvalidObjectException e) { 526 return null; 527 } 528 } 529 530 public PositionRef getDeclarationStart() { 531 try { 532 PositionBounds bounds = JavaMetamodel.getManager().getElementPosition(refObject); 533 if (bounds == null) 534 return null; 535 return bounds.getBegin (); 536 } catch (javax.jmi.reflect.InvalidObjectException e) { 537 return null; 538 } 539 } 540 541 private Element[] getChildrenElements() { 542 ElementOrder ck = (ElementOrder)myElement.getCookie( 543 ElementOrder.class); 544 if (ck == null) 545 return NO_CHILDREN; 546 return ck.getElements(); 547 } 548 549 public int getElementIndex(int offset) { 550 Element[] children = getChildrenElements(); 551 javax.swing.text.Element childElement; 552 553 for (int i = 0; i < children.length; i++) { 554 childElement = sourceToText(children[i]); 555 if (childElement.getStartOffset() <= offset && 556 childElement.getEndOffset() >= offset) { 557 return i; 558 } 559 } 560 return -1; 561 } 562 563 public javax.swing.text.AttributeSet getAttributes() { 564 return null; 565 } 566 567 public Element getSourceElement() { 568 return myElement; 569 } 570 571 public javax.swing.text.Document getDocument() { 572 return JavaParserGlue.this.getDocument(); 573 } 574 575 public javax.swing.text.Element getElement(int index) { 576 Element[] els = getChildrenElements(); 577 if (index > els.length) 578 throw new IllegalArgumentException (); 579 return sourceToText(els[index]); 580 } 581 582 public int getElementCount() { 583 return getChildrenElements().length; 584 } 585 586 public int getEndOffset() { 587 PositionBounds bounds = getBounds(); 588 return bounds != null ? getBounds().getEnd().getOffset() - 1 : 0; } 590 591 public String getName() { 592 return myElement.getClass().getName(); 593 } 594 595 public javax.swing.text.Element getParentElement() { 596 Element parent; 597 598 if (myElement instanceof MemberElement) { 599 parent = ((MemberElement)myElement).getDeclaringClass(); 600 if (parent == null && myElement instanceof ClassElement) { 601 parent = ((ClassElement)myElement).getSource(); 602 } 603 } else if (myElement instanceof InitializerElement) { 604 parent = ((InitializerElement)myElement).getDeclaringClass(); 605 } else 606 return null; 607 return sourceToText(parent); 608 } 609 610 public int getStartOffset() { 611 PositionBounds bounds = getBounds(); 612 return bounds != null ? bounds.getBegin().getOffset() : 0; 613 } 614 615 public boolean isLeaf() { 616 return getChildrenElements().length == 0; 617 } 618 } 619 } 620 | Popular Tags |