Index: src/org/openide/text/CloneableEditorSupport.java =================================================================== RCS file: /cvs/openide/src/org/openide/text/CloneableEditorSupport.java,v retrieving revision 1.95 diff -c -r1.95 CloneableEditorSupport.java *** src/org/openide/text/CloneableEditorSupport.java 27 Aug 2003 20:40:32 -0000 1.95 --- src/org/openide/text/CloneableEditorSupport.java 5 Sep 2003 14:38:40 -0000 *************** *** 80,85 **** --- 80,90 ---- /** 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; *************** *** 135,141 **** /** 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 --- 140,146 ---- /** 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 *************** *** 165,171 **** /** Flag whether the document is already modified or not.*/ // #34728 performance optimization private boolean alreadyModified = false; ! /** Creates new CloneableEditorSupport attached to given environment. * * @param env environment that is source of all actions around the --- 170,178 ---- /** Flag whether the document is already modified or not.*/ // #34728 performance optimization private boolean alreadyModified = false; ! ! private int documentStatus = DOCUMENT_NO; ! /** Creates new CloneableEditorSupport attached to given environment. * * @param env environment that is source of all actions around the *************** *** 270,282 **** return positionManager; } ! ! /** Overrides superclass method, first processes document preparation. * @see #prepareDocument */ public void open() { ! prepareDocument().waitFinished(); ! super.open(); } // --- 277,293 ---- 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); ! } } // *************** *** 302,308 **** } /** 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 --- 313,319 ---- } /** 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 *************** *** 334,399 **** * @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. */ --- 345,436 ---- * @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); ! } ! // The thread nume should be: "Loading document " + env; // NOI18N ! prepareTask = RequestProcessor.getDefault().post(new Runnable () { ! public void run () { ! 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) { ! t.printStackTrace(); ! throw t; ! ! } finally { ! ! synchronized (getLock()) { ! documentStatus = targetStatus; ! ! getLock().notifyAll(); } } ! ! } ! }); ! return prepareTask; } /** Clears the doc document. Helper method. */ *************** *** 425,441 **** * @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; } } --- 462,506 ---- * @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); ! } ! ! return openDocumentImpl(); } } *************** *** 445,468 **** * @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; ! } ! Task t = loadTask; ! if (t != null) { ! // if an task exists ! t.waitFinished (); ! return doc; ! } else { ! return null; } } ! ! /** Test whether the document is modified. * @return true if the document is in memory and is modified; * otherwise false --- 510,539 ---- * @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; ! } ! } ! } } } ! /** Test whether the document is modified. * @return true if the document is in memory and is modified; * otherwise false *************** *** 911,974 **** * 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-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(); --- 982,1045 ---- * 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(); *************** *** 1165,1178 **** * @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); --- 1236,1249 ---- * @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); *************** *** 1275,1308 **** /** 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(); } } --- 1346,1367 ---- /** 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; } } } } *************** *** 1324,1336 **** --- 1383,1400 ---- 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. *************** *** 1367,1379 **** //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 --- 1431,1460 ---- //RequestProcessor RequestProcessor.getDefault().post(new Runnable() { public void run () { ! synchronized (getLock()) { ! checkDocumentReload(); ! } } }); } } ! private void checkDocumentReload() { ! switch (documentStatus) { ! case DOCUMENT_NO: ! break; ! ! case DOCUMENT_LOADING: ! case DOCUMENT_RELOADING: ! openDocumentImpl(); ! checkDocumentReload(); ! break; ! ! default: ! reloadDocument(); ! break; ! } ! } /** Creates netbeans document for a given document. * @param d document to use as underlaying one *************** *** 1535,1541 **** /** Access to lock on operations on the support */ ! Object getLock () { return allEditors; } --- 1616,1622 ---- /** Access to lock on operations on the support */ ! final Object getLock () { return allEditors; } *************** *** 1683,1689 **** /** 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. --- 1764,1770 ---- /** 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. *************** *** 1714,1720 **** // Start listening on changes in document doc.addDocumentListener(getListener()); } ! } } --- 1795,1801 ---- // Start listening on changes in document doc.addDocumentListener(getListener()); } ! // } } Index: src/org/openide/text/DocumentLine.java =================================================================== RCS file: /cvs/openide/src/org/openide/text/DocumentLine.java,v retrieving revision 1.50 diff -c -r1.50 DocumentLine.java *** src/org/openide/text/DocumentLine.java 12 Aug 2003 09:38:11 -0000 1.50 --- src/org/openide/text/DocumentLine.java 5 Sep 2003 14:38:40 -0000 *************** *** 18,24 **** import java.util.*; import javax.swing.text.*; import javax.swing.event.*; - import javax.swing.SwingUtilities; import org.openide.ErrorManager; import org.openide.text.EnhancedChangeEvent; --- 18,23 ---- *************** *** 358,369 **** } public String getText() { ! StyledDocument doc = pos.getCloneableEditorSupport ().getDocument (); // document is not opened if (doc == null) return null; int lineNumber = getLineNumber(); int lineStart = NbDocument.findLineOffset(doc, lineNumber); // #24434: Check whether the next line exists --- 357,371 ---- } 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 *************** *** 377,387 **** } 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 */ --- 379,392 ---- } 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 */ *************** *** 552,569 **** } public String getText() { ! StyledDocument doc = position.getCloneableEditorSupport ().getDocument (); // document is not opened if (doc == null) return null; try { ! return doc.getText(position.getOffset(), getLength()); } catch (BadLocationException ex) { ErrorManager.getDefault ().notify ( ErrorManager.EXCEPTION, ex); ! return null; } } /** When document is opened or closed the annotations must be added or --- 557,581 ---- } public String getText() { ! final StyledDocument doc = position.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() try { ! retStringArray[0] = doc.getText(position.getOffset(), getLength()); } catch (BadLocationException ex) { ErrorManager.getDefault ().notify ( ErrorManager.EXCEPTION, ex); ! retStringArray[0] = null; } + // End of the code wrapped by doc.render() + }}); + return retStringArray[0]; + } /** When document is opened or closed the annotations must be added or *************** *** 645,655 **** } private void invoke(int op) { ! SwingUtilities.invokeLater(new LR(op)); } private void invoke(EnhancedChangeEvent ev) { ! SwingUtilities.invokeLater(new LR(ev)); } public void stateChanged (ChangeEvent ev) { --- 657,671 ---- } private void invoke(int op) { ! // part of #33165 - done synchronously not invoking into EQ ! //SwingUtilities.invokeLater(new LR(op)); ! new LR(op).run(); } private void invoke(EnhancedChangeEvent ev) { ! // part of #33165 - done synchronously not invoking into EQ ! //SwingUtilities.invokeLater(new LR(ev)); ! new LR(ev).run(); } public void stateChanged (ChangeEvent ev) { Index: src/org/openide/text/NbDocument.java =================================================================== RCS file: /cvs/openide/src/org/openide/text/NbDocument.java,v retrieving revision 1.51 diff -c -r1.51 NbDocument.java *** src/org/openide/text/NbDocument.java 27 Feb 2003 23:41:05 -0000 1.51 --- src/org/openide/text/NbDocument.java 5 Sep 2003 14:38:40 -0000 *************** *** 93,100 **** --- 93,104 ---- * is null. */ 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: src/org/openide/text/PositionRef.java =================================================================== RCS file: /cvs/openide/src/org/openide/text/PositionRef.java,v retrieving revision 1.49 diff -c -r1.49 PositionRef.java *** src/org/openide/text/PositionRef.java 2 Apr 2003 09:46:48 -0000 1.49 --- src/org/openide/text/PositionRef.java 5 Sep 2003 14:38:41 -0000 *************** *** 41,47 **** /** insert after? */ private boolean insertAfter; ! /** Creates new PositionRef using the given manager at the specified * position offset. * @param manager manager for the position --- 41,47 ---- /** insert after? */ private boolean insertAfter; ! /** Creates new PositionRef using the given manager at the specified * position offset. * @param manager manager for the position *************** *** 165,171 **** } public String toString() { ! return "Pos[" + getOffset () + "]"; // NOI18N } /** This class is responsible for the holding the Document object --- 165,171 ---- } public String toString() { ! return "Pos[" + getOffset () + "]" + ", kind=" + kind; // NOI18N } /** This class is responsible for the holding the Document object *************** *** 271,281 **** * 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; --- 271,282 ---- * 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; *************** *** 298,304 **** ref = ref.next; } ! } } /** Polls queue and increases the counter accordingly. --- 299,308 ---- ref = ref.next; } ! } ! */ ! ! new DocumentRenderer(DocumentRenderer.PROCESS_POSITIONS, toMemory).render(); } /** Polls queue and increases the counter accordingly. *************** *** 339,346 **** } /** Adds the position to this manager. */ ! Kind addPosition(PositionRef pos) { Kind kind; synchronized(this) { head.next = new ChainItem(pos, queue, head.next); --- 343,352 ---- } /** 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); *************** *** 348,353 **** --- 354,362 ---- pos.kind : pos.kind.toMemory(pos.insertAfter)); } + */ + + kind = (Kind)new DocumentRenderer(DocumentRenderer.ADD_POSITION, pos).renderToObject(); checkQueue(); *************** *** 418,423 **** --- 427,434 ---- /** Converts the kind to representation in memory */ public PositionKind toMemory (boolean insertAfter) { + + /* pre-33165 // try to find the right position Position p; try { *************** *** 426,431 **** --- 437,446 ---- 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 */ *************** *** 453,472 **** /** 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 --- 468,501 ---- /** 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 *************** *** 505,513 **** --- 534,553 ---- /** 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( *************** *** 590,601 **** /** 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 */ --- 630,647 ---- /** 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 */ *************** *** 638,643 **** --- 684,691 ---- /** Offset */ public int getOffset () { + + /* pre-33165 try { StyledDocument doc = getCloneableEditorSupport().getDocument(); if (doc == null) { *************** *** 648,653 **** --- 696,717 ---- // 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 */ *************** *** 677,682 **** --- 741,748 ---- /** Converts the kind to representation in memory */ public PositionKind toMemory (boolean insertAfter) { + + /* pre-33165 // try to find the right position Position p; try { *************** *** 684,695 **** } catch (BadLocationException e) { p = doc.getEndPosition (); } return new PositionKind (p); } } ! } } --- 750,1004 ---- } 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; ! try { ! p = NbDocument.createPosition (doc, argKind.getOffset (), ! 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 (); ! } ! 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; + } + } + + } + + } }