2b46136e45ad6bbd12c45673fb352fd29da733dc
[idea/community.git] / platform / platform-impl / src / com / intellij / openapi / wm / impl / LibraryDependentToolWindowManager.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.openapi.wm.impl;
3
4 import com.intellij.ProjectTopics;
5 import com.intellij.openapi.application.Application;
6 import com.intellij.openapi.application.ApplicationManager;
7 import com.intellij.openapi.application.ModalityState;
8 import com.intellij.openapi.application.ReadAction;
9 import com.intellij.openapi.extensions.ExtensionNotApplicableException;
10 import com.intellij.openapi.extensions.ExtensionPointListener;
11 import com.intellij.openapi.extensions.PluginDescriptor;
12 import com.intellij.openapi.project.Project;
13 import com.intellij.openapi.roots.ModuleRootEvent;
14 import com.intellij.openapi.roots.ModuleRootListener;
15 import com.intellij.openapi.startup.StartupActivity;
16 import com.intellij.openapi.wm.ToolWindow;
17 import com.intellij.openapi.wm.ToolWindowManager;
18 import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
19 import com.intellij.openapi.wm.ext.LibraryDependentToolWindow;
20 import com.intellij.openapi.wm.ext.LibrarySearchHelper;
21 import com.intellij.util.concurrency.SequentialTaskExecutor;
22 import com.intellij.util.containers.ContainerUtil;
23 import com.intellij.util.messages.SimpleMessageBusConnection;
24 import org.jetbrains.annotations.NotNull;
25
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.concurrent.Executor;
30
31 final class LibraryDependentToolWindowManager implements StartupActivity {
32   private static final Executor ourExecutor = SequentialTaskExecutor.createSequentialApplicationPoolExecutor("LibraryDependentToolWindowManager");
33
34   LibraryDependentToolWindowManager() {
35     Application app = ApplicationManager.getApplication();
36     if (app.isUnitTestMode() || app.isHeadlessEnvironment()) {
37       throw ExtensionNotApplicableException.INSTANCE;
38     }
39   }
40
41   @Override
42   public void runActivity(@NotNull Project project) {
43     ModuleRootListener rootListener = new ModuleRootListener() {
44       @Override
45       public void rootsChanged(@NotNull ModuleRootEvent event) {
46         checkToolWindowStatuses(project);
47       }
48     };
49
50     checkToolWindowStatuses(project);
51
52     SimpleMessageBusConnection connection = project.getMessageBus().simpleConnect();
53     connection.subscribe(ProjectTopics.PROJECT_ROOTS, rootListener);
54     LibraryDependentToolWindow.EXTENSION_POINT_NAME.addExtensionPointListener(new ExtensionPointListener<LibraryDependentToolWindow>() {
55       @Override
56       public void extensionAdded(@NotNull LibraryDependentToolWindow extension, @NotNull PluginDescriptor pluginDescriptor) {
57         checkToolWindowStatuses(project, Collections.singletonList(extension));
58       }
59
60       @Override
61       public void extensionRemoved(@NotNull LibraryDependentToolWindow extension, @NotNull PluginDescriptor pluginDescriptor) {
62         ToolWindow window = ToolWindowManager.getInstance(project).getToolWindow(extension.id);
63         if (window != null) {
64           window.remove();
65         }
66       }
67     }, project);
68   }
69
70   private void checkToolWindowStatuses(@NotNull final Project project) {
71     checkToolWindowStatuses(project, LibraryDependentToolWindow.EXTENSION_POINT_NAME.getExtensionList());
72   }
73
74   private void checkToolWindowStatuses(@NotNull Project project, @NotNull List<LibraryDependentToolWindow> extensions) {
75     ModalityState currentModalityState = ModalityState.current();
76     ReadAction
77       .nonBlocking(() -> new HashSet<>(ContainerUtil.findAll(extensions, ltw -> {
78         LibrarySearchHelper helper = ltw.getLibrarySearchHelper();
79         return helper != null && helper.isLibraryExists(project);
80       })))
81       .inSmartMode(project)
82       .coalesceBy(this)
83       .finishOnUiThread(currentModalityState, existing -> {
84         ToolWindowManagerEx toolWindowManagerEx = ToolWindowManagerEx.getInstanceEx(project);
85         for (LibraryDependentToolWindow libraryToolWindow : extensions) {
86           ToolWindow toolWindow = toolWindowManagerEx.getToolWindow(libraryToolWindow.id);
87           if (existing.contains(libraryToolWindow)) {
88             if (toolWindow == null) {
89               toolWindowManagerEx.initToolWindow(libraryToolWindow);
90             }
91           }
92           else {
93             if (toolWindow != null) {
94               toolWindow.remove();
95             }
96           }
97         }
98       })
99       .submit(ourExecutor);
100   }
101 }