1 19 20 package org.netbeans.modules.java; 21 22 import java.awt.Component ; 23 import java.awt.event.ActionEvent ; 24 import java.awt.event.ActionListener ; 25 import java.beans.PropertyChangeEvent ; 26 import java.beans.PropertyChangeListener ; 27 import java.beans.PropertyVetoException ; 28 import java.io.*; 29 import java.lang.ref.Reference ; 30 import java.lang.ref.ReferenceQueue ; 31 import java.lang.ref.WeakReference ; 32 import java.nio.CharBuffer ; 33 import java.util.*; 34 import java.util.regex.Matcher ; 35 import java.util.regex.Pattern ; 36 import javax.swing.*; 37 import javax.swing.Timer ; 38 import javax.swing.event.*; 39 import javax.jmi.reflect.JmiException; 40 import javax.swing.text.BadLocationException ; 41 import javax.swing.text.Caret ; 42 import javax.swing.text.Document ; 43 import javax.swing.text.EditorKit ; 44 import javax.swing.text.Position ; 45 import javax.swing.text.StyledDocument ; 46 import org.netbeans.api.java.classpath.ClassPath; 47 import org.netbeans.jmi.javamodel.*; 48 import org.netbeans.modules.java.settings.JavaSettings; 49 import org.netbeans.modules.java.ui.nodes.SourceNodeFactory; 50 import org.netbeans.modules.java.ui.nodes.SourceNodes; 51 import org.netbeans.modules.javacore.JMManager; 52 import org.netbeans.modules.javacore.RepositoryUpdater; 53 import org.netbeans.modules.javacore.RequestPoster; 54 import org.netbeans.modules.javacore.api.JavaModel; 55 import org.netbeans.modules.javacore.internalapi.JavaMetamodel; 56 import org.netbeans.modules.javacore.internalapi.ParsingListener; 57 import org.netbeans.modules.javacore.internalapi.UndoManager; 58 import org.netbeans.modules.javacore.jmiimpl.javamodel.ResourceImpl; 59 import org.openide.DialogDisplayer; 60 import org.openide.NotifyDescriptor; 61 import org.openide.awt.UndoRedo; 62 import org.openide.cookies.CloseCookie; 63 import org.openide.cookies.EditorCookie; 64 import org.openide.cookies.LineCookie; 65 import org.openide.cookies.OpenCookie; 66 import org.openide.cookies.PrintCookie; 67 import org.openide.cookies.SaveCookie; 68 import org.openide.filesystems.FileLock; 69 import org.openide.filesystems.FileObject; 70 import org.openide.loaders.DataObject; 71 import org.openide.nodes.Node; 72 import org.openide.nodes.Children; 73 import org.openide.src.SourceElement; 74 import org.openide.util.actions.SystemAction; 75 import org.openide.ErrorManager; 76 import org.openide.text.*; 77 import org.openide.text.Annotation; 78 import org.openide.util.Mutex; 79 import org.openide.util.NbBundle; 80 import org.openide.util.RequestProcessor; 81 import org.openide.util.Utilities; 82 import org.openide.windows.CloneableOpenSupport; 83 84 85 89 95 public class JavaEditor extends DataEditorSupport implements PropertyChangeListener , Node.Cookie, OpenCookie, EditorCookie.Observable, CloseCookie, PrintCookie { 96 97 final static String MAGIC_PREFIX = "//GEN-"; 99 102 private static String [] SECTION_MAGICS; 103 private static final int LONGEST_ITEM = 10; 104 105 private boolean shouldReload = false; 106 private boolean wasReloaded = false; 107 108 static { 109 110 StringBuffer sb = new StringBuffer (MAGIC_PREFIX); 111 int size = sb.length(); 112 113 SECTION_MAGICS = new String [7]; 114 SECTION_MAGICS[0] = sb.append("LINE:").toString(); sb.setLength(size); 116 SECTION_MAGICS[1] = sb.append("BEGIN:").toString(); sb.setLength(size); 118 SECTION_MAGICS[2] = sb.append("END:").toString(); sb.setLength(size); 120 SECTION_MAGICS[3] = sb.append("HEADER:").toString(); sb.setLength(size); 122 SECTION_MAGICS[4] = sb.append("HEADEREND:").toString(); sb.setLength(size); 124 SECTION_MAGICS[5] = sb.append("FIRST:").toString(); sb.setLength(size); 126 SECTION_MAGICS[6] = sb.append("LAST:").toString(); } 128 129 130 private final static int T_LINE = 0; 131 private final static int T_BEGIN = 1; 132 private final static int T_END = 2; 133 private final static int T_HEADER = 3; 134 private final static int T_HEADEREND = 4; 135 private final static int T_FIRST = 5; 137 private final static int T_LAST = 6; 138 139 143 HashMap sections = null; 144 145 146 Timer timer; 147 148 149 static final byte NEW_LINE_N = 0; 150 151 152 static final byte NEW_LINE_R = 1; 153 154 155 static final byte NEW_LINE_RN = 2; 156 157 158 byte newLineType; 159 160 private transient boolean hasAnnotations = false; 161 162 166 private boolean reloading = false; 167 168 private static final Comparator SECTION_COMPARATOR = new GuardedPositionComparator(); 169 170 171 private ArrayList errorAnnotations=new ArrayList(); 172 173 174 private static final RequestProcessor ERROR_ANNOTATION_QUEUE = 175 new RequestProcessor("Error Annotation Queue", 1); 177 private boolean parsingAttached; 178 179 private ParsingListener wParsingL; 180 181 private OverrideAnnotationSupport overriddensSupport; 182 183 186 private Reference sourceClasspath; 187 private Reference librariesClasspath; 188 private Reference bootClasspath; 189 190 private UndoRedo.Manager undoRedo = null; 191 private boolean undoRedoPrecreated = false; 192 193 private transient String resourceMofId = null; 194 private transient WeakReference resource = null; 195 196 private final ParsingListener listener = new ParsingListener() { 197 public void resourceParsed(final Resource resource) { 198 JavaMetamodel.getDefaultRepository().beginTrans(false); 199 try { 200 if (resource == getResource()) { 201 notifyParsingDone(); 202 } 203 } finally { 204 JavaMetamodel.getDefaultRepository().endTrans(); 205 } 206 } 207 }; 208 209 212 public JavaEditor(DataObject dob) { 213 super(dob, new JavaEditorEnv(dob)); 214 addChangeListener(new JavaEditorChangeListener()); 216 JavaMetamodel.getUndoManager().addPropertyChangeListener(new UndoManagerListener(this)); 217 } 218 219 private void changeTimeoutElapsed() { 220 parseSource(false, true); 221 } 222 223 protected boolean notifyModified() { 224 if (! super.notifyModified()) { 225 return false; 226 } 227 JavaDataObject obj = (JavaDataObject) getDataObject(); 228 if (obj.getCookie(SaveCookie.class) == null) { 229 obj.addSaveCookie(new Save()); 230 } 231 return true; 232 } 233 234 protected void notifyUnmodified() { 235 super.notifyUnmodified(); 236 JavaDataObject obj = (JavaDataObject) getDataObject(); 237 SaveCookie save = (SaveCookie) obj.getCookie(SaveCookie.class); 238 if (save != null) { 239 obj.removeSaveCookie(save); 240 } 241 } 242 243 private class Save implements SaveCookie { 244 public void save() throws IOException { 245 saveDocument(); 246 if (wasReloaded) { 247 getDataObject().setModified(true); 249 wasReloaded = false; 250 } else { 251 getDataObject().setModified(false); 252 } 253 } 254 } 255 256 257 private void parseSource(final boolean force, final boolean refreshAnnotations) { 258 ERROR_ANNOTATION_QUEUE.post(new Runnable () { 259 public void run() { 260 if (force) { 261 JavaMetamodel.getManager().addModified(getDataObject().getPrimaryFile()); 262 } else if (forceParseOnComponentActivated) { 263 ResourceImpl resource = (ResourceImpl) getResource(); 264 if (resource != null) resource.resetErrors(); 265 } 266 Document doc = getDocument(); 267 268 if (doc != null) 269 JavaUpToDateStatusProvider.get(doc).notifyParsingStarted(); 270 271 JavaMetamodel.getDefaultRepository().beginTrans(true); 273 JavaMetamodel.getDefaultRepository().endTrans(false); 274 if (refreshAnnotations) 275 refreshAnnotations(); 276 277 if (doc != null) 278 JavaUpToDateStatusProvider.get(doc).notifyParsingFinished(); 279 } 280 }); 281 } 282 283 private void classpathChanged() { 284 parseSource(true, true); 285 } 286 287 private void parsingErrorsChanged(PropertyChangeEvent evt) { 288 int errors=JavaSettings.getDefault().getParsingErrors(); 289 Integer old=(Integer )evt.getOldValue(); 290 int oldErrors=JavaSettings.DEFAULT_PARSING_ERRORS; 291 292 if (old!=null) { 293 oldErrors=old.intValue(); 294 } 295 if (oldErrors==errors) return; 297 if (errors==0 && !errorAnnotations.isEmpty()) { detachAnnotations(errorAnnotations); 299 errorAnnotations.clear(); 300 return; 301 } 302 if (oldErrors==errorAnnotations.size() || errors<errorAnnotations.size()) { refreshAnnotations(); 304 } 305 } 306 307 308 private void showOverridingChanged (PropertyChangeEvent event) { 309 if (getOpenedPanes() == null) return; 310 311 boolean newValue = JavaSettings.getDefault().getShowOverriding(); 312 if (newValue) { 313 overriddensSupport.processOverriddenAnnotation(); 315 } else { 316 synchronized (JavaEditor.this) { 317 overriddensSupport.suspend(); 318 overriddensSupport = new OverrideAnnotationSupport(JavaEditor.this); 319 } 320 } 321 } 322 323 private synchronized void attachParsingListener() { 324 if (!parsingAttached) { 325 if (wParsingL == null) 326 wParsingL = new WParsingListener(listener); 327 JavaMetamodel.addParsingListener(wParsingL); 328 parsingAttached = true; 329 } 330 if (overriddensSupport == null) { 331 overriddensSupport = new OverrideAnnotationSupport(this); 332 } 333 } 334 335 private synchronized void removeParsingListener() { 336 if (parsingAttached) { 337 JavaMetamodel.removeParsingListener(wParsingL); 338 parsingAttached=false; 339 } 340 } 341 342 345 void restartTimer(boolean onlyIfRunning) { 346 restartTimer(onlyIfRunning, false); 347 } 348 349 private boolean forceParseOnComponentActivated = false; 350 351 private void restartTimer(boolean onlyIfRunning, boolean componentActivated) { 352 int delay; 353 boolean timerRunning = timer!=null && timer.isRunning(); 354 355 if (onlyIfRunning && !timerRunning) 356 return; 357 358 if (!onlyIfRunning) 359 forceParseOnComponentActivated = componentActivated; 360 delay = JavaSettings.getDefault().getAutoParsingDelay(); 361 if (delay<=0) 362 return; 363 if (timer==null) { timer = new Timer (0, new ActionListener () { 365 public void actionPerformed(ActionEvent e) { 366 changeTimeoutElapsed(); 367 } 368 }); 369 timer.setRepeats(false); 370 } 371 timer.setInitialDelay(delay); 372 timer.restart(); 373 } 374 375 private void stopTimerIfPossible() { 376 if (forceParseOnComponentActivated && timer!=null) { 377 timer.stop(); 378 } 379 } 380 381 382 public void openAtPosition(PositionRef begin) { 383 openAt(begin, -1).getComponent().requestActive(); 384 } 385 386 public void openAt(PositionRef p) { 387 openAtPosition(p); 388 } 389 390 392 protected void notifyClosed() { 393 synchronized (this) { 394 removeParsingListener(); 395 if (overriddensSupport != null) overriddensSupport.suspend(); 396 overriddensSupport = null; 397 hasAnnotations = false; 398 } 399 boolean wasModified = this.isModified(); 400 401 synchronized (allEditors) { 404 super.notifyClosed(); 405 clearSections(); 406 } 407 408 if (wasModified) { 410 parseSource(true, false); 411 } 412 } 413 414 417 protected void notifyParsingDone() { 418 } 419 420 private void refreshAnnotations() { 421 ((JMManager) JMManager.getManager()).waitScanFinished(); 423 if (JMManager.PERF_DEBUG) Thread.dumpStack(); 424 Resource r = getResource(); 425 if (r != null) { 426 try { 427 final List errors = r.getErrors(); 428 errors.size(); 430 SwingUtilities.invokeLater(new Runnable () { 431 public void run() { 432 processAnnotations(errors); 433 } 434 }); 435 } catch (javax.jmi.reflect.InvalidObjectException e) { 436 } 439 } 440 } 441 442 public Resource getResource() { 443 Resource result = resource == null ? null : (Resource) resource.get(); 444 if (result != null) { 445 try { 446 result.refImmediateComposite(); 447 } catch (javax.jmi.reflect.InvalidObjectException e) { 448 resourceMofId = null; 449 result = null; 450 } 451 } 452 if (result == null || !result.isValid()) { 453 if (resourceMofId != null) { 454 result = (Resource) JavaMetamodel.getDefaultRepository().getByMofId(resourceMofId); 455 } 456 if (result == null || !result.isValid()) { 457 result = JavaMetamodel.getManager().getResource(getDataObject().getPrimaryFile()); 458 if (result==null) 459 return null; 460 resourceMofId = result.refMofId(); 461 } 462 resource = new WeakReference (result); 463 } 464 return result; 465 } 466 467 477 protected void loadFromStreamToKit (StyledDocument doc, InputStream stream, EditorKit kit) throws IOException, BadLocationException { 478 sections = new HashMap(10); 479 GuardedReader reader = new GuardedReader(stream, false, 480 Util.getFileEncoding(getDataObject().getPrimaryFile())); 481 kit.read(reader, doc, 0); 482 fillSections(reader, doc); 483 newLineType = reader.getNewLineType(); 484 486 final boolean forceUpdate = reloading; 489 490 reloading = false; 491 if (forceUpdate) { 492 ERROR_ANNOTATION_QUEUE.post(new Runnable () { 493 public void run() { 494 refreshAnnotations(); 495 } 496 }); 497 } 498 } 499 500 510 protected void saveFromKitToStream(StyledDocument doc, EditorKit kit, OutputStream stream) throws IOException, BadLocationException { 511 OutputStream os = new NewLineOutputStream(stream, newLineType); 512 String encoding = Util.getFileEncoding(getDataObject().getPrimaryFile()); 513 if (sections != null) { 514 ArrayList list = new ArrayList(sections.values()); 515 if (list.size() > 0) { 516 GuardedWriter writer = new GuardedWriter(os, list, encoding); 517 kit.write(writer, doc, 0, doc.getLength()); 518 return; 519 } 520 } 521 Writer w; 522 if (encoding == null) 523 w = new OutputStreamWriter(os); 524 else 525 w = new OutputStreamWriter(os, encoding); 526 kit.write(w, doc, 0, doc.getLength()); 527 } 528 529 532 public void saveDocument () throws IOException { 533 saveDocument(true); 534 if (shouldReload) { 535 reloadDocument(); 536 shouldReload = false; 537 wasReloaded = true; 538 } 539 } 540 541 545 private void saveDocument(boolean forceSave) throws IOException { 546 if (forceSave || isModified()) { 547 if (!checkCharsetConversion(Util.getFileEncoding(getDataObject().getPrimaryFile()))){ 548 return; 549 } 550 RepositoryUpdater.getDefault().addFileObjectToSave(getDataObject().getPrimaryFile()); 551 super.saveDocument(); 552 } 553 } 554 555 private boolean checkCharsetConversion(String encoding) { 556 if (encoding == null) 557 return true; 558 boolean value = true; 559 try { 560 java.nio.charset.CharsetEncoder coder = java.nio.charset.Charset.forName(encoding).newEncoder(); 561 if (!coder.canEncode(getDocument().getText(0, getDocument().getLength()))){ 562 NotifyDescriptor nd = new NotifyDescriptor.Confirmation( 563 NbBundle.getMessage(JavaEditor.class, "MSG_BadCharConversion", new Object [] { getDataObject().getPrimaryFile().getNameExt(), 565 encoding}), 566 NotifyDescriptor.YES_NO_OPTION, 567 NotifyDescriptor.WARNING_MESSAGE); 568 nd.setValue(NotifyDescriptor.NO_OPTION); 569 DialogDisplayer.getDefault().notify(nd); 570 if(nd.getValue() != NotifyDescriptor.YES_OPTION) 571 value = false; 572 } 573 } 574 catch (javax.swing.text.BadLocationException e){ 575 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 576 } 577 return value; 578 } 579 580 private void processAnnotations(List errors) { 581 ArrayList added,removed,unchanged; 582 Collection newAnnotations; 583 newAnnotations = getAnnotations(errors); 584 added=new ArrayList(newAnnotations); 585 added.removeAll(errorAnnotations); 586 unchanged=new ArrayList(errorAnnotations); 587 unchanged.retainAll(newAnnotations); 588 removed=errorAnnotations; 589 removed.removeAll(newAnnotations); 590 detachAnnotations(removed); 591 if (!added.isEmpty() && isDocumentLoaded()) { 592 593 final ArrayList finalAdded = added; 595 StyledDocument doc = getDocument(); 596 Runnable docRenderer = new Runnable () { 597 public void run() { 598 LineCookie cookie = (LineCookie)getDataObject().getCookie(LineCookie.class); 599 Line.Set lines = cookie.getLineSet(); 600 601 for (Iterator i=finalAdded.iterator();i.hasNext();) { 602 ParserAnnotation ann=(ParserAnnotation)i.next(); 603 604 ann.attachToLineSet(lines); 605 } 606 } 607 }; 608 609 if (doc != null) { 610 doc.render(docRenderer); 611 } else { 612 docRenderer.run(); 613 } 614 } 615 616 errorAnnotations=unchanged; 617 errorAnnotations.addAll(added); 618 } 619 620 621 622 private Collection getAnnotations(List errors) { 623 HashMap map = new HashMap(2*errors.size()); 624 int maxErrors = JavaSettings.getDefault().getParsingErrors(); 625 for (Iterator it = errors.iterator(); it.hasNext();) { 626 ErrorInfo err = (ErrorInfo) it.next(); 627 int line = err.getLineNumber(); 628 629 if (line>0) { int column = err.getColumn(); 631 String message = err.getDescription(); 632 ParserAnnotation anno = new ParserAnnotation(line, column, err.getSeverity(), message); 633 634 Integer lineInt = new Integer (line); 641 ParserAnnotation prev = (ParserAnnotation)map.get(lineInt); 642 if (prev != null) { 643 if (prev.getSeverity().equals(ErrorTypeEnum.WARNING)) { 644 map.put(lineInt, anno); 645 anno.chain(prev); 646 } else { 647 prev.chain(anno); 648 } 649 } else if (map.size() < maxErrors) { 650 map.put(lineInt, anno); 651 } 652 } 653 } 654 return map.values(); 655 } 656 657 private static void detachAnnotations(Collection anns) { 658 Iterator i; 659 660 for (i=anns.iterator();i.hasNext();) { 661 Annotation ann=(Annotation)i.next(); 662 if (ann.getAttachedAnnotatable() != null) { 663 ann.detach(); 664 } 665 } 666 } 667 668 private ClassPath getBootClassPath () { 669 ClassPath result; 670 if (this.bootClasspath == null || (result = (ClassPath)this.bootClasspath.get()) == null) { 671 result = ClassPath.getClassPath (getDataObject().getPrimaryFile(), ClassPath.BOOT); 672 if (result != null) { 673 this.bootClasspath = new WeakReference (result); 674 } 675 } 676 return result; 677 } 678 679 private ClassPath getLibrariesPath () { 680 ClassPath result; 681 if (this.librariesClasspath == null || (result = (ClassPath)this.librariesClasspath.get()) == null) { 682 result = ClassPath.getClassPath (getDataObject().getPrimaryFile(), ClassPath.COMPILE); 683 if (result != null) { 684 this.librariesClasspath = new WeakReference (result); 685 } 686 } 687 return result; 688 } 689 690 private ClassPath getSourcePath () { 691 ClassPath result; 692 if (this.sourceClasspath == null || (result = (ClassPath)this.sourceClasspath.get()) == null) { 693 result = ClassPath.getClassPath (getDataObject().getPrimaryFile(), ClassPath.SOURCE); 694 this.sourceClasspath = new WeakReference (result); 695 } 696 return result; 697 } 698 699 701 705 public SourceElement getSource() { 706 return ((JavaDataObject)getDataObject()).getSource(); 707 } 708 709 715 public javax.swing.text.Element sourceToText(org.openide.src.Element element) { 716 return null; 717 } 718 719 727 public org.openide.src.Element textToSource(javax.swing.text.Element element) throws NoSuchElementException { 728 throw new NoSuchElementException(); 729 } 730 731 736 public org.openide.src.Element findElement(int offset) { 737 return null; 738 } 739 740 742 755 public SimpleSection createSimpleSection(PositionRef pos, String name) 756 throws IllegalArgumentException , BadLocationException { 757 checkOverlap(pos); 758 return doCreateSimpleSection(pos, name); 759 } 760 761 774 public SimpleSection createSimpleSection(PositionBounds bounds, String name) 775 throws IllegalArgumentException , BadLocationException { 776 checkOverlap(bounds); 777 return doCreateSimpleSection(bounds, name); 778 } 779 780 private void checkOverlap(PositionRef pos) { 781 Iterator it = sections.values().iterator(); 782 while (it.hasNext()) { 783 GuardedSection s = (GuardedSection)it.next(); 784 if (s.contains(pos, false)) { 785 throw new IllegalArgumentException ("Sections overlap"); } 787 } 788 } 789 790 794 public boolean testOverlap(PositionBounds bounds) { 795 try { 796 openDocument(); 797 } 798 catch (IOException e) { 799 throw new IllegalArgumentException (); 800 } 801 try { 802 checkOverlap(bounds,true); 803 } catch (IllegalArgumentException e){ 804 return false; 805 } 806 return true; 807 } 808 809 private void checkOverlap(PositionBounds bounds) throws IllegalArgumentException { 810 checkOverlap(bounds,false); 811 } 812 813 private void checkOverlap(PositionBounds bounds,boolean allowHoles) throws IllegalArgumentException { 814 Collection c = new TreeSet(new GuardedPositionComparator()); 815 c.addAll(sections.values()); 816 817 Iterator it = c.iterator(); 818 PositionRef begin = bounds.getBegin(); 819 PositionRef end = bounds.getEnd(); 820 int beginOffset = begin.getOffset(); 821 int endOffset = end.getOffset(); 822 GuardedSection starting = null; 823 boolean overlapOK = false; 824 825 while (it.hasNext()) { 826 GuardedSection s = (GuardedSection)it.next(); 827 if (s.contains(begin, allowHoles) || s.contains(end, allowHoles)) 828 throw new IllegalArgumentException ("Sections overlap"); if (s.getBegin().getOffset() > beginOffset) { 830 if (s.getBegin().getOffset() < endOffset) { 831 throw new IllegalArgumentException ("Sections overlap"); } 833 break; 834 } 835 } 836 } 837 838 private SimpleSection doCreateSimpleSection(final PositionBounds bounds, final String name) 839 throws IllegalArgumentException , BadLocationException { 840 StyledDocument loadedDoc = null; 841 try { 842 loadedDoc = openDocument(); 843 } 844 catch (IOException e) { 845 throw new IllegalArgumentException ("Cannot load document"); } 847 final StyledDocument doc = loadedDoc; 848 final SimpleSection[] sect = new SimpleSection[] { null }; 849 850 Util.ExceptionRunnable run = new Util.ExceptionRunnable() { 851 public void run() throws Exception { 852 sect[0] = new SimpleSection(name, 853 createBounds(bounds.getBegin().getOffset(), bounds.getEnd().getOffset(), false) 854 ); 855 sections.put(sect[0].getName(), sect[0]); 856 sect[0].markGuarded(doc); 857 } 858 }; 859 try { 860 Util.runAtomic(doc, run); 861 notifyModified(); 862 } 863 catch (Exception e) { 864 if (e instanceof BadLocationException ) 865 throw (BadLocationException ) e; 866 else 867 throw new IllegalArgumentException (); 868 } 869 return sect[0]; 870 } 871 872 private SimpleSection doCreateSimpleSection(final PositionRef pos, final String name) 873 throws IllegalArgumentException , BadLocationException { 874 StyledDocument loadedDoc = null; 875 try { 876 loadedDoc = openDocument(); 877 } 878 catch (IOException e) { 879 throw new IllegalArgumentException (); 880 } 881 final StyledDocument doc = loadedDoc; 882 final SimpleSection[] sect = new SimpleSection[] { null }; 883 884 Util.ExceptionRunnable run = new Util.ExceptionRunnable() { 885 public void run() throws Exception { 886 int where = pos.getOffset(); 887 doc.insertString(where, "\n \n", null); sect[0] = new SimpleSection(name, 889 createBounds(where + 1, where + 3, false) 890 ); 891 sections.put(sect[0].getName(), sect[0]); 892 sect[0].markGuarded(doc); 893 } 894 }; 895 try { 896 Util.runAtomic(doc, run); 897 notifyModified(); 898 } 899 catch (Exception e) { 900 if (e instanceof BadLocationException ) 901 throw (BadLocationException ) e; 902 else 903 throw new IllegalArgumentException (); 904 } 905 return sect[0]; 906 } 907 908 916 public SimpleSection createSimpleSectionAfter(final GuardedSection previous, 917 final String name) 918 throws IllegalArgumentException , BadLocationException { 919 PositionBounds bounds; 920 if (previous instanceof SimpleSection) 921 bounds = ((SimpleSection) previous).bounds; 922 else 923 bounds = ((InteriorSection) previous).bottom; 924 if ((previous == null) || (!previous.valid)) 925 throw new IllegalArgumentException ("Invalid guarded block"); 927 return doCreateSimpleSection(bounds.getEnd(), name); 928 } 929 930 public InteriorSection createInteriorSection(PositionRef pos, String name) 931 throws IllegalArgumentException , BadLocationException { 932 checkOverlap(pos); 933 return doCreateInteriorSection(pos, name); 934 } 935 936 public InteriorSection createInteriorSectionAfter(GuardedSection previous, 937 String name) throws IllegalArgumentException , BadLocationException { 938 PositionBounds bounds; 939 if (previous instanceof SimpleSection) 940 bounds = ((SimpleSection) previous).bounds; 941 else 942 bounds = ((InteriorSection) previous).bottom; 943 if ((previous == null) || (!previous.valid)) 944 throw new IllegalArgumentException ("Invalid guarded block"); return doCreateInteriorSection(bounds.getEnd(), name); 946 } 947 948 public InteriorSection createInteriorSection(PositionBounds bounds, PositionBounds interior, 949 String name) throws IllegalArgumentException , BadLocationException { 950 checkOverlap(bounds); 951 if (bounds.getBegin().getOffset() > interior.getEnd().getOffset() || 952 bounds.getEnd().getOffset() < interior.getEnd().getOffset()) 953 throw new IllegalArgumentException ("Interior is not nested."); return doCreateInteriorSection(bounds, interior, name); 955 } 956 957 private InteriorSection doCreateInteriorSection(final PositionBounds bounds, 958 final PositionBounds interiorBounds, final String name) 959 throws IllegalArgumentException , BadLocationException { 960 StyledDocument loadedDoc = null; 961 try { 962 loadedDoc = openDocument(); 963 } 964 catch (IOException e) { 965 throw new IllegalArgumentException ("Cannot load document"); } 967 968 final StyledDocument doc = loadedDoc; 969 final InteriorSection[] sect = new InteriorSection[] { null }; 970 971 Util.ExceptionRunnable run = new Util.ExceptionRunnable() { 972 public void run() { 973 sect[0] = new InteriorSection(name, 974 createBounds(bounds.getBegin().getOffset(), interiorBounds.getBegin().getOffset(), false), 975 createBounds(interiorBounds.getBegin().getOffset(), interiorBounds.getEnd().getOffset(), true), 976 createBounds(interiorBounds.getEnd().getOffset(), bounds.getEnd().getOffset(), false) 977 ); 978 sections.put(sect[0].getName(), sect[0]); 979 sect[0].markGuarded(doc); 980 } 981 }; 982 try { 983 Util.runAtomic(doc, run); 984 notifyModified(); 985 } 986 catch (Exception e) { 987 if (e instanceof BadLocationException ) 988 throw (BadLocationException ) e; 989 else 990 throw new IllegalArgumentException (); 991 } 992 return sect[0]; 993 } 994 995 1002 private InteriorSection doCreateInteriorSection(final PositionRef pos, 1003 final String name) 1004 throws IllegalArgumentException , BadLocationException { 1005 StyledDocument loadedDoc = null; 1006 try { 1007 loadedDoc = openDocument(); 1008 } 1009 catch (IOException e) { 1010 throw new IllegalArgumentException (); 1011 } 1012 1013 final StyledDocument doc = loadedDoc; 1014 final InteriorSection[] sect = new InteriorSection[] { null }; 1015 1016 Util.ExceptionRunnable run = new Util.ExceptionRunnable() { 1017 public void run() throws Exception { 1018 int where = pos.getOffset(); 1019 doc.insertString(where, "\n \n \n \n", null); sect[0] = new InteriorSection(name, 1021 createBounds(where + 1, where + 3, false), 1022 createBounds(where + 3, where + 5, true), 1023 createBounds(where + 5, where + 7, false) 1024 ); 1025 sections.put(sect[0].getName(), sect[0]); 1026 sect[0].markGuarded(doc); 1027 } 1028 }; 1029 try { 1030 Util.runAtomic(doc, run); 1031 notifyModified(); 1032 } 1033 catch (Exception e) { 1034 if (e instanceof BadLocationException ) 1035 throw (BadLocationException ) e; 1036 else 1037 throw new IllegalArgumentException (); 1038 } 1039 return sect[0]; 1040 } 1041 1042 1047 public SimpleSection findSimpleSection(String name) { 1048 GuardedSection s = findSection(name); 1049 return (s instanceof SimpleSection) ? (SimpleSection) s : null; 1050 } 1051 1052 1057 public InteriorSection findInteriorSection(String name) { 1058 GuardedSection s = findSection(name); 1059 return (s instanceof InteriorSection) ? (InteriorSection) s : null; 1060 } 1061 1062 1067 public GuardedSection findSection(String name) { 1068 try { 1069 StyledDocument doc = openDocument (); 1070 synchronized (this) { 1071 if (sections != null) 1072 return (GuardedSection) sections.get(name); 1073 } 1074 } 1075 catch (IOException e) { 1076 } 1077 return null; 1078 } 1079 1080 1083 public Iterator getGuardedSections() { 1084 try { 1085 StyledDocument doc = openDocument (); 1086 synchronized (this) { 1087 if (sections != null) 1088 return ((HashMap)sections.clone()).values().iterator(); 1089 } 1090 } 1091 catch (IOException e) { 1092 } 1093 return Collections.EMPTY_SET.iterator(); 1094 } 1095 1096 1099 public Iterator getGuardedSectionNames() { 1100 try { 1101 StyledDocument doc = openDocument (); 1102 synchronized (this) { 1103 if (sections != null) 1104 return ((HashMap)sections.clone()).keySet().iterator(); 1105 } 1106 } 1107 catch (IOException e) { 1108 e.printStackTrace(); 1109 } 1110 return Collections.EMPTY_SET.iterator(); 1111 } 1112 1113 1120 public PositionRef findFreePosition(PositionBounds bnds) { 1121 StyledDocument doc; 1122 try { 1123 doc = openDocument(); 1124 } catch (IOException ex) { 1125 return null; 1126 } 1127 1128 PositionRef beginPos = bnds.getBegin(); 1129 int startOffs = beginPos.getOffset(); 1130 1131 TreeSet set = new TreeSet(SECTION_COMPARATOR); 1132 set.addAll(this.sections.values()); 1133 for (Iterator it = set.iterator(); it.hasNext(); ) { 1134 GuardedSection s = (GuardedSection)it.next(); 1135 PositionRef start = s.getBegin(); 1136 if (start.getOffset() > startOffs) { 1137 break; 1139 } 1140 if (s.contains(beginPos, false)) { 1141 PositionRef after = s.getPositionAfter(); 1143 if (after.getOffset() > bnds.getEnd().getOffset()) { 1144 return null; 1145 } 1146 return after; 1147 } 1148 } 1149 return beginPos; 1150 } 1151 1152 protected CloneableEditor createCloneableEditor() { 1153 return new JavaEditorComponent(this); 1154 } 1155 1156 1174 1177 synchronized void clearSections() { 1178 if (sections != null) { 1179 Iterator it = ((HashMap)sections.clone()).values().iterator(); 1180 while (it.hasNext()) { 1181 GuardedSection sect = (GuardedSection) it.next(); 1182 sect.valid = false; 1183 } 1184 sections = null; 1185 } 1186 } 1187 1188 PositionRef findUnguarded(PositionRef fromWhere, boolean allowHoles, boolean after) { 1189 Iterator it = getGuardedSections(); 1190 1191 while (it.hasNext()) { 1192 GuardedSection sect = (GuardedSection)it.next(); 1193 if (sect.contains(fromWhere, allowHoles)) { 1194 if (after) { 1195 return sect.getPositionAfter(); 1196 } else { 1197 return sect.getPositionBefore(); 1198 } 1199 } 1200 } 1201 return fromWhere; 1202 } 1203 1204 private static class JavaEditorEnv extends DataEditorSupport.Env { 1205 1206 static final long serialVersionUID = -6792511207355520950L; 1207 1208 public JavaEditorEnv(DataObject obj) { 1209 super(obj); 1210 } 1211 1212 protected FileObject getFile() { 1213 return getDataObject().getPrimaryFile(); 1214 } 1215 protected FileLock takeLock() throws IOException { 1216 return ((JavaDataObject) getDataObject()).getPrimaryEntry().takeLock(); 1217 } 1218 public CloneableOpenSupport findCloneableOpenSupport() { 1219 return (CloneableOpenSupport) getDataObject().getCookie(EditorCookie.class); 1222 } 1223 } 1224 1225 1230 public static class JavaEditorComponent extends CloneableEditor { 1231 1232 static final int SELECTED_NODES_DELAY = 1000; 1233 1234 Timer timerSelNodes; 1236 1237 1238 JavaEditor support; 1239 1240 1241 CaretListener caretListener; 1242 1243 1247 Component toolBar; 1248 1249 1250 int lastCaretOffset = -1; 1251 1252 static final long serialVersionUID =6223349196427270209L; 1253 1254 1255 public JavaEditorComponent () { 1256 super(); 1257 } 1258 1259 1260 public JavaEditorComponent (CloneableEditorSupport sup) { 1261 super(sup); 1262 initialize(); 1263 } 1264 1265 private transient RequestProcessor.Task selectionTask = null; 1266 1267 private final RequestPoster elementSelectionPoster = new RequestPoster(); 1268 1269 1270 void selectElementsAtOffset(final int offset) { 1271 elementSelectionPoster.post(new Runnable () { 1272 public void run() { 1273 ((JMManager) JMManager.getManager()).waitScanFinished(); 1274 final DataObject d = support.getDataObject(); 1275 if (!isActiveTC() || d == null || !d.isValid() || d.isTemplate()) { 1276 return; 1277 } 1278 1279 final Node n; 1280 n = (Node) Children.MUTEX.readAccess(new Mutex.Action() { 1281 public Object run() { 1282 return createNode(offset, d); 1283 } 1284 }); 1285 SwingUtilities.invokeLater(new Runnable () { 1286 public void run() { 1287 setActivatedNodes((n != null) ? new Node[] { n } : new Node[] {} ); 1288 } 1289 }); 1290 } 1291 }); 1292 } 1293 1294 private Node createNode(int offset, DataObject d) { 1295 SourceNodeFactory factory = SourceNodes.getExplorerFactory(); 1296 Node n = null; 1297 Element element; 1298 Element currentElement = null; 1299 Node[] nodes = getActivatedNodes(); 1300 if (nodes!=null && nodes.length == 1) { 1301 currentElement = (Element) nodes[0].getLookup().lookup(Element.class); 1302 } 1303 try { 1304 JMManager.getTransactionMutex().addPriorityThread(); 1305 JavaMetamodel.getDefaultRepository().beginTrans(false); 1306 try { 1307 FileObject fo=d.getPrimaryFile(); 1308 JavaModel.setClassPath(fo); 1309 Resource res = JavaMetamodel.getManager().getResource(fo); 1310 element = res == null? null: findElement(res, offset); 1311 if (element != null && currentElement != null && element.isValid() && currentElement.isValid()) { 1312 if (element.equals(currentElement)) { 1313 return nodes[0]; 1314 } 1315 } 1316 1317 if (element instanceof Field) { 1318 n = factory.createFieldNode((Field) element); 1319 } else if (element instanceof Attribute) { 1320 n = factory.createAnnotationTypeMethodNode((Attribute) element); 1321 } else if (element instanceof AnnotationType) { 1322 n = factory.createAnnotationTypeNode((AnnotationType) element); 1323 } else if (element instanceof Constructor) { 1324 n = factory.createConstructorNode((Constructor) element); 1325 } else if (element instanceof EnumConstant) { 1326 n = factory.createEnumConstantNode((EnumConstant) element); 1327 } else if (element instanceof Initializer) { 1328 n = factory.createInitializerNode((Initializer) element); 1329 } else if (element instanceof Method) { 1330 n = factory.createMethodNode((Method) element); 1331 } else if (element instanceof JavaEnum) { 1332 n = factory.createEnumNode((JavaEnum) element); 1333 } else if (element instanceof JavaClass) { 1334 n = factory.createClassNode((JavaClass) element); 1335 } else if (element instanceof Resource) { 1336 n = d.getNodeDelegate(); 1337 } else { 1338 n = null; 1339 } 1340 } finally { 1341 JavaMetamodel.getDefaultRepository().endTrans(); 1342 } 1343 } catch (JmiException e) { 1344 ErrorManager.getDefault().notify(ErrorManager.WARNING, e); 1345 } 1346 1347 return n; 1348 } 1349 1350 1357 private static Element findElement(Resource r, int offset) { 1358 Iterator cit = r.getClassifiers().iterator(); 1359 Element el = r; 1360 while (cit.hasNext()) { 1361 JavaClass jc = (JavaClass) cit.next(); 1362 PositionBounds bounds = JavaMetamodel.getManager().getElementPosition(jc); 1363 if (bounds != null && offset >= bounds.getBegin().getOffset() && 1364 offset <= bounds.getEnd().getOffset()) { 1365 el = findElement(jc, offset); 1366 break; 1367 } 1368 } 1369 return el; 1370 } 1371 1372 1375 private static Element findElement(JavaClass jc, int offset) { 1376 Iterator classIt = jc.getFeatures().iterator(); 1377 Element el = jc; 1378 while (classIt.hasNext()) { 1379 ClassMember cm = (ClassMember) classIt.next(); 1380 PositionBounds bounds = JavaMetamodel.getManager().getElementPosition(cm); 1381 if (offset >= bounds.getBegin().getOffset() && 1382 offset <= bounds.getEnd().getOffset()) { 1383 if (cm instanceof JavaClass) { 1384 el = findElement((JavaClass) cm, offset); 1385 } else { 1386 el = cm; 1387 } 1388 break; 1389 } 1390 } 1391 1392 return el; 1393 } 1394 1395 protected boolean isActiveTC() { 1396 return getRegistry().getActivated() == JavaEditorComponent.this; 1397 } 1398 1399 protected void notifyParsingDone() { 1400 } 1404 1405 1409 public SystemAction[] getSystemActions() { 1410 selectElementsAtOffset(lastCaretOffset); 1411 timerSelNodes.stop(); 1412 return super.getSystemActions(); 1413 } 1414 1415 1416 private void initialize () { 1417 support = (JavaEditor) cloneableEditorSupport(); 1418 if (support==null) return; 1421 timerSelNodes = new Timer (200, new ActionListener () { 1422 public void actionPerformed(ActionEvent e) { 1423 Timer t=support.timer; 1424 1425 if (t!=null && t.isRunning()) { 1426 timerSelNodes.restart(); 1427 return; 1428 } 1429 1430 if (!isActiveTC()) { 1431 return; 1434 } 1435 if (lastCaretOffset == -1 && getEditorPane() != null) { 1436 Caret caret = getEditorPane().getCaret(); 1437 if (caret != null) 1438 lastCaretOffset = caret.getDot(); 1439 } 1440 selectElementsAtOffset(lastCaretOffset); 1441 } 1442 }); 1443 timerSelNodes.setInitialDelay(200); 1444 timerSelNodes.setRepeats(false); 1445 caretListener = new CaretListener() { 1446 public void caretUpdate(CaretEvent e) { 1447 support.restartTimer(true); 1448 restartTimerSelNodes(e.getDot()); 1449 } 1450 }; 1451 timerSelNodes.restart(); 1452 } 1453 1454 1457 void restartTimerSelNodes(int pos) { 1458 timerSelNodes.setInitialDelay(SELECTED_NODES_DELAY); 1459 timerSelNodes.restart(); 1460 lastCaretOffset = pos; 1461 } 1462 1463 1466 protected void componentActivated () { 1467 JEditorPane p = getEditorPane(); 1468 if (p != null) 1469 p.addCaretListener(caretListener); 1470 super.componentActivated (); 1471 if (p != null) 1473 p.requestFocusInWindow(); 1474 if ((support.timer==null || !support.timer.isRunning())) { 1475 support.restartTimer(false, true); 1476 } 1477 if (!support.hasAnnotations) { ERROR_ANNOTATION_QUEUE.post(new Runnable () { 1479 public void run() { 1480 if (support.overriddensSupport != null) { support.overriddensSupport.processOverriddenAnnotation(); 1482 } 1483 } 1484 }, 1000, Thread.MIN_PRIORITY); 1485 } 1486 support.attachParsingListener(); 1487 } 1488 1489 public void requestFocus() { 1490 super.requestFocus(); 1491 JEditorPane p = getEditorPane(); 1492 if (p != null) { 1493 p.requestFocus(); 1494 } 1495 } 1496 1497 public boolean requestFocusInWindow() { 1498 super.requestFocusInWindow(); 1499 JEditorPane p = getEditorPane(); 1500 if (p != null) { 1501 return p.requestFocusInWindow(); 1502 } else { 1503 return false; 1504 } 1505 } 1506 1507 1511 protected void componentDeactivated () { 1512 JEditorPane p = getEditorPane(); 1513 if (p != null) 1514 p.removeCaretListener(caretListener); 1515 support.removeParsingListener(); 1516 synchronized (this) { 1517 if (selectionTask != null) { 1518 selectionTask.cancel(); 1519 selectionTask = null; 1520 } 1521 } 1522 support.stopTimerIfPossible(); 1523 super.componentDeactivated (); 1524 } 1525 1526 1529 public void readExternal (ObjectInput in) 1530 throws IOException, ClassNotFoundException { 1531 super.readExternal(in); 1532 initialize(); 1533 } 1534 1535 } 1537 1543 private void fillSections(GuardedReader is, StyledDocument doc) { 1544 JavaEditor.SectionDesc descBegin = null; 1545 1546 Iterator it = is.list.iterator(); 1547 while (it.hasNext()) { 1548 SectionDesc descCurrent = (SectionDesc) it.next(); 1549 GuardedSection sect = null; 1550 switch (descCurrent.type) { 1551 case T_LINE: 1552 sect = new SimpleSection(descCurrent.name, 1553 createBounds(descCurrent.begin, 1554 descCurrent.end, false)); 1555 break; 1556 1557 case T_BEGIN: 1558 case T_HEADER: 1559 case T_FIRST: 1560 descBegin = descCurrent; 1561 break; 1562 1563 case T_HEADEREND: 1564 if ((descBegin != null) && 1565 ((descBegin.type == T_HEADER) || (descBegin.type == T_FIRST)) && 1566 (descCurrent.name.equals(descBegin.name)) 1567 ) { 1568 descBegin.end = descCurrent.end; 1569 } 1570 else { 1571 descBegin = null; 1573 } 1574 break; 1575 1576 case T_END: 1577 case T_LAST: 1578 if ((descBegin != null) && (descBegin.name.equals(descCurrent.name))) { 1579 if ((descBegin.type == T_BEGIN) && (descCurrent.type == T_END)) { 1580 sect = new SimpleSection(descCurrent.name, 1582 createBounds(descBegin.begin, 1583 descCurrent.end, false)); 1584 break; 1585 } 1586 if (((descBegin.type == T_FIRST) && (descCurrent.type == T_LAST)) || 1587 ((descBegin.type == T_HEADER) && (descCurrent.type == T_END))) { 1588 sect = new InteriorSection(descCurrent.name, 1590 createBounds(descBegin.begin, descBegin.end, false), 1591 createBounds(descBegin.end, descCurrent.begin, true), 1592 createBounds(descCurrent.begin, descCurrent.end, false) 1593 ); 1594 break; 1595 } 1596 } 1597 descBegin = null; 1599 break; 1600 } 1601 1602 if (sect != null) { 1603 sections.put(sect.getName(), sect); 1604 descBegin = null; 1605 sect.markGuarded(doc); 1606 } 1607 } 1608 } 1609 1610 1611 public PositionBounds createBounds(int begin, int end, boolean dir) { 1612 if (!dir) { 1613 return new PositionBounds( 1614 createPositionRef(begin, Position.Bias.Forward), 1615 createPositionRef(end, Position.Bias.Backward) 1616 ); 1617 } 1618 else { 1619 return new PositionBounds( 1620 createPositionRef(begin, Position.Bias.Backward), 1621 createPositionRef(end, Position.Bias.Forward) 1622 ); 1623 } 1624 } 1625 1626 public void propertyChange(PropertyChangeEvent evt) { 1627 UndoManager undo = JavaMetamodel.getUndoManager(); 1628 if (undo.isUndoAvailable() || undo.isRedoAvailable()) { 1629 getUndoRedo().discardAllEdits(); 1630 } 1631 } 1632 1633 1635 1637 public abstract class GuardedSection extends Object { 1638 1639 String name; 1640 1641 1642 boolean valid; 1643 1644 1647 public String getName() { 1648 return name; 1649 } 1650 1651 1654 GuardedSection(String name) { 1655 this.name = name; 1656 valid = true; 1657 } 1658 1659 1663 public void setName(String name) throws PropertyVetoException { 1664 if (!this.name.equals(name)) { 1665 synchronized (JavaEditor.this) { 1666 if (valid) { 1667 if (sections.get(name) != null) 1668 throw new PropertyVetoException ("", new PropertyChangeEvent (this, "name", this.name, name)); sections.remove(this.name); 1670 this.name = name; 1671 sections.put(name, this); 1672 } 1673 } 1674 } 1675 } 1676 1677 1683 public boolean deleteSection() { 1684 synchronized (JavaEditor.this) { 1685 if (valid) { 1686 try { 1687 sections.remove(name); 1688 unmarkGuarded(getDocument()); 1692 deleteText(); 1693 valid = false; 1694 return true; 1695 } 1696 catch (BadLocationException e) { 1697 } 1698 catch (IOException e) { 1699 } 1700 } 1701 return false; 1702 } 1703 } 1704 1705 1709 public boolean isValid() { 1710 return valid; 1711 } 1712 1713 1719 public boolean removeSection() { 1720 synchronized (JavaEditor.this) { 1721 if (!valid) 1722 return false; 1723 sections.remove(name); 1724 unmarkGuarded(getDocument()); 1728 valid = false; 1729 return true; 1730 } 1731 } 1732 1733 1740 void deleteNewLineBeforeBlock(int offset) { 1741 if (offset > 1) { 1742 try { 1743 PositionBounds b = createBounds(offset - 1, offset, true); 1744 String s = b.getText(); 1745 if (s.equals("\n")) { b.setText(""); } 1748 } 1749 catch (IOException e) { 1750 } 1751 catch (BadLocationException e) { 1752 } 1753 } 1754 } 1755 1756 1758 public void openAt() { 1759 JavaEditor.this.openAt(getBegin()); 1760 } 1761 1762 1772 protected boolean setText(PositionBounds bounds, String text, boolean minLen) { 1773 if (!valid) 1774 return false; 1775 1776 if (minLen) { 1779 if (text.length() == 0) 1780 text = " \n"; else if (text.length() == 1) 1782 text = text.equals("\n") ? " \n" : text + "\n"; } 1784 1785 if (!text.endsWith("\n")) text = text + "\n"; 1788 try { 1789 bounds.setText(text); 1790 return true; 1791 } 1792 catch (BadLocationException e) { 1793 } 1794 catch (IOException e) { 1795 } 1796 return false; 1797 } 1798 1799 1804 void markGuarded(StyledDocument doc, PositionBounds bounds, boolean mark) { 1805 int begin = bounds.getBegin().getOffset(); 1806 int end = bounds.getEnd().getOffset(); 1807 if (mark) 1808 NbDocument.markGuarded(doc, begin, end - begin); 1809 else 1810 NbDocument.unmarkGuarded(doc, begin, end - begin); 1811 } 1812 1813 1816 abstract void markGuarded(StyledDocument doc); 1817 1818 1821 abstract void unmarkGuarded(StyledDocument doc); 1822 1823 1827 abstract void deleteText() throws BadLocationException , IOException; 1828 1829 1832 public abstract PositionRef getBegin(); 1833 1834 1837 public abstract String getText(); 1838 1839 1846 public abstract boolean contains(PositionRef pos,boolean permitHoles); 1847 1849 public abstract PositionRef getPositionAfter(); 1850 1852 public abstract PositionRef getPositionBefore(); 1853 } 1854 1855 1858 public final class SimpleSection extends GuardedSection { 1859 1860 PositionBounds bounds; 1861 1862 1866 SimpleSection(String name, PositionBounds bounds) { 1867 super(name); 1868 this.bounds = bounds; 1869 } 1870 1871 1876 public boolean setText(String text) { 1877 return setText(bounds, text, true); 1878 } 1879 1880 1884 void deleteText() throws BadLocationException , IOException { 1885 bounds.setText(""); deleteNewLineBeforeBlock(bounds.getBegin().getOffset()); 1887 } 1888 1889 1892 void markGuarded(StyledDocument doc) { 1893 markGuarded(doc, bounds, true); 1894 } 1895 1896 1899 void unmarkGuarded(StyledDocument doc) { 1900 markGuarded(doc, bounds, false); 1901 JavaEditor.this.notifyModified(); 1902 } 1903 1904 1908 public PositionRef getBegin() { 1909 return bounds.getBegin(); 1910 } 1911 1912 1915 public String getText() { 1916 StringBuffer buf = new StringBuffer (); 1917 try { 1918 buf.append(bounds.getText()); 1919 } 1920 catch (Exception e) { 1921 } 1922 return buf.toString(); 1923 } 1924 1925 1939 1940 public PositionRef getPositionAfter() { 1941 return createPositionRef(bounds.getEnd().getOffset(), Position.Bias.Backward); 1942 } 1943 1944 public boolean contains(PositionRef pos,boolean allowHoles) { 1945 return bounds.getBegin().getOffset() <= pos.getOffset() && 1946 bounds.getEnd().getOffset() >= pos.getOffset(); 1947 } 1948 1949 public PositionRef getPositionBefore() { 1950 return createPositionRef(bounds.getBegin().getOffset(), Position.Bias.Forward); 1951 } 1952 } 1953 1954 1958 public final class InteriorSection extends GuardedSection { 1959 1960 PositionBounds header; 1961 1962 1963 PositionBounds body; 1964 1965 1966 PositionBounds bottom; 1967 1968 1971 InteriorSection(String name, PositionBounds header, PositionBounds body, PositionBounds bottom) { 1972 super(name); 1973 this.header = header; 1974 this.body = body; 1975 this.bottom = bottom; 1976 } 1977 1978 1983 public boolean setBody(String text) { 1984 return setText(body, text, false); 1985 } 1986 1987 1992 public boolean setHeader(String text) { 1993 return setText(header, text, true); 1994 } 1995 1996 2001 public String getHeader() { 2002 if (!isValid()) 2003 return null; 2004 try { 2005 return header.getText(); 2006 } catch (IOException ex) { 2007 } catch (BadLocationException ex) { 2009 } 2011 return null; 2012 } 2013 2014 2022 public boolean setBottom(String text) { 2023 boolean endsWithEol = text.endsWith("\n"); int firstEol = text.indexOf('\n'); 2025 int lastEol = text.lastIndexOf('\n'); 2026 2027 if ((firstEol != lastEol) || (endsWithEol && (firstEol != -1))) { 2028 if (endsWithEol) { 2029 text = text.substring(0, text.length() - 1); 2030 } 2031 text = text.replace('\n', ' '); 2032 } 2033 return setText(bottom, text, true); 2034 } 2035 2036 2041 public String getBottom() throws IOException, BadLocationException { 2042 if (!isValid()) 2043 return null; 2044 try { 2045 return bottom.getText(); 2046 } catch (IOException ex) { 2047 } catch (BadLocationException ex) { 2049 } 2051 return null; 2052 } 2053 2054 2059 public PositionRef getBegin() { 2060 return body.getBegin(); 2061 } 2062 2063 2067 void deleteText() throws BadLocationException , IOException { 2068 header.setText(""); body.setText(""); bottom.setText(""); deleteNewLineBeforeBlock(header.getBegin().getOffset()); 2072 } 2073 2074 2077 void markGuarded(StyledDocument doc) { 2078 markGuarded(doc, header, true); 2079 markGuarded(doc, bottom, true); 2080 } 2081 2082 2085 void unmarkGuarded(StyledDocument doc) { 2086 markGuarded(doc, header, false); 2087 markGuarded(doc, bottom, false); 2088 JavaEditor.this.notifyModified(); 2089 } 2090 2091 2094 public String getText() { 2095 StringBuffer buf = new StringBuffer (); 2096 try { 2097 buf.append(header.getText()); 2098 buf.append(body.getText()); 2099 buf.append(bottom.getText()); 2100 } 2101 catch (Exception e) { 2102 } 2103 return buf.toString(); 2104 } 2105 2106 2126 public boolean contains(PositionRef pos,boolean allowHoles) { 2127 if (!allowHoles) { 2128 return header.getBegin().getOffset() <= pos.getOffset() && 2129 bottom.getEnd().getOffset() >= pos.getOffset(); 2130 } else { 2131 if (header.getBegin().getOffset() <= pos.getOffset() && 2132 header.getEnd().getOffset() >= pos.getOffset()) { 2133 return true; 2134 } 2135 return bottom.getBegin().getOffset() <= pos.getOffset() && 2136 bottom.getEnd().getOffset() >= pos.getOffset(); 2137 } 2138 } 2139 2140 public PositionRef getPositionBefore() { 2141 return createPositionRef(header.getBegin().getOffset(), Position.Bias.Forward); 2142 } 2143 2144 public PositionRef getPositionAfter() { 2145 return createPositionRef(bottom.getEnd().getOffset(), Position.Bias.Backward); 2146 } 2147 } 2148 2149 2151 private class JavaEditorChangeListener implements ChangeListener { 2152 private PropertyChangeListener classpathListener; 2153 private PropertyChangeListener settingListener; 2154 2155 public void stateChanged(ChangeEvent ev) { 2156 JavaSettings js=JavaSettings.getDefault(); 2157 2158 if (classpathListener == null) { 2160 classpathListener = new PropertyChangeListener () { 2161 public void propertyChange(PropertyChangeEvent evt) { 2162 if (ClassPath.PROP_ROOTS.equals(evt.getPropertyName())) { 2163 classpathChanged(); 2164 } 2165 } 2166 }; 2167 } 2168 if (settingListener==null) 2169 settingListener=new PropertyChangeListener () { 2170 public void propertyChange(PropertyChangeEvent evt) { 2171 if (JavaSettings.PROP_PARSING_ERRORS.equals(evt.getPropertyName())) { 2172 parsingErrorsChanged(evt); 2173 } 2174 if (JavaSettings.PROP_SHOW_OVERRIDING.equals(evt.getPropertyName())) { 2175 showOverridingChanged (evt); 2176 } 2177 } 2178 }; 2179 ClassPath sourceClasspath = getSourcePath(); 2180 ClassPath librariesClasspath = getLibrariesPath(); 2181 ClassPath bootClassPath = getBootClassPath(); 2182 if (sourceClasspath != null) { 2183 sourceClasspath.removePropertyChangeListener(classpathListener); 2184 } 2185 if (librariesClasspath != null) { 2186 librariesClasspath.removePropertyChangeListener(classpathListener); 2187 } 2188 if (bootClassPath != null) { 2189 bootClassPath.removePropertyChangeListener(classpathListener); 2190 } 2191 js.removePropertyChangeListener(settingListener); 2192 if (isDocumentLoaded()) { 2193 if (sourceClasspath != null) { 2194 sourceClasspath.addPropertyChangeListener(classpathListener); 2195 } 2196 if (librariesClasspath != null) { 2197 librariesClasspath.addPropertyChangeListener (classpathListener); 2198 } 2199 if (bootClassPath != null) { 2200 bootClassPath.addPropertyChangeListener(classpathListener); 2201 } 2202 js.addPropertyChangeListener(settingListener); 2203 } 2204 } 2205 2206 } 2207 2210 private static class GuardedPositionComparator implements Comparator { 2211 2214 public int compare(Object o1, Object o2) { 2215 return getOffset(o1) - getOffset(o2); 2216 } 2217 2218 2219 private int getOffset(Object o) { 2220 if (o instanceof SimpleSection) { 2221 return ((SimpleSection)o).bounds.getBegin().getOffset(); 2222 } 2223 else { 2224 return ((InteriorSection)o).header.getBegin().getOffset(); 2225 } 2226 } 2227 } 2228 2229 2233 private static class SectionDesc { 2234 2235 int type; 2236 2237 2238 String name; 2239 2240 2241 int begin; 2242 2243 2244 int end; 2245 2246 2247 SectionDesc(int type) { 2248 this.type = type; 2249 name = null; 2250 begin = 0; 2251 end = 0; 2252 } 2253 } 2254 2255 2261 static class GuardedReader extends Reader { 2262 2263 Reader reader; 2264 2265 2266 char[] charBuff; 2267 char[] readBuff; 2268 int howmany; 2269 Pattern magicsAsRE; 2270 2271 2274 boolean justFilter; 2275 2276 2277 int position; 2278 2279 2280 LinkedList list; 2281 2282 2283 final int[] newLineTypes; 2284 2285 2291 GuardedReader(InputStream is, boolean justFilter) throws IOException { 2292 this(is, justFilter, null); 2293 } 2294 2295 GuardedReader(InputStream is, boolean justFilter, String encoding) throws IOException { 2296 if (encoding == null) 2297 reader = new InputStreamReader(is); 2298 else 2299 reader = new InputStreamReader(is, encoding); 2300 this.justFilter = justFilter; 2301 position = 0; 2302 list = new LinkedList(); 2303 newLineTypes = new int[] { 0, 0, 0 }; 2304 } 2305 2306 2307 public int read(char[] cbuf, int off, int len) throws IOException { 2308 2309 if (charBuff == null) { 2310 readCharBuff(); 2311 translateToCharBuff(); 2312 } 2313 2314 if (howmany <= 0) { 2315 return -1; 2316 } else { 2317 int min = Math.min(len, howmany); 2318 System.arraycopy(charBuff, position, cbuf, off, min); 2319 howmany -= min; 2320 position += min; 2321 return min; 2322 } 2323 } 2324 2325 2326 final void readCharBuff() throws IOException { 2327 2328 char[] tmp = new char[2048]; 2329 int read; 2330 ArrayList buffs = new ArrayList(20); 2331 2332 for (;;) { 2333 read = readFully(tmp); 2334 buffs.add(tmp); 2335 if (read < 2048) { 2336 break; 2337 } else { 2338 tmp = new char[2048]; 2339 } 2340 } 2341 2342 int listsize = buffs.size() - 1; 2343 int size = listsize * 2048 + read; 2344 readBuff = new char[size]; 2345 charBuff = new char[size]; 2346 int copy = 0; 2347 2348 for (int i = 0; i < listsize; i++) { 2349 char[] tmp2 = (char[]) buffs.get(i); 2350 System.arraycopy(tmp2, 0, readBuff, copy, 2048); 2351 copy += 2048; 2352 } 2353 System.arraycopy(tmp, 0, readBuff, copy, read); 2354 } 2355 2356 2357 final int readFully(final char[] buff) throws IOException { 2358 int read = 0; 2359 int sum = 0; 2360 2361 do { 2362 read = reader.read(buff, sum, buff.length - sum); 2363 sum += read; 2364 } while ((sum < buff.length) && (read > 0)); 2365 2366 return sum + 1; 2367 } 2368 2369 2370 final void translateToCharBuff() { 2371 position = 0; 2372 2373 int charBuffPtr = 0; 2375 int stop = readBuff.length - 1; 2376 2377 int c; 2379 int i = 0; 2381 int lastNewLine = 0; 2383 2384 int fatpos = 0; 2386 final int MAGICLEN = MAGIC_PREFIX.length(); 2387 2388 2389 while (i < stop) { 2392 c = readBuff[i]; 2393 switch (c) { 2394 case (int)'\n': 2395 newLineTypes[NEW_LINE_N]++; 2396 charBuff[charBuffPtr++] = '\n'; 2397 lastNewLine = charBuffPtr; 2398 i++; 2399 break; 2400 case (int)'\r': 2401 int c2 = readBuff[i + 1]; 2402 if (c2 != (int)'\n') { 2403 newLineTypes[NEW_LINE_R]++; 2404 i++; 2405 } else { 2406 i +=2; 2407 newLineTypes[NEW_LINE_RN]++; 2408 } 2409 charBuff[charBuffPtr++] = '\n'; 2410 lastNewLine = charBuffPtr; 2411 break; 2412 2413 default: 2414 charBuff[charBuffPtr++] = readBuff[i++]; 2415 } 2416 2417 switch (fatpos) { 2418 case 0: 2419 if (c == '/') { 2420 fatpos++; 2421 } else { 2422 fatpos = 0; 2423 } 2424 break; 2425 2426 case 1: 2427 if (c == '/') { 2428 fatpos++; 2429 } else { 2430 fatpos = 0; 2431 } 2432 break; 2433 2434 case 2: 2435 if (c == 'G') { 2436 fatpos++; 2437 } else if (c == '/') { 2438 fatpos = 2; } else { 2440 fatpos = 0; 2441 } 2442 break; 2443 2444 case 3: 2445 if (c == 'E') { 2446 fatpos++; 2447 } else { 2448 fatpos = 0; 2449 } 2450 break; 2451 2452 case 4: 2453 if (c == 'N') { 2454 fatpos++; 2455 } else { 2456 fatpos = 0; 2457 } 2458 break; 2459 2460 case 5: 2461 if (c == '-') { 2462 fatpos++; 2463 } else { 2464 fatpos = 0; 2465 } 2466 break; 2467 2468 default: 2469 fatpos = 0; 2470 } 2471 2472 if(fatpos == MAGICLEN) { 2474 fatpos = 0; 2475 Pattern magics = getMagicsAsRE(); 2476 int searchLen = Math.min(LONGEST_ITEM, readBuff.length - i); 2477 CharBuffer chi = CharBuffer.wrap(readBuff, i, searchLen); 2478 Matcher matcher = magics.matcher(chi); 2479 if (matcher.find()) { 2480 String match = matcher.group(); 2481 2482 charBuffPtr -= MAGICLEN; 2483 i += match.length(); 2484 int toNl = toNewLine(i); 2485 int sectionSize=MAGICLEN+match.length()+toNl; 2486 2487 if (!justFilter) { 2488 int type = string2Type(match); 2489 SectionDesc desc = new SectionDesc(type); 2490 desc.begin = lastNewLine; 2491 desc.end = charBuffPtr + sectionSize + 1; 2492 desc.name = new String (readBuff, i, toNl); 2493 list.add(desc); 2494 } 2495 i += toNl; 2496 Arrays.fill(charBuff,charBuffPtr,charBuffPtr+sectionSize,' '); 2497 charBuffPtr+=sectionSize; 2498 } 2499 } 2500 } 2501 2502 if (i == stop) { 2503 c = readBuff[i]; 2504 switch (c) { 2505 case (int)'\n': 2506 newLineTypes[NEW_LINE_N]++; 2507 charBuff[charBuffPtr++] = '\n'; 2508 break; 2509 case (int)'\r': 2510 newLineTypes[NEW_LINE_R]++; 2511 charBuff[charBuffPtr++] = '\n'; 2512 break; 2513 2514 default: 2515 charBuff[charBuffPtr++] = readBuff[i++]; 2516 } 2517 } 2518 2519 if (!justFilter && (list.size() > 0)) { 2521 SectionDesc desc = (SectionDesc) list.getLast(); 2522 if (desc.end > charBuffPtr) { 2523 desc.end = charBuffPtr; 2524 } 2525 } 2526 2527 howmany = charBuffPtr; 2528 readBuff = null; 2529 } 2530 2531 2532 static int string2Type(String match) { 2533 StringBuffer sb = new StringBuffer (MAGIC_PREFIX); 2534 sb.append(match); 2535 match = sb.toString(); 2536 2537 final int len = SECTION_MAGICS.length; 2538 2539 for (int i = 0; i < len; i++) { 2540 if (match.equals(SECTION_MAGICS[i])) { 2541 return i; 2542 } 2543 } 2544 return -1; 2545 } 2546 2547 2548 final int toNewLine(int i) { 2549 int c; 2550 int counter = i; 2551 final int len = readBuff.length; 2552 while (counter < len) { 2553 c = readBuff[counter++]; 2554 if (c == '\r' || c == '\n') { 2555 counter--; 2556 break; 2557 } 2558 } 2559 2560 return counter - i; 2561 } 2562 2563 2564 final Pattern getMagicsAsRE() { 2565 if (magicsAsRE == null) { 2566 magicsAsRE = Pattern.compile(makeOrRegexp()); 2567 } 2568 return magicsAsRE; 2569 } 2570 2571 2572 final String makeOrRegexp() { 2573 StringBuffer sb = new StringBuffer (100); 2574 final int len = MAGIC_PREFIX.length(); 2575 final int slen = SECTION_MAGICS.length - 1; 2576 for (int i = 0; i < slen; i++) { 2577 sb.append(SECTION_MAGICS[i].substring(len)); 2578 sb.append('|'); 2579 } 2580 sb.append(SECTION_MAGICS[slen].substring(len)); 2581 return sb.toString(); 2582 } 2583 2584 2585 byte getNewLineType() { 2586 if (newLineTypes[0] == newLineTypes[1] && 2588 newLineTypes[1] == newLineTypes[2]) { 2589 2590 String s = System.getProperty("line.separator"); 2591 if ("\r".equals(s)) return NEW_LINE_R; 2593 else if ("\r\n".equals(s)) return NEW_LINE_RN; 2595 else 2596 return NEW_LINE_N; 2597 } 2598 if (newLineTypes[0] > newLineTypes[1]) { 2599 return (newLineTypes[0] > newLineTypes[2]) ? (byte) 0 : 2; 2600 } 2601 else { 2602 return (newLineTypes[1] > newLineTypes[2]) ? (byte) 1 : 2; 2603 } 2604 } 2605 2606 2607 public void close() throws IOException { 2608 reader.close(); 2609 } 2610 } 2611 2612 2614 class GuardedWriter extends Writer { 2615 2616 BufferedWriter writer; 2617 2618 2621 Iterator sections; 2622 2623 2626 SectionDesc current; 2627 2628 2631 int offsetCounter; 2632 2633 2634 boolean wasNewLine; 2635 2636 2637 int spaces; 2638 2639 2643 GuardedWriter(OutputStream os, ArrayList list, String encoding) throws IOException { 2644 if (encoding == null) 2645 writer = new BufferedWriter(new OutputStreamWriter(os)); 2646 else 2647 writer = new BufferedWriter(new OutputStreamWriter(os, encoding)); 2648 offsetCounter = 0; 2649 sections = prepareSections(list); 2650 nextSection(); 2651 wasNewLine = false; 2652 } 2653 2654 2655 public void write(char[] cbuf, int off, int len) throws IOException { 2656 for (int i = 0; i < len; i++) { 2657 writeOneChar(cbuf[i + off]); 2658 } 2659 } 2660 2661 2662 public void close() throws IOException { 2663 writer.flush(); 2664 } 2665 2666 2667 public void flush() throws IOException { 2668 writer.flush(); 2669 } 2670 2671 2675 private Iterator prepareSections(ArrayList list) { 2676 LinkedList dest = new LinkedList(); 2677 Collections.sort(list, new GuardedPositionComparator()); 2678 2679 Iterator it = list.iterator(); 2680 while (it.hasNext()) { 2681 GuardedSection o = (GuardedSection) it.next(); 2682 if (o instanceof SimpleSection) { 2683 SectionDesc desc = new SectionDesc(T_LINE); 2684 desc.name = o.name; 2685 desc.begin = ((SimpleSection)o).bounds.getBegin().getOffset(); 2686 desc.end = ((SimpleSection)o).bounds.getEnd().getOffset(); 2687 dest.add(desc); 2688 } 2689 else { 2690 SectionDesc desc = new SectionDesc(T_HEADER); 2691 desc.begin = (((InteriorSection)o).header).getBegin().getOffset(); 2692 desc.end = (((InteriorSection)o).header).getEnd().getOffset(); 2693 desc.name = o.name; 2694 dest.add(desc); 2695 2696 desc = new SectionDesc(T_END); 2697 desc.begin = (((InteriorSection)o).bottom).getBegin().getOffset(); 2698 desc.end = (((InteriorSection)o).bottom).getEnd().getOffset(); 2699 desc.name = o.name; 2700 dest.add(desc); 2701 } 2702 } 2703 return dest.iterator(); 2704 } 2705 2706 2710 void writeOneChar(int b) throws IOException { 2711 if (b == '\r') 2712 return; 2713 2714 if (current != null) { 2715 if (offsetCounter == current.begin) { 2716 wasNewLine = false; 2717 } 2718 if ((b == '\n') && (current.begin <= offsetCounter)) { 2719 switch (current.type) { 2720 case T_LINE: 2721 if (!wasNewLine) { 2722 if (offsetCounter + 1 >= current.end) { 2723 writeMagic(T_LINE, current.name); 2724 nextSection(); 2725 } 2726 else { 2727 writeMagic(T_BEGIN, current.name); 2728 wasNewLine = true; 2729 } 2730 } 2731 else { 2732 if (offsetCounter + 1 >= current.end) { 2733 writeMagic(T_END, current.name); 2734 nextSection(); 2735 } 2736 } 2737 break; 2738 2739 case T_HEADER: 2740 if (!wasNewLine) { 2741 if (offsetCounter + 1 >= current.end) { 2742 writeMagic(T_FIRST, current.name); 2743 nextSection(); 2744 } 2745 else { 2746 writeMagic(T_FIRST, current.name); 2747 wasNewLine = true; 2748 } 2749 } 2750 else { 2751 if (offsetCounter + 1 >= current.end) { 2752 writeMagic(T_HEADEREND, current.name); 2753 nextSection(); 2754 } 2755 } 2756 break; 2757 2758 case T_END: 2759 writeMagic(T_LAST, current.name); 2760 nextSection(); 2761 break; 2762 } 2763 } 2764 } 2765 if (b==' ') 2766 spaces++; 2767 else { 2768 char[] sp=new char[spaces]; 2769 2770 Arrays.fill(sp,' '); 2771 writer.write(sp); 2772 writer.write(b); 2773 spaces=0; 2774 } 2775 offsetCounter++; 2776 } 2777 2778 2781 private void nextSection() { 2782 current = (SectionDesc) (sections.hasNext() ? sections.next() : null); 2783 } 2784 2785 2789 private void writeMagic(int type, String name) throws IOException { 2790 if (!shouldReload) { 2791 shouldReload = spaces != SECTION_MAGICS[type].length() + name.length(); 2792 } 2793 spaces=0; 2794 writer.write(SECTION_MAGICS[type], 0, SECTION_MAGICS[type].length()); 2795 writer.write(name, 0, name.length()); 2796 } 2797 } 2798 2799 2802 private static class NewLineOutputStream extends OutputStream { 2803 2804 OutputStream stream; 2805 2806 2807 byte newLineType; 2808 2809 2813 public NewLineOutputStream(OutputStream stream, byte newLineType) { 2814 this.stream = stream; 2815 this.newLineType = newLineType; 2816 } 2817 2818 2821 public void write(int b) throws IOException { 2822 if (b == '\n') { 2823 switch (newLineType) { 2824 case NEW_LINE_R: 2825 stream.write('\r'); 2826 break; 2827 case NEW_LINE_RN: 2828 stream.write('\r'); 2829 case NEW_LINE_N: 2830 stream.write('\n'); 2831 break; 2832 } 2833 } 2834 else { 2835 stream.write(b); 2836 } 2837 } 2838 } 2839 2840 static class WParsingListener extends WeakReference implements ParsingListener, Runnable { 2841 WParsingListener(ParsingListener orig) { 2842 super(orig, Utilities.activeReferenceQueue()); 2843 } 2844 2845 public void run() { 2846 JavaMetamodel.removeParsingListener(this); 2847 } 2848 2849 ParsingListener getListener() { 2850 Object o = get(); 2851 if (o == null) { 2852 JavaMetamodel.removeParsingListener(this); 2853 } 2854 return (ParsingListener) o; 2855 } 2856 2857 public void resourceParsed(Resource rsc) { 2858 ParsingListener l = getListener(); 2859 if (l != null) 2860 l.resourceParsed(rsc); 2861 } 2862 } 2863 2864 private static class UndoManagerListener implements PropertyChangeListener { 2865 2866 private class ActiveQueueReference extends WeakReference implements Runnable { 2867 public ActiveQueueReference(Object o, ReferenceQueue q) { 2868 super(o, q); 2869 } 2870 2871 public void run() { 2872 UndoManager undo = JavaMetamodel.getUndoManager(); 2873 undo.removePropertyChangeListener(UndoManagerListener.this); 2874 } 2875 } 2876 2877 private WeakReference ref; 2878 2879 UndoManagerListener(JavaEditor editor) { 2880 ref = new ActiveQueueReference(editor, Utilities.activeReferenceQueue()); 2881 } 2882 2883 public void propertyChange(PropertyChangeEvent evt) { 2884 UndoManager undo = JavaMetamodel.getUndoManager(); 2885 JavaEditor editor = (JavaEditor) ref.get(); 2886 if (editor == null) { 2887 undo.removePropertyChangeListener(this); 2888 return; 2889 } 2890 if (undo.isUndoAvailable() || undo.isRedoAvailable()) { 2891 editor.getUndoRedo().discardAllEdits(); 2892 } 2893 } 2894 } 2895} 2896 | Popular Tags |