diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/NewProjectWizardModuleBuilder.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/NewProjectWizardModuleBuilder.kt
index a75025b707c..e6230b4ec0e 100644
--- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/NewProjectWizardModuleBuilder.kt
+++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/NewProjectWizardModuleBuilder.kt
@@ -12,9 +12,9 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ui.configuration.ModulesProvider
import com.intellij.openapi.ui.Messages
import com.intellij.util.SystemProperties
+import org.jetbrains.kotlin.idea.configuration.ExperimentalFeatures
import org.jetbrains.kotlin.idea.framework.KotlinModuleSettingStep
import org.jetbrains.kotlin.idea.framework.KotlinTemplatesFactory
-import org.jetbrains.kotlin.idea.projectWizard.NewProjectWizardService
import org.jetbrains.kotlin.idea.projectWizard.ProjectCreationStats
import org.jetbrains.kotlin.idea.projectWizard.UiEditorUsageStats
import org.jetbrains.kotlin.idea.projectWizard.WizardStatsService
@@ -61,7 +61,7 @@ class NewProjectWizardModuleBuilder : EmptyModuleBuilder() {
private const val INVALID_PROJECT_NAME_MESSAGE = "Invalid project name"
}
- override fun isAvailable(): Boolean = NewProjectWizardService.isEnabled
+ override fun isAvailable(): Boolean = ExperimentalFeatures.NewWizard.isEnabled
private var wizardContext: WizardContext? = null
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AbstractPerformanceJavaToKotlinCopyPasteConversionTest.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AbstractPerformanceJavaToKotlinCopyPasteConversionTest.kt
index b95c24ab433..b94995caae9 100644
--- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AbstractPerformanceJavaToKotlinCopyPasteConversionTest.kt
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AbstractPerformanceJavaToKotlinCopyPasteConversionTest.kt
@@ -11,11 +11,11 @@ import com.intellij.openapi.application.runWriteAction
import com.intellij.psi.PsiDocumentManager
import com.intellij.util.ui.UIUtil
import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.idea.configuration.ExperimentalFeatures
import org.jetbrains.kotlin.idea.conversion.copy.AbstractJavaToKotlinCopyPasteConversionTest
import org.jetbrains.kotlin.idea.conversion.copy.ConvertJavaCopyPasteProcessor
import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP
import org.jetbrains.kotlin.idea.testFramework.commitAllDocuments
-import org.jetbrains.kotlin.j2k.J2kConverterExtension
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
@@ -38,7 +38,7 @@ abstract class AbstractPerformanceJavaToKotlinCopyPasteConversionTest(private va
override fun setUp() {
super.setUp()
- J2kConverterExtension.isNewJ2k = newJ2K
+ ExperimentalFeatures.NewJ2k.isEnabled = newJ2K
val index = j2kIndex()
if (!warmedUp[index]) {
diff --git a/idea/resources/META-INF/extensions/ide.xml b/idea/resources/META-INF/extensions/ide.xml
index 08eecd58c6a..a673325201d 100644
--- a/idea/resources/META-INF/extensions/ide.xml
+++ b/idea/resources/META-INF/extensions/ide.xml
@@ -131,6 +131,16 @@
description="Allow a trailing comma on call-site"
defaultValue="false"
restartRequired="false"/>
+
+
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt
index ef67b6be1c3..db10e1bf7cc 100644
--- a/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/actions/JavaToKotlinAction.kt
@@ -47,6 +47,7 @@ import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiManager
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.idea.configuration.ExperimentalFeatures
import org.jetbrains.kotlin.idea.core.util.toPsiFile
import org.jetbrains.kotlin.idea.formatter.commitAndUnblockDocument
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
@@ -129,7 +130,7 @@ class JavaToKotlinAction : AnAction() {
project,
ConverterSettings.defaultSettings,
IdeaJavaToKotlinServices
- ) else J2kConverterExtension.extension().createJavaToKotlinConverter(
+ ) else J2kConverterExtension.extension(useNewJ2k = ExperimentalFeatures.NewJ2k.isEnabled).createJavaToKotlinConverter(
project,
module,
ConverterSettings.defaultSettings,
@@ -138,7 +139,7 @@ class JavaToKotlinAction : AnAction() {
converterResult = converter.filesToKotlin(
javaFiles,
if (forceUsingOldJ2k) J2kPostProcessor(formatCode = true)
- else J2kConverterExtension.extension().createPostProcessor(formatCode = true),
+ else J2kConverterExtension.extension(useNewJ2k = ExperimentalFeatures.NewJ2k.isEnabled).createPostProcessor(formatCode = true),
progress = ProgressManager.getInstance().progressIndicator!!
)
}
@@ -153,7 +154,7 @@ class JavaToKotlinAction : AnAction() {
logJ2kConversionStatistics(
ConversionType.FILES,
- J2kConverterExtension.isNewJ2k,
+ ExperimentalFeatures.NewJ2k.isEnabled,
conversionTime,
linesCount,
javaFiles.size
@@ -232,7 +233,7 @@ class JavaToKotlinAction : AnAction() {
.showInCenterOf(statusBar.component)
}
- if (!J2kConverterExtension.extension().doCheckBeforeConversion(project, module)) return
+ if (!J2kConverterExtension.extension(useNewJ2k = ExperimentalFeatures.NewJ2k.isEnabled).doCheckBeforeConversion(project, module)) return
val firstSyntaxError = javaFiles.asSequence().map { PsiTreeUtil.findChildOfType(it, PsiErrorElement::class.java) }.firstOrNull()
diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/ExperimentalFeatures.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/ExperimentalFeatures.kt
new file mode 100644
index 00000000000..09414de39d4
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/configuration/ExperimentalFeatures.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010-2020 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.configuration
+
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.ui.components.JBCheckBox
+import org.jdesktop.swingx.VerticalLayout
+import org.jetbrains.kotlin.config.KotlinCompilerVersion
+import org.jetbrains.kotlin.idea.PlatformVersion
+import org.jetbrains.kotlin.idea.projectWizard.WizardStatsService
+import org.jetbrains.kotlin.idea.util.isDev
+import org.jetbrains.kotlin.idea.util.isEap
+import org.jetbrains.kotlin.idea.util.isSnapshot
+import javax.swing.JCheckBox
+import javax.swing.JPanel
+
+object ExperimentalFeatures {
+ val NewJ2k = ExperimentalFeature(
+ title = "New Java to Kotlin Converter",
+ registryKey = "kotlin.experimental.new.j2k",
+ enabledByDefault = true
+ )
+
+ val NewWizard = ExperimentalFeature(
+ title = "New Experimental Project Wizard",
+ registryKey = "kotlin.experimental.project.wizard",
+ enabledByDefault = false,
+ shouldBeShown = {
+ val platformVersion = PlatformVersion.getCurrent() ?: return@ExperimentalFeature true
+ platformVersion.platform != PlatformVersion.Platform.ANDROID_STUDIO
+ },
+ onFeatureStatusChanged = { enabled ->
+ WizardStatsService.logWizardStatusChanged(isEnabled = enabled)
+ }
+ )
+
+ val allFeatures: List = listOf(
+ NewJ2k,
+ NewWizard
+ )
+}
+
+class ExperimentalFeature(
+ val title: String,
+ private val registryKey: String,
+ private val enabledByDefault: Boolean,
+ val shouldBeShown: () -> Boolean = { true },
+ val onFeatureStatusChanged: (enabled: Boolean) -> Unit = {}
+) {
+ var isEnabled
+ get() = Registry.`is`(registryKey, enabledByDefault)
+ set(value) {
+ Registry.get(registryKey).setValue(value)
+ }
+}
+
+class ExperimentalFeaturesPanel : JPanel(VerticalLayout(5)) {
+ private val featuresWithCheckboxes = ExperimentalFeatures.allFeatures.map { feature ->
+ FeatureWithCheckbox(
+ feature,
+ JBCheckBox(feature.title, feature.isEnabled)
+ )
+ }
+
+ init {
+ featuresWithCheckboxes.forEach { (feature, checkBox) ->
+ if (feature.shouldBeShown()) {
+ add(checkBox)
+ }
+ }
+ }
+
+ private data class FeatureWithCheckbox(
+ val feature: ExperimentalFeature,
+ val checkbox: JCheckBox
+ )
+
+ fun isModified() = featuresWithCheckboxes.any { (feature, checkBox) ->
+ feature.isEnabled != checkBox.isSelected
+ }
+
+ fun applySelectedChanges() {
+ featuresWithCheckboxes.forEach { (feature, checkBox) ->
+ if (feature.isEnabled != checkBox.isSelected) {
+ feature.isEnabled = checkBox.isSelected
+ feature.onFeatureStatusChanged(checkBox.isSelected)
+ }
+ }
+ }
+
+ companion object {
+ fun shouldBeShown(): Boolean {
+ val version = KotlinCompilerVersion.VERSION
+ return isEap(version) || isDev(version) || isSnapshot(version)
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinLanguageConfiguration.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinLanguageConfiguration.kt
index 7bb78bf2e69..f0d315adb08 100644
--- a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinLanguageConfiguration.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinLanguageConfiguration.kt
@@ -13,8 +13,6 @@ import org.jetbrains.kotlin.idea.KotlinPluginUpdater
import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.PluginUpdateStatus
import org.jetbrains.kotlin.idea.configuration.ui.KotlinLanguageConfigurationForm
-import org.jetbrains.kotlin.idea.projectWizard.NewProjectWizardService
-import org.jetbrains.kotlin.j2k.J2kConverterExtension
import javax.swing.JComponent
class KotlinLanguageConfiguration : SearchableConfigurable, Configurable.NoScroll {
@@ -65,14 +63,12 @@ class KotlinLanguageConfiguration : SearchableConfigurable, Configurable.NoScrol
override fun getDisplayName(): String = "Kotlin"
override fun isModified() =
- form.useNewJ2kCheckBox.isSelected != J2kConverterExtension.isNewJ2k
- || form.useNewProjectWizardCheckBox.isSelected != NewProjectWizardService.isEnabled
+ form.experimentalFeaturesPanel.isModified()
override fun apply() {
// Selected channel is now saved automatically
- J2kConverterExtension.isNewJ2k = form.useNewJ2kCheckBox.isSelected
- NewProjectWizardService.isEnabled = form.useNewProjectWizardCheckBox.isSelected
+ form.experimentalFeaturesPanel.applySelectedChanges()
}
private fun setInstalledVersion(installedVersion: String?, installingStatus: String?) {
@@ -81,8 +77,6 @@ class KotlinLanguageConfiguration : SearchableConfigurable, Configurable.NoScrol
}
override fun createComponent(): JComponent? {
- form.useNewJ2kCheckBox.isSelected = J2kConverterExtension.isNewJ2k
- form.useNewProjectWizardCheckBox.isSelected = NewProjectWizardService.isEnabled
form.updateCheckProgressIcon.suspend()
form.updateCheckProgressIcon.setPaintPassiveIcon(false)
diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/ui/KotlinLanguageConfigurationForm.form b/idea/src/org/jetbrains/kotlin/idea/configuration/ui/KotlinLanguageConfigurationForm.form
index 71e522348cb..7717588c78c 100644
--- a/idea/src/org/jetbrains/kotlin/idea/configuration/ui/KotlinLanguageConfigurationForm.form
+++ b/idea/src/org/jetbrains/kotlin/idea/configuration/ui/KotlinLanguageConfigurationForm.form
@@ -150,7 +150,7 @@
-
+
@@ -161,22 +161,17 @@
-
+
-
+
-
-
-
+
-
+
-
+
-
-
-
-
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/ui/KotlinLanguageConfigurationForm.java b/idea/src/org/jetbrains/kotlin/idea/configuration/ui/KotlinLanguageConfigurationForm.java
index c8ac3a6eb2f..8a034bd3f82 100644
--- a/idea/src/org/jetbrains/kotlin/idea/configuration/ui/KotlinLanguageConfigurationForm.java
+++ b/idea/src/org/jetbrains/kotlin/idea/configuration/ui/KotlinLanguageConfigurationForm.java
@@ -10,6 +10,7 @@ import com.intellij.openapi.util.registry.Registry;
import com.intellij.util.ui.AsyncProcessIcon;
import org.jetbrains.kotlin.idea.KotlinPluginUtil;
import org.jetbrains.kotlin.idea.PlatformVersion;
+import org.jetbrains.kotlin.idea.configuration.ExperimentalFeaturesPanel;
import org.jetbrains.kotlin.idea.util.VersioningKt;
import javax.swing.*;
@@ -28,14 +29,12 @@ public class KotlinLanguageConfigurationForm {
private JTextPane currentVersion;
private JPanel bundledCompilerVersionPanel;
private JTextPane compilerVersion;
- public JCheckBox useNewJ2kCheckBox;
- public JCheckBox useNewProjectWizardCheckBox;
+ public ExperimentalFeaturesPanel experimentalFeaturesPanel;
+ private JPanel experimentalFeaturesPanelContainer;
public KotlinLanguageConfigurationForm() {
showVerifierDisabledStatus();
-
- useNewProjectWizardCheckBox.setVisible(!isAndroidStudio());
-
+ experimentalFeaturesPanelContainer.setVisible(ExperimentalFeaturesPanel.Companion.shouldBeShown());
String pluginVersion = KotlinPluginUtil.getPluginVersion();
if (KotlinPluginUtil.isPatched()) {
diff --git a/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPasteProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPasteProcessor.kt
index 4e53207495c..4173aa63c2e 100644
--- a/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPasteProcessor.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/conversion/copy/ConvertJavaCopyPasteProcessor.kt
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.idea.actions.JavaToKotlinAction
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.codeInsight.KotlinCopyPasteReferenceProcessor
import org.jetbrains.kotlin.idea.codeInsight.KotlinReferenceData
+import org.jetbrains.kotlin.idea.configuration.ExperimentalFeatures
import org.jetbrains.kotlin.idea.core.util.range
import org.jetbrains.kotlin.idea.core.util.start
import org.jetbrains.kotlin.idea.editor.KotlinEditorOptions
@@ -190,7 +191,7 @@ class ConvertJavaCopyPasteProcessor : CopyPastePostProcessor("org.jetbrains.kotlin.j2kConverterExtension")
- fun extension(useNewJ2k: Boolean = isNewJ2k): J2kConverterExtension =
+ fun extension(useNewJ2k: Boolean): J2kConverterExtension =
EP_NAME.extensions.first { it.isNewJ2k == useNewJ2k }
}
}