From e4c2ba61543bda2601347fbc1b90e7560f0c2d75 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Fri, 8 Oct 2010 18:14:09 +0400 Subject: [PATCH] correctly adding/removing listeners in documents --- .../openapi/editor/impl/DocumentImpl.java | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java index 5c5c5ffbbe09..b1e5f2cd43c9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java @@ -77,6 +77,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { private final PropertyChangeSupport myPropertyChangeSupport = new PropertyChangeSupport(this); private volatile MarkupModelEx myMarkupModel; + private DocumentListener[] myCachedDocumentListeners; private final List myReadOnlyListeners = new ArrayList(1); private int myCheckGuardedBlocks = 0; @@ -468,12 +469,11 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { return null; // suppress events in shutdown hook } DocumentEvent event = new DocumentEventImpl(this, offset, oldString, newString, myModificationStamp, wholeTextReplaced); - //System.out.printf("%nbefore change: offset=%d, old text='%s', new text='%s', document modification stamp=%d%nDocument:'%s'%n", - // event.getOffset(), event.getOldFragment(), event.getNewFragment(), event.getDocument().getModificationStamp(), - // event.getDocument().getText()); - for (int i = myDocumentListeners.size() - 1; i >= 0; i--) { + + DocumentListener[] listeners = getCachedListeners(); + for (int i = listeners.length - 1; i >= 0; i--) { try { - myDocumentListeners.get(i).beforeDocumentChange(event); + listeners[i].beforeDocumentChange(event); } catch (Throwable e) { LOG.error(e); @@ -484,10 +484,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { return event; } - @SuppressWarnings({"ForLoopReplaceableByForEach"}) private void changedUpdate(DocumentEvent event, long newModificationStamp) { - //System.out.printf("after change: new modification stamp=%d%ndocument='%s'%n", event.getDocument().getModificationStamp(), - // event.getDocument().getText()); if (ShutDownTracker.isShutdownHookRunning()) { return; // suppress events in shutdown hook } @@ -497,10 +494,10 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { myLineSet.changedUpdate(event); setModificationStamp(newModificationStamp); - // Don't use for-each in order to avoid unnecessary iterator construction during frequent document updates. - for (int i = 0; i < myDocumentListeners.size(); i++) { + DocumentListener[] listeners = getCachedListeners(); + for (DocumentListener listener : listeners) { try { - myDocumentListeners.get(i).documentChanged(event); + listener.documentChanged(event); } catch (Throwable e) { LOG.error(e); @@ -557,21 +554,9 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { public void addDocumentListener(@NotNull DocumentListener listener) { + myCachedDocumentListeners = null; LOG.assertTrue(!myDocumentListeners.contains(listener), listener); - if (!(listener instanceof PrioritizedDocumentListener)) { - myDocumentListeners.add(listener); - return; - } - int i = Collections.binarySearch(myDocumentListeners, listener, PrioritizedDocumentListener.COMPARATOR); - if (i < 0) { - i = -i - 1; - } - if (i >= myDocumentListeners.size()) { - myDocumentListeners.add(listener); - } - else { - myDocumentListeners.add(i, listener); - } + myDocumentListeners.add(listener); } public void addDocumentListener(@NotNull final DocumentListener listener, @NotNull Disposable parentDisposable) { @@ -584,6 +569,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { } public void removeDocumentListener(@NotNull DocumentListener listener) { + myCachedDocumentListeners = null; boolean success = myDocumentListeners.remove(listener); LOG.assertTrue(success); } @@ -631,6 +617,15 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { return lineCount; } + private DocumentListener[] getCachedListeners() { + if (myCachedDocumentListeners == null) { + Collections.sort(myDocumentListeners, PrioritizedDocumentListener.COMPARATOR); + myCachedDocumentListeners = myDocumentListeners.toArray(new DocumentListener[myDocumentListeners.size()]); + } + + return myCachedDocumentListeners; + } + public void fireReadOnlyModificationAttempt() { ApplicationManagerEx.getApplicationEx().assertReadAccessToDocumentsAllowed(); EditReadOnlyListener[] listeners = myReadOnlyListeners.toArray(