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
This commit is contained in:
Roman Golyshev
2019-08-16 15:18:05 +03:00
committed by Roman Golyshev
parent 23f662cfe2
commit 6c35c40bb9
13 changed files with 302 additions and 158 deletions
@@ -29,6 +29,10 @@ abstract class ScratchFile(val project: Project, val editor: TextEditor) {
var replScratchExecutor: SequentialScratchExecutor? = null var replScratchExecutor: SequentialScratchExecutor? = null
var compilingScratchExecutor: ScratchExecutor? = null var compilingScratchExecutor: ScratchExecutor? = null
private val moduleListeners: MutableList<() -> Unit> = mutableListOf()
var module: Module? = null
private set
fun getExpressions(): List<ScratchExpression> = runReadAction { fun getExpressions(): List<ScratchExpression> = runReadAction {
getPsiFile()?.let { getExpressions(it) } ?: emptyList() 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) PsiDocumentManager.getInstance(project).getPsiFile(editor.editor.document)
} }
fun getModule(): Module? { fun setModule(value: Module?) {
return editor.getScratchPanel()?.getModule() 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 val options: ScratchFileOptions
@@ -38,7 +38,9 @@ class ScratchFileModuleInfoProvider(val project: Project) : ProjectComponent {
override fun projectOpened() { override fun projectOpened() {
project.messageBus.connect().subscribe(ScratchPanelListener.TOPIC, object : ScratchPanelListener { project.messageBus.connect().subscribe(ScratchPanelListener.TOPIC, object : ScratchPanelListener {
override fun panelAdded(panel: ScratchTopPanel) { 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 val file = ktFile.virtualFile ?: return
// BUNCH: 181 scratch files are created with .kt extension // BUNCH: 181 scratch files are created with .kt extension
@@ -59,7 +61,7 @@ class ScratchFileModuleInfoProvider(val project: Project) : ProjectComponent {
return return
} }
panel.addModuleListener { psiFile, module -> scratchFile.addModuleListener { psiFile, module ->
psiFile.virtualFile.scriptRelatedModuleName = module?.name psiFile.virtualFile.scriptRelatedModuleName = module?.name
// Drop caches for old module // Drop caches for old module
@@ -69,13 +71,11 @@ class ScratchFileModuleInfoProvider(val project: Project) : ProjectComponent {
} }
if (file.isKotlinWorksheet) { if (file.isKotlinWorksheet) {
panel.hideModuleSelector()
val module = file.getModule(project) ?: return val module = file.getModule(project) ?: return
panel.setModule(module) scratchFile.setModule(module)
} else { } else {
val module = file.scriptRelatedModuleName?.let { ModuleManager.getInstance(project).findModuleByName(it) } ?: return val module = file.scriptRelatedModuleName?.let { ModuleManager.getInstance(project).findModuleByName(it) } ?: return
panel.setModule(module) scratchFile.setModule(module)
} }
} }
}) })
@@ -69,7 +69,7 @@ class RunScratchAction : ScratchAction(
val isMakeBeforeRun = scratchFile.options.isMakeBeforeRun val isMakeBeforeRun = scratchFile.options.isMakeBeforeRun
log.printDebugMessage("Run Action: isMakeBeforeRun = $isMakeBeforeRun") log.printDebugMessage("Run Action: isMakeBeforeRun = $isMakeBeforeRun")
val module = scratchFile.getModule() val module = scratchFile.module
log.printDebugMessage("Run Action: module = ${module?.name}") log.printDebugMessage("Run Action: module = ${module?.name}")
if (!isAutoRun && module != null && isMakeBeforeRun) { if (!isAutoRun && module != null && isMakeBeforeRun) {
@@ -70,7 +70,7 @@ class KtScratchExecutionSession(
) ?: return ) ?: return
try { 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) LOG.printDebugMessage(commandLine.commandLineString)
@@ -42,7 +42,7 @@ class KtScratchReplExecutor(file: ScratchFile) : SequentialScratchExecutor(file)
private var osProcessHandler: OSProcessHandler? = null private var osProcessHandler: OSProcessHandler? = null
override fun startExecution() { override fun startExecution() {
val module = file.getModule() val module = file.module
val cmdLine = KotlinConsoleKeeper.createReplCommandLine(file.project, module) val cmdLine = KotlinConsoleKeeper.createReplCommandLine(file.project, module)
LOG.printDebugMessage("Execute REPL: ${cmdLine.commandLineString}") LOG.printDebugMessage("Execute REPL: ${cmdLine.commandLineString}")
@@ -61,14 +61,14 @@ fun TextEditor.getScratchPanel(): ScratchTopPanel? {
fun TextEditor.addScratchPanel(panel: ScratchTopPanel) { fun TextEditor.addScratchPanel(panel: ScratchTopPanel) {
scratchTopPanel = panel scratchTopPanel = panel
FileEditorManager.getInstance(panel.scratchFile.project).addTopComponent(this, panel) FileEditorManager.getInstance(panel.scratchFile.project).addTopComponent(this, panel.component)
Disposer.register(this, panel) Disposer.register(this, panel)
panel.scratchFile.project.syncPublisherWithDisposeCheck(ScratchPanelListener.TOPIC).panelAdded(panel) panel.scratchFile.project.syncPublisherWithDisposeCheck(ScratchPanelListener.TOPIC).panelAdded(panel)
} }
fun TextEditor.removeScratchPanel() { 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 scratchTopPanel = null
} }
@@ -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)
}
}
}
@@ -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)
}
}
}
@@ -17,27 +17,16 @@
package org.jetbrains.kotlin.idea.scratch.ui package org.jetbrains.kotlin.idea.scratch.ui
import com.intellij.application.options.ModulesComboBox
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.execution.ui.ConfigurationModuleSelector
import com.intellij.openapi.Disposable import com.intellij.openapi.Disposable
import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.actionSystem.ActionPlaces
import com.intellij.openapi.actionSystem.ActionToolbar
import com.intellij.openapi.actionSystem.DefaultActionGroup
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.fileEditor.TextEditor 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.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager import com.intellij.psi.PsiManager
import com.intellij.ui.components.panels.HorizontalLayout
import com.intellij.util.messages.Topic import com.intellij.util.messages.Topic
import org.jetbrains.annotations.TestOnly 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.ScratchFile
import org.jetbrains.kotlin.idea.scratch.ScratchFileLanguageProvider import org.jetbrains.kotlin.idea.scratch.ScratchFileLanguageProvider
import org.jetbrains.kotlin.idea.scratch.actions.ClearScratchAction 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.addScratchPanel
import org.jetbrains.kotlin.idea.scratch.output.ScratchOutputHandlerAdapter import org.jetbrains.kotlin.idea.scratch.output.ScratchOutputHandlerAdapter
import org.jetbrains.kotlin.idea.scratch.removeScratchPanel 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() { override fun dispose() {
scratchFile.replScratchExecutor?.stop() scratchFile.replScratchExecutor?.stop()
scratchFile.compilingScratchExecutor?.stop() scratchFile.compilingScratchExecutor?.stop()
@@ -91,54 +80,89 @@ class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : JPanel
} }
} }
private val moduleChooser: ModulesComboBox private val moduleChooserAction: ModulesComboBoxAction = ModulesComboBoxAction(scratchFile)
private val moduleChooserLabel: JLabel
private val isReplCheckbox: JCheckBox
private val isMakeBeforeRunCheckbox: JCheckBox
private val isInteractiveCheckbox: JCheckBox
private val moduleSeparator: JSeparator
private val actionsToolbar: ActionToolbar private val actionsToolbar: ActionToolbar
init { init {
actionsToolbar = createActionsToolbar() scratchFile.addModuleListener { _, _ -> updateToolbar() }
add(actionsToolbar.component)
moduleChooser = createModuleChooser(scratchFile.project) val toolbarGroup = DefaultActionGroup().apply {
moduleChooserLabel = JLabel("Use classpath of module") add(RunScratchAction())
add(moduleChooserLabel) add(StopScratchAction())
add(moduleChooser) addSeparator()
add(ClearScratchAction())
isMakeBeforeRunCheckbox = JCheckBox("Make module before Run") addSeparator()
add(isMakeBeforeRunCheckbox) add(moduleChooserAction)
isMakeBeforeRunCheckbox.addItemListener { add(IsMakeBeforeRunAction())
scratchFile.saveOptions { addSeparator()
copy(isMakeBeforeRun = isMakeBeforeRunCheckbox.isSelected) add(IsInteractiveCheckboxAction())
} addSeparator()
add(IsReplCheckboxAction())
} }
moduleSeparator = JSeparator(SwingConstants.VERTICAL) actionsToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, toolbarGroup, true)
add(moduleSeparator) }
changeMakeModuleCheckboxVisibility(false) val component: JComponent = actionsToolbar.component
isInteractiveCheckbox = JCheckBox("Interactive mode") @TestOnly
add(isInteractiveCheckbox) fun setReplMode(isSelected: Boolean) {
isInteractiveCheckbox.addItemListener { scratchFile.saveOptions { copy(isRepl = isSelected) }
scratchFile.saveOptions { }
copy(isInteractiveMode = isInteractiveCheckbox.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") override fun setSelected(e: AnActionEvent, isMakeBeforeRun: Boolean) {
add(isReplCheckbox) scratchFile.saveOptions { copy(isMakeBeforeRun = isMakeBeforeRun) }
isReplCheckbox.addItemListener { }
scratchFile.saveOptions { }
copy(isRepl = isReplCheckbox.isSelected)
} private inner class IsInteractiveCheckboxAction : SmallBorderCheckboxAction("Interactive mode") {
if (isReplCheckbox.isSelected) { 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 // 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 // Now it is switched off due to KT-18355: REPL process is keep alive if no command is executed
//scratchFile.replScratchExecutor?.start() //scratchFile.replScratchExecutor?.start()
@@ -146,87 +170,6 @@ class ScratchTopPanel private constructor(val scratchFile: ScratchFile) : JPanel
scratchFile.replScratchExecutor?.stop() 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)
}
} }
} }
@@ -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
}
}
@@ -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
}
}
@@ -212,6 +212,12 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
action.actionPerformed(e) 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) { protected fun waitUntilScratchFinishes(shouldStopRepl: Boolean = true) {
UIUtil.dispatchAllInvocationEvents() UIUtil.dispatchAllInvocationEvents()
@@ -317,7 +323,7 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
} }
if (module != null && !InTextDirectivesUtils.isDirectiveDefined(fileText, "// NO_MODULE")) { if (module != null && !InTextDirectivesUtils.isDirectiveDefined(fileText, "// NO_MODULE")) {
scratchPanel.setModule(module) scratchPanel.scratchFile.setModule(module)
} }
} }
@@ -9,9 +9,6 @@ import org.jetbrains.kotlin.idea.scratch.ui.ScratchTopPanel
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.Assert import org.junit.Assert
import org.junit.runner.RunWith import org.junit.runner.RunWith
import javax.swing.JCheckBox
import kotlin.reflect.full.createType
import kotlin.reflect.full.declaredMemberProperties
@RunWith(JUnit3WithIdeaConfigurationRunner::class) @RunWith(JUnit3WithIdeaConfigurationRunner::class)
class ScratchOptionsTest : AbstractScratchRunActionTest() { class ScratchOptionsTest : AbstractScratchRunActionTest() {
@@ -19,12 +16,6 @@ class ScratchOptionsTest : AbstractScratchRunActionTest() {
fun testOptionsSaveOnClosingFile() { fun testOptionsSaveOnClosingFile() {
val scratchPanelBeforeClosingFile = configureScratchByText("scratch_1.kts", testScratchText()) 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 newIsReplValue = !scratchPanelBeforeClosingFile.scratchFile.options.isRepl
val newIsMakeBeforeRunValue = !scratchPanelBeforeClosingFile.scratchFile.options.isMakeBeforeRun val newIsMakeBeforeRunValue = !scratchPanelBeforeClosingFile.scratchFile.options.isMakeBeforeRun
val newIsInteractiveModeValue = !scratchPanelBeforeClosingFile.scratchFile.options.isInteractiveMode val newIsInteractiveModeValue = !scratchPanelBeforeClosingFile.scratchFile.options.isInteractiveMode
@@ -54,13 +45,13 @@ class ScratchOptionsTest : AbstractScratchRunActionTest() {
fun testModuleSelectionPanelIsVisibleForScratchFile() { fun testModuleSelectionPanelIsVisibleForScratchFile() {
val scratchTopPanel = configureScratchByText("scratch_1.kts", testScratchText()) 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() { fun testModuleSelectionPanelIsHiddenForWorksheetFile() {
val scratchTopPanel = configureWorksheetByText("worksheet.ws.kts", testScratchText()) 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() { fun testCurrentModuleIsAutomaticallySelectedForWorksheetFile() {
@@ -69,8 +60,12 @@ class ScratchOptionsTest : AbstractScratchRunActionTest() {
Assert.assertEquals( Assert.assertEquals(
"Selected module should be equal to current project module for worksheets", "Selected module should be equal to current project module for worksheets",
myFixture.module, myFixture.module,
scratchTopPanel.getModule() scratchTopPanel.scratchFile.module
) )
} }
private fun isModuleSelectorVisible(scratchTopPanel: ScratchTopPanel): Boolean {
return getActionVisibility(scratchTopPanel.getModuleSelectorAction())
}
} }