| /* |
| * Copyright 2000-2009 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.intellij.pom.wrappers; |
| |
| import com.intellij.lang.ASTNode; |
| import com.intellij.pom.PomModel; |
| import com.intellij.pom.PomModelAspect; |
| import com.intellij.pom.event.PomModelEvent; |
| import com.intellij.pom.tree.TreeAspect; |
| import com.intellij.pom.tree.events.ChangeInfo; |
| import com.intellij.pom.tree.events.ReplaceChangeInfo; |
| import com.intellij.pom.tree.events.TreeChange; |
| import com.intellij.pom.tree.events.TreeChangeEvent; |
| import com.intellij.pom.tree.events.impl.ChangeInfoImpl; |
| import com.intellij.pom.tree.events.impl.TreeChangeImpl; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.PsiFile; |
| import com.intellij.psi.impl.PsiManagerImpl; |
| import com.intellij.psi.impl.PsiTreeChangeEventImpl; |
| import com.intellij.psi.impl.source.SourceTreeToPsiMap; |
| |
| import java.util.Collections; |
| |
| public class PsiEventWrapperAspect implements PomModelAspect{ |
| private final TreeAspect myTreeAspect; |
| |
| public PsiEventWrapperAspect(PomModel model, TreeAspect aspect) { |
| myTreeAspect = aspect; |
| model.registerAspect(PsiEventWrapperAspect.class, this, Collections.singleton((PomModelAspect)aspect)); |
| } |
| |
| @Override |
| public void update(PomModelEvent event) { |
| final TreeChangeEvent changeSet = (TreeChangeEvent)event.getChangeSet(myTreeAspect); |
| if(changeSet == null) return; |
| sendAfterEvents(changeSet); |
| } |
| |
| private static void sendAfterEvents(TreeChangeEvent changeSet) { |
| ASTNode rootElement = changeSet.getRootElement(); |
| final PsiFile file = (PsiFile)SourceTreeToPsiMap.treeElementToPsi(rootElement); |
| final PsiManagerImpl manager = (PsiManagerImpl)file.getManager(); |
| if(manager == null) return; |
| |
| if (!file.isPhysical()) { |
| manager.afterChange(false); |
| return; |
| } |
| final ASTNode[] changedElements = changeSet.getChangedElements(); |
| for (ASTNode changedElement : changedElements) { |
| TreeChange changesByElement = changeSet.getChangesByElement(changedElement); |
| PsiElement psiParent = null; |
| |
| while (changedElement != null && |
| ((psiParent = changedElement.getPsi()) == null || !checkPsiForChildren(changesByElement.getAffectedChildren()))) { |
| final ASTNode parent = changedElement.getTreeParent(); |
| final ChangeInfoImpl changeInfo = ChangeInfoImpl.create(ChangeInfo.CONTENTS_CHANGED, changedElement); |
| changeInfo.compactChange(changesByElement); |
| changesByElement = new TreeChangeImpl(parent); |
| changesByElement.addChange(changedElement, changeInfo); |
| changedElement = parent; |
| } |
| if (changedElement == null) continue; |
| |
| final ASTNode[] affectedChildren = changesByElement.getAffectedChildren(); |
| |
| for (final ASTNode treeElement : affectedChildren) { |
| PsiTreeChangeEventImpl psiEvent = new PsiTreeChangeEventImpl(manager); |
| psiEvent.setParent(psiParent); |
| psiEvent.setFile(file); |
| |
| final PsiElement psiChild = treeElement.getPsi(); |
| psiEvent.setChild(psiChild); |
| |
| final ChangeInfo changeByChild = changesByElement.getChangeByChild(treeElement); |
| switch (changeByChild.getChangeType()) { |
| case ChangeInfo.ADD: |
| psiEvent.setOffset(treeElement.getStartOffset()); |
| psiEvent.setOldLength(0); |
| manager.childAdded(psiEvent); |
| break; |
| case ChangeInfo.REPLACE: |
| final ReplaceChangeInfo change = (ReplaceChangeInfo)changeByChild; |
| psiEvent.setOffset(treeElement.getStartOffset()); |
| final ASTNode replaced = change.getReplaced(); |
| psiEvent.setOldChild(replaced.getPsi()); |
| psiEvent.setNewChild(psiChild); |
| psiEvent.setOldLength(replaced.getTextLength()); |
| manager.childReplaced(psiEvent); |
| break; |
| case ChangeInfo.CONTENTS_CHANGED: |
| psiEvent.setOffset(treeElement.getStartOffset()); |
| psiEvent.setParent(psiChild); |
| psiEvent.setOldLength(changeByChild.getOldLength()); |
| manager.childrenChanged(psiEvent); |
| break; |
| case ChangeInfo.REMOVED: |
| psiEvent.setOffset(changesByElement.getChildOffsetInNewTree(treeElement)); |
| psiEvent.setOldParent(psiParent); |
| psiEvent.setOldChild(psiChild); |
| psiEvent.setOldLength(changeByChild.getOldLength()); |
| manager.childRemoved(psiEvent); |
| break; |
| } |
| } |
| } |
| } |
| |
| private static boolean checkPsiForChildren(final ASTNode[] affectedChildren) { |
| for (final ASTNode astNode : affectedChildren) { |
| //if (TreeUtil.isCollapsedChameleon(astNode)) return false; |
| if (astNode.getPsi() == null) return false; |
| } |
| return true; |
| } |
| } |