ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / changes / RecursiveFileHolder.java
blobee08855a3ed1f649847d5f4c180c167c334a8034
1 /*
2 * Copyright (c) 2007, Your Corporation. All Rights Reserved.
3 */
5 package com.intellij.openapi.vcs.changes;
7 import com.intellij.openapi.application.ApplicationManager;
8 import com.intellij.openapi.diff.impl.patch.formove.FilePathComparator;
9 import com.intellij.openapi.project.Project;
10 import com.intellij.openapi.vcs.FilePathImpl;
11 import com.intellij.openapi.vcs.ProjectLevelVcsManager;
12 import com.intellij.openapi.vfs.VfsUtil;
13 import com.intellij.openapi.vfs.VirtualFile;
14 import com.intellij.util.containers.MultiMap;
15 import org.jetbrains.annotations.NotNull;
17 import java.util.*;
19 /**
20 * @author max
22 public class RecursiveFileHolder implements FileHolder {
23 protected final HolderType myHolderType;
24 protected final Map<VirtualFile, String> myFiles = new HashMap<VirtualFile, String>();
25 protected List<VirtualFile> mySwitchRoots;
26 protected final Project myProject;
28 public RecursiveFileHolder(final Project project, final HolderType holderType) {
29 myProject = project;
30 myHolderType = holderType;
33 public synchronized void cleanAll() {
34 myFiles.clear();
35 if (mySwitchRoots != null) {
36 mySwitchRoots.clear();
40 public void cleanScope(final VcsDirtyScope scope) {
41 ApplicationManager.getApplication().runReadAction(new Runnable() {
42 public void run() {
43 // to avoid deadlocks caused by incorrect lock ordering, need to lock on this after taking read action
44 synchronized(RecursiveFileHolder.this) {
45 if (myProject.isDisposed()) return;
46 final List<VirtualFile> currentFiles = new ArrayList<VirtualFile>(myFiles.keySet());
47 for (VirtualFile file : currentFiles) {
48 if (isFileDirty(scope, file)) {
49 if (mySwitchRoots != null) {
50 mySwitchRoots.remove(file);
52 myFiles.remove(file);
57 });
60 protected boolean isFileDirty(final VcsDirtyScope scope, final VirtualFile file) {
61 return fileDropped(file) || scope.belongsTo(new FilePathImpl(file));
64 public HolderType getType() {
65 return myHolderType;
68 protected boolean fileDropped(final VirtualFile file) {
69 return !file.isValid() || ProjectLevelVcsManager.getInstance(myProject).getVcsFor(file) == null;
72 public synchronized void addFile(VirtualFile file, @NotNull String branchName, final boolean recursive) {
73 myFiles.put(file, branchName);
76 // remove switched to same branch decsendants
77 private void preCheckFiles() {
78 // do not take latest as parent
79 for (int i = 0; i < (mySwitchRoots.size() - 1); i++) {
80 final VirtualFile switchRoot = mySwitchRoots.get(i);
81 final String parentUrl = myFiles.get(switchRoot);
83 for (Iterator<VirtualFile> iterator = mySwitchRoots.listIterator(i + 1); iterator.hasNext();) {
84 final VirtualFile file = iterator.next();
85 final String childUrl = myFiles.get(file);
87 if (VfsUtil.isAncestor(switchRoot, file, true) && childUrl.startsWith(parentUrl)) {
88 if (childUrl.length() > parentUrl.length()) {
89 //check paths same
90 String subUrl = childUrl.substring(parentUrl.length());
91 subUrl = subUrl.startsWith("/") ? subUrl.substring(1) : subUrl;
92 String relativePath = VfsUtil.getRelativePath(file, switchRoot, '/');
93 if (relativePath != null) {
94 relativePath = relativePath.startsWith("/") ? relativePath.substring(1) : relativePath;
95 if (relativePath.equals(subUrl)) {
96 iterator.remove();
99 } else if (childUrl.length() == parentUrl.length()) {
100 iterator.remove();
106 // remove from map also
107 for (Iterator<Map.Entry<VirtualFile, String>> iterator = myFiles.entrySet().iterator(); iterator.hasNext();) {
108 final Map.Entry<VirtualFile, String> entry = iterator.next();
109 if (! mySwitchRoots.contains(entry.getKey())) {
110 iterator.remove();
115 public synchronized void calculateChildren() {
116 // recursive is always true, so just go for children
117 mySwitchRoots = new ArrayList<VirtualFile>(myFiles.keySet());
118 Collections.sort(mySwitchRoots, FilePathComparator.getInstance());
120 preCheckFiles();
122 Collections.reverse(mySwitchRoots);
125 public synchronized void removeFile(VirtualFile file) {
126 myFiles.remove(file);
127 if (mySwitchRoots != null) {
128 mySwitchRoots.remove(file);
132 public synchronized RecursiveFileHolder copy() {
133 final RecursiveFileHolder copyHolder = new RecursiveFileHolder(myProject, myHolderType);
134 copyHolder.myFiles.putAll(myFiles);
135 return copyHolder;
138 public synchronized boolean containsFile(final VirtualFile file) {
139 return getBranchForFile(file) != null;
142 public synchronized MultiMap<String, VirtualFile> getBranchToFileMap() {
143 MultiMap<String, VirtualFile> result = new MultiMap<String, VirtualFile>();
144 for(Map.Entry<VirtualFile, String> e: myFiles.entrySet()) {
145 result.putValue(e.getValue(), e.getKey());
147 return result;
150 public String getBranchForFile(final VirtualFile file) {
151 for (VirtualFile vf : myFiles.keySet()) {
152 if (VfsUtil.isAncestor(vf, file, false)) {
153 return myFiles.get(vf);
156 return null;
159 public boolean equals(final Object o) {
160 if (this == o) return true;
161 if (o == null || getClass() != o.getClass()) return false;
163 final RecursiveFileHolder that = (RecursiveFileHolder)o;
165 if (!myFiles.equals(that.myFiles)) return false;
167 return true;
170 public int hashCode() {
171 return myFiles.hashCode();