Index: editor/libsrc/org/netbeans/editor/Annotations.java =================================================================== RCS file: /cvs/editor/libsrc/org/netbeans/editor/Annotations.java,v retrieving revision 1.12 diff -c -r1.12 Annotations.java *** editor/libsrc/org/netbeans/editor/Annotations.java 27 Feb 2003 23:36:14 -0000 1.12 --- editor/libsrc/org/netbeans/editor/Annotations.java 20 Oct 2003 16:44:09 -0000 *************** *** 45,50 **** --- 45,51 ---- import javax.swing.JCheckBoxMenuItem; import java.awt.event.ItemListener; import java.awt.event.ItemEvent; + import javax.swing.SwingUtilities; import org.netbeans.editor.LocaleSupport; import org.netbeans.editor.Settings; import org.netbeans.editor.BaseKit; *************** *** 165,208 **** /** Add annotation */ public void addAnnotation(AnnotationDesc anno) { // create mark for this annotation. One mark can be shared by more annotations MarkChain chain = getLayer().getMarkChain(); try { ! chain.addMark(anno.getOffset()); } catch (BadLocationException e) { ! return; } // attach created mark to annotation ! anno.setMark(chain.getAddedMark()); ! // fine LineAnnotations instance corresponding to the line of this annotation ! // or create new LineAnnotations if this is first annotation on this line ! LineAnnotations lineAnnos = getLineAnnotations(anno.getLine()); if (lineAnnos == null) { ! lineAnnos = new LineAnnotations(); ! lineAnnos.addAnnotation(anno); ! lineAnnotationsByMark.put(anno.getMark(), lineAnnos); ! ! // insert newly created LineAnnotations into sorted array ! boolean inserted = false; ! for (int i=0; i < lineAnnotationsArray.size(); i++) { ! if (((LineAnnotations)lineAnnotationsArray.get(i)).getLine() > lineAnnos.getLine()) { ! lineAnnotationsArray.add(i, lineAnnos); ! inserted = true; ! break; } - } - if (!inserted) - lineAnnotationsArray.add(lineAnnos); ! } ! else { lineAnnos.addAnnotation(anno); - // check whether this mark is in lineAnnotationsByMark Map - // it is possible that Line.Part annotations will have more marks - // for one line - if (lineAnnotationsByMark.get(anno.getMark()) == null) - lineAnnotationsByMark.put(anno.getMark(), lineAnnos); } // add listener on changes of annotation type --- 166,268 ---- /** Add annotation */ public void addAnnotation(AnnotationDesc anno) { + // Should always be run in EQ + if (!SwingUtilities.isEventDispatchThread()) { + throw new IllegalStateException("Must be run in EQ"); // NOI18N + } + // create mark for this annotation. One mark can be shared by more annotations MarkChain chain = getLayer().getMarkChain(); try { ! /* Always adds a fresh mark. It helps to behave well ! * in the following scenario: ! * 1. add annotaion at line e.g. 3. ! * 2. add annotation at line 4. ! * 3. goto begining of line 2. ! * 4. select lines 2,3,4,5 by pressing down arrow. ! * 5. remove selected lines. ! * 6. Undo by ctrl-z. ! * If reusing marks this will result into line selection ! * being at line 2 but gutter marking of annotations ! * being at line 4. ! * It happens because although DocumentLine.updatePositionRef() ! * removes and adds the annotations on modified lines, it does that ! * sequentially for each line so it removes ! * first of the two DocumentLine's annotations ! * and tries to readd it to begining of removed block ! * but it finds there an existing mark ! * from second DocumentLine's annotation. ! * It reuses the mark but as the mark was inside ! * the removed block originally the undo restores its position ! * inside the block. ! * Creation of fresh marks fixes that problem. ! */ ! chain.addMark(anno.getOffset(), true); ! } catch (BadLocationException e) { ! /* ! * This is problematic point. ! * Once this place is reached the annotation desc ! * will have null mark and will ! * not in fact be actively present ! * in the document. ! * Such annotation will then throw NPE ! * in removeAnnotation(). ! * Hopefully causes of getting to this place ! * were eliminated. ! */ ! throw new IllegalStateException("offset=" + anno.getOffset() // NOI18N ! + ", docLen=" + doc.getLength()); // NOI18N } // attach created mark to annotation ! MarkFactory.ChainDrawMark annoMark = chain.getAddedMark(); ! if (annoMark == null) { ! throw new NullPointerException(); ! } ! anno.setMark(annoMark); ! ! // #33165 - different strategy - first trying to search ! // by the mark in the map [mark, lineAnnos]. That should ! // eliminate problems when a mark is tried to be removed ! // from the mark chain a second time. ! // Hopefully this will not cause any other sorts of problems. ! LineAnnotations lineAnnos = (LineAnnotations)lineAnnotationsByMark.get(annoMark); if (lineAnnos == null) { ! // fine LineAnnotations instance corresponding to the line of this annotation ! // or create new LineAnnotations if this is first annotation on this line ! lineAnnos = getLineAnnotations(anno.getLine()); ! if (lineAnnos == null) { ! lineAnnos = new LineAnnotations(); ! lineAnnos.addAnnotation(anno); ! if (lineAnnotationsByMark.put(anno.getMark(), lineAnnos) != null) { ! throw new IllegalStateException("Mark already in the map."); } ! // insert newly created LineAnnotations into sorted array ! boolean inserted = false; ! for (int i=0; i < lineAnnotationsArray.size(); i++) { ! if (((LineAnnotations)lineAnnotationsArray.get(i)).getLine() > lineAnnos.getLine()) { ! lineAnnotationsArray.add(i, lineAnnos); ! inserted = true; ! break; ! } ! } ! if (!inserted) ! lineAnnotationsArray.add(lineAnnos); ! ! } ! else { ! lineAnnos.addAnnotation(anno); ! // check whether this mark is in lineAnnotationsByMark Map ! // it is possible that Line.Part annotations will have more marks ! // for one line ! if (lineAnnotationsByMark.get(anno.getMark()) == null) ! lineAnnotationsByMark.put(anno.getMark(), lineAnnos); ! } ! ! } else { // mark was already in lineAnnotationsByMark map lineAnnos.addAnnotation(anno); } // add listener on changes of annotation type *************** *** 218,239 **** // notify view that it must be redrawn refreshLine(lineAnnos.getLine()); } /** Remove annotation */ public void removeAnnotation(AnnotationDesc anno) { // find LineAnnotations for the mark ! LineAnnotations lineAnnos = (LineAnnotations)lineAnnotationsByMark.get(anno.getMark()); int line = lineAnnos.getLine(); // remove annotation from the line lineAnnos.removeAnnotation(anno); // check if this mark is referenced or not. If not, remove it ! if (!lineAnnos.isMarkStillReferenced(anno.getMark())) { ! lineAnnotationsByMark.remove(anno.getMark()); MarkChain chain = getLayer().getMarkChain(); ! chain.removeMark(anno.getOffset()); } // if there is no more annotations on the line, remove LineAnnotations --- 278,319 ---- // notify view that it must be redrawn refreshLine(lineAnnos.getLine()); + + // System.out.println("AFTER ADD:\n" + dumpLineAnnotationsArray()); } /** Remove annotation */ public void removeAnnotation(AnnotationDesc anno) { + // Should always be run in EQ + if (!SwingUtilities.isEventDispatchThread()) { + throw new IllegalStateException("Must be run in EQ"); // NOI18N + } + // find LineAnnotations for the mark ! MarkFactory.ChainDrawMark annoMark = (MarkFactory.ChainDrawMark)anno.getMark(); ! if (annoMark == null) { ! throw new NullPointerException(); ! } ! ! LineAnnotations lineAnnos = (LineAnnotations)lineAnnotationsByMark.get(annoMark); ! int line = lineAnnos.getLine(); // remove annotation from the line lineAnnos.removeAnnotation(anno); // check if this mark is referenced or not. If not, remove it ! if (!lineAnnos.isMarkStillReferenced(annoMark)) { ! if (lineAnnotationsByMark.remove(annoMark) != lineAnnos) { ! throw new IllegalStateException(); ! } ! MarkChain chain = getLayer().getMarkChain(); ! // Partial fix of #33165 - rather remove mark explicitly than through its offset ! //chain.removeMark(anno.getOffset()); ! if (!chain.removeMark(annoMark)) { ! throw new IllegalStateException("Mark not removed"); // NOI18N ! } } // if there is no more annotations on the line, remove LineAnnotations *************** *** 249,254 **** --- 329,335 ---- // notify view that must be redrawn refreshLine(line); + // System.out.println("AFTER REMOVE:\n" + dumpLineAnnotationsArray()); } /** Finds active annotation for the Mark. It is called from DrawLayer *************** *** 378,383 **** --- 459,465 ---- int changedLine = be.getLine(); + /* #33165 - line in line-annotations handled in a different way LineAnnotations annos; for (int i=0; i changedLine) annos.setLine(annos.getLine()-countOfDeletedLines); } + */ // fire event to AnnotationsListeners that everything should be redraw fireChangedAll(); } *************** *** 398,403 **** --- 481,487 ---- if (countOfInsertedLines == 0) return; + /* #33165 - line in line-annotations handled in a different way int changedLine = be.getLine(); LineAnnotations annos; *************** *** 411,416 **** --- 495,501 ---- } if (current != null) current.setLine(current.getLine()+countOfInsertedLines); + */ // fire event to AnnotationsListeners that everything should be redraw fireChangedAll(); *************** *** 628,633 **** --- 713,741 ---- return createMenu(kit, line, !bkgInit); } + private String dumpAnnotaionDesc(AnnotationDesc ad) { + return "offset=" + ad.getOffset() // NOI18N + + "(ls=" + doc.getParagraphElement(ad.getOffset()).getStartOffset() + + "), line=" + ad.getLine() // NOI18N + + ", type=" + ad.getAnnotationType(); // NOI18N + } + + private String dumpLineAnnotationsArray() { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < lineAnnotationsArray.size(); i++) { + LineAnnotations la = (LineAnnotations)lineAnnotationsArray.get(i); + LinkedList annos = la.annos; + sb.append("[" + i + "]: line=" + la.getLine() // NOI18N + + ", anos:"); // NOI18N + for (int j = 0; j < annos.size(); j++) { + sb.append("\n [" + j + "]: " + dumpAnnotaionDesc((AnnotationDesc)annos.get(j))); // NOI18N + } + sb.append('\n'); + } + return sb.toString(); + } + + /** Manager of all annotations attached to one line. Class stores * the references to all annotations from one line in List and also * stores which annotation is active, count of visible annotations *************** *** 645,662 **** private AnnotationDesc active; /** Line number */ ! private int lineNumber; protected LineAnnotations() { annos = new LinkedList(); annosVisible = new LinkedList(); ! lineNumber = -1; } /** Add annotation to this line and activate it. */ public void addAnnotation(AnnotationDesc anno) { ! if (lineNumber == -1) ! lineNumber = anno.getLine(); annos.add(anno); if (anno.isVisible()) { active = anno; --- 753,770 ---- private AnnotationDesc active; /** Line number */ ! // private int lineNumber; protected LineAnnotations() { annos = new LinkedList(); annosVisible = new LinkedList(); ! // lineNumber = -1; } /** Add annotation to this line and activate it. */ public void addAnnotation(AnnotationDesc anno) { ! // if (lineNumber == -1) ! // lineNumber = anno.getLine(); annos.add(anno); if (anno.isVisible()) { active = anno; *************** *** 682,693 **** /** Getter for the line number property */ public int getLine() { ! return lineNumber; } /** Setter for the line number property */ public void setLine(int line) { ! lineNumber = line; } /** Gets the array of all pasive and visible annotations */ --- 790,806 ---- /** Getter for the line number property */ public int getLine() { ! // #33165 - delegating of getting of the line number to first anno ! return (annos.size() > 0) ! ? ((AnnotationDesc)annos.get(0)).getLine() ! : 0; ! // return lineNumber; } /** Setter for the line number property */ public void setLine(int line) { ! // lineNumber = line; ! throw new IllegalStateException("Setting of line number not allowed"); // NOI18N } /** Gets the array of all pasive and visible annotations */ Index: editor/libsrc/org/netbeans/editor/DrawGraphics.java =================================================================== RCS file: /cvs/editor/libsrc/org/netbeans/editor/DrawGraphics.java,v retrieving revision 1.13.16.1 diff -c -r1.13.16.1 DrawGraphics.java *** editor/libsrc/org/netbeans/editor/DrawGraphics.java 21 Aug 2003 15:11:02 -0000 1.13.16.1 --- editor/libsrc/org/netbeans/editor/DrawGraphics.java 20 Oct 2003 16:44:09 -0000 *************** *** 325,330 **** --- 325,337 ---- private Color underlineColor; private Color waveUnderlineColor; + + /** Whether annotations were drawn on the current line already */ + private int lastDrawnAnnosY; + private int lastDrawnAnnosX; + + /** Annotation description cached for the lastDrawnAnnosY */ + private AnnotationDesc[] passiveAnnosAtY; /** Alpha used for drawing the glyphs on the background */ private AlphaComposite alpha = null; *************** *** 336,341 **** --- 343,350 ---- GraphicsDG(Graphics graphics) { this.graphics = graphics; + // #33165 - set invalid y initially + this.y = -1; } public void setForeColor(Color foreColor) { *************** *** 416,467 **** } private void flush() { ! if (startOffset < 0) { ! return; ! } ! if (startOffset == endOffset) { ! startOffset = -1; ! return; } ! // First possibly fill the rectangle ! fillRectImpl(startX, startY, x - startX); ! ! if (AnnotationTypes.getTypes().isBackgroundDrawing().booleanValue()) { ! ! if (alpha == null) ! alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, AnnotationTypes.getTypes().getBackgroundGlyphAlpha().intValue() / 100f); ! ! AnnotationDesc[] annosArray = annos.getPasiveAnnotations( (int)( (float)startY / (float)lineHeight )); ! int glyphX=2; ! if (annosArray != null) { ! Graphics2D g2d = (Graphics2D) graphics; ! ! Shape shape = graphics.getClip(); ! ! // set alpha composite ! Composite origin = g2d.getComposite(); ! g2d.setComposite(alpha); ! ! // clip the drawing area ! Rectangle r = new Rectangle(startX, startY, x - startX, lineHeight); ! r = r.intersection(shape.getBounds()); ! graphics.setClip(r); ! ! for (int i=0; i < annosArray.length; i++) { ! g2d.drawImage(annosArray[i].getGlyph(), glyphX, startY, null); ! glyphX += annosArray[i].getGlyph().getWidth(null)+1; ! } ! // restore original clip region ! graphics.setClip(shape); ! // restore original ocmposite ! g2d.setComposite(origin); ! } } ! // Check whether the graphics uses right color if (foreColor != gColor) { graphics.setColor(foreColor); --- 425,494 ---- } private void flush() { ! flush(false); ! } ! private void flush(boolean atEOL) { ! if (y < 0) { // not yet initialized ! return ; } + + if (startOffset >= 0 && startOffset != endOffset) { // some text on the line + // First possibly fill the rectangle + fillRectImpl(startX, startY, x - startX); + } + + // #33165 - for each fragment getPasiveAnnotations() was called + // but it can done just once per line. + if (lastDrawnAnnosY != y) { + lastDrawnAnnosY = y; + lastDrawnAnnosX = 0; + if (AnnotationTypes.getTypes().isBackgroundDrawing().booleanValue()) { + if (alpha == null) + alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, AnnotationTypes.getTypes().getBackgroundGlyphAlpha().intValue() / 100f); + + passiveAnnosAtY = annos.getPasiveAnnotations( (int)( (float)y / (float)lineHeight )); + } else { + passiveAnnosAtY = null; + } + } + + int glyphX=2; + if (passiveAnnosAtY != null) { + Graphics2D g2d = (Graphics2D) graphics; + + Shape shape = graphics.getClip(); + + // set alpha composite + Composite origin = g2d.getComposite(); + g2d.setComposite(alpha); + + // clip the drawing area + int endX = atEOL ? Integer.MAX_VALUE : x; + int startX = Math.min(lastDrawnAnnosX, this.startX); + Rectangle r = new Rectangle(startX, y, endX - startX, lineHeight); + lastDrawnAnnosX = endX; + r = r.intersection(shape.getBounds()); + graphics.setClip(r); + + for (int i=0; i < passiveAnnosAtY.length; i++) { + g2d.drawImage(passiveAnnosAtY[i].getGlyph(), glyphX, y, null); + glyphX += passiveAnnosAtY[i].getGlyph().getWidth(null)+1; + } ! // restore original clip region ! graphics.setClip(shape); ! // restore original ocmposite ! g2d.setComposite(origin); ! } ! // If no text on the line then return ! if (startOffset < 0 || startOffset == endOffset) { ! startOffset = -1; ! return; } ! // Check whether the graphics uses right color if (foreColor != gColor) { graphics.setColor(foreColor); *************** *** 590,596 **** } public void eol() { ! flush(); } } --- 617,623 ---- } public void eol() { ! flush(true); } } Index: editor/libsrc/org/netbeans/editor/Mark.java =================================================================== RCS file: /cvs/editor/libsrc/org/netbeans/editor/Mark.java,v retrieving revision 1.10 diff -c -r1.10 Mark.java *** editor/libsrc/org/netbeans/editor/Mark.java 27 Feb 2003 23:36:22 -0000 1.10 --- editor/libsrc/org/netbeans/editor/Mark.java 20 Oct 2003 16:44:09 -0000 *************** *** 83,89 **** + ", class=" + this.getClass()); } ! if (offset < 0 || offset > ldoc.getLength()) { throw new BadLocationException("Invalid offset", offset); } --- 83,89 ---- + ", class=" + this.getClass()); } ! if (offset < 0 || offset > ldoc.getLength() + 1) { // doc.getEndPosition() is valid throw new BadLocationException("Invalid offset", offset); } Index: editor/libsrc/org/netbeans/editor/MarkChain.java =================================================================== RCS file: /cvs/editor/libsrc/org/netbeans/editor/MarkChain.java,v retrieving revision 1.18 diff -c -r1.18 MarkChain.java *** editor/libsrc/org/netbeans/editor/MarkChain.java 27 Feb 2003 23:36:23 -0000 1.18 --- editor/libsrc/org/netbeans/editor/MarkChain.java 20 Oct 2003 16:44:09 -0000 *************** *** 127,141 **** return mark; } - /** Add mark to the chain - * @return true if the mark was added - * false if there's already mark at that pos - */ public boolean addMark(int pos) throws BadLocationException { int rel = compareMark(pos); if (rel == 0) { ! recentlyAddedMark = curMark; ! return false; // already exists } else if (rel > 0) { // curMark after pos MarkFactory.ChainDrawMark mark = createAndInsertNewMark(pos); recentlyAddedMark = mark; --- 127,160 ---- return mark; } public boolean addMark(int pos) throws BadLocationException { + return addMark(pos, false); + } + + /** Add mark to the chain + * @param pos position at which the mark should be added + * @param forceAdd force adding of a fresh mark + * even if the mark at the same position already exists + * @return true if the mark was added + * false if there's already mark at that pos + */ + public boolean addMark(int pos, boolean forceAdd) throws BadLocationException { int rel = compareMark(pos); if (rel == 0) { ! if (forceAdd) { // create fresh ! MarkFactory.ChainDrawMark mark = createAndInsertNewMark(pos); ! recentlyAddedMark = mark; ! if (curMark == chain) { // curMark is first mark ! chain = curMark.insertChain(mark); ! } else { // curMark is not first mark ! curMark.insertChain(mark); ! } ! ! } else { // return existing ! recentlyAddedMark = curMark; ! return false; // already exists ! } ! } else if (rel > 0) { // curMark after pos MarkFactory.ChainDrawMark mark = createAndInsertNewMark(pos); recentlyAddedMark = mark; *************** *** 182,187 **** --- 201,234 ---- } return true; } else { // not found + return false; + } + } + + public boolean removeMark(MarkFactory.ChainDrawMark mark) { + if (mark == null) { + throw new NullPointerException(); + } + + if (curMark != mark) { + // dumb impl + curMark = chain; + while (curMark != null) { + if (curMark == mark) { + break; + } + curMark = curMark.next; + } + } + + if (curMark != null) { + boolean first = (curMark == chain); + curMark = curMark.removeChain(); + if (first) { + chain = curMark; + } + return true; + } else { return false; } } Index: editor/src/org/netbeans/modules/editor/NbEditorDocument.java =================================================================== RCS file: /cvs/editor/src/org/netbeans/modules/editor/NbEditorDocument.java,v retrieving revision 1.33 diff -c -r1.33 NbEditorDocument.java *** editor/src/org/netbeans/modules/editor/NbEditorDocument.java 27 Feb 2003 23:36:38 -0000 1.33 --- editor/src/org/netbeans/modules/editor/NbEditorDocument.java 20 Oct 2003 16:44:10 -0000 *************** *** 41,46 **** --- 41,47 ---- import org.netbeans.editor.Annotations; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; + import java.util.WeakHashMap; import org.netbeans.editor.BaseDocument; import javax.swing.text.BadLocationException; import org.netbeans.editor.AnnotationDesc; *************** *** 73,79 **** /** Map of [Annotation, AnnotationDesc] */ private HashMap annoMap; ! public NbEditorDocument(Class kitClass) { super(kitClass); addStyleToLayerMapping(NbDocument.BREAKPOINT_STYLE_NAME, --- 74,80 ---- /** Map of [Annotation, AnnotationDesc] */ private HashMap annoMap; ! public NbEditorDocument(Class kitClass) { super(kitClass); addStyleToLayerMapping(NbDocument.BREAKPOINT_STYLE_NAME, *************** *** 154,160 **** return (f != null) ? f : super.getFormatter(); } - /** Add annotation to the document. For annotation of whole line * the length parameter can be ignored (specify value -1). * @param startPos position which represent begining --- 155,160 ---- *************** *** 163,172 **** * the whole line will be annotated * @param annotation annotation which is attached to this text */ public void addAnnotation(Position startPos, int length, Annotation annotation) { ! if (annotation.getAnnotationType() != null) { ! AnnotationDesc a = new AnnotationDescDelegate(this, startPos, length, annotation); ! annoMap.put(annotation, a); ! getAnnotations().addAnnotation(a); } } --- 163,193 ---- * the whole line will be annotated * @param annotation annotation which is attached to this text */ public void addAnnotation(Position startPos, int length, Annotation annotation) { ! // partial fix of #33165 - read-locking of the document added ! // BTW should only be invoked in EQ - see NbDocument.addAnnotation() ! readLock(); ! try { ! // Recreate annotation's position to make sure it's in this doc at a valid offset ! int docLen = getLength(); ! int offset = startPos.getOffset(); ! offset = Math.min(offset, docLen); ! try { ! startPos = createPosition(offset); ! } catch (BadLocationException e) { ! startPos = null; // should never happen ! } ! ! if (annoMap.get(annotation) != null) { // already added before ! throw new IllegalStateException("Annotation " + annotation // NOI18N ! + " already added"); // NOI18N ! } ! if (annotation.getAnnotationType() != null) { ! AnnotationDesc a = new AnnotationDescDelegate(this, startPos, length, annotation); ! annoMap.put(annotation, a); ! getAnnotations().addAnnotation(a); ! } ! } finally { ! readUnlock(); } } *************** *** 177,196 **** return; // can't do more as the rest of stacktrace is in openide and ant } ! if (annotation.getAnnotationType() != null) { ! AnnotationDescDelegate a = (AnnotationDescDelegate)annoMap.get(annotation); ! try { ! a.detachListeners(); ! } catch (NullPointerException ex) { ! ErrorManager.getDefault().annotate(ex, ErrorManager.INFORMATIONAL, ! "Editor module received request to remove annotation which does not exist in the document. "+ ! "Cause of this error is either in OpenIDE module or in module which originated the annotation. "+ ! "Annotation class = "+annotation, null, null, null); ! ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); ! return; } ! getAnnotations().removeAnnotation(a); ! annoMap.remove(annotation); } } --- 198,224 ---- return; // can't do more as the rest of stacktrace is in openide and ant } ! // partial fix of #33165 - read-locking of the document added ! // BTW should only be invoked in EQ - see NbDocument.removeAnnotation() ! readLock(); ! try { ! if (annotation.getAnnotationType() != null) { ! AnnotationDescDelegate a = (AnnotationDescDelegate)annoMap.get(annotation); ! try { ! a.detachListeners(); ! } catch (NullPointerException ex) { ! ErrorManager.getDefault().annotate(ex, ErrorManager.INFORMATIONAL, ! "Editor module received request to remove annotation which does not exist in the document. "+ ! "Cause of this error is either in OpenIDE module or in module which originated the annotation. "+ ! "Annotation class = "+annotation, null, null, null); ! ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); ! return; ! } ! getAnnotations().removeAnnotation(a); ! annoMap.remove(annotation); } ! } finally { ! readUnlock(); } } Index: editor/src/org/netbeans/modules/editor/NbToolTip.java =================================================================== RCS file: /cvs/editor/src/org/netbeans/modules/editor/NbToolTip.java,v retrieving revision 1.7 diff -c -r1.7 NbToolTip.java *** editor/src/org/netbeans/modules/editor/NbToolTip.java 27 Feb 2003 23:36:38 -0000 1.7 --- editor/src/org/netbeans/modules/editor/NbToolTip.java 20 Oct 2003 16:44:10 -0000 *************** *** 14,19 **** --- 14,20 ---- package org.netbeans.modules.editor; import javax.swing.text.JTextComponent; + import javax.swing.text.StyledDocument; import javax.swing.text.BadLocationException; import org.openide.filesystems.FileChangeAdapter; import org.openide.filesystems.FileObject; *************** *** 156,184 **** if (tts != null) { BaseDocument doc = Utilities.getDocument(target); if (doc != null) { ! int offset = target.viewToModel(tts.getLastMouseEvent().getPoint()); ! if (offset >= 0) { ! try { ! int line = Utilities.getLineOffset(doc, offset); ! int col = offset - Utilities.getRowStart(target, offset); ! ! DataObject dob = NbEditorUtilities.getDataObject(doc); ! if (dob != null) { ! EditorCookie ec = (EditorCookie)dob.getCookie(EditorCookie.class); ! if (ec != null) { ! Line.Set ls = ec.getLineSet(); ! if (ls != null) { ! Line l = ls.getCurrent(line); ! if (l != null) { ! Line.Part lp = l.createPart(col, 0); ! if (lp != null) { ! new Request(annos, lp, tts).run(); } } } } } - } catch (BadLocationException e) { } } } --- 157,201 ---- if (tts != null) { BaseDocument doc = Utilities.getDocument(target); if (doc != null) { ! DataObject dob = NbEditorUtilities.getDataObject(doc); ! if (dob != null) { ! EditorCookie ec = (EditorCookie)dob.getCookie(EditorCookie.class); ! if (ec != null) { ! StyledDocument openedDoc; ! try { ! openedDoc = ec.openDocument(); ! } catch (IOException e) { ! openedDoc = null; // should return in next if stmt ! } ! ! if (openedDoc != doc) { // doc has changed in meantime ! return; ! } ! ! // partial fix of #33165 - read-locking of the document added ! doc.readLock(); ! try { ! int offset = target.viewToModel(tts.getLastMouseEvent().getPoint()); ! if (offset >= 0) { ! try { ! int line = Utilities.getLineOffset(doc, offset); ! int col = offset - Utilities.getRowStart(target, offset); ! Line.Set ls = ec.getLineSet(); ! if (ls != null) { ! Line l = ls.getCurrent(line); ! if (l != null) { ! Line.Part lp = l.createPart(col, 0); ! if (lp != null) { ! new Request(annos, lp, tts).run(); ! } } } + } catch (BadLocationException e) { } } + } finally { + doc.readUnlock(); } } } } Index: java/src/org/netbeans/modules/java/JavaEditor.java =================================================================== RCS file: /cvs/java/src/org/netbeans/modules/java/JavaEditor.java,v retrieving revision 1.138.4.2.6.1 diff -c -r1.138.4.2.6.1 JavaEditor.java *** java/src/org/netbeans/modules/java/JavaEditor.java 5 Sep 2003 14:15:05 -0000 1.138.4.2.6.1 --- java/src/org/netbeans/modules/java/JavaEditor.java 20 Oct 2003 16:44:12 -0000 *************** *** 423,430 **** } private void processAnnotations(ParserMessage[] errors) { ! ArrayList added,removed,unchanged; ! Iterator i; Collection newAnnotations; if (errors==null) { // request processed by someone else ErrorManager.getDefault().log("request for "+findDataObject().getPrimaryFile().getPath()+" processed by someone else"); --- 423,429 ---- } private void processAnnotations(ParserMessage[] errors) { ! ArrayList added,removed,unchanged; Collection newAnnotations; if (errors==null) { // request processed by someone else ErrorManager.getDefault().log("request for "+findDataObject().getPrimaryFile().getPath()+" processed by someone else"); *************** *** 440,454 **** removed.removeAll(newAnnotations); detachAnnotations(removed); if (!added.isEmpty() && isDocumentLoaded()) { ! LineCookie cookie = (LineCookie)findDataObject().getCookie(LineCookie.class); ! Line.Set lines = cookie.getLineSet(); ! ! for (i=added.iterator();i.hasNext();) { ! ParserAnnotation ann=(ParserAnnotation)i.next(); ! ! ann.attachToLineSet(lines); } } annotations=unchanged; annotations.addAll(added); } --- 439,468 ---- removed.removeAll(newAnnotations); detachAnnotations(removed); if (!added.isEmpty() && isDocumentLoaded()) { ! ! // Partial fix of #33165 - document read-locking ! final ArrayList finalAdded = added; ! StyledDocument doc = getDocument(); ! Runnable docRenderer = new Runnable() { ! public void run() { ! LineCookie cookie = (LineCookie)findDataObject().getCookie(LineCookie.class); ! Line.Set lines = cookie.getLineSet(); ! ! for (Iterator i=finalAdded.iterator();i.hasNext();) { ! ParserAnnotation ann=(ParserAnnotation)i.next(); ! ! ann.attachToLineSet(lines); ! } ! } ! }; ! ! if (doc != null) { ! doc.render(docRenderer); ! } else { ! docRenderer.run(); } } + annotations=unchanged; annotations.addAll(added); } Index: openide/src/org/openide/text/CloneableEditorSupport.java =================================================================== RCS file: /cvs/openide/src/org/openide/text/CloneableEditorSupport.java,v retrieving revision 1.81.2.2.2.1 diff -c -r1.81.2.2.2.1 CloneableEditorSupport.java *** openide/src/org/openide/text/CloneableEditorSupport.java 7 Oct 2003 03:07:57 -0000 1.81.2.2.2.1 --- openide/src/org/openide/text/CloneableEditorSupport.java 20 Oct 2003 16:44:16 -0000 *************** *** 82,87 **** --- 82,92 ---- /** Common name for editor mode. */ public static final String EDITOR_MODE = "editor"; // NOI18N + private static final int DOCUMENT_NO = 0; + private static final int DOCUMENT_LOADING = 1; + private static final int DOCUMENT_READY = 2; + private static final int DOCUMENT_RELOADING = 3; + /** Flag saying if the CloneableEditorSupport handles already the UserQuestionException*/ private boolean inUserQuestionExceptionHandler; *************** *** 137,143 **** /** position manager */ private PositionRef.Manager positionManager; ! /** The string which will be appended to the name of top component * when top component becomes modified */ // protected String modifiedAppendix = " *"; // NOI18N --- 142,148 ---- /** position manager */ private PositionRef.Manager positionManager; ! /** The string which will be appended to the name of top component * when top component becomes modified */ // protected String modifiedAppendix = " *"; // NOI18N *************** *** 161,166 **** --- 166,175 ---- /** Support for property change listeners*/ private PropertyChangeSupport propertyChangeSupport; + private int documentStatus = DOCUMENT_NO; + + private RuntimeException prepareDocumentRuntimeException; + /** Creates new CloneableEditorSupport attached to given environment. * * @param env environment that is source of all actions around the *************** *** 234,246 **** return positionManager; } ! ! /** Overrides superclass method, first processes document preparation. * @see #prepareDocument */ public void open() { ! prepareDocument().waitFinished(); ! super.open(); } // --- 243,259 ---- return positionManager; } ! /** Overrides superclass method, first processes document preparation. * @see #prepareDocument */ public void open() { ! try { ! openDocument(); ! super.open(); ! } catch (IOException e) { ! ErrorManager.getDefault().notify( ! ErrorManager.INFORMATIONAL, e); ! } } // *************** *** 266,272 **** } /** Report a bound property update to any registered listeners. ! * @param propertyName the programmatic name of the property that was changed. * @param oldValue rhe old value of the property. * @param newValue the new value of the property. * @since 3.40 --- 279,285 ---- } /** Report a bound property update to any registered listeners. ! * @param propertyName the programmatic name of the property that was changed. * @param oldValue rhe old value of the property. * @param newValue the new value of the property. * @since 3.40 *************** *** 298,363 **** * @return task for control over loading */ public Task prepareDocument() { ! return prepareDocument(false); } /** @param clearDocument indicates whether the document is needed * to clear before (used for reloading) */ private Task prepareDocument(final boolean clearDocument) { ! // first test is done outside of getLock block because the getLock ! // can be held for a long time ! Task t = prepareTask; ! if (t != null) { ! return t; ! } ! ! synchronized (getLock ()) { ! if (prepareTask != null) ! return prepareTask; ! // listen to modifications on env, but remove ! // previous instance first ! env.removePropertyChangeListener(getListener()); ! env.addPropertyChangeListener(getListener()); ! // after call to this method the originalDoc and kit are initialized ! // in spite of that the document is not yet fully read in ! kit = createEditorKit (); ! if (doc == null) { ! doc = createStyledDocument (kit); ! } ! // The thread nume should be: "Loading document " + env; // NOI18N ! prepareTask = RequestProcessor.getDefault().post(new Runnable () { ! public void run () { try { ! synchronized (getLock ()) { if(clearDocument) { // #24676. Reloading: Put positions into memory // and fire document is closing (little trick // to detach annotations). getPositionManager().documentClosed(); fireDocumentChange(doc, true); clearDocument(); } ! // uses the listener's run method to initialize whole document loadTask = new Task(getListener()); loadTask.run (); ! } fireDocumentChange(doc, false); } catch (RuntimeException t) { t.printStackTrace(); throw t; } } ! }); ! return prepareTask; ! } } /** Clears the doc document. Helper method. */ --- 311,435 ---- * @return task for control over loading */ public Task prepareDocument() { ! synchronized (getLock()) { ! switch (documentStatus) { ! case DOCUMENT_NO: ! documentStatus = DOCUMENT_LOADING; ! return prepareDocument(false); ! ! default: ! if (prepareTask == null) { // should never happen ! throw new IllegalStateException(); ! } ! return prepareTask; ! } ! } } + /** @param clearDocument indicates whether the document is needed * to clear before (used for reloading) */ private Task prepareDocument(final boolean clearDocument) { ! if (prepareTask != null) ! return prepareTask; ! // listen to modifications on env, but remove ! // previous instance first ! env.removePropertyChangeListener(getListener()); ! env.addPropertyChangeListener(getListener()); ! // after call to this method the originalDoc and kit are initialized ! // in spite of that the document is not yet fully read in ! kit = createEditorKit (); ! if (doc == null) { ! doc = createStyledDocument (kit); ! } ! final StyledDocument docToLoad = doc; ! ! // The thread nume should be: "Loading document " + env; // NOI18N ! prepareTask = RequestProcessor.getDefault().post(new Runnable () { ! ! private boolean runningInAtomicLock; ! ! public void run () { ! ! // Run the operations under atomic lock primarily due ! // to reload which occurs in a widely published document instance ! // where another threads may operate already ! if (!runningInAtomicLock) { ! runningInAtomicLock = true; ! NbDocument.runAtomic(docToLoad, this); ! ! // Add undoable listener after atomic change has finished ! synchronized (getLock()) { ! if (doc == docToLoad) { // document still valid ! doc.addUndoableEditListener(getUndoRedo()); ! } ! } ! return; ! } ! ! // Prevent operating on top of no longer active document ! synchronized (getLock()) { ! // Check whether the document to be loaded was not closed ! if (doc != docToLoad) { ! return; // do not load closed document ! } ! ! prepareDocumentRuntimeException = null; ! int targetStatus = DOCUMENT_NO; // be pesimistic initially try { ! // synchronized (getLock ()) { if(clearDocument) { + // document no longer valid here + documentStatus = DOCUMENT_RELOADING; + // #24676. Reloading: Put positions into memory // and fire document is closing (little trick // to detach annotations). getPositionManager().documentClosed(); + + updateLineSet(true); + fireDocumentChange(doc, true); clearDocument(); } ! // uses the listener's run method to initialize whole document loadTask = new Task(getListener()); loadTask.run (); ! // } ! ! // assign before fireDocumentChange() as listener should be able to access getDocument() ! documentStatus = DOCUMENT_READY; fireDocumentChange(doc, false); + + // Confirm that whole loading succeeded + targetStatus = DOCUMENT_READY; + } catch (RuntimeException t) { + prepareDocumentRuntimeException = t; t.printStackTrace(); throw t; + + } finally { + + synchronized (getLock()) { + documentStatus = targetStatus; + + getLock().notifyAll(); + } } + } ! } ! }); ! return prepareTask; } /** Clears the doc document. Helper method. */ *************** *** 389,405 **** * @exception IOException if the document could not be loaded */ public StyledDocument openDocument () throws IOException { ! for (;;) { ! // load the document ! prepareDocument ().waitFinished (); ! IOException loadExc = getListener().checkLoadException(); ! if (loadExc != null) { ! throw loadExc; ! } ! ! StyledDocument d = doc; ! if (d != null) ! return d; } } --- 461,509 ---- * @exception IOException if the document could not be loaded */ public StyledDocument openDocument () throws IOException { ! synchronized (getLock()) { ! return openDocumentCheckIOE(); ! } ! } ! ! private StyledDocument openDocumentCheckIOE() throws IOException { ! StyledDocument doc = openDocumentImpl(); ! ! IOException ioe = getListener().checkLoadException(); ! if (ioe != null) { ! throw ioe; ! } ! ! return doc; ! } ! ! /** ! * Must be called under getLock(). ! */ ! private StyledDocument openDocumentImpl() { ! switch (documentStatus) { ! case DOCUMENT_NO: ! documentStatus = DOCUMENT_LOADING; ! prepareDocument(false); ! return openDocumentImpl(); ! ! case DOCUMENT_RELOADING: // proceed to DOCUMENT_READY ! case DOCUMENT_READY: ! return doc; ! ! default: // loading ! try { ! getLock().wait(); ! } catch (InterruptedException e) { ! ErrorManager.getDefault().notify( ! ErrorManager.INFORMATIONAL, e); ! } ! ! if (prepareDocumentRuntimeException != null) { ! throw prepareDocumentRuntimeException; ! } ! ! return openDocumentImpl(); } } *************** *** 409,429 **** * @return document or null if it is not yet loaded */ public StyledDocument getDocument () { ! // XXX #16048. In case there is called this method from loadTask ! // (possible only via LineListener->DocumentLine..). ! // PENDING Needs to be tried to redesign DocumentLine to avoid this. ! if(LOCAL_LOAD_TASK.get() != null) { ! return doc; ! } ! ! for (;;) { ! Task t = loadTask; ! if (t != null) { ! // if an task exists ! t.waitFinished (); ! return doc; ! } else { ! return null; } } } --- 513,538 ---- * @return document or null if it is not yet loaded */ public StyledDocument getDocument () { ! synchronized (getLock()) { ! while (true) { ! switch (documentStatus) { ! case DOCUMENT_NO: ! return null; ! ! default: // ready, loading or reloading ! // XXX #16048. In case there is called this method from loadTask ! // (possible only via LineListener->DocumentLine..). ! // PENDING Needs to be tried to redesign DocumentLine to avoid this. ! if (LOCAL_LOAD_TASK.get() != null) { ! return doc; ! } ! ! try { ! return openDocumentCheckIOE(); ! } catch (IOException e) { ! return null; ! } ! } } } } *************** *** 846,911 **** * by calling prepareDocument(). */ protected Task reloadDocument() { ! synchronized (getLock ()) { ! if (doc != null) { ! // UndoManager must be detached from document here because it will be attached in loadDocument() ! doc.removeUndoableEditListener (getUndoRedo ()); ! // Remember caret positions in all opened panes ! final JEditorPane[] panes = getOpenedPanes(); ! final int[] carets; ! if (panes != null) { ! carets = new int[panes.length]; ! for(int i = 0; i < panes.length; i++) { ! carets[i] = panes[i].getCaretPosition(); ! } ! } else { ! carets = new int[0]; } ! ! prepareTask = null; // make sure new loading will occur ! final Task docLoadTask = prepareDocument(true); ! ! docLoadTask.addTaskListener( ! new TaskListener() { ! public void taskFinished (Task task) { ! //Bugfix #12338: This Swing code replanned to AWT thread ! SwingUtilities.invokeLater(new Runnable() { ! public void run () { ! if (panes != null) { ! for (int i = 0; i < panes.length; i++) { ! // #26407 Adjusts caret position, ! // (reloaded doc could be shorter). ! int textLength = panes[i].getText().length(); ! if(carets[i] > textLength) { ! carets[i] = textLength; ! } ! ! panes[i].setCaretPosition(carets[i]); } } - getUndoRedo().discardAllEdits(); // reset undo manager - // Insert before-save undo event to enable unmodifying undo - getUndoRedo().undoableEditHappened( - new UndoableEditEvent( - CloneableEditorSupport.this, - new BeforeSaveEdit(lastSaveTime) - ) - ); - - notifyUnmodified (); - updateLineSet(true); } ! }); ! docLoadTask.removeTaskListener(this); ! } ! } ! ); ! ! ! return docLoadTask; ! } } ! return prepareDocument(); } --- 955,1020 ---- * by calling prepareDocument(). */ protected Task reloadDocument() { ! if (doc != null) { ! // UndoManager must be detached from document here because it will be attached in loadDocument() ! doc.removeUndoableEditListener (getUndoRedo ()); ! // Remember caret positions in all opened panes ! final JEditorPane[] panes = getOpenedPanes(); ! final int[] carets; ! if (panes != null) { ! carets = new int[panes.length]; ! for(int i = 0; i < panes.length; i++) { ! carets[i] = panes[i].getCaretPosition(); } ! } else { ! carets = new int[0]; ! } ! ! documentStatus = DOCUMENT_RELOADING; ! ! prepareTask = null; // make sure new loading will occur ! final Task docLoadTask = prepareDocument(true); ! ! docLoadTask.addTaskListener( ! new TaskListener() { ! public void taskFinished (Task task) { ! //Bugfix #12338: This Swing code replanned to AWT thread ! SwingUtilities.invokeLater(new Runnable() { ! public void run () { ! if (panes != null) { ! for (int i = 0; i < panes.length; i++) { ! // #26407 Adjusts caret position, ! // (reloaded doc could be shorter). ! int textLength = panes[i].getText().length(); ! if(carets[i] >= textLength) { ! carets[i] = textLength-1; } + + panes[i].setCaretPosition(carets[i]); } } ! getUndoRedo().discardAllEdits(); // reset undo manager ! // Insert before-save undo event to enable unmodifying undo ! getUndoRedo().undoableEditHappened( ! new UndoableEditEvent( ! CloneableEditorSupport.this, ! new BeforeSaveEdit(lastSaveTime) ! ) ! ); ! ! notifyUnmodified (); ! updateLineSet(true); ! } ! }); ! docLoadTask.removeTaskListener(this); ! } ! } ! ); ! ! ! return docLoadTask; } ! return prepareDocument(); } *************** *** 1097,1110 **** * @return the set */ Line.Set updateLineSet (boolean clear) { ! synchronized(LOCK_LINE_SET) { if(lineSet != null && !clear) { return lineSet; } Line.Set oldSet = lineSet; ! if (doc == null) { lineSet = new EditorSupportLineSet.Closed(CloneableEditorSupport.this); } else { lineSet = new EditorSupportLineSet(CloneableEditorSupport.this, doc); --- 1206,1219 ---- * @return the set */ Line.Set updateLineSet (boolean clear) { ! synchronized(getLock()) { if(lineSet != null && !clear) { return lineSet; } Line.Set oldSet = lineSet; ! if (doc == null || documentStatus == DOCUMENT_RELOADING) { lineSet = new EditorSupportLineSet.Closed(CloneableEditorSupport.this); } else { lineSet = new EditorSupportLineSet(CloneableEditorSupport.this, doc); *************** *** 1168,1175 **** } finally { is.close (); } - // attach undo/redo manager - doc.addUndoableEditListener (getUndoRedo ()); } catch (IOException ex) { aProblem = ex; throw ex; --- 1277,1282 ---- *************** *** 1207,1240 **** /** Clears all data from memory. */ private void closeDocument () { ! for (;;) { ! Task prep; ! ! synchronized (getLock()) { ! if (doc == null) { ! return; ! } ! ! if (loadTask == null) { ! return; ! } ! ! prep = prepareTask; ! if (prep == null) { ! return; ! } ! ! if (prep.isFinished ()) { ! doCloseDocument (); ! return; } } - - /* Wait for loading task to be finished - * so that the document etc. stays valid - * during the load operation. - */ - prep.waitFinished(); } } --- 1314,1335 ---- /** Clears all data from memory. */ private void closeDocument () { ! synchronized (getLock()) { ! while (true) { ! switch (documentStatus) { ! case DOCUMENT_NO: ! return; ! ! case DOCUMENT_LOADING: ! case DOCUMENT_RELOADING: ! openDocumentImpl(); ! break; // try to close again ! ! default: ! doCloseDocument(); ! return; } } } } *************** *** 1256,1284 **** if (positionManager != null) { positionManager.documentClosed (); fireDocumentChange(doc, true); } doc = null; kit = null; updateLineSet (true); } /** Handles the actual reload of document. * @param doReload false if we should first ask the user */ private void checkReload(boolean doReload) { ! StyledDocument doc = this.doc; ! ! if (doc == null) { ! return; } ! if (!doReload && !reloadDialogOpened) { String msg = NbBundle.getMessage (CloneableEditorSupport.class, "FMT_External_change", // NOI18N ! doc.getProperty (javax.swing.text.Document.TitleProperty) ); NotifyDescriptor nd = new NotifyDescriptor.Confirmation(msg, NotifyDescriptor.YES_NO_OPTION); --- 1351,1388 ---- if (positionManager != null) { positionManager.documentClosed (); + + documentStatus = DOCUMENT_NO; fireDocumentChange(doc, true); } + + documentStatus = DOCUMENT_NO; doc = null; kit = null; updateLineSet (true); + } /** Handles the actual reload of document. * @param doReload false if we should first ask the user */ private void checkReload(boolean doReload) { ! StyledDocument d; ! synchronized (getLock()) { ! switch (documentStatus) { ! case DOCUMENT_NO: ! return; // return if no document loaded ! } ! ! d = doc; // used with reload dialog - should not be null } ! if (!doReload && !reloadDialogOpened) { String msg = NbBundle.getMessage (CloneableEditorSupport.class, "FMT_External_change", // NOI18N ! d.getProperty (javax.swing.text.Document.TitleProperty) ); NotifyDescriptor nd = new NotifyDescriptor.Confirmation(msg, NotifyDescriptor.YES_NO_OPTION); *************** *** 1294,1312 **** } } ! if (doReload) { ! //Bugfix #9612: Call of reloadDocument() is now posted to ! //RequestProcessor ! RequestProcessor.getDefault().post(new Runnable() { ! public void run () { ! reloadDocument(); ! } ! }); } } - - /** Creates netbeans document for a given document. * @param d document to use as underlaying one * @return styled document that could support Guarded.ATTRIBUTE --- 1398,1433 ---- } } ! synchronized (getLock()) { ! switch (documentStatus) { ! case DOCUMENT_NO: ! return; // return if no document loaded ! ! case DOCUMENT_LOADING: ! case DOCUMENT_RELOADING: ! openDocumentImpl(); // finish opening first ! break; ! } ! ! if (doReload) { ! // #33165 ! // reloadDocument() itself should be fast and the task ! // that it returns is scheduled to RP automatically ! reloadDocument(); ! ! /* #33165 - not posting to RP, reason is above ! //Bugfix #9612: Call of reloadDocument() is now posted to ! //RequestProcessor ! RequestProcessor.getDefault().post(new Runnable() { ! public void run () { ! reloadDocument().waitFinished(); ! } ! }); ! */ ! } } } /** Creates netbeans document for a given document. * @param d document to use as underlaying one * @return styled document that could support Guarded.ATTRIBUTE *************** *** 1359,1371 **** // of CloneableTopCoponent then CloneableEditor could be in allEditors. /** Opens a CloneableEditor component. */ private CloneableEditor openEditorComponent() { synchronized (getLock()) { ! CloneableEditor ce = getAnyEditor(); ! if(ce != null) { ! ce.open(); ! return ce; ! } else { // no opened editor String msg = messageOpening (); if (msg != null) { --- 1480,1491 ---- // of CloneableTopCoponent then CloneableEditor could be in allEditors. /** Opens a CloneableEditor component. */ private CloneableEditor openEditorComponent() { + CloneableEditor ce = null; + boolean displayMsgOpened = false; synchronized (getLock()) { ! ce = getAnyEditor(); ! if(ce == null) { // no opened editor String msg = messageOpening (); if (msg != null) { *************** *** 1378,1393 **** ce = createCloneableEditor (); initializeCloneableEditor(ce); ce.setReference(allEditors); ! ce.open(); ! msg = messageOpened (); ! if (msg == null) { ! msg = ""; // NOI18N ! } ! StatusDisplayer.getDefault().setStatusText(msg); ! return ce; } } } /** If one or more editors are opened finds one. --- 1498,1521 ---- ce = createCloneableEditor (); initializeCloneableEditor(ce); ce.setReference(allEditors); ! ! // signal opened msg should be displayed after subsequent open finishes ! displayMsgOpened = true; ! } ! } ! // #36601 - open moved outside getLock() synchronization ! ce.open(); ! ! if (displayMsgOpened) { ! String msg = messageOpened (); ! if (msg == null) { ! msg = ""; // NOI18N } + StatusDisplayer.getDefault().setStatusText(msg); } + + return ce; } /** If one or more editors are opened finds one. *************** *** 1467,1473 **** /** Access to lock on operations on the support */ ! Object getLock () { return allEditors; } --- 1595,1601 ---- /** Access to lock on operations on the support */ ! final Object getLock () { return allEditors; } *************** *** 1544,1550 **** * It resets loadExc to null. */ public IOException checkLoadException() { IOException ret = loadExc; ! loadExc = null; return ret; } --- 1672,1678 ---- * It resets loadExc to null. */ public IOException checkLoadException() { IOException ret = loadExc; ! // loadExc = null; return ret; } *************** *** 1615,1621 **** /** Initialization of the document. */ public void run () { ! synchronized (getLock ()) { /* Remove existing listener before running the loading task * This should prevent firing of insertUpdate() during load (or reload) * which can prevent dedloks that sometimes occured during file reload. --- 1743,1749 ---- /** Initialization of the document. */ public void run () { ! // synchronized (getLock ()) { /* Remove existing listener before running the loading task * This should prevent firing of insertUpdate() during load (or reload) * which can prevent dedloks that sometimes occured during file reload. *************** *** 1646,1652 **** // Start listening on changes in document doc.addDocumentListener(getListener()); } ! } } --- 1774,1780 ---- // Start listening on changes in document doc.addDocumentListener(getListener()); } ! // } } Index: openide/src/org/openide/text/DocumentLine.java =================================================================== RCS file: /cvs/openide/src/org/openide/text/DocumentLine.java,v retrieving revision 1.47 diff -c -r1.47 DocumentLine.java *** openide/src/org/openide/text/DocumentLine.java 13 Jun 2002 12:47:58 -0000 1.47 --- openide/src/org/openide/text/DocumentLine.java 20 Oct 2003 16:44:16 -0000 *************** *** 17,23 **** import java.util.*; import javax.swing.text.*; import javax.swing.event.*; - import javax.swing.SwingUtilities; import org.openide.ErrorManager; import org.openide.loaders.DataObject; --- 17,22 ---- *************** *** 287,293 **** try { if (!anno.isInDocument()) { anno.setInDocument(true); ! NbDocument.addAnnotation (doc, pos.getPosition(), -1, anno); } } catch (IOException ex) { ErrorManager.getDefault ().notify ( ErrorManager.EXCEPTION, ex); --- 286,295 ---- try { if (!anno.isInDocument()) { anno.setInDocument(true); ! // #33165 - find position that is surely at begining of line ! FindAnnotationPosition fap = new FindAnnotationPosition(doc, pos.getPosition()); ! doc.render(fap); ! NbDocument.addAnnotation (doc, fap.getAnnotationPosition(), -1, anno); } } catch (IOException ex) { ErrorManager.getDefault ().notify ( ErrorManager.EXCEPTION, ex); *************** *** 316,332 **** * removed. * @since 1.27 */ void attachDetachAnnotations(StyledDocument doc, boolean closing) { java.util.List list = getAnnotations(); for (int i=0; i correct + try { + annoPos = doc.createPosition(lineStartOffset); + } catch (BadLocationException e) { + throw new IllegalArgumentException(); // should never fail + } + } + } + + Position getAnnotationPosition() { + return annoPos; + } + + } + public String getText() { ! final StyledDocument doc = pos.getCloneableEditorSupport ().getDocument (); // document is not opened if (doc == null) return null; + final String[] retStringArray = new String[1]; + doc.render(new Runnable() { public void run() { + // Part of #33165 - the following code is wrapped by doc.render() int lineNumber = getLineNumber(); int lineStart = NbDocument.findLineOffset(doc, lineNumber); // #24434: Check whether the next line exists *************** *** 362,372 **** } try { ! return doc.getText(lineStart, lineEnd - lineStart); } catch (BadLocationException ex) { ErrorManager.getDefault ().notify ( ErrorManager.EXCEPTION, ex); ! return null; } } /** Attach created Line.Part to the parent Line */ --- 409,422 ---- } try { ! retStringArray[0] = doc.getText(lineStart, lineEnd - lineStart); } catch (BadLocationException ex) { ErrorManager.getDefault ().notify ( ErrorManager.EXCEPTION, ex); ! retStringArray[0] = null; } + // End of the code wrapped by doc.render() + }}); + return retStringArray[0]; } /** Attach created Line.Part to the parent Line */ *************** *** 396,401 **** --- 446,497 ---- i++; } } + + // #33165 - fix the position in the positionRef in case this line changes + // and reattach the annotations. + // The fix of #32764 in notifyMove() would only reattach + // the annotations in case the position does not go at a line begining + // after the modification but that is not enough + // to fix undo-related issues. + Position p; + try { + p = pos.getPosition(); + } catch (IOException ex) { + ErrorManager.getDefault ().notify ( ErrorManager.EXCEPTION, ex); + p = null; + } + + if (p != null) { + int lineStartOffset = doc.getParagraphElement(p.getOffset()).getStartOffset(); + CloneableEditorSupport support = pos.getCloneableEditorSupport(); + // Recreate positionRef unconditionally to avoid undo problems + pos = new PositionRef( + support.getPositionManager(), lineStartOffset, Position.Bias.Forward + ); + + List annos = getAnnotations(); + int annosSize = annos.size(); + if (annosSize > 0) { + try { + p = pos.getPosition(); + } catch (IOException e) { + throw new IllegalArgumentException(); // should not fail + } + + for (int i=0; ipos the way it points at the start of line. */ private void updatePositionRef() { ! CloneableEditorSupport support = pos.getCloneableEditorSupport(); int startOffset = NbDocument.findLineOffset(support.getDocument(), getLineNumber()); if(pos.getOffset() != startOffset) { pos = new PositionRef( support.getPositionManager(), startOffset, Position.Bias.Forward ); } } --- 505,546 ---- /** Updates pos the way it points at the start of line. */ private void updatePositionRef() { ! // #33165 - Moved handling that follows into notifyChange() ! // due to problems with undo operations. ! // Rest of notifyMove() should work as the code in notifyChange() ! // in fact includes the same work as done here and notifyChange() ! // is called before notifyMove() ! // (see linesChanged()/linesMoved() in LineListener). ! ! /* CloneableEditorSupport support = pos.getCloneableEditorSupport(); int startOffset = NbDocument.findLineOffset(support.getDocument(), getLineNumber()); + if(pos.getOffset() != startOffset) { pos = new PositionRef( support.getPositionManager(), startOffset, Position.Bias.Forward ); + + // fix of #32764 + List annos = getAnnotations(); + for (int i=0; inull. */ public static int findLineNumber (StyledDocument doc, int offset) { + /* pre-33165 Element paragraphsParent = findLineRootElement (doc); return paragraphsParent.getElementIndex (offset); + */ + + return new DocumentRenderer(DocumentRenderer.FIND_LINE_NUMBER, doc, offset).renderToInt(); } /** Finds column number given an offset. *************** *** 105,113 **** --- 109,120 ---- * is null. */ public static int findLineColumn (StyledDocument doc, int offset) { + /* Element paragraphsParent = findLineRootElement (doc); int indx = paragraphsParent.getElementIndex (offset); return offset - paragraphsParent.getElement (indx).getStartOffset (); + */ + return new DocumentRenderer(DocumentRenderer.FIND_LINE_COLUMN, doc, offset).renderToInt(); } /** Finds offset of the beginning of a line. *************** *** 120,125 **** --- 127,133 ---- * lineNumber value is inserted */ public static int findLineOffset (StyledDocument doc, int lineNumber) { + /* Element paragraphsParent = findLineRootElement (doc); Element line = paragraphsParent.getElement (lineNumber); *************** *** 129,134 **** --- 137,145 ---- } return line.getStartOffset (); + */ + + return new DocumentRenderer(DocumentRenderer.FIND_LINE_OFFSET, doc, lineNumber).renderToInt(); } /** Creates position with a bias. If the bias is {@link javax.swing.text.Position.Bias#Backward} *************** *** 573,577 **** * @param annotation annotation which is going to be removed */ public void removeAnnotation(Annotation annotation); } ! } --- 584,648 ---- * @param annotation annotation which is going to be removed */ public void removeAnnotation(Annotation annotation); } ! ! private static final class DocumentRenderer implements Runnable { ! ! private static final int FIND_LINE_NUMBER = 0; ! private static final int FIND_LINE_COLUMN = 1; ! private static final int FIND_LINE_OFFSET = 2; ! ! private StyledDocument doc; ! ! private int opCode; ! ! private int argInt; ! ! private int retInt; ! ! DocumentRenderer(int opCode, StyledDocument doc, int argInt) { ! this.opCode = opCode; ! this.doc = doc; ! this.argInt = argInt; ! } ! ! int renderToInt() { ! doc.render(this); ! return retInt; ! } ! ! ! public void run() { ! switch (opCode) { ! case FIND_LINE_NUMBER: { ! Element paragraphsParent = findLineRootElement (doc); ! retInt = paragraphsParent.getElementIndex (argInt); // argInt is offset ! break; } ! ! ! case FIND_LINE_COLUMN: { ! Element paragraphsParent = findLineRootElement (doc); ! int indx = paragraphsParent.getElementIndex (argInt); // argInt is offset ! retInt = argInt - paragraphsParent.getElement (indx).getStartOffset (); ! break; } ! ! ! case FIND_LINE_OFFSET: { ! Element paragraphsParent = findLineRootElement (doc); ! Element line = paragraphsParent.getElement (argInt); // argInt is lineNumber ! ! if(line == null) { ! throw new IndexOutOfBoundsException( ! "Index=" + argInt + " is out of bounds."); // NOI18N ! } ! ! retInt = line.getStartOffset (); ! break; } ! ! default: ! throw new IllegalStateException(); ! ! } ! } ! } ! } Index: openide/src/org/openide/text/PositionRef.java =================================================================== RCS file: /cvs/openide/src/org/openide/text/PositionRef.java,v retrieving revision 1.48 diff -c -r1.48 PositionRef.java *** openide/src/org/openide/text/PositionRef.java 3 Dec 2002 14:12:07 -0000 1.48 --- openide/src/org/openide/text/PositionRef.java 20 Oct 2003 16:44:16 -0000 *************** *** 20,25 **** --- 20,26 ---- import javax.swing.text.Position; import javax.swing.text.StyledDocument; import javax.swing.text.BadLocationException; + import javax.swing.text.Element; import org.openide.loaders.DataObject; import org.openide.util.RequestProcessor; *************** *** 42,48 **** /** insert after? */ private boolean insertAfter; ! /** Creates new PositionRef using the given manager at the specified * position offset. * @param manager manager for the position --- 43,49 ---- /** insert after? */ private boolean insertAfter; ! /** Creates new PositionRef using the given manager at the specified * position offset. * @param manager manager for the position *************** *** 159,165 **** } public String toString() { ! return "Pos[" + getOffset () + "]"; // NOI18N } /** This class is responsible for the holding the Document object --- 160,166 ---- } public String toString() { ! return "Pos[" + getOffset () + "]" + ", kind=" + kind; // NOI18N } /** This class is responsible for the holding the Document object *************** *** 261,271 **** * pass sweep of the data structure (inlined in the code). * @param toMemory puts positions to memory if true, * from memory if false */ ! private void processPositions(boolean toMemory) { // clear the queue, we'll do the sweep inline anyway while(queue.poll() != null); counter = 0; ! synchronized(this) { ChainItem previous = head; ChainItem ref = previous.next; --- 262,273 ---- * pass sweep of the data structure (inlined in the code). * @param toMemory puts positions to memory if true, * from memory if false */ ! private void processPositions(final boolean toMemory) { // clear the queue, we'll do the sweep inline anyway while(queue.poll() != null); counter = 0; ! ! /* pre-33165 synchronized(this) { ChainItem previous = head; ChainItem ref = previous.next; *************** *** 288,294 **** ref = ref.next; } ! } } /** Polls queue and increases the counter accordingly. --- 290,299 ---- ref = ref.next; } ! } ! */ ! ! new DocumentRenderer(DocumentRenderer.PROCESS_POSITIONS, toMemory).render(); } /** Polls queue and increases the counter accordingly. *************** *** 329,336 **** } /** Adds the position to this manager. */ ! Kind addPosition(PositionRef pos) { Kind kind; synchronized(this) { head.next = new ChainItem(pos, queue, head.next); --- 334,343 ---- } /** Adds the position to this manager. */ ! Kind addPosition(final PositionRef pos) { Kind kind; + + /* pre-33165 synchronized(this) { head.next = new ChainItem(pos, queue, head.next); *************** *** 338,343 **** --- 345,353 ---- pos.kind : pos.kind.toMemory(pos.insertAfter)); } + */ + + kind = (Kind)new DocumentRenderer(DocumentRenderer.ADD_POSITION, pos).renderToObject(); checkQueue(); *************** *** 408,413 **** --- 418,425 ---- /** Converts the kind to representation in memory */ public PositionKind toMemory (boolean insertAfter) { + + /* pre-33165 // try to find the right position Position p; try { *************** *** 416,421 **** --- 428,437 ---- p = doc.getEndPosition (); } return new PositionKind (p); + */ + + return (PositionKind)new DocumentRenderer( + DocumentRenderer.KIND_TO_MEMORY, this, insertAfter).renderToObject(); } /** Converts the kind to representation out from memory */ *************** *** 443,462 **** /** Get the line number */ public int getLine() { ! return NbDocument.findLineNumber(doc, getOffset()); } /** Get the column number */ public int getColumn() { ! return NbDocument.findLineColumn(doc, getOffset()); } /** Writes the kind to stream */ public void write (DataOutput os) throws IOException { int offset = getOffset(); int line = getLine(); int column = getColumn(); if(offset < 0 || line < 0 || column < 0) { throw new IOException( "Illegal PositionKind: " + pos + "[offset=" // NOI18N --- 459,492 ---- /** Get the line number */ public int getLine() { ! // pre-33165 return NbDocument.findLineNumber(doc, getOffset()); ! return new DocumentRenderer( ! DocumentRenderer.POSITION_KIND_GET_LINE, this).renderToInt(); } /** Get the column number */ public int getColumn() { ! // pre-33165 return NbDocument.findLineColumn(doc, getOffset()); ! return new DocumentRenderer( ! DocumentRenderer.POSITION_KIND_GET_COLUMN, this).renderToInt(); } /** Writes the kind to stream */ public void write (DataOutput os) throws IOException { + + /* pre-33165 int offset = getOffset(); int line = getLine(); int column = getColumn(); + */ + + DocumentRenderer renderer = new DocumentRenderer( + DocumentRenderer.POSITION_KIND_WRITE, this); + int offset = renderer.renderToIntIOE(); + int line = renderer.getLine(); + int column = renderer.getColumn(); + if(offset < 0 || line < 0 || column < 0) { throw new IOException( "Illegal PositionKind: " + pos + "[offset=" // NOI18N *************** *** 495,503 **** --- 525,544 ---- /** Constructs the out kind from the position kind. */ public OutKind (PositionKind kind) { + + /* pre-33165 int offset = kind.getOffset(); int line = kind.getLine(); int column = kind.getColumn(); + */ + + + DocumentRenderer renderer = new DocumentRenderer( + DocumentRenderer.OUT_KIND_CONSTRUCTOR, kind); + + int offset = renderer.renderToInt(); + int line = renderer.getLine(); + int column = renderer.getColumn(); if(offset < 0 || line < 0 || column < 0) { throw new IndexOutOfBoundsException( *************** *** 580,591 **** /** Get the line number */ public int getLine() throws IOException { ! return NbDocument.findLineNumber(getCloneableEditorSupport().openDocument(), offset); } /** Get the column number */ public int getColumn() throws IOException { ! return NbDocument.findLineColumn (getCloneableEditorSupport().openDocument(), offset); } /** Writes the kind to stream */ --- 621,638 ---- /** Get the line number */ public int getLine() throws IOException { ! // pre-33165 return NbDocument.findLineNumber(getCloneableEditorSupport().openDocument(), offset); ! getCloneableEditorSupport().openDocument(); // make sure document is fully read ! return new DocumentRenderer(DocumentRenderer.OFFSET_KIND_GET_LINE, ! this, offset).renderToIntIOE(); } /** Get the column number */ public int getColumn() throws IOException { ! // pre-33165 return NbDocument.findLineColumn (getCloneableEditorSupport().openDocument(), offset); ! getCloneableEditorSupport().openDocument(); // make sure document fully read ! return new DocumentRenderer(DocumentRenderer.OFFSET_KIND_GET_COLUMN, ! this, offset).renderToIntIOE(); } /** Writes the kind to stream */ *************** *** 628,633 **** --- 675,682 ---- /** Offset */ public int getOffset () { + + /* pre-33165 try { StyledDocument doc = getCloneableEditorSupport().getDocument(); if (doc == null) { *************** *** 638,643 **** --- 687,708 ---- // what to do? hopefully unlikelly return 0; } + */ + + + try { + StyledDocument doc = getCloneableEditorSupport().getDocument(); + if (doc == null) { + doc = getCloneableEditorSupport().openDocument(); + } + int retOffset = new DocumentRenderer(DocumentRenderer.LINE_KIND_GET_OFFSET, + this, line, column, doc).renderToInt(); + return retOffset; + + } catch (IOException e) { + // what to do? hopefully unlikelly + return 0; + } } /** Get the line number */ *************** *** 667,672 **** --- 732,739 ---- /** Converts the kind to representation in memory */ public PositionKind toMemory (boolean insertAfter) { + + /* pre-33165 // try to find the right position Position p; try { *************** *** 674,685 **** } catch (BadLocationException e) { p = doc.getEndPosition (); } return new PositionKind (p); } } ! } } --- 741,1023 ---- } catch (BadLocationException e) { p = doc.getEndPosition (); } + */ + + Position p = (Position)new DocumentRenderer( + DocumentRenderer.LINE_KIND_TO_MEMORY, this, + line, column, insertAfter).renderToObject(); + return new PositionKind (p); } } + + /** + * Helper class ensuring that critical parts will run under document's read lock + * by using {@link javax.swing.text.Document#render(Runnable)}. + */ + private final class DocumentRenderer implements Runnable { + + private static final int KIND_TO_MEMORY = 0; + + private static final int POSITION_KIND_GET_LINE = KIND_TO_MEMORY + 1; + + private static final int POSITION_KIND_GET_COLUMN = POSITION_KIND_GET_LINE + 1; + + private static final int POSITION_KIND_WRITE = POSITION_KIND_GET_COLUMN + 1; ! private static final int OUT_KIND_CONSTRUCTOR = POSITION_KIND_WRITE + 1; ! ! private static final int OFFSET_KIND_GET_LINE = OUT_KIND_CONSTRUCTOR + 1; ! ! private static final int OFFSET_KIND_GET_COLUMN = OFFSET_KIND_GET_LINE + 1; ! ! private static final int LINE_KIND_GET_OFFSET = OFFSET_KIND_GET_COLUMN + 1; ! ! private static final int LINE_KIND_TO_MEMORY = LINE_KIND_GET_OFFSET + 1; ! ! private static final int PROCESS_POSITIONS = LINE_KIND_TO_MEMORY + 1; ! ! private static final int ADD_POSITION = PROCESS_POSITIONS + 1; ! ! private final int opCode; ! ! private Kind argKind; ! ! private boolean argInsertAfter; ! ! private boolean argToMemory; ! ! private int argInt; ! ! private Object retObject; ! ! private int retInt; ! ! private int argLine; ! ! private int argColumn; ! ! private PositionRef argPos; ! ! private StyledDocument argDoc; ! ! private IOException ioException; ! ! DocumentRenderer(int opCode, Kind argKind) { ! this.opCode = opCode; ! this.argKind = argKind; ! } ! ! DocumentRenderer(int opCode, Kind argKind, boolean argInsertAfter) { ! this(opCode, argKind); ! this.argInsertAfter = argInsertAfter; ! } ! ! DocumentRenderer(int opCode, Kind argKind, int argInt) { ! this(opCode, argKind); ! this.argInt = argInt; ! } ! ! DocumentRenderer(int opCode, Kind argKind, int argLine, int argColumn) { ! this(opCode, argKind); ! this.argLine = argLine; ! this.argColumn = argColumn; ! } ! ! DocumentRenderer(int opCode, Kind argKind, int argLine, int argColumn, StyledDocument argDoc) { ! this(opCode, argKind, argLine, argColumn); ! this.argDoc = argDoc; ! } ! ! DocumentRenderer(int opCode, Kind argKind, int argLine, int argColumn, boolean argInsertAfter) { ! this(opCode, argKind, argLine, argColumn); ! this.argInsertAfter = argInsertAfter; ! } ! ! DocumentRenderer(int opCode, boolean toMemory) { ! this.opCode = opCode; ! this.argToMemory = toMemory; ! } ! ! DocumentRenderer(int opCode, PositionRef argPos) { ! this.opCode = opCode; ! this.argPos = argPos; ! } ! ! void render() { ! if (doc != null) { ! doc.render(this); ! } else { ! this.run(); ! } ! } ! ! Object renderToObjectIOE() throws IOException { ! Object o = renderToObject(); ! ! if (ioException != null) { ! throw ioException; ! } ! ! return o; ! } ! ! Object renderToObject() { ! render(); ! return retObject; ! } ! ! int renderToIntIOE() throws IOException { ! int i = renderToInt(); ! ! if (ioException != null) { ! throw ioException; ! } ! ! return i; ! } ! ! int renderToInt() { ! render(); ! return retInt; ! } ! ! int getLine() { ! return argLine; ! } ! ! int getColumn() { ! return argColumn; ! } ! ! public void run() { ! try { ! switch (opCode) { ! case KIND_TO_MEMORY: { ! // try to find the right position ! Position p; ! ! int offset = argKind.getOffset(); ! ! // #33165 ! // Try to use line:column instead ! // Following code can be commented out to retain old behavior ! if (argKind.getClass() == OutKind.class) { ! try { ! int line = argKind.getLine(); ! int col = argKind.getColumn(); ! Element lineRoot = NbDocument.findLineRootElement(doc); ! if (line < lineRoot.getElementCount()) { ! Element lineElem = lineRoot.getElement(line); ! int lineStartOffset = lineElem.getStartOffset(); ! int lineLen = lineElem.getEndOffset() ! - lineStartOffset; ! if (lineLen >= 1) { // should always be at least '\n' ! col = Math.min(col, lineLen - 1); ! offset = lineStartOffset + col; ! } ! } ! } catch (IOException e) { ! // use offset in that case ! } ! } ! ! try { ! p = NbDocument.createPosition (doc, offset, ! argInsertAfter ? Position.Bias.Forward : Position.Bias.Backward); ! } catch (BadLocationException e) { ! p = doc.getEndPosition (); ! } ! retObject = (PositionKind)new PositionKind (p); ! break; } ! ! case POSITION_KIND_GET_LINE: { ! retInt = NbDocument.findLineNumber(doc, argKind.getOffset()); ! break; } ! ! case POSITION_KIND_GET_COLUMN: { ! retInt = NbDocument.findLineColumn(doc, argKind.getOffset()); ! break; } ! ! case POSITION_KIND_WRITE: ! case OUT_KIND_CONSTRUCTOR: { ! retInt = argKind.getOffset(); ! argLine = argKind.getLine(); ! argColumn = argKind.getColumn(); ! break; } ! ! case OFFSET_KIND_GET_LINE: { ! retInt = NbDocument.findLineNumber(getCloneableEditorSupport().openDocument(), argInt); ! break; } ! ! case OFFSET_KIND_GET_COLUMN: { ! retInt = NbDocument.findLineColumn (getCloneableEditorSupport().openDocument(), argInt); ! break; } ! ! case LINE_KIND_GET_OFFSET: { ! retInt = NbDocument.findLineOffset (argDoc, argLine) + argColumn; ! break; } ! ! case LINE_KIND_TO_MEMORY: { ! // try to find the right position ! try { ! retObject = NbDocument.createPosition (doc, ! NbDocument.findLineOffset (doc, argLine) + argColumn, ! argInsertAfter ? Position.Bias.Forward : Position.Bias.Backward); ! } catch (BadLocationException e) { ! retObject = doc.getEndPosition (); ! } catch (IndexOutOfBoundsException e) { ! retObject = doc.getEndPosition(); ! } ! break; } ! ! case PROCESS_POSITIONS: { ! synchronized(Manager.this) { ! ChainItem previous = head; ! ChainItem ref = previous.next; ! ! while(ref != null) { ! PositionRef pos = (PositionRef)ref.get(); ! if(pos == null) { ! // Remove the item from data structure. ! previous.next = ref.next; ! } else { ! // Process the PostionRef. ! if(argToMemory) { ! pos.kind = pos.kind.toMemory(pos.insertAfter); ! } else { ! pos.kind = pos.kind.fromMemory(); ! } ! ! previous = ref; ! } ! ! ref = ref.next; ! } ! } ! break; } ! ! case ADD_POSITION: { ! synchronized(Manager.this) { ! head.next = new ChainItem(argPos, queue, head.next); ! ! retObject = (doc == null ? ! argPos.kind : ! argPos.kind.toMemory(argPos.insertAfter)); ! } ! break; } + default: + throw new IllegalStateException(); // Unknown opcode + } + } catch (IOException e) { + ioException = e; + } + } + + } + + } }