IDEADEV-41995
[fedora-idea.git] / plugins / cvs / cvs-plugin / src / com / intellij / cvsSupport2 / application / CvsEntriesManager.java
blob5239937f1b9d1c6f74ee1ddf24387b039b22bfda
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.cvsSupport2.application;
18 import com.intellij.cvsSupport2.CvsUtil;
19 import com.intellij.cvsSupport2.config.CvsApplicationLevelConfiguration;
20 import com.intellij.cvsSupport2.config.CvsRootConfiguration;
21 import com.intellij.cvsSupport2.connections.CvsConnectionSettings;
22 import com.intellij.cvsSupport2.connections.IDEARootFormatter;
23 import com.intellij.cvsSupport2.cvsIgnore.IgnoredFilesInfo;
24 import com.intellij.cvsSupport2.cvsIgnore.UserDirIgnores;
25 import com.intellij.cvsSupport2.cvsstatuses.CvsEntriesListener;
26 import com.intellij.cvsSupport2.util.CvsVfsUtil;
27 import com.intellij.openapi.application.ApplicationManager;
28 import com.intellij.openapi.components.ServiceManager;
29 import com.intellij.openapi.diagnostic.Logger;
30 import com.intellij.openapi.progress.ProcessCanceledException;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.openapi.project.ProjectManager;
33 import com.intellij.openapi.vcs.FileStatusManager;
34 import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
35 import com.intellij.openapi.vfs.*;
36 import com.intellij.util.ArrayUtil;
37 import com.intellij.util.containers.HashMap;
38 import com.intellij.util.containers.HashSet;
39 import org.jetbrains.annotations.NotNull;
40 import org.jetbrains.annotations.Nullable;
41 import org.netbeans.lib.cvsclient.admin.Entry;
43 import java.io.File;
44 import java.util.ArrayList;
45 import java.util.Collection;
46 import java.util.Map;
48 /**
49 * author: lesya
52 public class CvsEntriesManager extends VirtualFileAdapter {
54 private static final Logger LOG = Logger.getInstance("#com.intellij.cvsSupport2.application.CvsEntriesManager");
56 private final Map<VirtualFile, CvsInfo> myInfoByParentDirectoryPath = new HashMap<VirtualFile, CvsInfo>();
58 private static final String CVS_ADMIN_DIRECTORY_NAME = CvsUtil.CVS;
60 private final Collection<CvsEntriesListener> myEntriesListeners = new ArrayList<CvsEntriesListener>();
61 private int myIsActive = 0;
62 private final Collection<String> myFilesToRefresh = new HashSet<String>();
63 private int mySynchronizationActionLocks = 0;
65 private final Map<String, CvsConnectionSettings> myStringToSettingsMap = new HashMap<String, CvsConnectionSettings>();
66 private final UserDirIgnores myUserDirIgnores = new UserDirIgnores();
67 private final MyVirtualFileManagerListener myVirtualFileManagerListener = new MyVirtualFileManagerListener();
68 private final CvsApplicationLevelConfiguration myApplicationLevelConfiguration;
70 public static CvsEntriesManager getInstance() {
71 return ServiceManager.getService(CvsEntriesManager.class);
74 public CvsEntriesManager(final CvsApplicationLevelConfiguration applicationLevelConfiguration) {
75 myApplicationLevelConfiguration = applicationLevelConfiguration;
78 private class MyVirtualFileManagerListener implements VirtualFileManagerListener {
79 public void afterRefreshFinish(boolean asynchonous) {
80 ensureFilesCached(); //to cache for next refreshes
83 public void beforeRefreshStart(boolean asynchonous) {
87 public void registerAsVirtualFileListener() {
88 if (myIsActive == 0) {
89 VirtualFileManager.getInstance().addVirtualFileListener(this);
90 VirtualFileManager.getInstance().addVirtualFileManagerListener(myVirtualFileManagerListener);
92 myIsActive++;
95 public synchronized void unregisterAsVirtualFileListener() {
96 LOG.assertTrue(isActive());
97 myIsActive--;
98 if (myIsActive == 0) {
99 VirtualFileManager.getInstance().removeVirtualFileListener(this);
100 VirtualFileManager.getInstance().removeVirtualFileManagerListener(myVirtualFileManagerListener);
101 myInfoByParentDirectoryPath.clear();
105 public void beforePropertyChange(VirtualFilePropertyEvent event) {
106 processEvent(event);
109 public void beforeContentsChange(VirtualFileEvent event) {
110 processEvent(event);
113 public void contentsChanged(VirtualFileEvent event) {
114 fireStatusChanged(event.getFile());
118 @NotNull
119 private synchronized CvsInfo getInfoFor(VirtualFile parent) {
120 if (!myInfoByParentDirectoryPath.containsKey(parent)) {
121 CvsInfo cvsInfo = new CvsInfo(parent, this);
122 myInfoByParentDirectoryPath.put(cvsInfo.getKey(), cvsInfo);
124 return myInfoByParentDirectoryPath.get(parent);
127 public synchronized void clearCachedFiltersFor(final VirtualFile parent) {
128 for (final VirtualFile file : myInfoByParentDirectoryPath.keySet()) {
129 if (file == null) continue;
130 if (!file.isValid()) continue;
131 if (VfsUtil.isAncestor(parent, file, false)) {
132 myInfoByParentDirectoryPath.get(file)
133 .clearFilter();
136 fileStatusesChanged();
139 private static void fileStatusesChanged() {
140 Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
141 for (Project project : openProjects) {
142 VcsDirtyScopeManager.getInstance(project).markEverythingDirty();
146 private static boolean isCvsIgnoreFile(VirtualFile file) {
147 return CvsUtil.CVS_IGNORE_FILE.equals(file.getName());
150 public IgnoredFilesInfo getFilter(VirtualFile parent) {
151 return getInfoFor(parent).getIgnoreFilter();
154 public void beforeFileDeletion(VirtualFileEvent event) {
155 processEvent(event);
158 public void beforeFileMovement(VirtualFileMoveEvent event) {
159 processEvent(event);
162 public void fileCreated(VirtualFileEvent event) {
163 processEvent(event);
166 private void processEvent(VirtualFileEvent event) {
167 VirtualFile file = event.getFile();
169 if (isUserHomeCvsIgnoreFile(file)) {
170 myUserDirIgnores.clearInfo();
171 fileStatusesChanged();
172 return;
175 if (isCvsIgnoreFile(file)) {
176 clearCachedFiltersFor(file.getParent());
177 return;
180 if (isCvsAdminDir(file.getParent())) {
181 VirtualFile parent = file.getParent().getParent();
182 clearCachedEntriesFor(parent);
183 return;
186 if (isCvsAdminDir(file)) {
187 clearCachedEntriesFor(file.getParent());
188 return;
191 if (file.isDirectory()) {
192 clearCachedEntriesRecursive(file);
196 private static boolean isCvsAdminDir(VirtualFile file) {
197 if (file == null) return false;
198 return file.isDirectory() && CVS_ADMIN_DIRECTORY_NAME.equals(file.getName());
201 private synchronized void clearCachedEntriesRecursive(VirtualFile parent) {
202 if (!parent.isDirectory()) return;
204 for (final VirtualFile file : myInfoByParentDirectoryPath.keySet()) {
205 if (file == null) continue;
206 if (!file.isValid()) continue;
207 if (VfsUtil.isAncestor(parent, file, false)) clearCachedEntriesFor(file);
211 public Entry getEntryFor(VirtualFile parent, String name) {
212 return getCvsInfo(parent).getEntryNamed(name);
215 public Entry getEntryFor(@NotNull VirtualFile file) {
216 final CvsInfo cvsInfo = getCvsInfo(file.getParent());
217 assert(cvsInfo != null);
218 return cvsInfo.getEntryNamed(file.getName());
221 public void clearCachedEntriesFor(final VirtualFile parent) {
222 if (parent == null) return;
224 CvsInfo cvsInfo = getInfoFor(parent);
225 cvsInfo.clearFilter();
226 if (cvsInfo.isLoaded()) {
227 cvsInfo.clearAll();
228 ApplicationManager.getApplication().invokeLater(new Runnable() {
229 public void run() {
230 if (parent.isValid()) {
231 onEntriesChanged(parent);
238 @Nullable
239 public Entry getCachedEntry(VirtualFile parent, String fileName){
240 if (parent == null) return null;
242 CvsInfo cvsInfo = getInfoFor(parent);
244 if (!cvsInfo.isLoaded()) return null;
245 return cvsInfo.getEntryNamed(fileName);
248 public void setEntryForFile(final VirtualFile parent, final Entry entry) {
249 if (parent == null) return;
251 CvsInfo cvsInfo = getInfoFor(parent);
253 if (!cvsInfo.isLoaded()) return;
255 cvsInfo.setEntryAndReturnReplacedEntry(entry);
257 ApplicationManager.getApplication().invokeLater(new Runnable() {
258 public void run() {
259 final VirtualFile file = CvsVfsUtil.findChild(parent, entry.getFileName());
260 if (file != null) {
261 onEntryChanged(file);
267 public void removeEntryForFile(final File parent, final String fileName) {
268 CvsInfo cvsInfo = getInfoFor(CvsVfsUtil.findFileByIoFile(parent));
269 if (!cvsInfo.isLoaded()) return;
271 cvsInfo.removeEntryNamed(fileName);
273 final VirtualFile[] file = new VirtualFile[1];
275 ApplicationManager.getApplication().invokeLater(new Runnable() {
276 public void run() {
277 ApplicationManager.getApplication().runReadAction(new Runnable() {
278 public void run() {
279 file[0] = LocalFileSystem.getInstance().findFileByIoFile(new File(parent, fileName));
282 if (file[0] != null) {
283 onEntryChanged(file[0]);
289 private void onEntriesChanged(final VirtualFile parent) {
290 final CvsEntriesListener[] listeners = myEntriesListeners.toArray(new CvsEntriesListener[myEntriesListeners.size()]);
291 for (CvsEntriesListener listener : listeners) {
292 listener.entriesChanged(parent);
296 private void onEntryChanged(final VirtualFile file) {
297 final CvsEntriesListener[] listeners = myEntriesListeners.toArray(new CvsEntriesListener[myEntriesListeners.size()]);
298 for (CvsEntriesListener listener : listeners) {
299 listener.entryChanged(file);
303 public void watchForCvsAdminFiles(final VirtualFile parent) {
304 if (parent == null) return;
305 synchronized (myFilesToRefresh) {
306 myFilesToRefresh.add(parent.getPath() + "/" + CVS_ADMIN_DIRECTORY_NAME);
311 public Collection<Entry> getEntriesIn(VirtualFile parent) {
312 return getCvsInfo(parent).getEntries();
316 private CvsInfo getCvsInfo(VirtualFile parent) {
317 if (! isActive()) {
318 throw new ProcessCanceledException();
320 if (parent == null) return CvsInfo.getDummyCvsInfo();
321 return getInfoFor(parent);
324 public void addCvsEntriesListener(CvsEntriesListener listener) {
325 myEntriesListeners.add(listener);
328 public void removeCvsEntriesListener(CvsEntriesListener listener) {
329 myEntriesListeners.remove(listener);
332 public synchronized void clearAll() {
333 myInfoByParentDirectoryPath.clear();
336 public boolean fileIsIgnored(VirtualFile file) {
337 VirtualFile parent = file.getParent();
338 if (parent == null) {
339 return false;
341 if (CvsUtil.fileIsUnderCvs(file)) return false;
342 return getFilter(parent).shouldBeIgnored(file.getName());
345 public void lockSynchronizationActions() {
346 mySynchronizationActionLocks++;
349 public void unlockSynchronizationActions() {
350 LOG.assertTrue(mySynchronizationActionLocks > 0);
351 mySynchronizationActionLocks--;
354 private void ensureFilesCached() {
355 String[] paths;
356 synchronized (myFilesToRefresh) {
357 paths = ArrayUtil.toStringArray(myFilesToRefresh);
358 myFilesToRefresh.clear();
360 for (String path : paths) {
361 VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(path);
362 if (virtualFile != null) virtualFile.getChildren();
366 public CvsConnectionSettings getCvsConnectionSettingsFor(VirtualFile root) {
367 return getInfoFor(root).getConnectionSettings();
370 public CvsConnectionSettings getCvsConnectionSettingsFor(@NotNull File root) {
371 return getCvsConnectionSettingsFor(CvsVfsUtil.refreshAndFindFileByIoFile(root));
374 public CvsInfo getCvsInfoFor(VirtualFile directory) {
375 return getInfoFor(directory);
378 public CvsConnectionSettings createConnectionSettingsOn(String cvsRoot) {
379 if (!myStringToSettingsMap.containsKey(cvsRoot)) {
380 final CvsRootConfiguration rootConfiguration = myApplicationLevelConfiguration.getConfigurationForCvsRoot(cvsRoot);
381 CvsConnectionSettings settings = new IDEARootFormatter(rootConfiguration).createConfiguration();
382 myStringToSettingsMap.put(cvsRoot, settings);
384 return myStringToSettingsMap.get(cvsRoot);
387 public UserDirIgnores getUserdIgnores() {
388 return myUserDirIgnores;
391 private static void fireStatusChanged(VirtualFile file) {
392 Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
393 for (Project project : openProjects) {
394 FileStatusManager.getInstance(project).fileStatusChanged(file);
395 VcsDirtyScopeManager.getInstance(project).fileDirty(file);
399 private boolean isUserHomeCvsIgnoreFile(VirtualFile file) {
400 return myUserDirIgnores.userHomeCvsIgnoreFile().equals(CvsVfsUtil.getFileFor(file));
403 public boolean isActive() {
404 return myIsActive > 0;
407 public String getRepositoryFor(VirtualFile root) {
408 return getInfoFor(root).getRepository();
411 public void cacheCvsAdminInfoIn(VirtualFile root) {
412 getInfoFor(root).cacheAll();
415 public String getStickyTagFor(VirtualFile fileByIoFile) {
416 return getCvsInfo(fileByIoFile).getStickyTag();
419 public void encodingChanged() {
420 if (!isActive()) return;
421 clearAll();
422 fileStatusesChanged();