public static void doActualPsiChange(@NotNull final PsiFile file, final DiffLog diffLog) {
    file.getViewProvider().beforeContentsSynchronized();

    try {
      final Document document = file.getViewProvider().getDocument();
      PsiDocumentManagerImpl documentManager =
          (PsiDocumentManagerImpl) PsiDocumentManager.getInstance(file.getProject());
      PsiToDocumentSynchronizer.DocumentChangeTransaction transaction =
          documentManager.getSynchronizer().getTransaction(document);

      final PsiFileImpl fileImpl = (PsiFileImpl) file;

      if (transaction == null) {
        final PomModel model = PomManager.getModel(fileImpl.getProject());

        model.runTransaction(
            new PomTransactionBase(fileImpl, model.getModelAspect(TreeAspect.class)) {
              @Override
              public PomModelEvent runInner() {
                return new TreeAspectEvent(model, diffLog.performActualPsiChange(file));
              }
            });
      } else {
        diffLog.performActualPsiChange(file);
      }
    } catch (IncorrectOperationException e) {
      LOG.error(e);
    }
  }
  public PsiElement setName(@NotNull final String name) throws IncorrectOperationException {
    final PomModel model = PomManager.getModel(getProject());
    final XmlAspect aspect = model.getModelAspect(XmlAspect.class);
    model.runTransaction(
        new PomTransactionBase(this, aspect) {
          public PomModelEvent runInner() throws IncorrectOperationException {
            final String oldName = getName();
            final XmlTagImpl dummyTag =
                (XmlTagImpl)
                    XmlElementFactory.getInstance(getProject())
                        .createTagFromText(XmlTagUtil.composeTagText(name, "aa"));
            final XmlTagImpl tag = XmlTagImpl.this;
            final CharTable charTableByTree = SharedImplUtil.findCharTableByTree(tag);
            ASTNode child = XmlChildRole.START_TAG_NAME_FINDER.findChild(tag);
            LOG.assertTrue(child != null, "It seems '" + name + "' is not a valid tag name");
            TreeElement tagElement =
                (TreeElement) XmlChildRole.START_TAG_NAME_FINDER.findChild(dummyTag);
            LOG.assertTrue(tagElement != null, "What's wrong with it? '" + name + "'");
            tag.replaceChild(child, ChangeUtil.copyElement(tagElement, charTableByTree));
            final ASTNode childByRole = XmlChildRole.CLOSING_TAG_NAME_FINDER.findChild(tag);
            if (childByRole != null) {
              final TreeElement treeElement =
                  (TreeElement) XmlChildRole.CLOSING_TAG_NAME_FINDER.findChild(dummyTag);
              if (treeElement != null) {
                tag.replaceChild(childByRole, ChangeUtil.copyElement(treeElement, charTableByTree));
              }
            }

            return XmlTagNameChangedImpl.createXmlTagNameChanged(model, tag, oldName);
          }
        });
    return this;
  }
  public void collapseIfEmpty() {
    final XmlTag[] tags = getSubTags();
    if (tags.length > 0) {
      return;
    }
    final ASTNode closingName = XmlChildRole.CLOSING_TAG_NAME_FINDER.findChild(this);
    final ASTNode startTagEnd = XmlChildRole.START_TAG_END_FINDER.findChild(this);
    if (closingName == null || startTagEnd == null) {
      return;
    }

    final PomModel pomModel = PomManager.getModel(getProject());
    final PomTransactionBase transaction =
        new PomTransactionBase(this, pomModel.getModelAspect(XmlAspect.class)) {

          @Nullable
          public PomModelEvent runInner() {
            final ASTNode closingBracket = closingName.getTreeNext();
            removeRange(startTagEnd, closingBracket);
            final LeafElement emptyTagEnd =
                Factory.createSingleLeafElement(
                    XmlTokenType.XML_EMPTY_ELEMENT_END, "/>", 0, 2, null, getManager());
            replaceChild(closingBracket, emptyTagEnd);
            return null;
          }
        };
    try {
      pomModel.runTransaction(transaction);
    } catch (IncorrectOperationException e) {
      LOG.error(e);
    }
  }
 public void deleteChildInternal(@NotNull final ASTNode child) {
   final PomModel model = PomManager.getModel(getProject());
   final XmlAspect aspect = model.getModelAspect(XmlAspect.class);
   try {
     model.runTransaction(
         new PomTransactionBase(this, aspect) {
           public PomModelEvent runInner() {
             XmlDocumentImpl.super.deleteChildInternal(child);
             return XmlDocumentChangedImpl.createXmlDocumentChanged(model, XmlDocumentImpl.this);
           }
         });
   } catch (IncorrectOperationException ignored) {
   }
 }
 public TreeElement addInternal(
     final TreeElement first, final ASTNode last, final ASTNode anchor, final Boolean before) {
   final PomModel model = PomManager.getModel(getProject());
   final XmlAspect aspect = model.getModelAspect(XmlAspect.class);
   final TreeElement[] holder = new TreeElement[1];
   try {
     model.runTransaction(
         new PomTransactionBase(this, aspect) {
           public PomModelEvent runInner() {
             holder[0] = XmlDocumentImpl.super.addInternal(first, last, anchor, before);
             return XmlDocumentChangedImpl.createXmlDocumentChanged(model, XmlDocumentImpl.this);
           }
         });
   } catch (IncorrectOperationException ignored) {
   }
   return holder[0];
 }
  public void deleteChildInternal(@NotNull final ASTNode child) {
    final PomModel model = PomManager.getModel(getProject());
    final XmlAspect aspect = model.getModelAspect(XmlAspect.class);

    if (child.getElementType() == XmlElementType.XML_ATTRIBUTE) {
      try {
        model.runTransaction(
            new PomTransactionBase(this, aspect) {
              public PomModelEvent runInner() {
                final String name = ((XmlAttribute) child).getName();
                XmlTagImpl.super.deleteChildInternal(child);
                return XmlAttributeSetImpl.createXmlAttributeSet(
                    model, XmlTagImpl.this, name, null);
              }
            });
      } catch (IncorrectOperationException e) {
        LOG.error(e);
      }
    } else {
      final ASTNode treePrev = child.getTreePrev();
      final ASTNode treeNext = child.getTreeNext();
      XmlTagImpl.super.deleteChildInternal(child);
      if (treePrev != null
          && treeNext != null
          && treePrev.getElementType() == XmlElementType.XML_TEXT
          && treeNext.getElementType() == XmlElementType.XML_TEXT) {
        final XmlText prevText = (XmlText) treePrev.getPsi();
        final XmlText nextText = (XmlText) treeNext.getPsi();
        try {
          prevText.setValue(prevText.getValue() + nextText.getValue());
          nextText.delete();
        } catch (IncorrectOperationException e) {
          LOG.error(e);
        }
      }
    }
  }
  private TreeElement addInternal(TreeElement child, ASTNode anchor, boolean before)
      throws IncorrectOperationException {
    final PomModel model = PomManager.getModel(getProject());
    if (anchor != null && child.getElementType() == XmlElementType.XML_TEXT) {
      XmlText psi = null;
      if (anchor.getPsi() instanceof XmlText) {
        psi = (XmlText) anchor.getPsi();
      } else {
        final ASTNode other = before ? anchor.getTreePrev() : anchor.getTreeNext();
        if (other != null && other.getPsi() instanceof XmlText) {
          before = !before;
          psi = (XmlText) other.getPsi();
        }
      }

      if (psi != null) {
        if (before) {
          psi.insertText(((XmlText) child.getPsi()).getValue(), 0);
        } else {
          psi.insertText(((XmlText) child.getPsi()).getValue(), psi.getValue().length());
        }
        return (TreeElement) psi.getNode();
      }
    }
    LOG.assertTrue(child.getPsi() instanceof XmlAttribute || child.getPsi() instanceof XmlTagChild);
    final InsertTransaction transaction;
    if (child.getElementType() == XmlElementType.XML_ATTRIBUTE) {
      transaction = new InsertAttributeTransaction(child, anchor, before, model);
    } else if (anchor == null) {
      transaction = getBodyInsertTransaction(child);
    } else {
      transaction = new GenericInsertTransaction(child, anchor, before);
    }
    model.runTransaction(transaction);
    return transaction.getFirstInserted();
  }
  public DomManagerImpl(
      Project project,
      SemService semService,
      ConverterManager converterManager,
      DomApplicationComponent appComponent) {
    myProject = project;
    mySemService = semService;
    myConverterManager = converterManager;
    myApplicationComponent = appComponent;

    final PomModel pomModel = PomManager.getModel(project);
    pomModel.addModelListener(
        new PomModelListener() {
          public void modelChanged(PomModelEvent event) {
            if (myChanging) return;

            final XmlChangeSet changeSet =
                (XmlChangeSet) event.getChangeSet(pomModel.getModelAspect(XmlAspect.class));
            if (changeSet != null) {
              for (XmlFile file : changeSet.getChangedFiles()) {
                DomFileElementImpl<DomElement> element = getCachedFileElement(file);
                if (element != null) {
                  fireEvent(new DomEvent(element, false));
                }
              }
            }
          }

          public boolean isAspectChangeInteresting(PomModelAspect aspect) {
            return aspect instanceof XmlAspect;
          }
        },
        project);

    Runnable setupVfsListeners =
        new Runnable() {
          public void run() {
            final VirtualFileAdapter listener =
                new VirtualFileAdapter() {
                  private final List<DomEvent> myDeletionEvents = new SmartList<DomEvent>();

                  public void contentsChanged(VirtualFileEvent event) {
                    if (event.isFromSave()) return;

                    processVfsChange(event.getFile());
                  }

                  public void fileCreated(VirtualFileEvent event) {
                    processVfsChange(event.getFile());
                  }

                  public void beforeFileDeletion(final VirtualFileEvent event) {
                    if (!myProject.isDisposed()) {
                      beforeFileDeletion(event.getFile());
                    }
                  }

                  private void beforeFileDeletion(final VirtualFile file) {
                    if (file.isDirectory() && file instanceof NewVirtualFile) {
                      for (final VirtualFile child : ((NewVirtualFile) file).getCachedChildren()) {
                        beforeFileDeletion(child);
                      }
                      return;
                    }

                    if (file.isValid() && StdFileTypes.XML.equals(file.getFileType())) {
                      final PsiFile psiFile = getCachedPsiFile(file);
                      if (psiFile instanceof XmlFile) {
                        Collections.addAll(
                            myDeletionEvents, recomputeFileElement((XmlFile) psiFile));
                      }
                    }
                  }

                  public void fileDeleted(VirtualFileEvent event) {
                    if (!myDeletionEvents.isEmpty()) {
                      if (!myProject.isDisposed()) {
                        for (DomEvent domEvent : myDeletionEvents) {
                          fireEvent(domEvent);
                        }
                      }
                      myDeletionEvents.clear();
                    }
                  }

                  public void propertyChanged(VirtualFilePropertyEvent event) {
                    final VirtualFile file = event.getFile();
                    if (!file.isDirectory()
                        && VirtualFile.PROP_NAME.equals(event.getPropertyName())) {
                      processVfsChange(file);
                    }
                  }
                };
            VirtualFileManager.getInstance().addVirtualFileListener(listener, myProject);
          }
        };

    StartupManager startupManager = StartupManager.getInstance(project);
    if (!((StartupManagerEx) startupManager).startupActivityPassed()) {
      startupManager.registerStartupActivity(setupVfsListeners);
    } else {
      setupVfsListeners.run();
    }
  }