IDEA-54010 (NPE at git4idea.history.browser.GitProjectLogManager.getCaption)
[idea/community.git] / plugins / git4idea / src / git4idea / history / browser / GitProjectLogManager.java
1 /*
2  * Copyright 2000-2010 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package git4idea.history.browser;
17
18 import com.intellij.openapi.components.ProjectComponent;
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.openapi.project.DumbAwareRunnable;
21 import com.intellij.openapi.project.Project;
22 import com.intellij.openapi.startup.StartupManager;
23 import com.intellij.openapi.util.ThrowableComputable;
24 import com.intellij.openapi.vcs.ProjectLevelVcsManager;
25 import com.intellij.openapi.vcs.VcsException;
26 import com.intellij.openapi.vcs.VcsListener;
27 import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager;
28 import com.intellij.openapi.vfs.VfsUtil;
29 import com.intellij.openapi.vfs.VirtualFile;
30 import com.intellij.ui.content.Content;
31 import com.intellij.ui.content.ContentFactory;
32 import com.intellij.util.CalculateContinuation;
33 import com.intellij.util.CatchingConsumer;
34 import com.intellij.util.containers.HashMap;
35 import git4idea.GitBranch;
36 import git4idea.GitBranchesSearcher;
37 import git4idea.GitVcs;
38 import org.jetbrains.annotations.NotNull;
39 import org.jetbrains.annotations.Nullable;
40
41 import java.util.Arrays;
42 import java.util.HashSet;
43 import java.util.Map;
44 import java.util.Set;
45 import java.util.concurrent.atomic.AtomicReference;
46
47 public class GitProjectLogManager implements ProjectComponent {
48   private final static Logger LOG = Logger.getInstance("#git4idea.history.browser.GitProjectLogManager");
49   private final Project myProject;
50   private final ProjectLevelVcsManager myVcsManager;
51
52   private final AtomicReference<Map<VirtualFile, Content>> myComponentsMap;
53   private VcsListener myListener;
54
55   public GitProjectLogManager(final Project project, final ProjectLevelVcsManager vcsManager) {
56     myProject = project;
57     myVcsManager = vcsManager;
58     myComponentsMap = new AtomicReference<Map<VirtualFile, Content>>(new HashMap<VirtualFile, Content>());
59     myListener = new VcsListener() {
60       public void directoryMappingChanged() {
61         recalculateWindows();
62       }
63     };
64   }
65
66   public static GitProjectLogManager getInstance(final Project project) {
67     return project.getComponent(GitProjectLogManager.class);
68   }
69
70   public void projectClosed() {
71     myVcsManager.removeVcsListener(myListener);
72   }
73
74   public void projectOpened() {
75     StartupManager.getInstance(myProject).registerPostStartupActivity(new DumbAwareRunnable() {
76       public void run() {
77         myVcsManager.addVcsListener(myListener);
78         recalculateWindows();
79       }
80     });
81   }
82
83   private void recalculateWindows() {
84     final GitVcs vcs = GitVcs.getInstance(myProject);
85     final VirtualFile[] roots = myVcsManager.getRootsUnderVcs(vcs);
86
87     final Map<VirtualFile, Content> currentState = myComponentsMap.get();
88     final Set<VirtualFile> currentKeys = new HashSet<VirtualFile>(currentState.keySet());
89     currentKeys.removeAll(Arrays.asList(roots));
90
91     final Map<VirtualFile, Content> newKeys = new HashMap<VirtualFile, Content>(currentState);
92
93     final ChangesViewContentManager cvcm = ChangesViewContentManager.getInstance(myProject);
94
95     final VirtualFile baseDir = myProject.getBaseDir();
96     final ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
97     for (final VirtualFile root : roots) {
98       if (! currentState.containsKey(root)) {
99         final GitLogTree tree = new GitLogTree(myProject, root);
100         tree.setParentDisposable(myProject);
101         tree.initView();
102         final Content content = contentFactory.createContent(tree.getComponent(), getCaption(baseDir, root), false);
103         content.setCloseable(false);
104         cvcm.addContent(content);
105         newKeys.put(root, content);
106         
107         new CalculateContinuation<String>().calculateAndContinue(new ThrowableComputable<String, Exception>() {
108           public String compute() throws Exception {
109             return getCaption(baseDir, root);
110           }
111         }, new CatchingConsumer<String, Exception>() {
112           public void consume(Exception e) {
113             //should not
114           }
115           public void consume(final String caption) {
116             content.setDisplayName(caption);
117           }
118         });
119       }
120     }
121
122     for (VirtualFile currentKey : currentKeys) {
123       final Content content = newKeys.remove(currentKey);
124       cvcm.removeContent(content);
125     }
126
127     myComponentsMap.set(newKeys);
128   }
129
130   private String getCaption(@Nullable VirtualFile baseDir, final VirtualFile root) {
131     String result = root.getPresentableUrl();                                                                                      
132     if (baseDir != null) {
133       if (baseDir.equals(root)) {
134         result = "<Project root>";
135       } else {
136         final String variant = VfsUtil.getRelativePath(baseDir, root, '/');
137         if ((variant != null) && (variant.length() < result.length())) {
138           result = variant;
139         }
140       }
141     }
142
143     GitBranchesSearcher searcher = null;
144     try {
145       searcher = new GitBranchesSearcher(myProject, root, false);
146     }
147     catch (VcsException e) {
148       LOG.info(e);
149     }
150
151     if (searcher != null) {
152       final GitBranch branch = searcher.getLocal();
153       if (branch != null) {
154         result += " (" + branch.getName() + ")";
155       }
156     }
157     return "Log: " + result;
158   }
159
160   @NotNull
161   public String getComponentName() {
162     return "git4idea.history.browser.GitProjectLogManager";
163   }
164
165   public void initComponent() {
166   }
167
168   public void disposeComponent() {
169   }
170 }