diff --git a/platform/lang-api/src/com/intellij/execution/dashboard/RunDashboardManager.java b/platform/lang-api/src/com/intellij/execution/dashboard/RunDashboardManager.java index 9f0194c372c9..de98645cdcad 100644 --- a/platform/lang-api/src/com/intellij/execution/dashboard/RunDashboardManager.java +++ b/platform/lang-api/src/com/intellij/execution/dashboard/RunDashboardManager.java @@ -15,12 +15,18 @@ */ package com.intellij.execution.dashboard; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.wm.ToolWindow; import com.intellij.ui.content.ContentManager; import com.intellij.util.messages.Topic; +import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.util.List; /** * @author konstantin.aleev @@ -38,4 +44,10 @@ public interface RunDashboardManager { String getToolWindowId(); Icon getToolWindowIcon(); + + boolean isToolWindowAvailable(); + + void createToolWindowContent(@NotNull ToolWindow toolWindow); + + List> getRunConfigurations(); } diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardContent.java b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardContent.java index a1d66f9cd1b4..0c21f8a901ef 100644 --- a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardContent.java +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardContent.java @@ -15,11 +15,9 @@ */ package com.intellij.execution.dashboard; -import com.intellij.execution.*; +import com.intellij.execution.ExecutionBundle; import com.intellij.execution.dashboard.tree.DashboardGrouper; import com.intellij.execution.dashboard.tree.RunDashboardTreeStructure; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.ide.CommonActionsManager; import com.intellij.ide.DataManager; import com.intellij.ide.DefaultTreeExpander; @@ -30,7 +28,6 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.util.Comparing; @@ -40,10 +37,8 @@ import com.intellij.ui.components.JBPanelWithEmptyText; import com.intellij.ui.content.*; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.ObjectUtils; -import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.TreeExpansionEvent; @@ -231,59 +226,6 @@ public class RunDashboardContent extends JPanel implements TreeContent, Disposab }; myBuilder.initRootNode(); Disposer.register(this, myBuilder); - RunManagerEx.getInstanceEx(myProject).addRunManagerListener(new RunManagerListener() { - @Override - public void runConfigurationAdded(@NotNull RunnerAndConfigurationSettings settings) { - updateTreeIfNeeded(settings); - } - - @Override - public void runConfigurationRemoved(@NotNull RunnerAndConfigurationSettings settings) { - updateTreeIfNeeded(settings); - } - - @Override - public void runConfigurationChanged(@NotNull RunnerAndConfigurationSettings settings) { - updateTreeIfNeeded(settings); - } - }); - MessageBusConnection connection = myProject.getMessageBus().connect(myProject); - connection.subscribe(ExecutionManager.EXECUTION_TOPIC, new ExecutionListener() { - @Override - public void processStarted(@NotNull String executorId, @NotNull ExecutionEnvironment env, final @NotNull ProcessHandler handler) { - updateTreeIfNeeded(env.getRunnerAndConfigurationSettings()); - } - - @Override - public void processTerminated(@NotNull String executorId, - @NotNull ExecutionEnvironment env, - @NotNull ProcessHandler handler, - int exitCode) { - updateTreeIfNeeded(env.getRunnerAndConfigurationSettings()); - } - }); - connection.subscribe(RunDashboardManager.DASHBOARD_TOPIC, new DashboardListener() { - @Override - public void contentChanged(boolean withStructure) { - updateTree(withStructure); - } - }); - connection.subscribe(DumbService.DUMB_MODE, new DumbService.DumbModeListener() { - @Override - public void enteredDumbMode() { - } - - @Override - public void exitDumbMode() { - updateTree(false); - } - }); - } - - private void updateTreeIfNeeded(@Nullable RunnerAndConfigurationSettings settings) { - if (settings != null && RunDashboardContributor.isShowInDashboard(settings.getType())) { - updateTree(true); - } } private JComponent createToolbar() { @@ -330,8 +272,11 @@ public class RunDashboardContent extends JPanel implements TreeContent, Disposab public void dispose() { } - public void updateTree(boolean withStructure) { + public void updateContent(boolean withStructure) { ApplicationManager.getApplication().invokeLater(() -> myBuilder.queueUpdate(withStructure).doWhenDone(() -> { + if (!withStructure) { + return; + } // Remove nodes not presented in the tree from collapsed node values set. // Children retrieving is quick since grouping and run configuration nodes are already constructed. Set nodes = new HashSet<>(); @@ -378,7 +323,7 @@ public class RunDashboardContent extends JPanel implements TreeContent, Disposab @Override public void setSelected(AnActionEvent e, boolean state) { myGrouper.setEnabled(state); - updateTree(true); + updateContent(true); } } } diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardManagerImpl.java index c4f80f60bb02..e1c7132d8835 100644 --- a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardManagerImpl.java @@ -15,15 +15,23 @@ */ package com.intellij.execution.dashboard; +import com.intellij.execution.*; +import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.dashboard.tree.DashboardGrouper; +import com.intellij.execution.impl.ExecutionManagerImpl; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.icons.AllIcons; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.StoragePathMacros; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; @@ -33,6 +41,7 @@ import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentFactory; import com.intellij.ui.content.ContentManager; import com.intellij.ui.content.ContentUI; +import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,6 +49,7 @@ import javax.swing.*; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; /** @@ -50,35 +60,81 @@ import java.util.stream.Collectors; storages = @Storage(StoragePathMacros.WORKSPACE_FILE) ) public class RunDashboardManagerImpl implements RunDashboardManager, PersistentStateComponent { + @NotNull private final Project myProject; @NotNull private final ContentManager myContentManager; - private List myGroupers = new ArrayList<>(); + @NotNull private final List myGroupers; + + private RunDashboardContent myDashboardContent; public RunDashboardManagerImpl(@NotNull final Project project) { + myProject = project; + ContentFactory contentFactory = ContentFactory.SERVICE.getInstance(); ContentUI contentUI = new PanelContentUI(); myContentManager = contentFactory.createContentManager(contentUI, false, project); - ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project); - ToolWindow toolWindow = toolWindowManager.registerToolWindow(getToolWindowId(), false, ToolWindowAnchor.BOTTOM, - project, true); - toolWindow.setIcon(getToolWindowIcon()); - if (!ApplicationManager.getApplication().isUnitTestMode()) { - myGroupers = Arrays.stream(DashboardGroupingRule.EP_NAME.getExtensions()) - .sorted(DashboardGroupingRule.PRIORITY_COMPARATOR) - .map(DashboardGrouper::new) - .collect(Collectors.toList()); + myGroupers = Arrays.stream(DashboardGroupingRule.EP_NAME.getExtensions()) + .sorted(DashboardGroupingRule.PRIORITY_COMPARATOR) + .map(DashboardGrouper::new) + .collect(Collectors.toList()); - RunDashboardContent dashboardContent = new RunDashboardContent(project, myContentManager, myGroupers); - Content content = contentFactory.createContent(dashboardContent, null, false); - Disposer.register(content, dashboardContent); - toolWindow.getContentManager().addContent(content); + if (isDashboardEnabled()) { + initToolWindowListeners(); } + } - if (!Registry.is("ide.run.dashboard")) { - toolWindow.setAvailable(false, null); - } + private static boolean isDashboardEnabled() { + return Registry.is("ide.run.dashboard") && RunDashboardContributor.EP_NAME.getExtensions().length > 0; + } - // TODO [konstantin.aleev] control tool window availability and visibility. + private void initToolWindowListeners() { + RunManagerEx.getInstanceEx(myProject).addRunManagerListener(new RunManagerListener() { + @Override + public void runConfigurationAdded(@NotNull RunnerAndConfigurationSettings settings) { + updateDashboardIfNeeded(settings); + } + + @Override + public void runConfigurationRemoved(@NotNull RunnerAndConfigurationSettings settings) { + updateDashboardIfNeeded(settings); + } + + @Override + public void runConfigurationChanged(@NotNull RunnerAndConfigurationSettings settings) { + updateDashboardIfNeeded(settings); + } + }); + MessageBusConnection connection = myProject.getMessageBus().connect(myProject); + connection.subscribe(ExecutionManager.EXECUTION_TOPIC, new ExecutionListener() { + @Override + public void processStarted(@NotNull String executorId, @NotNull ExecutionEnvironment env, final @NotNull ProcessHandler handler) { + updateDashboardIfNeeded(env.getRunnerAndConfigurationSettings()); + } + + @Override + public void processTerminated(@NotNull String executorId, + @NotNull ExecutionEnvironment env, + @NotNull ProcessHandler handler, + int exitCode) { + updateDashboardIfNeeded(env.getRunnerAndConfigurationSettings()); + } + }); + connection.subscribe(RunDashboardManager.DASHBOARD_TOPIC, new DashboardListener() { + @Override + public void contentChanged(boolean withStructure) { + updateDashboard(withStructure); + } + }); + connection.subscribe(DumbService.DUMB_MODE, new DumbService.DumbModeListener() { + @Override + public void enteredDumbMode() { + } + + @Override + public void exitDumbMode() { + updateDashboard(false); + } + }); } @Override @@ -96,6 +152,105 @@ public class RunDashboardManagerImpl implements RunDashboardManager, PersistentS return AllIcons.Toolwindows.ToolWindowRun; // TODO [konstantin.aleev] provide new icon } + @Override + public boolean isToolWindowAvailable() { + return isDashboardEnabled() && hasContent(); + } + + @Override + public void createToolWindowContent(@NotNull ToolWindow toolWindow) { + myDashboardContent = new RunDashboardContent(myProject, myContentManager, myGroupers); + ContentManager contentManager = toolWindow.getContentManager(); + Content content = contentManager.getFactory().createContent(myDashboardContent, null, false); + Disposer.register(content, myDashboardContent); + Disposer.register(content, () -> myDashboardContent = null); + toolWindow.getContentManager().addContent(content); + } + + @Override + public List> getRunConfigurations() { + List> result = new ArrayList<>(); + + List configurations = RunManager.getInstance(myProject).getAllSettings().stream() + .filter(runConfiguration -> RunDashboardContributor.isShowInDashboard(runConfiguration.getType())) + .collect(Collectors.toList()); + + //noinspection ConstantConditions ??? + ExecutionManagerImpl executionManager = ExecutionManagerImpl.getInstance(myProject); + configurations.forEach(configurationSettings -> { + List descriptors = executionManager.getDescriptors( + settings -> Comparing.equal(settings.getConfiguration(), configurationSettings.getConfiguration())); + if (descriptors.isEmpty()) { + result.add(Pair.create(configurationSettings, null)); + } else { + descriptors.forEach(descriptor -> result.add(Pair.create(configurationSettings, descriptor))); + } + }); + + // It is possible that run configuration was deleted, but there is running content descriptor for such run configuration. + // It should be shown in he dashboard tree. + List storedConfigurations = configurations.stream().map(RunnerAndConfigurationSettings::getConfiguration) + .collect(Collectors.toList()); + List notStoredDescriptors = executionManager.getRunningDescriptors(settings -> { + RunConfiguration configuration = settings.getConfiguration(); + return RunDashboardContributor.isShowInDashboard(settings.getType()) && !storedConfigurations.contains(configuration); + }); + notStoredDescriptors.forEach(descriptor -> { + Set settings = executionManager.getConfigurations(descriptor); + settings.forEach(setting -> result.add(Pair.create(setting, descriptor))); + }); + + return result; + } + + private void updateDashboardIfNeeded(@Nullable RunnerAndConfigurationSettings settings) { + if (settings != null && RunDashboardContributor.isShowInDashboard(settings.getType())) { + updateDashboard(true); + } + } + + private void updateDashboard(final boolean withStructure) { + final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject); + toolWindowManager.invokeLater(() -> { + if (myProject.isDisposed()) { + return; + } + + if (withStructure) { + boolean available = hasContent(); + ToolWindow toolWindow = toolWindowManager.getToolWindow(getToolWindowId()); + if (toolWindow == null) { + if (available) { + createToolWindow(); + } + return; + } + + boolean doShow = !toolWindow.isAvailable() && available; + toolWindow.setAvailable(available, null); + if (doShow) { + toolWindow.show(null); + } + } + + if (myDashboardContent != null) { + myDashboardContent.updateContent(withStructure); + } + }); + } + + private void createToolWindow() { + ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject); + ToolWindow toolWindow = toolWindowManager.registerToolWindow(getToolWindowId(), false, ToolWindowAnchor.BOTTOM, + myProject, true); + toolWindow.setIcon(getToolWindowIcon()); + createToolWindowContent(toolWindow); + } + + private boolean hasContent() { + return !getRunConfigurations().isEmpty(); + } + @Nullable @Override public State getState() { diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardToolWindowFactory.java b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardToolWindowFactory.java new file mode 100644 index 000000000000..6a7fb2f88ce4 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardToolWindowFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.dashboard; + +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowFactory; +import org.jetbrains.annotations.NotNull; + +/** + * @author konstantin.aleev + */ +public class RunDashboardToolWindowFactory implements ToolWindowFactory, Condition, DumbAware { + @Override + public boolean value(Project project) { + return RunDashboardManager.getInstance(project).isToolWindowAvailable(); + } + + @Override + public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) { + RunDashboardManager.getInstance(project).createToolWindowContent(toolWindow); + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/tree/RunConfigurationNode.java b/platform/lang-impl/src/com/intellij/execution/dashboard/tree/RunConfigurationNode.java index 229b978701f2..e0771d60f363 100644 --- a/platform/lang-impl/src/com/intellij/execution/dashboard/tree/RunConfigurationNode.java +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/tree/RunConfigurationNode.java @@ -43,9 +43,8 @@ import java.util.Collections; */ class RunConfigurationNode extends AbstractTreeNode> implements DashboardRunConfigurationNode { - public RunConfigurationNode(Project project, @NotNull RunnerAndConfigurationSettings configurationSettings, - @Nullable RunContentDescriptor descriptor) { - super(project, Pair.create(configurationSettings, descriptor)); + public RunConfigurationNode(Project project, @NotNull Pair value) { + super(project, value); } @Override @@ -69,20 +68,24 @@ class RunConfigurationNode extends AbstractTreeNode getChildren() { - List nodes = new ArrayList<>(); - - List configurations = RunManager.getInstance(myProject).getAllSettings().stream() - .filter(runConfiguration -> RunDashboardContributor.isShowInDashboard(runConfiguration.getType())) - .collect(Collectors.toList()); - - //noinspection ConstantConditions ??? - ExecutionManagerImpl executionManager = ExecutionManagerImpl.getInstance(myProject); - configurations.forEach(configurationSettings -> { - List descriptors = executionManager.getDescriptors(settings -> - Comparing.equal(settings.getConfiguration(), configurationSettings.getConfiguration())); - if (descriptors.isEmpty()) { - nodes.add(new RunConfigurationNode(myProject, configurationSettings, null)); - } else { - descriptors.forEach(descriptor -> nodes.add(new RunConfigurationNode(myProject, configurationSettings, descriptor))); - } - }); - - // It is possible that run configuration was deleted, but there is running content descriptor for such run configuration. - // It should be shown in he dashboard tree. - List storedConfigurations = configurations.stream().map(RunnerAndConfigurationSettings::getConfiguration) - .collect(Collectors.toList()); - List notStoredDescriptors = executionManager.getRunningDescriptors(settings -> { - RunConfiguration configuration = settings.getConfiguration(); - return RunDashboardContributor.isShowInDashboard(settings.getType()) && !storedConfigurations.contains(configuration); - }); - notStoredDescriptors.forEach(descriptor -> { - Set settings = executionManager.getConfigurations(descriptor); - settings.forEach(setting -> nodes.add(new RunConfigurationNode(myProject, setting, descriptor))); - }); + List nodes = RunDashboardManager.getInstance(myProject).getRunConfigurations().stream() + .map(value -> new RunConfigurationNode(myProject, value)).collect(Collectors.toList()); return group(myProject, this, diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 8a227b9449fd..3222057a6ccb 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -792,6 +792,9 @@ factoryClass="com.intellij.ide.structureView.impl.StructureViewToolWindowFactory"/> + diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index affe6be791c9..46fefda3e985 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -935,6 +935,7 @@ select.run.configuration.from.context.description=Select run configuration when ide.run.dashboard=false ide.run.dashboard.description=Enable Run Dashboard tool window +ide.run.dashboard.restartRequired=true ide.run.dashboard.spring.boot.jmx=true ide.run.dashboard.spring.boot.jmx.description=Enable JMX Remote with disabled security for Spring Boot applications to access runtime information