/* * 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.ide.projectView; import com.intellij.ide.util.treeView.AbstractTreeUpdater; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.util.PsiModificationTracker; import org.jetbrains.annotations.NotNull; import javax.swing.tree.DefaultMutableTreeNode; public abstract class ProjectViewPsiTreeChangeListener extends PsiTreeChangeAdapter { private final PsiModificationTracker myModificationTracker; private long myOutOfCodeBlockModificationCount; protected ProjectViewPsiTreeChangeListener(@NotNull Project project) { myModificationTracker = PsiManager.getInstance(project).getModificationTracker(); myOutOfCodeBlockModificationCount = myModificationTracker.getOutOfCodeBlockModificationCount(); } protected abstract AbstractTreeUpdater getUpdater(); protected abstract boolean isFlattenPackages(); protected abstract DefaultMutableTreeNode getRootNode(); @Override public final void childRemoved(@NotNull PsiTreeChangeEvent event) { PsiElement child = event.getOldChild(); if (child instanceof PsiWhiteSpace) return; //optimization childrenChanged(event.getParent(), true); } @Override public final void childAdded(@NotNull PsiTreeChangeEvent event) { PsiElement child = event.getNewChild(); if (child instanceof PsiWhiteSpace) return; //optimization childrenChanged(event.getParent(), true); } @Override public final void childReplaced(@NotNull PsiTreeChangeEvent event) { PsiElement oldChild = event.getOldChild(); PsiElement newChild = event.getNewChild(); if (oldChild instanceof PsiWhiteSpace && newChild instanceof PsiWhiteSpace) return; //optimization childrenChanged(event.getParent(), true); } @Override public final void childMoved(@NotNull PsiTreeChangeEvent event) { childrenChanged(event.getOldParent(), false); childrenChanged(event.getNewParent(), true); } @Override public final void childrenChanged(@NotNull PsiTreeChangeEvent event) { childrenChanged(event.getParent(), true); } protected void childrenChanged(PsiElement parent, final boolean stopProcessingForThisModificationCount) { if (parent instanceof PsiDirectory && isFlattenPackages()){ getUpdater().addSubtreeToUpdate(getRootNode()); return; } long newModificationCount = myModificationTracker.getOutOfCodeBlockModificationCount(); if (newModificationCount == myOutOfCodeBlockModificationCount) return; if (stopProcessingForThisModificationCount) { myOutOfCodeBlockModificationCount = newModificationCount; } while (true) { if (parent == null) break; if (parent instanceof PsiFile) { VirtualFile virtualFile = ((PsiFile)parent).getVirtualFile(); if (virtualFile != null && virtualFile.getFileType() != FileTypes.PLAIN_TEXT) { // adding a class within a file causes a new node to appear in project view => entire dir should be updated parent = ((PsiFile)parent).getContainingDirectory(); if (parent == null) break; } } if (getUpdater().addSubtreeToUpdateByElement(parent)) { break; } if (parent instanceof PsiFile || parent instanceof PsiDirectory) break; parent = parent.getParent(); } } @Override public void propertyChanged(@NotNull PsiTreeChangeEvent event) { String propertyName = event.getPropertyName(); PsiElement element = event.getElement(); DefaultMutableTreeNode rootNode = getRootNode(); AbstractTreeUpdater updater = getUpdater(); if (propertyName.equals(PsiTreeChangeEvent.PROP_ROOTS)) { updater.addSubtreeToUpdate(rootNode); } else if (propertyName.equals(PsiTreeChangeEvent.PROP_WRITABLE)){ if (!updater.addSubtreeToUpdateByElement(element) && element instanceof PsiFile) { updater.addSubtreeToUpdateByElement(((PsiFile)element).getContainingDirectory()); } } else if (propertyName.equals(PsiTreeChangeEvent.PROP_FILE_NAME) || propertyName.equals(PsiTreeChangeEvent.PROP_DIRECTORY_NAME)){ if (element instanceof PsiDirectory && isFlattenPackages()){ updater.addSubtreeToUpdate(rootNode); return; } final PsiElement parent = element.getParent(); if (parent == null || !updater.addSubtreeToUpdateByElement(parent)) { updater.addSubtreeToUpdateByElement(element); } } else if (propertyName.equals(PsiTreeChangeEvent.PROP_FILE_TYPES)){ updater.addSubtreeToUpdate(rootNode); } } }