From: Dmitry Trofimov Date: Tue, 11 Oct 2016 01:46:03 +0000 (+0200) Subject: Revert to Tool Window API X-Git-Tag: dbe/163.6109~1 X-Git-Url: https://git.jetbrains.org/?p=idea%2Fcommunity.git;a=commitdiff_plain;h=89408841498e28f241a41ed0f1602c3230194c50 Revert to Tool Window API --- diff --git a/platform/lang-api/src/com/intellij/execution/Executor.java b/platform/lang-api/src/com/intellij/execution/Executor.java index d5cec10d5f84..b5258d2991a0 100644 --- a/platform/lang-api/src/com/intellij/execution/Executor.java +++ b/platform/lang-api/src/com/intellij/execution/Executor.java @@ -33,9 +33,6 @@ import javax.swing.*; */ public abstract class Executor { public static final ExtensionPointName EXECUTOR_EXTENSION_NAME = ExtensionPointName.create("com.intellij.executor"); - /* Extension point for non-user facing executors, in order to use RunContentManager with custom toolwindows */ - public static final ExtensionPointName INTERNAL_EXECUTOR_EXTENSION_NAME = - ExtensionPointName.create("com.intellij.internal_executor"); /** * Returns the ID of the toolwindow in which the run tabs created by this executor will be displayed. diff --git a/platform/lang-impl/src/com/intellij/execution/runners/ConsoleTitleGen.kt b/platform/lang-impl/src/com/intellij/execution/runners/ConsoleTitleGen.kt index 6bd14252e928..e203e29530cb 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/ConsoleTitleGen.kt +++ b/platform/lang-impl/src/com/intellij/execution/runners/ConsoleTitleGen.kt @@ -22,7 +22,7 @@ import com.intellij.openapi.project.Project import java.util.stream.Collectors /** - * Created by Yuli Fiterman on 9/13/2016. + * @author traff */ open class ConsoleTitleGen @JvmOverloads constructor(private val myProject: Project, private val consoleTitle: String, private val shouldAddNumberToTitle: Boolean = true) { diff --git a/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java index e53676eb12bc..189b6fa2a982 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java @@ -30,7 +30,6 @@ import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; @@ -88,11 +87,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable { } for (Executor executor : ExecutorRegistry.getInstance().getRegisteredExecutors()) { - registerToolwindow(executor, toolWindowManager, true); - } - - for (Executor executor : Extensions.getExtensions(Executor.INTERNAL_EXECUTOR_EXTENSION_NAME)) { - registerToolwindow(executor, toolWindowManager, false); + registerToolwindow(executor, toolWindowManager); } toolWindowManager.addToolWindowManagerListener(new ToolWindowManagerAdapter() { @@ -121,9 +116,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable { public void dispose() { } - private void registerToolwindow(@NotNull final Executor executor, - @NotNull ToolWindowManagerEx toolWindowManager, - boolean autoRemoveOnEmpty) { + private void registerToolwindow(@NotNull final Executor executor, @NotNull ToolWindowManagerEx toolWindowManager) { final String toolWindowId = executor.getToolWindowId(); if (toolWindowManager.getToolWindow(toolWindowId) != null) { return; @@ -153,9 +146,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable { toolWindow.setIcon(executor.getToolWindowIcon()); myToolwindowIdToBaseIconMap.put(toolWindowId, executor.getToolWindowIcon()); - if (autoRemoveOnEmpty) { - new ContentManagerWatcher(toolWindow, contentManager); - } + new ContentManagerWatcher(toolWindow, contentManager); contentManager.addContentManagerListener(new ContentManagerAdapter() { @Override public void selectionChanged(final ContentManagerEvent event) { @@ -264,8 +255,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable { } final ContentManager contentManager = getContentManagerForRunner(executor); - RunContentDescriptor oldDescriptor = - chooseReuseContentForDescriptor(contentManager, descriptor, executionId, descriptor.getDisplayName()); + RunContentDescriptor oldDescriptor = chooseReuseContentForDescriptor(contentManager, descriptor, executionId, descriptor.getDisplayName()); final Content content; if (oldDescriptor == null) { content = createNewContent(contentManager, descriptor, executor); @@ -373,9 +363,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable { } @Override - public void showRunContent(@NotNull Executor info, - @NotNull RunContentDescriptor descriptor, - @Nullable RunContentDescriptor contentToReuse) { + public void showRunContent(@NotNull Executor info, @NotNull RunContentDescriptor descriptor, @Nullable RunContentDescriptor contentToReuse) { copyContentAndBehavior(descriptor, contentToReuse); showRunContent(info, descriptor, descriptor.getExecutionId()); } @@ -421,7 +409,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable { return null; } final RunContentDescriptor oldDescriptor = getRunContentDescriptorByContent(content); - if (oldDescriptor != null && !oldDescriptor.isContentReuseProhibited()) { + if (oldDescriptor != null && !oldDescriptor.isContentReuseProhibited() ) { //content.setExecutionId(executionId); return oldDescriptor; } @@ -620,8 +608,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable { } final boolean destroyProcess; //noinspection deprecation - if (processHandler.isSilentlyDestroyOnClose() || - Boolean.TRUE.equals(processHandler.getUserData(ProcessHandler.SILENTLY_DESTROY_ON_CLOSE))) { + if (processHandler.isSilentlyDestroyOnClose() || Boolean.TRUE.equals(processHandler.getUserData(ProcessHandler.SILENTLY_DESTROY_ON_CLOSE))) { destroyProcess = true; } else { @@ -654,7 +641,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable { { if (killable) { - String cancelText = ExecutionBundle.message("terminating.process.progress.kill"); + String cancelText= ExecutionBundle.message("terminating.process.progress.kill"); setCancelText(cancelText); setCancelTooltipText(cancelText); } diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index cec19d6cc0fd..94009d6d5886 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -428,10 +428,6 @@ - - - diff --git a/python/ide/src/META-INF/pycharm-core.xml b/python/ide/src/META-INF/pycharm-core.xml index 3cb80f00d5d2..b9e322946fb7 100644 --- a/python/ide/src/META-INF/pycharm-core.xml +++ b/python/ide/src/META-INF/pycharm-core.xml @@ -28,6 +28,14 @@ + + + com.jetbrains.python.console.PythonConsoleToolWindow + + + + + @@ -76,8 +84,10 @@ - - + + + diff --git a/python/src/com/jetbrains/python/actions/PyExecuteSelectionAction.java b/python/src/com/jetbrains/python/actions/PyExecuteSelectionAction.java index bc00af821211..c9b74190e31f 100644 --- a/python/src/com/jetbrains/python/actions/PyExecuteSelectionAction.java +++ b/python/src/com/jetbrains/python/actions/PyExecuteSelectionAction.java @@ -33,6 +33,7 @@ import com.intellij.util.Consumer; import com.jetbrains.python.console.PyCodeExecutor; import com.jetbrains.python.console.PydevConsoleRunner; import com.jetbrains.python.console.PythonConsoleRunnerFactory; +import com.jetbrains.python.console.PythonConsoleToolWindow; import com.jetbrains.python.psi.PyFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -179,9 +180,22 @@ public class PyExecuteSelectionAction extends AnAction { } private static Collection getConsoles(Project project) { + PythonConsoleToolWindow toolWindow = PythonConsoleToolWindow.getInstance(project); + if (toolWindow != null && toolWindow.getToolWindow().isVisible()) { + RunContentDescriptor selectedContentDescriptor = toolWindow.getSelectedContentDescriptor(); + return selectedContentDescriptor != null ? Lists.newArrayList(selectedContentDescriptor) : Lists.newArrayList(); + } + + Collection descriptors = + ExecutionHelper.findRunningConsole(project, dom -> dom.getExecutionConsole() instanceof PyCodeExecutor && isAlive(dom)); - return ExecutionHelper.findRunningConsole(project, dom -> dom.getExecutionConsole() instanceof PyCodeExecutor && isAlive(dom)); + if (descriptors.isEmpty() && toolWindow != null) { + return toolWindow.getConsoleContentDescriptors(); + } + else { + return descriptors; + } } private static boolean isAlive(RunContentDescriptor dom) { @@ -203,21 +217,33 @@ public class PyExecuteSelectionAction extends AnAction { private static void startConsole(final Project project, final Consumer consumer, Module context) { + final PythonConsoleToolWindow toolWindow = PythonConsoleToolWindow.getInstance(project); + + if (toolWindow != null) { + toolWindow.activate(() -> { + List descs = toolWindow.getConsoleContentDescriptors(); - PythonConsoleRunnerFactory consoleRunnerFactory = PythonConsoleRunnerFactory.getInstance(); - PydevConsoleRunner runner = consoleRunnerFactory.createConsoleRunner(project, null); - runner.addConsoleListener(new PydevConsoleRunner.ConsoleListener() { - @Override - public void handleConsoleInitialized(LanguageConsoleView consoleView) { - if (consoleView instanceof PyCodeExecutor) { - consumer.consume((PyCodeExecutor)consoleView); + RunContentDescriptor descriptor = descs.get(0); + if (descriptor != null && descriptor.getExecutionConsole() instanceof PyCodeExecutor) { + consumer.consume((PyCodeExecutor)descriptor.getExecutionConsole()); } - } - }); - runner.run(); + }); + } + else { + PythonConsoleRunnerFactory consoleRunnerFactory = PythonConsoleRunnerFactory.getInstance(); + PydevConsoleRunner runner = consoleRunnerFactory.createConsoleRunner(project, null); + runner.addConsoleListener(new PydevConsoleRunner.ConsoleListener() { + @Override + public void handleConsoleInitialized(LanguageConsoleView consoleView) { + if (consoleView instanceof PyCodeExecutor) { + consumer.consume((PyCodeExecutor)consoleView); + } + } + }); + runner.run(); + } } - private static boolean canFindConsole(AnActionEvent e) { Project project = e.getProject(); if (project != null) { diff --git a/python/src/com/jetbrains/python/console/PyConsoleStarter.kt b/python/src/com/jetbrains/python/console/PyConsoleStarter.kt deleted file mode 100644 index b5ea727a25c8..000000000000 --- a/python/src/com/jetbrains/python/console/PyConsoleStarter.kt +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2000-2016 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.jetbrains.python.console - -import com.intellij.execution.ExecutionManager -import com.intellij.ide.util.PropertiesComponent -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.ModalityState -import com.intellij.openapi.application.TransactionGuard -import com.intellij.openapi.project.Project -import com.intellij.openapi.startup.StartupActivity -import com.intellij.openapi.util.Condition -import com.intellij.openapi.wm.ToolWindow -import com.intellij.openapi.wm.ToolWindowManager -import com.intellij.openapi.wm.ex.ToolWindowManagerEx -import com.intellij.openapi.wm.ex.ToolWindowManagerListener -import com.intellij.openapi.wm.impl.content.ToolWindowContentUi -import com.intellij.util.Alarm - -/** - * Created by Yuli Fiterman on 9/12/2016. - */ -class PyConsoleStarter : StartupActivity { - override fun runActivity(project: Project) { - if (!ApplicationManager.getApplication().isUnitTestMode) { - ConsoleStateTracker(project) - } - } - - private class ConsoleStateTracker(private val project: Project) { - private val VISIBLE: String = "com.jetbrains.python.console.ToolWindowVisible" - private var toolWindowVisible: Boolean = PropertiesComponent.getInstance(project).getBoolean(VISIBLE, false) - set(value) { - if (value != field) { - PropertiesComponent.getInstance(project).setValue(VISIBLE, value, false) - } - field = value - } - - private val toolWindow: ToolWindow? - get() { - return ToolWindowManager.getInstance(project).getToolWindow(PyConsoleToolWindowExecutor.TOOLWINDOW_ID) - } - - - init { - ExecutionManager.getInstance(project).contentManager //Using this for the side effect. Force init - toolWindow!!.isAutoHide = false - toolWindow!!.isToHideOnEmptyContent = true - toolWindow!!.component.putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "true") - - - val tvm = ToolWindowManager.getInstance(project) as ToolWindowManagerEx - - tvm.addToolWindowManagerListener(object : ToolWindowManagerListener { - override fun toolWindowRegistered(id: String) { - } - - override fun stateChanged() { - val toolW = toolWindow ?: return; - if (toolW.isVisible && toolW.contentManager.contentCount == 0) { - val runner = PythonConsoleRunnerFactory.getInstance().createConsoleRunner(project, null); - runner.runSync(); - } - if (toolWindowVisible != toolW.isVisible) { - ApplicationManager.getApplication().invokeLater( - { - toolWindowVisible = toolWindow?.isVisible ?: false - }, ModalityState.NON_MODAL, { !project.isOpen || project.isDisposed }) - - - } - } - }) - - - if (toolWindowVisible) { - toolWindow!!.setAvailable(true) { - TransactionGuard.submitTransaction(project, Runnable { toolWindow!!.show(null) }) - - } - } - - } - } - -} diff --git a/python/src/com/jetbrains/python/console/PyConsoleToolWindowExecutor.java b/python/src/com/jetbrains/python/console/PyConsoleToolWindowExecutor.java deleted file mode 100644 index fb5a683c8906..000000000000 --- a/python/src/com/jetbrains/python/console/PyConsoleToolWindowExecutor.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2000-2016 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.jetbrains.python.console; - -import com.intellij.execution.Executor; -import com.intellij.openapi.extensions.Extensions; -import icons.PythonIcons; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; - -/** - * Created by Yuli Fiterman on 9/11/2016. - */ -public class PyConsoleToolWindowExecutor extends Executor { - - - public static final String ID = "PyConsoleToolWindowExecutor"; - public static final String TOOLWINDOW_ID = "Python Console"; - - @Nullable - public static PyConsoleToolWindowExecutor findInstance() { - for (Executor t : Extensions.getExtensions(INTERNAL_EXECUTOR_EXTENSION_NAME)) { - if (PyConsoleToolWindowExecutor.class.isInstance(t)) { - return (PyConsoleToolWindowExecutor)t; - } - } - - return null; - } - - @Override - public String getToolWindowId() { - return TOOLWINDOW_ID; - } - - @Override - public Icon getToolWindowIcon() { - return PythonIcons.Python.PythonConsoleToolWindow; - } - - @NotNull - @Override - public Icon getIcon() { - return PythonIcons.Python.PythonConsoleToolWindow; - } - - @Override - public Icon getDisabledIcon() { - return null; - } - - @Override - public String getDescription() { - return null; - } - - @NotNull - @Override - public String getActionName() { - return "Run Python Console"; - } - - @NotNull - @Override - public String getId() { - return ID; - } - - @NotNull - @Override - public String getStartActionText() { - return "Starting Python Console"; - } - - @Override - public String getContextActionId() { - return ""; - } - - @Override - public String getHelpId() { - return null; - } -} diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java index d638fcbc0e93..b5b3771e05db 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java @@ -60,7 +60,7 @@ public interface PydevConsoleRunner { Key CONSOLE_KEY = new Key<>("PYDEV_CONSOLE_KEY"); Key CONSOLE_SDK = new Key<>("PYDEV_CONSOLE_SDK_KEY"); - public interface ConsoleListener { + interface ConsoleListener { void handleConsoleInitialized(LanguageConsoleView consoleView); } @@ -219,6 +219,8 @@ public interface PydevConsoleRunner { return containingFile != null ? containingFile.getCopyableUserData(CONSOLE_SDK) : null; } + void open(); + void runSync(); void run(); diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunnerFactory.java b/python/src/com/jetbrains/python/console/PydevConsoleRunnerFactory.java index 9046a494f0a0..cdb18d421d9a 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunnerFactory.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunnerFactory.java @@ -26,6 +26,7 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Consumer; import com.intellij.util.PathMapper; import com.jetbrains.python.buildout.BuildoutFacet; import com.jetbrains.python.run.PythonCommandLineState; @@ -112,11 +113,11 @@ public class PydevConsoleRunnerFactory extends PythonConsoleRunnerFactory { Map envs = Maps.newHashMap(settingsProvider.getEnvs()); putIPythonEnvFlag(project, envs); - //The transaction is needed due the the FileDocumentManager.getInstance().saveAllDocuments() call in PydevConsoleRunnerImpl - Runnable rerunAction = () -> TransactionGuard.submitTransaction(project, () -> { + Consumer rerunAction = title -> { PydevConsoleRunnerImpl runner = createConsoleRunner(project, module); + runner.setConsoleTitle(title); runner.run(); - }); + }; return createConsoleRunner(project, sdk, workingDir, envs, PyConsoleType.PYTHON, settingsProvider, rerunAction, setupFragment); } @@ -133,7 +134,7 @@ public class PydevConsoleRunnerFactory extends PythonConsoleRunnerFactory { Map envs, PyConsoleType consoleType, PyConsoleOptions.PyConsoleSettings settingsProvider, - Runnable rerunAction, String... setupFragment) { + Consumer rerunAction, String... setupFragment) { return new PydevConsoleRunnerImpl(project, sdk, consoleType, workingDir, envs, settingsProvider, rerunAction, setupFragment); } } diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java b/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java index 971f2d1bc909..578323d58e0a 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java @@ -16,6 +16,7 @@ package com.jetbrains.python.console; import com.google.common.base.CharMatcher; +import com.google.common.collect.Lists; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionHelper; @@ -43,6 +44,7 @@ import com.intellij.internal.statistic.UsageTrigger; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.TransactionGuard; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Document; @@ -72,10 +74,8 @@ import com.intellij.remote.Tunnelable; import com.intellij.testFramework.LightVirtualFile; import com.intellij.ui.JBColor; import com.intellij.ui.SideBorder; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IJSwingUtilities; -import com.intellij.util.PathMappingSettings; -import com.intellij.util.TimeoutUtil; +import com.intellij.ui.content.Content; +import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.net.NetUtils; import com.intellij.util.ui.MessageCategory; @@ -109,11 +109,12 @@ import java.io.IOException; import java.net.ServerSocket; import java.util.*; import java.util.List; +import java.util.stream.Collectors; import static com.intellij.execution.runners.AbstractConsoleRunnerWithHistory.registerActionShortcuts; /** - * @author oleg + * @author traff, oleg */ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { public static final String WORKING_DIR_ENV = "WORKING_DIR_AND_PYTHON_PATHS"; @@ -127,8 +128,7 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { private final Project myProject; private final String myTitle; private final String myWorkingDir; - private final Executor myExecutor; - private final Runnable myRunRunAction; + private final Consumer myRerunAction; @NotNull private Sdk mySdk; private GeneralCommandLine myGeneralCommandLine; @@ -157,7 +157,7 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { @Nullable final String workingDir, Map environmentVariables, @NotNull PyConsoleOptions.PyConsoleSettings settingsProvider, - @NotNull Runnable rerunAction, String... statementsToExecute) { + @NotNull Consumer rerunAction, String... statementsToExecute) { myProject = project; mySdk = sdk; myTitle = consoleType.getTitle(); @@ -166,11 +166,12 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { myEnvironmentVariables = environmentVariables; myConsoleSettings = settingsProvider; myStatementsToExecute = statementsToExecute; - myRunRunAction = rerunAction; - PyConsoleToolWindowExecutor toolWindowExecutor = PyConsoleToolWindowExecutor.findInstance(); - myExecutor = toolWindowExecutor != null ? toolWindowExecutor : DefaultRunExecutor.getRunExecutorInstance(); + myRerunAction = rerunAction; } + public void setConsoleTitle(String consoleTitle) { + myConsoleTitle = consoleTitle; + } private List fillToolBarActions(final DefaultActionGroup toolbarActions, final RunContentDescriptor contentDescriptor) { @@ -214,6 +215,16 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { return actions; } + @Override + public void open() { + PythonConsoleToolWindow toolWindow = PythonConsoleToolWindow.getInstance(myProject); + if (toolWindow != null) { + toolWindow.getToolWindow().activate(() -> {}, true); + } else { + runSync(); + } + } + @Override public void runSync() { myPorts = findAvailablePorts(myProject, myConsoleType); @@ -243,7 +254,7 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { @Override public void run() { - ApplicationManager.getApplication().invokeAndWait(() -> FileDocumentManager.getInstance().saveAllDocuments()); + TransactionGuard.submitTransaction(myProject, () -> FileDocumentManager.getInstance().saveAllDocuments()); myPorts = findAvailablePorts(myProject, myConsoleType); @@ -301,8 +312,24 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { actionGroup.add(createCloseAction(contentDescriptor)); - ExecutionManager.getInstance(myProject).getContentManager().showRunContent(myExecutor, contentDescriptor); + showContentDescriptor(contentDescriptor); + } + + + private void showContentDescriptor(RunContentDescriptor contentDescriptor) { + PythonConsoleToolWindow toolWindow = PythonConsoleToolWindow.getInstance(myProject); + if (toolWindow != null) { + toolWindow + .init(PythonConsoleToolWindow.getToolWindow(myProject), contentDescriptor); + } + else { + ExecutionManager + .getInstance(myProject).getContentManager().showRunContent(getExecutor(), contentDescriptor); + } + } + private static Executor getExecutor() { + return DefaultRunExecutor.getRunExecutorInstance(); } private static int[] findAvailablePorts(Project project, PyConsoleType consoleType) { @@ -572,8 +599,26 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { actionToolbar.setTargetComponent(panel); + if (myConsoleTitle == null) { + myConsoleTitle = new ConsoleTitleGen(myProject, myTitle) { + @NotNull + @Override + protected List getActiveConsoles(@NotNull String consoleTitle) { + PythonConsoleToolWindow toolWindow = PythonConsoleToolWindow.getInstance(myProject); + if (toolWindow != null && toolWindow.getToolWindow() != null) { + return Lists.newArrayList(toolWindow.getToolWindow().getContentManager().getContents()).stream().map(c -> c.getDisplayName()) + .collect( + Collectors.toList()); + } + else { + return super.getActiveConsoles(consoleTitle); + } + } + }.makeTitle(); + } + final RunContentDescriptor contentDescriptor = - new RunContentDescriptor(myConsoleView, myProcessHandler, panel, new ConsoleTitleGen(myProject, myTitle).makeTitle(), null); + new RunContentDescriptor(myConsoleView, myProcessHandler, panel, myConsoleTitle, null); contentDescriptor.setFocusComputable(() -> myConsoleView.getConsoleEditor().getContentComponent()); contentDescriptor.setAutoFocusContent(true); @@ -584,7 +629,7 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { registerActionShortcuts(actions, myConsoleView.getConsoleEditor().getComponent()); registerActionShortcuts(actions, panel); - ExecutionManager.getInstance(myProject).getContentManager().showRunContent(myExecutor, contentDescriptor); + showContentDescriptor(contentDescriptor); } private void connect(final String[] statements2execute) { @@ -610,6 +655,7 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { } fireConsoleInitializedEvent(consoleView); + consoleView.initialized(); }); } else { @@ -686,7 +732,6 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { } - private boolean isIndentSubstring(String text) { int indentSize = myConsoleExecuteActionHandler.getPythonIndent(); return text.length() >= indentSize && CharMatcher.WHITESPACE.matchesAllOf(text.substring(text.length() - indentSize)); @@ -744,7 +789,7 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { } private AnAction createCloseAction(final RunContentDescriptor descriptor) { - final AnAction generalCloseAction = new CloseAction(myExecutor, descriptor, myProject); + final AnAction generalCloseAction = new CloseAction(getExecutor(), descriptor, myProject); final AnAction stopAction = new DumbAwareAction() { @Override @@ -766,6 +811,12 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { } protected void clearContent(RunContentDescriptor descriptor) { + PythonConsoleToolWindow toolWindow = PythonConsoleToolWindow.getInstance(myProject); + if (toolWindow != null && toolWindow.getToolWindow() != null) { + Content content = toolWindow.getToolWindow().getContentManager().findContent(descriptor.getDisplayName()); + assert content != null; + toolWindow.getToolWindow().getContentManager().removeContent(content, true); + } } private AnActionEvent stopConsole(AnActionEvent e) { @@ -895,8 +946,7 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { } UIUtil.invokeLaterIfNeeded(() -> { - - myRunRunAction.run(); + myRerunAction.consume(myConsoleTitle); }); } }.queue(); diff --git a/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java b/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java new file mode 100644 index 000000000000..362206ac7a1c --- /dev/null +++ b/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java @@ -0,0 +1,191 @@ +/* + * Copyright 2000-2014 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.jetbrains.python.console; + +import com.google.common.base.Function; +import com.google.common.base.Predicates; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.Lists; +import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.SimpleToolWindowPanel; +import com.intellij.openapi.util.ActionCallback; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.openapi.wm.ex.ToolWindowManagerEx; +import com.intellij.openapi.wm.ex.ToolWindowManagerListener; +import com.intellij.openapi.wm.impl.content.ToolWindowContentUi; +import com.intellij.ui.content.Content; +import com.intellij.ui.content.ContentFactory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.util.List; + +/** + * @author traff + */ +public class PythonConsoleToolWindow { + public static final Key CONTENT_DESCRIPTOR = Key.create("CONTENT_DESCRIPTOR"); + + public static final Function + CONTENT_TO_DESCRIPTOR_FUNCTION = new Function() { + @Override + public RunContentDescriptor apply(@Nullable Content input) { + return input != null ? input.getUserData(CONTENT_DESCRIPTOR) : null; + } + }; + + private final Project myProject; + + private boolean myInitialized = false; + + public PythonConsoleToolWindow(Project project) { + myProject = project; + } + + public static PythonConsoleToolWindow getInstance(@NotNull Project project) { + return project.getComponent(PythonConsoleToolWindow.class); + } + + public List getConsoleContentDescriptors() { + return FluentIterable.from(Lists.newArrayList(getToolWindow(myProject).getContentManager().getContents())) + .transform(CONTENT_TO_DESCRIPTOR_FUNCTION).filter( + Predicates.notNull()).toList(); + } + + + public void init(final @NotNull ToolWindow toolWindow, final @NotNull RunContentDescriptor contentDescriptor) { + setContent(toolWindow, contentDescriptor); + + if (!myInitialized) { + doInit(toolWindow); + } + } + + private void doInit(@NotNull final ToolWindow toolWindow) { + myInitialized = true; + + toolWindow.setToHideOnEmptyContent(true); + + ((ToolWindowManagerEx)ToolWindowManager.getInstance(myProject)).addToolWindowManagerListener(new ToolWindowManagerListener() { + @Override + public void toolWindowRegistered(@NotNull String id) { + } + + @Override + public void stateChanged() { + ToolWindow window = getToolWindow(myProject); + if (window != null) { + boolean visible = window.isVisible(); + if (visible && toolWindow.getContentManager().getContentCount() == 0) { + PydevConsoleRunner runner = PythonConsoleRunnerFactory.getInstance().createConsoleRunner(myProject, null); + runner.run(); + } + } + } + }); + } + + private static void setContent(ToolWindow toolWindow, RunContentDescriptor contentDescriptor) { + toolWindow.getComponent().putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "true"); + + Content content = toolWindow.getContentManager().findContent(contentDescriptor.getDisplayName()); + if (content == null) { + content = createContent(contentDescriptor); + toolWindow.getContentManager().addContent(content); + } + else { + SimpleToolWindowPanel panel = new SimpleToolWindowPanel(false, true); + resetContent(contentDescriptor, panel, content); + } + + toolWindow.getContentManager().setSelectedContent(content); + } + + public ToolWindow getToolWindow() { + return getToolWindow(myProject); + } + + public static ToolWindow getToolWindow(Project project) { + return ToolWindowManager.getInstance(project).getToolWindow(PythonConsoleToolWindowFactory.Companion.getID()); + } + + public void setContent(RunContentDescriptor contentDescriptor) { + setContent(getToolWindow(myProject), contentDescriptor); + } + + private static Content createContent(final @NotNull RunContentDescriptor contentDescriptor) { + SimpleToolWindowPanel panel = new SimpleToolWindowPanel(false, true); + + Content content = ContentFactory.SERVICE.getInstance().createContent(panel, contentDescriptor.getDisplayName(), false); + content.setCloseable(true); + + resetContent(contentDescriptor, panel, content); + + return content; + } + + private static void resetContent(RunContentDescriptor contentDescriptor, SimpleToolWindowPanel panel, Content content) { + RunContentDescriptor oldDescriptor = + content.getDisposer() instanceof RunContentDescriptor ? (RunContentDescriptor)content.getDisposer() : null; + if (oldDescriptor != null) Disposer.dispose(oldDescriptor); + + panel.setContent(contentDescriptor.getComponent()); + + content.setComponent(panel); + content.setDisposer(contentDescriptor); + content.setPreferredFocusableComponent(contentDescriptor.getComponent()); + + content.putUserData(CONTENT_DESCRIPTOR, contentDescriptor); + } + + private static FocusListener createFocusListener(final ToolWindow toolWindow) { + return new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + JComponent component = getComponentToFocus(toolWindow); + if (component != null) { + component.requestFocusInWindow(); + } + } + + @Override + public void focusLost(FocusEvent e) { + + } + }; + } + + private static JComponent getComponentToFocus(ToolWindow window) { + return window.getContentManager().getComponent(); + } + + + public void activate(@NotNull Runnable runnable) { + getToolWindow(myProject).activate(runnable); + } + + @Nullable + public RunContentDescriptor getSelectedContentDescriptor() { + return CONTENT_TO_DESCRIPTOR_FUNCTION.apply(getToolWindow(myProject).getContentManager().getSelectedContent()); + } +} diff --git a/python/src/com/jetbrains/python/console/PythonConsoleToolWindowFactory.kt b/python/src/com/jetbrains/python/console/PythonConsoleToolWindowFactory.kt new file mode 100644 index 000000000000..3f22047efdd5 --- /dev/null +++ b/python/src/com/jetbrains/python/console/PythonConsoleToolWindowFactory.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2014 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.jetbrains.python.console + +import com.intellij.execution.console.LanguageConsoleView +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project +import com.intellij.openapi.wm.ToolWindow +import com.intellij.openapi.wm.ToolWindowFactory + +/** + * @author traff + */ +class PythonConsoleToolWindowFactory : ToolWindowFactory, DumbAware { + + override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { + val runner = PythonConsoleRunnerFactory.getInstance().createConsoleRunner(project, null) + runner.runSync() + } + + companion object { + val ID = "Python Console" + } +} diff --git a/python/src/com/jetbrains/python/console/PythonConsoleView.java b/python/src/com/jetbrains/python/console/PythonConsoleView.java index 4219b40a3760..e5e41604b94d 100644 --- a/python/src/com/jetbrains/python/console/PythonConsoleView.java +++ b/python/src/com/jetbrains/python/console/PythonConsoleView.java @@ -43,6 +43,7 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; @@ -90,6 +91,7 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable private boolean myFirstRun = true; private XStandaloneVariablesView mySplitView; + private ActionCallback myInitialized = new ActionCallback(); public PythonConsoleView(final Project project, final String title, final Sdk sdk) { super(project, title, PythonLanguage.getInstance()); @@ -141,28 +143,30 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable @Override public void executeCode(final @NotNull String code, @Nullable final Editor editor) { - ProgressManager.getInstance().run(new Task.Backgroundable(null, "Executing Code in Console...", false) { - @Override - public void run(@NotNull final ProgressIndicator indicator) { - long time = System.currentTimeMillis(); - while (!myExecuteActionHandler.isEnabled() || !myExecuteActionHandler.canExecuteNow()) { - if (indicator.isCanceled()) { - break; - } - if (System.currentTimeMillis() - time > 1000) { - if (editor != null) { - UIUtil.invokeLaterIfNeeded( - () -> HintManager.getInstance().showErrorHint(editor, myExecuteActionHandler.getCantExecuteMessage())); - } - return; - } - TimeoutUtil.sleep(300); - } - if (!indicator.isCanceled()) { - executeInConsole(code); - } - } - }); + myInitialized.doWhenDone(() -> + ProgressManager.getInstance().run(new Task.Backgroundable(null, "Executing Code in Console...", false) { + @Override + public void run(@NotNull final ProgressIndicator indicator) { + long time = System.currentTimeMillis(); + while (!myExecuteActionHandler.isEnabled() || !myExecuteActionHandler.canExecuteNow()) { + if (indicator.isCanceled()) { + break; + } + if (System.currentTimeMillis() - time > 1000) { + if (editor != null) { + UIUtil.invokeLaterIfNeeded( + () -> HintManager.getInstance() + .showErrorHint(editor, myExecuteActionHandler.getCantExecuteMessage())); + } + return; + } + TimeoutUtil.sleep(300); + } + if (!indicator.isCanceled()) { + executeInConsole(code); + } + } + })); } @@ -422,4 +426,8 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable public void setPromptAttributes(@NotNull ConsoleViewContentType textAttributes) { myPromptView.setPromptAttributes(textAttributes); } + + public void initialized() { + myInitialized.setDone(); + } } diff --git a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java index 4c189321417b..0e5d682198dd 100644 --- a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java +++ b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java @@ -51,6 +51,6 @@ public class RunPythonConsoleAction extends AnAction implements DumbAware { public void actionPerformed(final AnActionEvent e) { PydevConsoleRunner runner = PythonConsoleRunnerFactory.getInstance().createConsoleRunner(e.getData(CommonDataKeys.PROJECT), e.getData(LangDataKeys.MODULE)); - runner.runSync(); + runner.open(); } } diff --git a/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java b/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java index d7ea4e12e208..b0797faad76c 100644 --- a/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java +++ b/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java @@ -125,8 +125,7 @@ public class PythonScriptCommandLineState extends PythonCommandLineState { CommandLinePatcher[] patchers, PyConsoleOptions.PyConsoleSettings consoleSettings, String... statementsToExecute) { - super(project, sdk, consoleType, workingDir, environmentVariables, consoleSettings, () -> { - }, statementsToExecute); + super(project, sdk, consoleType, workingDir, environmentVariables, consoleSettings, (s) -> {}, statementsToExecute); myPatchers = patchers; } @@ -135,7 +134,6 @@ public class PythonScriptCommandLineState extends PythonCommandLineState { AnAction a = new ConsoleExecuteAction(super.getConsoleView(), myConsoleExecuteActionHandler, myConsoleExecuteActionHandler.getEmptyExecuteAction(), myConsoleExecuteActionHandler); registerActionShortcuts(Lists.newArrayList(a), getConsoleView().getConsoleEditor().getComponent()); - } @Override diff --git a/python/testSrc/com/jetbrains/env/python/console/PyConsoleTask.java b/python/testSrc/com/jetbrains/env/python/console/PyConsoleTask.java index 2cba3d2e4069..b1c2e4c34c94 100644 --- a/python/testSrc/com/jetbrains/env/python/console/PyConsoleTask.java +++ b/python/testSrc/com/jetbrains/env/python/console/PyConsoleTask.java @@ -146,8 +146,7 @@ public class PyConsoleTask extends PyExecutionFixtureTestTask { PydevConsoleRunner consoleRunner = new PydevConsoleRunnerImpl(project, sdk, PyConsoleType.PYTHON, myFixture.getTempDirPath(), Maps.newHashMap(), PyConsoleOptions.getInstance(project).getPythonConsoleSettings(), - () -> { - }, new String[]{}); + (s) -> {}); before(); myConsoleInitSemaphore = new Semaphore(0);