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.
17 package com.intellij.openapi.vcs.changes.ui;
19 import com.intellij.openapi.Disposable;
20 import com.intellij.openapi.application.ApplicationManager;
21 import com.intellij.openapi.application.ModalityState;
22 import com.intellij.openapi.components.AbstractProjectComponent;
23 import com.intellij.openapi.project.DumbAwareRunnable;
24 import com.intellij.openapi.project.Project;
25 import com.intellij.openapi.startup.StartupManager;
26 import com.intellij.openapi.util.Disposer;
27 import com.intellij.openapi.util.IconLoader;
28 import com.intellij.openapi.util.Key;
29 import com.intellij.openapi.vcs.AbstractVcs;
30 import com.intellij.openapi.vcs.ProjectLevelVcsManager;
31 import com.intellij.openapi.vcs.VcsBundle;
32 import com.intellij.openapi.vcs.VcsListener;
33 import com.intellij.openapi.wm.ToolWindow;
34 import com.intellij.openapi.wm.ToolWindowAnchor;
35 import com.intellij.openapi.wm.ToolWindowManager;
36 import com.intellij.ui.content.*;
37 import com.intellij.util.Alarm;
38 import com.intellij.util.NotNullFunction;
39 import org.jetbrains.annotations.NonNls;
40 import org.jetbrains.annotations.NotNull;
41 import org.jetbrains.annotations.Nullable;
49 public class ChangesViewContentManager extends AbstractProjectComponent {
50 public static final String TOOLWINDOW_ID = VcsBundle.message("changes.toolwindow.name");
51 private static final Key<ChangesViewContentEP> myEPKey = Key.create("ChangesViewContentEP");
52 private MyContentManagerListener myContentManagerListener;
53 private final ProjectLevelVcsManager myVcsManager;
55 public static ChangesViewContentManager getInstance(Project project) {
56 return project.getComponent(ChangesViewContentManager.class);
59 private ContentManager myContentManager;
60 private ToolWindow myToolWindow;
61 private final VcsListener myVcsListener = new MyVcsListener();
62 private final Alarm myVcsChangeAlarm;
63 private final List<Content> myAddedContents = new ArrayList<Content>();
65 public ChangesViewContentManager(final Project project, final ProjectLevelVcsManager vcsManager) {
67 myVcsManager = vcsManager;
68 myVcsChangeAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, project);
71 public void projectOpened() {
72 if (ApplicationManager.getApplication().isHeadlessEnvironment()) return;
73 StartupManager.getInstance(myProject).registerPostStartupActivity(new DumbAwareRunnable() {
75 final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject);
76 if (toolWindowManager != null) {
77 myToolWindow = toolWindowManager.registerToolWindow(TOOLWINDOW_ID, true, ToolWindowAnchor.BOTTOM, myProject, true);
78 myToolWindow.setIcon(IconLoader.getIcon("/general/toolWindowChanges.png"));
79 updateToolWindowAvailability();
80 final ContentManager contentManager = myToolWindow.getContentManager();
81 myContentManagerListener = new MyContentManagerListener();
82 contentManager.addContentManagerListener(myContentManagerListener);
84 myVcsManager.addVcsListener(myVcsListener);
86 Disposer.register(myProject, new Disposable(){
87 public void dispose() {
88 contentManager.removeContentManagerListener(myContentManagerListener);
90 myVcsManager.removeVcsListener(myVcsListener);
95 myContentManager = contentManager;
96 final List<Content> ordered = doPresetOrdering(myAddedContents);
97 for(Content content: ordered) {
98 myContentManager.addContent(content);
100 myAddedContents.clear();
101 if (contentManager.getContentCount() > 0) {
102 contentManager.setSelectedContent(contentManager.getContent(0));
109 private void loadExtensionTabs() {
110 final List<Content> contentList = new LinkedList<Content>();
111 final ChangesViewContentEP[] contentEPs = myProject.getExtensions(ChangesViewContentEP.EP_NAME);
112 for(ChangesViewContentEP ep: contentEPs) {
113 final NotNullFunction<Project,Boolean> predicate = ep.newPredicateInstance(myProject);
114 if (predicate == null || predicate.fun(myProject).equals(Boolean.TRUE)) {
115 final Content content = ContentFactory.SERVICE.getInstance().createContent(new ContentStub(ep), ep.getTabName(), false);
116 content.setCloseable(false);
117 content.putUserData(myEPKey, ep);
118 contentList.add(content);
121 myAddedContents.addAll(0, contentList);
124 private void addExtensionTab(final ChangesViewContentEP ep) {
125 final Content content = ContentFactory.SERVICE.getInstance().createContent(new ContentStub(ep), ep.getTabName(), false);
126 content.setCloseable(false);
127 content.putUserData(myEPKey, ep);
128 addIntoCorrectPlace(content);
131 private void updateExtensionTabs() {
132 final ChangesViewContentEP[] contentEPs = myProject.getExtensions(ChangesViewContentEP.EP_NAME);
133 for(ChangesViewContentEP ep: contentEPs) {
134 final NotNullFunction<Project,Boolean> predicate = ep.newPredicateInstance(myProject);
135 if (predicate == null) continue;
136 Content epContent = findEPContent(ep);
137 final Boolean predicateResult = predicate.fun(myProject);
138 if (predicateResult.equals(Boolean.TRUE) && epContent == null) {
141 else if (predicateResult.equals(Boolean.FALSE) && epContent != null) {
142 if (!(epContent.getComponent() instanceof ContentStub)) {
143 ep.getInstance(myProject).disposeContent();
145 myContentManager.removeContent(epContent, true);
151 private Content findEPContent(final ChangesViewContentEP ep) {
152 final Content[] contents = myContentManager.getContents();
153 for(Content content: contents) {
154 if (content.getUserData(myEPKey) == ep) {
161 private void updateToolWindowAvailability() {
162 final AbstractVcs[] abstractVcses = myVcsManager.getAllActiveVcss();
163 myToolWindow.setAvailable(abstractVcses.length > 0, null);
166 public void projectClosed() {
167 myVcsChangeAlarm.cancelAllRequests();
171 public String getComponentName() {
172 return "ChangesViewContentManager";
175 public void addContent(Content content) {
176 if (myContentManager == null) {
177 myAddedContents.add(content);
180 addIntoCorrectPlace(content);
184 public void removeContent(final Content content) {
185 if (myContentManager != null) { // for unit tests
186 myContentManager.removeContent(content, true);
190 public void setSelectedContent(final Content content) {
191 myContentManager.setSelectedContent(content);
195 public <T> T getActiveComponent(final Class<T> aClass) {
196 final Content content = myContentManager.getSelectedContent();
197 if (content != null && aClass.isInstance(content.getComponent())) {
198 //noinspection unchecked
199 return (T) content.getComponent();
204 public void selectContent(final String tabName) {
205 for(Content content: myContentManager.getContents()) {
206 if (content.getDisplayName().equals(tabName)) {
207 myContentManager.setSelectedContent(content);
213 private class MyVcsListener implements VcsListener {
214 public void directoryMappingChanged() {
215 myVcsChangeAlarm.cancelAllRequests();
216 myVcsChangeAlarm.addRequest(new Runnable() {
218 if (myProject.isDisposed()) return;
219 updateToolWindowAvailability();
220 updateExtensionTabs();
222 }, 100, ModalityState.NON_MODAL);
226 private static class ContentStub extends JPanel {
227 private final ChangesViewContentEP myEP;
229 private ContentStub(final ChangesViewContentEP EP) {
233 public ChangesViewContentEP getEP() {
238 private class MyContentManagerListener extends ContentManagerAdapter {
239 public void selectionChanged(final ContentManagerEvent event) {
240 Content content = event.getContent();
241 if (content.getComponent() instanceof ContentStub) {
242 ChangesViewContentEP ep = ((ContentStub) content.getComponent()).getEP();
243 ChangesViewContentProvider provider = ep.getInstance(myProject);
244 final JComponent contentComponent = provider.initContent();
245 content.setComponent(contentComponent);
246 if (contentComponent instanceof Disposable) {
247 content.setDisposer((Disposable) contentComponent);
253 private static final String[] ourPresetOrder = {"Local", "Repository", "Incoming", "Shelf"};
254 private static List<Content> doPresetOrdering(final List<Content> contents) {
255 final List<Content> result = new ArrayList<Content>(contents.size());
256 for (final String preset : ourPresetOrder) {
257 for (Iterator<Content> iterator = contents.iterator(); iterator.hasNext();) {
258 final Content current = iterator.next();
259 if (preset.equals(current.getTabName())) {
265 result.addAll(contents);
269 private void addIntoCorrectPlace(final Content content) {
270 final String name = content.getTabName();
271 final Content[] contents = myContentManager.getContents();
273 int idxOfBeingInserted = -1;
274 for (int i = 0; i < ourPresetOrder.length; i++) {
275 final String s = ourPresetOrder[i];
276 if (s.equals(name)) {
277 idxOfBeingInserted = i;
280 if (idxOfBeingInserted == -1) {
281 myContentManager.addContent(content);
285 final Set<String> existingNames = new HashSet<String>();
286 for (Content existingContent : contents) {
287 existingNames.add(existingContent.getTabName());
290 int place = idxOfBeingInserted;
291 for (int i = 0; i < idxOfBeingInserted; i++) {
292 if (! existingNames.contains(ourPresetOrder[i])) {
297 myContentManager.addContent(content, place);