2 * Copyright (c) 2007, Your Corporation. All Rights Reserved.
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
;
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
) {
30 myHolderType
= holderType
;
33 public synchronized void cleanAll() {
35 if (mySwitchRoots
!= null) {
36 mySwitchRoots
.clear();
40 public void cleanScope(final VcsDirtyScope scope
) {
41 ApplicationManager
.getApplication().runReadAction(new Runnable() {
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
);
60 protected boolean isFileDirty(final VcsDirtyScope scope
, final VirtualFile file
) {
61 return fileDropped(file
) || scope
.belongsTo(new FilePathImpl(file
));
64 public HolderType
getType() {
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()) {
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
)) {
99 } else if (childUrl
.length() == parentUrl
.length()) {
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())) {
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());
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
);
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());
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
);
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;
170 public int hashCode() {
171 return myFiles
.hashCode();