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;
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 import org.jetbrains.annotations.Nullable;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Objects;
31 import java.util.concurrent.Executor;
33 final class LibraryDependentToolWindowManager implements StartupActivity {
34 private static final Executor ourExecutor = SequentialTaskExecutor.createSequentialApplicationPoolExecutor("LibraryDependentToolWindowManager");
36 LibraryDependentToolWindowManager() {
37 Application app = ApplicationManager.getApplication();
38 if (app.isUnitTestMode() || app.isHeadlessEnvironment()) {
39 throw ExtensionNotApplicableException.INSTANCE;
44 public void runActivity(@NotNull Project project) {
45 ModuleRootListener rootListener = new ModuleRootListener() {
47 public void rootsChanged(@NotNull ModuleRootEvent event) {
48 checkToolWindowStatuses(project);
52 checkToolWindowStatuses(project);
54 SimpleMessageBusConnection connection = project.getMessageBus().simpleConnect();
55 connection.subscribe(ProjectTopics.PROJECT_ROOTS, rootListener);
56 LibraryDependentToolWindow.EXTENSION_POINT_NAME.addExtensionPointListener(new ExtensionPointListener<>() {
58 public void extensionAdded(@NotNull LibraryDependentToolWindow extension, @NotNull PluginDescriptor pluginDescriptor) {
59 checkToolWindowStatuses(project, extension.id);
63 public void extensionRemoved(@NotNull LibraryDependentToolWindow extension, @NotNull PluginDescriptor pluginDescriptor) {
64 ToolWindow window = ToolWindowManager.getInstance(project).getToolWindow(extension.id);
72 private void checkToolWindowStatuses(@NotNull Project project) {
73 checkToolWindowStatuses(project, null);
76 private void checkToolWindowStatuses(@NotNull Project project, @Nullable String extensionId) {
77 ModalityState currentModalityState = ModalityState.current();
80 List<LibraryDependentToolWindow> extensions = LibraryDependentToolWindow.EXTENSION_POINT_NAME.getExtensionList();
81 if (extensionId != null) {
82 extensions = ContainerUtil.filter(extensions, ltw -> Objects.equals(ltw.id, extensionId));
85 Set<LibraryDependentToolWindow> existing = new HashSet<>(ContainerUtil.findAll(extensions, ltw -> {
86 LibrarySearchHelper helper = ltw.getLibrarySearchHelper();
87 return helper != null && helper.isLibraryExists(project);
90 return new LibraryWindowsState(project, extensions, existing);
93 .coalesceBy(this, project)
94 .finishOnUiThread(currentModalityState, LibraryDependentToolWindowManager::applyWindowsState)
98 private static void applyWindowsState(LibraryWindowsState state) {
99 ToolWindowManagerEx toolWindowManagerEx = ToolWindowManagerEx.getInstanceEx(state.project);
100 for (LibraryDependentToolWindow libraryToolWindow : state.extensions) {
101 ToolWindow toolWindow = toolWindowManagerEx.getToolWindow(libraryToolWindow.id);
102 if (state.existing.contains(libraryToolWindow)) {
103 if (toolWindow == null) {
104 toolWindowManagerEx.initToolWindow(libraryToolWindow);
108 if (toolWindow != null) {
115 private static class LibraryWindowsState {
116 final @NotNull Project project;
117 final List<LibraryDependentToolWindow> extensions;
118 final Set<LibraryDependentToolWindow> existing;
120 private LibraryWindowsState(@NotNull Project project,
121 List<LibraryDependentToolWindow> extensions,
122 Set<LibraryDependentToolWindow> existing) {
123 this.project = project;
124 this.extensions = extensions;
125 this.existing = existing;