blob: 0c2a490daff214fbfc84a736cc3c0fb5ffd590c2 [file] [log] [blame]
/*
* Copyright 2000-2013 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.todo;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.HashMap;
import java.util.*;
/**
* @author Vladimir Kondratyev
*/
final class FileTree {
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.todo.FileTree");
private final Map<VirtualFile, List<VirtualFile>> myDirectory2Children;
private final Set<VirtualFile> myFiles;
private final Map<VirtualFile, List<VirtualFile>> myStrictDirectory2Children;
FileTree() {
myDirectory2Children = new HashMap<VirtualFile, List<VirtualFile>>();
myFiles = new HashSet<VirtualFile>();
myStrictDirectory2Children = new HashMap<VirtualFile, List<VirtualFile>>();
}
void add(VirtualFile file) {
if (myFiles.contains(file)) {
return;
}
VirtualFile dir = file.getParent();
if (dir == null) {
LOG.error(file);
return;
}
myFiles.add(file);
List<VirtualFile> children = myStrictDirectory2Children.get(dir);
if (children != null) {
LOG.assertTrue(!children.contains(file));
children.add(file);
}
else {
children = new ArrayList<VirtualFile>(2);
children.add(file);
myStrictDirectory2Children.put(dir, children);
}
children = myDirectory2Children.get(dir);
if (children != null) {
LOG.assertTrue(!children.contains(file));
children.add(file);
return;
}
else {
children = new ArrayList<VirtualFile>(2);
children.add(file);
myDirectory2Children.put(dir, children);
}
VirtualFile parent = dir.getParent();
while (parent != null) {
children = myDirectory2Children.get(parent);
if (children != null) {
if ((!children.contains(dir))) {
children.add(dir);
}
return;
}
else {
children = new ArrayList<VirtualFile>(2);
children.add(dir);
myDirectory2Children.put(parent, children);
}
dir = parent;
parent = parent.getParent();
}
}
boolean isDirectoryEmpty(VirtualFile dir) {
final List<VirtualFile> files = myStrictDirectory2Children.get(dir);
return files == null || files.isEmpty();
}
List<VirtualFile> getFilesUnderDirectory(VirtualFile dir) {
List<VirtualFile> filesList = new ArrayList<VirtualFile>();
List<VirtualFile> files = myStrictDirectory2Children.get(dir);
if (files != null) {
filesList.addAll(files);
}
return filesList;
}
void removeFile(VirtualFile file) {
if (!myFiles.contains(file)) {
return;
}
myFiles.remove(file);
List<VirtualFile> dirsToBeRemoved = null;
for (VirtualFile _directory : myDirectory2Children.keySet()) {
List<VirtualFile> children = myDirectory2Children.get(_directory);
LOG.assertTrue(children != null);
if (children.contains(file)) {
children.remove(file);
if (children.size() == 0) {
if (dirsToBeRemoved == null) {
dirsToBeRemoved = new ArrayList<VirtualFile>(2);
}
dirsToBeRemoved.add(_directory); // we have to remove empty _directory
}
}
}
for (VirtualFile dir : myStrictDirectory2Children.keySet()) {
List<VirtualFile> children = myStrictDirectory2Children.get(dir);
LOG.assertTrue(children != null);
if (children.contains(file)) {
children.remove(file);
}
}
// We have remove also all removed (empty) directories
if (dirsToBeRemoved != null) {
LOG.assertTrue(dirsToBeRemoved.size() > 0);
for (VirtualFile dirToBeRemoved : dirsToBeRemoved) {
removeDir(dirToBeRemoved);
}
}
}
/**
* The method removes specified <code>psiDirectory</code> from the tree. The directory should be empty,
* otherwise the method shows java.lang.IllegalArgumentException
*/
private void removeDir(VirtualFile psiDirectory) {
if (!myDirectory2Children.containsKey(psiDirectory)) {
throw new IllegalArgumentException("directory is not in the tree: " + psiDirectory);
}
List<VirtualFile> children = myDirectory2Children.remove(psiDirectory);
if (children == null) {
throw new IllegalArgumentException("directory has no children list: " + psiDirectory);
}
if (children.size() > 0) {
throw new IllegalArgumentException("directory isn't empty: " + psiDirectory);
}
//
myStrictDirectory2Children.remove(psiDirectory);
List<VirtualFile> dirsToBeRemoved = null;
for (VirtualFile _directory : myDirectory2Children.keySet()) {
children = myDirectory2Children.get(_directory);
LOG.assertTrue(children != null);
if (children.contains(psiDirectory)) {
children.remove(psiDirectory);
if (children.size() == 0) {
if (dirsToBeRemoved == null) {
dirsToBeRemoved = new ArrayList<VirtualFile>(2);
}
dirsToBeRemoved.add(_directory); // we have remove empty _directory
}
}
}
//
if (dirsToBeRemoved != null) {
for (VirtualFile dirToBeRemoved : dirsToBeRemoved) {
removeDir(dirToBeRemoved);
}
}
}
boolean contains(VirtualFile file) {
return myFiles.contains(file);
}
void clear() {
myStrictDirectory2Children.clear();
myDirectory2Children.clear();
myFiles.clear();
}
/**
* @return iterator of all files.
*/
Iterator<VirtualFile> getFileIterator() {
return myFiles.iterator();
}
/**
* @return all files (in depth) located under specified <code>psiDirectory</code>.
* Please note that returned files can be invalid.
*/
List<VirtualFile> getFiles(VirtualFile dir) {
List<VirtualFile> filesList = new ArrayList<VirtualFile>();
collectFiles(dir, filesList);
return filesList;
}
private void collectFiles(VirtualFile dir, List<VirtualFile> filesList) {
List<VirtualFile> children = myDirectory2Children.get(dir);
if (children != null) {
for (VirtualFile child : children) {
if (!child.isDirectory()) {
LOG.assertTrue(!filesList.contains(child));
filesList.add(child);
}
else {
collectFiles(child, filesList);
}
}
}
}
}