blob: 54c461caeed4c666f6a149af28eba9ca80d05760 [file] [log] [blame]
/*
* 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;
}
}