public boolean commitTransaction(final Document document) {
    ApplicationManager.getApplication().assertIsDispatchThread();
    final DocumentChangeTransaction documentChangeTransaction = removeTransaction(document);
    if (documentChangeTransaction == null) return false;
    final PsiElement changeScope = documentChangeTransaction.getChangeScope();
    try {
      mySyncDocument = document;

      final PsiTreeChangeEventImpl fakeEvent = new PsiTreeChangeEventImpl(changeScope.getManager());
      fakeEvent.setParent(changeScope);
      fakeEvent.setFile(changeScope.getContainingFile());
      doSync(
          fakeEvent,
          true,
          new DocSyncAction() {
            @Override
            public void syncDocument(Document document, PsiTreeChangeEventImpl event) {
              doCommitTransaction(document, documentChangeTransaction);
            }
          });
      myBus
          .syncPublisher(PsiDocumentTransactionListener.TOPIC)
          .transactionCompleted(document, (PsiFile) changeScope);
    } finally {
      mySyncDocument = null;
    }
    return true;
  }
  public boolean commitTransaction(final Document document) {
    ApplicationManager.getApplication().assertIsDispatchThread();
    final DocumentChangeTransaction documentChangeTransaction = removeTransaction(document);
    if (documentChangeTransaction == null) return false;
    final PsiFile changeScope = documentChangeTransaction.myChangeScope;
    try {
      mySyncDocument = document;

      final PsiTreeChangeEventImpl fakeEvent = new PsiTreeChangeEventImpl(changeScope.getManager());
      fakeEvent.setParent(changeScope);
      fakeEvent.setFile(changeScope);
      checkPsiModificationAllowed(fakeEvent);
      doSync(
          fakeEvent,
          true,
          new DocSyncAction() {
            @Override
            public void syncDocument(
                @NotNull Document document, @NotNull PsiTreeChangeEventImpl event) {
              doCommitTransaction(document, documentChangeTransaction);
            }
          });
      myBus
          .syncPublisher(PsiDocumentTransactionListener.TOPIC)
          .transactionCompleted(document, changeScope);
    } catch (Throwable e) {
      myPsiDocumentManager.forceReload(
          changeScope.getViewProvider().getVirtualFile(), changeScope.getViewProvider());
      ExceptionUtil.rethrowAllAsUnchecked(e);
    } finally {
      mySyncDocument = null;
    }
    return true;
  }
 public void childrenChanged(@NotNull PsiTreeChangeEventImpl event) {
   event.setCode(PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED);
   if (LOG.isDebugEnabled()) {
     LOG.debug("childrenChanged: parent = " + event.getParent());
   }
   fireEvent(event);
   afterChange(true);
 }
 public void childRemoved(@NotNull PsiTreeChangeEventImpl event) {
   event.setCode(PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED);
   if (LOG.isDebugEnabled()) {
     LOG.debug("childRemoved: child = " + event.getChild() + ", parent = " + event.getParent());
   }
   fireEvent(event);
   afterChange(true);
 }
 public void beforeChildrenChange(@NotNull PsiTreeChangeEventImpl event) {
   beforeChange(true);
   event.setCode(PsiTreeChangeEventImpl.PsiEventType.BEFORE_CHILDREN_CHANGE);
   if (LOG.isDebugEnabled()) {
     LOG.debug("beforeChildrenChange: parent = " + event.getParent());
   }
   fireEvent(event);
 }
 @Override
 public void beforeChildAddition(@NotNull PsiTreeChangeEventImpl event) {
   beforeChange(true);
   event.setCode(PsiTreeChangeEventImpl.PsiEventType.BEFORE_CHILD_ADDITION);
   if (LOG.isDebugEnabled()) {
     LOG.debug("beforeChildAddition: parent = " + event.getParent());
   }
   fireEvent(event);
 }
 @Override
 public void beforeChildRemoval(@NotNull PsiTreeChangeEventImpl event) {
   beforeChange(true);
   event.setCode(PsiTreeChangeEventImpl.PsiEventType.BEFORE_CHILD_REMOVAL);
   if (LOG.isDebugEnabled()) {
     LOG.debug(
         "beforeChildRemoval: child = " + event.getChild() + ", parent = " + event.getParent());
   }
   fireEvent(event);
 }
 @Override
 public void beforeChildReplacement(@NotNull PsiTreeChangeEventImpl event) {
   beforeChange(true);
   event.setCode(PsiTreeChangeEventImpl.PsiEventType.BEFORE_CHILD_REPLACEMENT);
   if (LOG.isDebugEnabled()) {
     LOG.debug(
         "beforeChildReplacement: oldChild = "
             + event.getOldChild()
             + ", parent = "
             + event.getParent());
   }
   fireEvent(event);
 }
 public void beforePropertyChange(@NotNull PsiTreeChangeEventImpl event) {
   beforeChange(true);
   event.setCode(PsiTreeChangeEventImpl.PsiEventType.BEFORE_PROPERTY_CHANGE);
   if (LOG.isDebugEnabled()) {
     LOG.debug(
         "beforePropertyChange: element = "
             + event.getElement()
             + ", propertyName = "
             + event.getPropertyName()
             + ", oldValue = "
             + event.getOldValue());
   }
   fireEvent(event);
 }
 public void beforeChildMovement(@NotNull PsiTreeChangeEventImpl event) {
   beforeChange(true);
   event.setCode(PsiTreeChangeEventImpl.PsiEventType.BEFORE_CHILD_MOVEMENT);
   if (LOG.isDebugEnabled()) {
     LOG.debug(
         "beforeChildMovement: child = "
             + event.getChild()
             + ", oldParent = "
             + event.getOldParent()
             + ", newParent = "
             + event.getNewParent());
   }
   fireEvent(event);
 }
 public void propertyChanged(@NotNull PsiTreeChangeEventImpl event) {
   event.setCode(PsiTreeChangeEventImpl.PsiEventType.PROPERTY_CHANGED);
   if (LOG.isDebugEnabled()) {
     LOG.debug(
         "propertyChanged: element = "
             + event.getElement()
             + ", propertyName = "
             + event.getPropertyName()
             + ", oldValue = "
             + event.getOldValue()
             + ", newValue = "
             + event.getNewValue());
   }
   fireEvent(event);
   afterChange(true);
 }
  private void fireEvent(@NotNull PsiTreeChangeEventImpl event) {
    boolean isRealTreeChange =
        event.getCode() != PsiTreeChangeEventImpl.PsiEventType.PROPERTY_CHANGED
            && event.getCode() != PsiTreeChangeEventImpl.PsiEventType.BEFORE_PROPERTY_CHANGE;

    PsiFile file = event.getFile();
    if (file == null || file.isPhysical()) {
      ApplicationManager.getApplication().assertWriteAccessAllowed();
    }
    if (isRealTreeChange) {
      LOG.assertTrue(
          !myTreeChangeEventIsFiring, "Changes to PSI are not allowed inside event processing");
      myTreeChangeEventIsFiring = true;
    }
    try {
      for (PsiTreeChangePreprocessor preprocessor : myTreeChangePreprocessors) {
        preprocessor.treeChanged(event);
      }

      for (PsiTreeChangeListener listener : myTreeChangeListeners) {
        try {
          switch (event.getCode()) {
            case BEFORE_CHILD_ADDITION:
              listener.beforeChildAddition(event);
              break;

            case BEFORE_CHILD_REMOVAL:
              listener.beforeChildRemoval(event);
              break;

            case BEFORE_CHILD_REPLACEMENT:
              listener.beforeChildReplacement(event);
              break;

            case BEFORE_CHILD_MOVEMENT:
              listener.beforeChildMovement(event);
              break;

            case BEFORE_CHILDREN_CHANGE:
              listener.beforeChildrenChange(event);
              break;

            case BEFORE_PROPERTY_CHANGE:
              listener.beforePropertyChange(event);
              break;

            case CHILD_ADDED:
              listener.childAdded(event);
              break;

            case CHILD_REMOVED:
              listener.childRemoved(event);
              break;

            case CHILD_REPLACED:
              listener.childReplaced(event);
              break;

            case CHILD_MOVED:
              listener.childMoved(event);
              break;

            case CHILDREN_CHANGED:
              listener.childrenChanged(event);
              break;

            case PROPERTY_CHANGED:
              listener.propertyChanged(event);
              break;
          }
        } catch (Exception e) {
          LOG.error(e);
        }
      }
    } finally {
      if (isRealTreeChange) {
        myTreeChangeEventIsFiring = false;
      }
    }
  }