From 6c35c40bb9b2bfb63da4a81edb1fa317d57152e6 Mon Sep 17 00:00:00 2001 From: Roman Golyshev Date: Fri, 16 Aug 2019 15:18:05 +0300 Subject: [PATCH] KT-32366: Refactor `ScratchTopPanel` to actions instead of custom UI - migrate module to the `ScratchPanel` class because it is information that matters to him most of all - move logic for showing\hiding checkboxes to the related actions --- .../kotlin/idea/scratch/ScratchFile.kt | 20 +- .../scratch/ScratchFileModuleInfoProvider.kt | 12 +- .../idea/scratch/actions/RunScratchAction.kt | 2 +- .../compile/KtScratchExecutionSession.kt | 2 +- .../scratch/repl/KtScratchReplExecutor.kt | 2 +- .../kotlin/idea/scratch/scratchUtils.kt | 4 +- .../idea/scratch/ui/ModulesComboBoxAction.kt | 73 ++++++ .../scratch/ui/ModulesComboBoxAction.kt.183 | 73 ++++++ .../kotlin/idea/scratch/ui/ScratchTopPanel.kt | 207 +++++++----------- .../scratch/ui/SmallBorderCheckboxAction.kt | 19 ++ .../ui/SmallBorderCheckboxAction.kt.183 | 19 ++ .../scratch/AbstractScratchRunActionTest.kt | 8 +- .../kotlin/idea/scratch/ScratchOptionsTest.kt | 19 +- 13 files changed, 302 insertions(+), 158 deletions(-) create mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ModulesComboBoxAction.kt create mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ModulesComboBoxAction.kt.183 create mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/SmallBorderCheckboxAction.kt create mode 100644 idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/SmallBorderCheckboxAction.kt.183 diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchFile.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchFile.kt index 56ed81b32eb..edfb3f0354d 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchFile.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchFile.kt @@ -29,6 +29,10 @@ abstract class ScratchFile(val project: Project, val editor: TextEditor) { var replScratchExecutor: SequentialScratchExecutor? = null var compilingScratchExecutor: ScratchExecutor? = null + private val moduleListeners: MutableList<() -> Unit> = mutableListOf() + var module: Module? = null + private set + fun getExpressions(): List = runReadAction { getPsiFile()?.let { getExpressions(it) } ?: emptyList() } @@ -37,8 +41,20 @@ abstract class ScratchFile(val project: Project, val editor: TextEditor) { PsiDocumentManager.getInstance(project).getPsiFile(editor.editor.document) } - fun getModule(): Module? { - return editor.getScratchPanel()?.getModule() + fun setModule(value: Module?) { + module = value + moduleListeners.forEach { it() } + } + + fun addModuleListener(f: (PsiFile, Module?) -> Unit) { + moduleListeners.add { + val selectedModule = module + + val psiFile = getPsiFile() + if (psiFile != null) { + f(psiFile, selectedModule) + } + } } val options: ScratchFileOptions diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchFileModuleInfoProvider.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchFileModuleInfoProvider.kt index c34ebc989b0..4a3395e071a 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchFileModuleInfoProvider.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ScratchFileModuleInfoProvider.kt @@ -38,7 +38,9 @@ class ScratchFileModuleInfoProvider(val project: Project) : ProjectComponent { override fun projectOpened() { project.messageBus.connect().subscribe(ScratchPanelListener.TOPIC, object : ScratchPanelListener { override fun panelAdded(panel: ScratchTopPanel) { - val ktFile = panel.scratchFile.getPsiFile() as? KtFile ?: return + val scratchFile = panel.scratchFile + + val ktFile = scratchFile.getPsiFile() as? KtFile ?: return val file = ktFile.virtualFile ?: return // BUNCH: 181 scratch files are created with .kt extension @@ -59,7 +61,7 @@ class ScratchFileModuleInfoProvider(val project: Project) : ProjectComponent { return } - panel.addModuleListener { psiFile, module -> + scratchFile.addModuleListener { psiFile, module -> psiFile.virtualFile.scriptRelatedModuleName = module?.name // Drop caches for old module @@ -69,13 +71,11 @@ class ScratchFileModuleInfoProvider(val project: Project) : ProjectComponent { } if (file.isKotlinWorksheet) { - panel.hideModuleSelector() - val module = file.getModule(project) ?: return - panel.setModule(module) + scratchFile.setModule(module) } else { val module = file.scriptRelatedModuleName?.let { ModuleManager.getInstance(project).findModuleByName(it) } ?: return - panel.setModule(module) + scratchFile.setModule(module) } } }) diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/actions/RunScratchAction.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/actions/RunScratchAction.kt index a7ee4fcd170..7818c3691db 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/actions/RunScratchAction.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/actions/RunScratchAction.kt @@ -69,7 +69,7 @@ class RunScratchAction : ScratchAction( val isMakeBeforeRun = scratchFile.options.isMakeBeforeRun log.printDebugMessage("Run Action: isMakeBeforeRun = $isMakeBeforeRun") - val module = scratchFile.getModule() + val module = scratchFile.module log.printDebugMessage("Run Action: module = ${module?.name}") if (!isAutoRun && module != null && isMakeBeforeRun) { diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtScratchExecutionSession.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtScratchExecutionSession.kt index c609bb0a05a..d4ce0b3e060 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtScratchExecutionSession.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtScratchExecutionSession.kt @@ -70,7 +70,7 @@ class KtScratchExecutionSession( ) ?: return try { - val commandLine = createCommandLine(psiFile, file.getModule(), result.mainClassName, tempDir.path) + val commandLine = createCommandLine(psiFile, file.module, result.mainClassName, tempDir.path) LOG.printDebugMessage(commandLine.commandLineString) diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/repl/KtScratchReplExecutor.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/repl/KtScratchReplExecutor.kt index c63a46fd321..dddb8709631 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/repl/KtScratchReplExecutor.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/repl/KtScratchReplExecutor.kt @@ -42,7 +42,7 @@ class KtScratchReplExecutor(file: ScratchFile) : SequentialScratchExecutor(file) private var osProcessHandler: OSProcessHandler? = null override fun startExecution() { - val module = file.getModule() + val module = file.module val cmdLine = KotlinConsoleKeeper.createReplCommandLine(file.project, module) LOG.printDebugMessage("Execute REPL: ${cmdLine.commandLineString}") diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/scratchUtils.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/scratchUtils.kt index fafe24d4717..e453575a276 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/scratchUtils.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/scratchUtils.kt @@ -61,14 +61,14 @@ fun TextEditor.getScratchPanel(): ScratchTopPanel? { fun TextEditor.addScratchPanel(panel: ScratchTopPanel) { scratchTopPanel = panel - FileEditorManager.getInstance(panel.scratchFile.project).addTopComponent(this, panel) + FileEditorManager.getInstance(panel.scratchFile.project).addTopComponent(this, panel.component) Disposer.register(this, panel) panel.scratchFile.project.syncPublisherWithDisposeCheck(ScratchPanelListener.TOPIC).panelAdded(panel) } fun TextEditor.removeScratchPanel() { - scratchTopPanel?.let { FileEditorManager.getInstance(it.scratchFile.project).removeTopComponent(this, it) } + scratchTopPanel?.let { FileEditorManager.getInstance(it.scratchFile.project).removeTopComponent(this, it.component) } scratchTopPanel = null } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ModulesComboBoxAction.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ModulesComboBoxAction.kt new file mode 100644 index 00000000000..a812b700e82 --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ModulesComboBoxAction.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scratch.ui + +import com.intellij.execution.ui.ConfigurationModuleSelector +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.DefaultActionGroup +import com.intellij.openapi.actionSystem.Presentation +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.module.ModuleType +import com.intellij.openapi.project.DumbAwareAction +import com.intellij.openapi.vcs.changes.committed.LabeledComboBoxAction +import com.intellij.util.ui.UIUtil +import org.jetbrains.kotlin.idea.caches.project.productionSourceInfo +import org.jetbrains.kotlin.idea.caches.project.testSourceInfo +import org.jetbrains.kotlin.idea.scratch.ScratchFile +import org.jetbrains.kotlin.idea.scratch.isKotlinWorksheet +import javax.swing.JComponent + +class ModulesComboBoxAction(private val scratchFile: ScratchFile) : LabeledComboBoxAction("Use classpath of module") { + override fun createPopupActionGroup(button: JComponent): DefaultActionGroup { + val actionGroup = DefaultActionGroup() + actionGroup.add(ModuleIsNotSelectedAction(ConfigurationModuleSelector.NO_MODULE_TEXT)) + + val modules = ModuleManager.getInstance(scratchFile.project).modules.filter { + it.productionSourceInfo() != null || it.testSourceInfo() != null + } + + actionGroup.addAll(modules.map { SelectModuleAction(it) }) + + return actionGroup + } + + /** + * By default this action uses big font for label, so we have to decrease it + * to make it look the same as in [CheckboxAction]. + */ + override fun createCustomComponent(presentation: Presentation, place: String): JComponent { + val customComponent = super.createCustomComponent(presentation, place) + customComponent.components.forEach { it.font = UIUtil.getFont(UIUtil.FontSize.SMALL, it.font) } + return customComponent + } + + override fun update(e: AnActionEvent) { + super.update(e) + val selectedModule = scratchFile.module + + e.presentation.apply { + icon = selectedModule?.let { ModuleType.get(it).icon } + text = selectedModule?.name ?: ConfigurationModuleSelector.NO_MODULE_TEXT + } + + val isWorksheetFile = scratchFile.getPsiFile()?.virtualFile?.isKotlinWorksheet == true + e.presentation.isVisible = !isWorksheetFile + } + + private inner class ModuleIsNotSelectedAction(placeholder: String) : DumbAwareAction(placeholder) { + override fun actionPerformed(e: AnActionEvent) { + scratchFile.setModule(null) + } + } + + private inner class SelectModuleAction(private val module: Module) : + DumbAwareAction(module.name, null, ModuleType.get(module).icon) { + override fun actionPerformed(e: AnActionEvent) { + scratchFile.setModule(module) + } + } +} \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ModulesComboBoxAction.kt.183 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ModulesComboBoxAction.kt.183 new file mode 100644 index 00000000000..6dfa4fa39eb --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ModulesComboBoxAction.kt.183 @@ -0,0 +1,73 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scratch.ui + +import com.intellij.execution.ui.ConfigurationModuleSelector +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.DefaultActionGroup +import com.intellij.openapi.actionSystem.Presentation +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.module.ModuleType +import com.intellij.openapi.project.DumbAwareAction +import com.intellij.openapi.vcs.changes.committed.LabeledComboBoxAction +import com.intellij.util.ui.UIUtil +import org.jetbrains.kotlin.idea.caches.project.productionSourceInfo +import org.jetbrains.kotlin.idea.caches.project.testSourceInfo +import org.jetbrains.kotlin.idea.scratch.ScratchFile +import org.jetbrains.kotlin.idea.scratch.isKotlinWorksheet +import javax.swing.JComponent + +class ModulesComboBoxAction(private val scratchFile: ScratchFile) : LabeledComboBoxAction("Use classpath of module") { + override fun createPopupActionGroup(button: JComponent): DefaultActionGroup { + val actionGroup = DefaultActionGroup() + actionGroup.add(ModuleIsNotSelectedAction(ConfigurationModuleSelector.NO_MODULE_TEXT)) + + val modules = ModuleManager.getInstance(scratchFile.project).modules.filter { + it.productionSourceInfo() != null || it.testSourceInfo() != null + } + + actionGroup.addAll(modules.map { SelectModuleAction(it) }) + + return actionGroup + } + + /** + * By default this action uses big font for label, so we have to decrease it + * to make it look the same as in [CheckboxAction]. + */ + override fun createCustomComponent(presentation: Presentation): JComponent { + val customComponent = super.createCustomComponent(presentation) + customComponent.components.forEach { it.font = UIUtil.getFont(UIUtil.FontSize.SMALL, it.font) } + return customComponent + } + + override fun update(e: AnActionEvent) { + super.update(e) + val selectedModule = scratchFile.module + + e.presentation.apply { + icon = selectedModule?.let { ModuleType.get(it).icon } + text = selectedModule?.name ?: ConfigurationModuleSelector.NO_MODULE_TEXT + } + + val isWorksheetFile = scratchFile.getPsiFile()?.virtualFile?.isKotlinWorksheet == true + e.presentation.isVisible = !isWorksheetFile + } + + private inner class ModuleIsNotSelectedAction(placeholder: String) : DumbAwareAction(placeholder) { + override fun actionPerformed(e: AnActionEvent) { + scratchFile.setModule(null) + } + } + + private inner class SelectModuleAction(private val module: Module) : + DumbAwareAction(module.name, null, ModuleType.get(module).icon) { + override fun actionPerformed(e: AnActionEvent) { + scratchFile.setModule(module) + } + } +} \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ScratchTopPanel.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ScratchTopPanel.kt index c340ae93e39..811745b030f 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ScratchTopPanel.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/ScratchTopPanel.kt @@ -17,27 +17,16 @@ package org.jetbrains.kotlin.idea.scratch.ui -import com.intellij.application.options.ModulesComboBox import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer -import com.intellij.execution.ui.ConfigurationModuleSelector import com.intellij.openapi.Disposable -import com.intellij.openapi.actionSystem.ActionManager -import com.intellij.openapi.actionSystem.ActionPlaces -import com.intellij.openapi.actionSystem.ActionToolbar -import com.intellij.openapi.actionSystem.DefaultActionGroup +import com.intellij.openapi.actionSystem.* import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.fileEditor.TextEditor -import com.intellij.openapi.module.Module -import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.PsiFile import com.intellij.psi.PsiManager -import com.intellij.ui.components.panels.HorizontalLayout import com.intellij.util.messages.Topic import org.jetbrains.annotations.TestOnly -import org.jetbrains.kotlin.idea.caches.project.productionSourceInfo -import org.jetbrains.kotlin.idea.caches.project.testSourceInfo import org.jetbrains.kotlin.idea.scratch.ScratchFile import org.jetbrains.kotlin.idea.scratch.ScratchFileLanguageProvider import org.jetbrains.kotlin.idea.scratch.actions.ClearScratchAction @@ -46,9 +35,9 @@ import org.jetbrains.kotlin.idea.scratch.actions.StopScratchAction import org.jetbrains.kotlin.idea.scratch.addScratchPanel import org.jetbrains.kotlin.idea.scratch.output.ScratchOutputHandlerAdapter import org.jetbrains.kotlin.idea.scratch.removeScratchPanel -import javax.swing.* +import javax.swing.JComponent -class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : JPanel(HorizontalLayout(5)), Disposable { +class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : Disposable { override fun dispose() { scratchFile.replScratchExecutor?.stop() scratchFile.compilingScratchExecutor?.stop() @@ -91,54 +80,89 @@ class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : JPanel } } - private val moduleChooser: ModulesComboBox - private val moduleChooserLabel: JLabel - private val isReplCheckbox: JCheckBox - private val isMakeBeforeRunCheckbox: JCheckBox - private val isInteractiveCheckbox: JCheckBox - - private val moduleSeparator: JSeparator + private val moduleChooserAction: ModulesComboBoxAction = ModulesComboBoxAction(scratchFile) private val actionsToolbar: ActionToolbar init { - actionsToolbar = createActionsToolbar() - add(actionsToolbar.component) + scratchFile.addModuleListener { _, _ -> updateToolbar() } - moduleChooser = createModuleChooser(scratchFile.project) - moduleChooserLabel = JLabel("Use classpath of module") - add(moduleChooserLabel) - add(moduleChooser) - - isMakeBeforeRunCheckbox = JCheckBox("Make module before Run") - add(isMakeBeforeRunCheckbox) - isMakeBeforeRunCheckbox.addItemListener { - scratchFile.saveOptions { - copy(isMakeBeforeRun = isMakeBeforeRunCheckbox.isSelected) - } + val toolbarGroup = DefaultActionGroup().apply { + add(RunScratchAction()) + add(StopScratchAction()) + addSeparator() + add(ClearScratchAction()) + addSeparator() + add(moduleChooserAction) + add(IsMakeBeforeRunAction()) + addSeparator() + add(IsInteractiveCheckboxAction()) + addSeparator() + add(IsReplCheckboxAction()) } - moduleSeparator = JSeparator(SwingConstants.VERTICAL) - add(moduleSeparator) + actionsToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, toolbarGroup, true) + } - changeMakeModuleCheckboxVisibility(false) + val component: JComponent = actionsToolbar.component - isInteractiveCheckbox = JCheckBox("Interactive mode") - add(isInteractiveCheckbox) - isInteractiveCheckbox.addItemListener { - scratchFile.saveOptions { - copy(isInteractiveMode = isInteractiveCheckbox.isSelected) - } + @TestOnly + fun setReplMode(isSelected: Boolean) { + scratchFile.saveOptions { copy(isRepl = isSelected) } + } + + @TestOnly + fun setMakeBeforeRun(isSelected: Boolean) { + scratchFile.saveOptions { copy(isMakeBeforeRun = isSelected) } + } + + @TestOnly + fun setInteractiveMode(isSelected: Boolean) { + scratchFile.saveOptions { copy(isInteractiveMode = isSelected) } + } + + @TestOnly + fun getModuleSelectorAction(): AnAction = moduleChooserAction + + private fun updateToolbar() { + ApplicationManager.getApplication().invokeLater { + actionsToolbar.updateActionsImmediately() + } + } + + private inner class IsMakeBeforeRunAction : SmallBorderCheckboxAction("Make module before Run") { + override fun update(e: AnActionEvent) { + super.update(e) + e.presentation.isVisible = scratchFile.module != null } - add(JSeparator(SwingConstants.VERTICAL)) + override fun isSelected(e: AnActionEvent): Boolean { + return scratchFile.options.isMakeBeforeRun + } - isReplCheckbox = JCheckBox("Use REPL") - add(isReplCheckbox) - isReplCheckbox.addItemListener { - scratchFile.saveOptions { - copy(isRepl = isReplCheckbox.isSelected) - } - if (isReplCheckbox.isSelected) { + override fun setSelected(e: AnActionEvent, isMakeBeforeRun: Boolean) { + scratchFile.saveOptions { copy(isMakeBeforeRun = isMakeBeforeRun) } + } + } + + private inner class IsInteractiveCheckboxAction : SmallBorderCheckboxAction("Interactive mode") { + override fun isSelected(e: AnActionEvent): Boolean { + return scratchFile.options.isInteractiveMode + } + + override fun setSelected(e: AnActionEvent, isInteractiveMode: Boolean) { + scratchFile.saveOptions { copy(isInteractiveMode = isInteractiveMode) } + } + } + + private inner class IsReplCheckboxAction : SmallBorderCheckboxAction("Use REPL") { + override fun isSelected(e: AnActionEvent): Boolean { + return scratchFile.options.isRepl + } + + override fun setSelected(e: AnActionEvent, isRepl: Boolean) { + scratchFile.saveOptions { copy(isRepl = isRepl) } + + if (isRepl) { // TODO start REPL process when checkbox is selected to speed up execution // Now it is switched off due to KT-18355: REPL process is keep alive if no command is executed //scratchFile.replScratchExecutor?.start() @@ -146,87 +170,6 @@ class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : JPanel scratchFile.replScratchExecutor?.stop() } } - - add(JSeparator(SwingConstants.VERTICAL)) - - scratchFile.options.let { - isReplCheckbox.isSelected = it.isRepl - isMakeBeforeRunCheckbox.isSelected = it.isMakeBeforeRun - isInteractiveCheckbox.isSelected = it.isInteractiveMode - } - } - - fun getModule(): Module? = moduleChooser.selectedModule - - fun setModule(module: Module) { - moduleChooser.selectedModule = module - } - - fun hideModuleSelector() { - moduleChooser.isVisible = false - moduleChooserLabel.isVisible = false - } - - fun addModuleListener(f: (PsiFile, Module?) -> Unit) { - moduleChooser.addActionListener { - val selectedModule = moduleChooser.selectedModule - - changeMakeModuleCheckboxVisibility(selectedModule != null) - - val psiFile = scratchFile.getPsiFile() - if (psiFile != null) { - f(psiFile, selectedModule) - } - } - } - - @TestOnly - fun setReplMode(isSelected: Boolean) { - isReplCheckbox.isSelected = isSelected - } - - @TestOnly - fun setMakeBeforeRun(isSelected: Boolean) { - isMakeBeforeRunCheckbox.isSelected = isSelected - } - - @TestOnly - fun setInteractiveMode(isSelected: Boolean) { - isInteractiveCheckbox.isSelected = isSelected - } - - @TestOnly - fun isModuleSelectorVisible(): Boolean = moduleChooser.isVisible && moduleChooserLabel.isVisible - - private fun changeMakeModuleCheckboxVisibility(isVisible: Boolean) { - isMakeBeforeRunCheckbox.isVisible = isVisible - moduleSeparator.isVisible = isVisible - } - - fun updateToolbar() { - ApplicationManager.getApplication().invokeLater { - actionsToolbar.updateActionsImmediately() - } - } - - private fun createActionsToolbar(): ActionToolbar { - val toolbarGroup = DefaultActionGroup().apply { - add(RunScratchAction()) - add(StopScratchAction()) - addSeparator() - add(ClearScratchAction()) - } - - return ActionManager.getInstance().createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, toolbarGroup, true) - } - - private fun createModuleChooser(project: Project): ModulesComboBox { - return ModulesComboBox().apply { - setModules(ModuleManager.getInstance(project).modules.filter { - it.productionSourceInfo() != null || it.testSourceInfo() != null - }) - allowEmptySelection(ConfigurationModuleSelector.NO_MODULE_TEXT) - } } } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/SmallBorderCheckboxAction.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/SmallBorderCheckboxAction.kt new file mode 100644 index 00000000000..aee304b44d7 --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/SmallBorderCheckboxAction.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scratch.ui + +import com.intellij.openapi.actionSystem.Presentation +import com.intellij.openapi.actionSystem.ex.CheckboxAction +import com.intellij.util.ui.JBUI +import javax.swing.JComponent + +abstract class SmallBorderCheckboxAction(label: String) : CheckboxAction(label) { + override fun createCustomComponent(presentation: Presentation, place: String): JComponent { + val checkbox = super.createCustomComponent(presentation, place) + checkbox.border = JBUI.Borders.emptyRight(4) + return checkbox + } +} \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/SmallBorderCheckboxAction.kt.183 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/SmallBorderCheckboxAction.kt.183 new file mode 100644 index 00000000000..29bec03cf83 --- /dev/null +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/SmallBorderCheckboxAction.kt.183 @@ -0,0 +1,19 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scratch.ui + +import com.intellij.openapi.actionSystem.Presentation +import com.intellij.openapi.actionSystem.ex.CheckboxAction +import com.intellij.util.ui.JBUI +import javax.swing.JComponent + +abstract class SmallBorderCheckboxAction(label: String) : CheckboxAction(label) { + override fun createCustomComponent(presentation: Presentation): JComponent { + val checkbox = super.createCustomComponent(presentation) + checkbox.border = JBUI.Borders.emptyRight(4) + return checkbox + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt index 1752e983369..029c5266cd8 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt @@ -212,6 +212,12 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() { action.actionPerformed(e) } + protected fun getActionVisibility(action: AnAction): Boolean { + val e = getActionEvent(myFixture.file.virtualFile, action) + action.beforeActionPerformedUpdate(e) + return e.presentation.isVisible + } + protected fun waitUntilScratchFinishes(shouldStopRepl: Boolean = true) { UIUtil.dispatchAllInvocationEvents() @@ -317,7 +323,7 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() { } if (module != null && !InTextDirectivesUtils.isDirectiveDefined(fileText, "// NO_MODULE")) { - scratchPanel.setModule(module) + scratchPanel.scratchFile.setModule(module) } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/scratch/ScratchOptionsTest.kt b/idea/tests/org/jetbrains/kotlin/idea/scratch/ScratchOptionsTest.kt index 1cca3f96476..b404f1ccbe7 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/scratch/ScratchOptionsTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/scratch/ScratchOptionsTest.kt @@ -9,9 +9,6 @@ import org.jetbrains.kotlin.idea.scratch.ui.ScratchTopPanel import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner import org.junit.Assert import org.junit.runner.RunWith -import javax.swing.JCheckBox -import kotlin.reflect.full.createType -import kotlin.reflect.full.declaredMemberProperties @RunWith(JUnit3WithIdeaConfigurationRunner::class) class ScratchOptionsTest : AbstractScratchRunActionTest() { @@ -19,12 +16,6 @@ class ScratchOptionsTest : AbstractScratchRunActionTest() { fun testOptionsSaveOnClosingFile() { val scratchPanelBeforeClosingFile = configureScratchByText("scratch_1.kts", testScratchText()) - Assert.assertEquals( - "This test checks that checkbox options are restored after file closing. Not all checkboxes are checked in this test", - 3, - ScratchTopPanel::class.declaredMemberProperties.filter { it.returnType == JCheckBox::class.createType() }.size - ) - val newIsReplValue = !scratchPanelBeforeClosingFile.scratchFile.options.isRepl val newIsMakeBeforeRunValue = !scratchPanelBeforeClosingFile.scratchFile.options.isMakeBeforeRun val newIsInteractiveModeValue = !scratchPanelBeforeClosingFile.scratchFile.options.isInteractiveMode @@ -54,13 +45,13 @@ class ScratchOptionsTest : AbstractScratchRunActionTest() { fun testModuleSelectionPanelIsVisibleForScratchFile() { val scratchTopPanel = configureScratchByText("scratch_1.kts", testScratchText()) - Assert.assertTrue("Module selector should be visible for scratches", scratchTopPanel.isModuleSelectorVisible()) + Assert.assertTrue("Module selector should be visible for scratches", isModuleSelectorVisible(scratchTopPanel)) } fun testModuleSelectionPanelIsHiddenForWorksheetFile() { val scratchTopPanel = configureWorksheetByText("worksheet.ws.kts", testScratchText()) - Assert.assertFalse("Module selector should be hidden for worksheets", scratchTopPanel.isModuleSelectorVisible()) + Assert.assertFalse("Module selector should be hidden for worksheets", isModuleSelectorVisible(scratchTopPanel)) } fun testCurrentModuleIsAutomaticallySelectedForWorksheetFile() { @@ -69,8 +60,12 @@ class ScratchOptionsTest : AbstractScratchRunActionTest() { Assert.assertEquals( "Selected module should be equal to current project module for worksheets", myFixture.module, - scratchTopPanel.getModule() + scratchTopPanel.scratchFile.module ) } + private fun isModuleSelectorVisible(scratchTopPanel: ScratchTopPanel): Boolean { + return getActionVisibility(scratchTopPanel.getModuleSelectorAction()) + } + } \ No newline at end of file