refactoring [ui]: Convert ConfigurableBuilder to Kotlin

GitOrigin-RevId: 47b6959b49555320f3a70cb7badd8d9be1fe6d15
This commit is contained in:
Pavel Porvatov
2025-11-19 21:10:18 +00:00
committed by intellij-monorepo-bot
parent fcc319656f
commit da6aae5f67
2 changed files with 83 additions and 136 deletions
@@ -1,149 +1,113 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.options;
package com.intellij.openapi.options
import com.intellij.ide.ui.search.BooleanOptionDescription;
import com.intellij.ide.ui.search.OptionDescription;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.util.Setter;
import com.intellij.ui.dsl.builder.Panel;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import com.intellij.ide.ui.search.BooleanOptionDescription
import com.intellij.ide.ui.search.OptionDescription
import com.intellij.openapi.util.Comparing
import com.intellij.openapi.util.Getter
import com.intellij.openapi.util.NlsContexts
import com.intellij.openapi.util.Setter
import com.intellij.ui.dsl.builder.Panel
import com.intellij.util.ui.UIUtil
import org.jetbrains.annotations.ApiStatus
import java.util.function.Function
import java.util.function.Supplier
import javax.swing.JCheckBox
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
@Deprecated("Use identical {@link BeanConfigurable} for replacement")
abstract class ConfigurableBuilder protected constructor() : UiDslUnnamedConfigurable.Simple(), UiDslUnnamedConfigurable, ConfigurableWithOptionDescriptors {
/**
* @deprecated Use identical {@link BeanConfigurable} for replacement
*/
@Deprecated(forRemoval = true)
public abstract class ConfigurableBuilder extends UiDslUnnamedConfigurable.Simple
implements UiDslUnnamedConfigurable, ConfigurableWithOptionDescriptors {
@ApiStatus.Internal
internal class CallbackAccessor(private val myGetter: Supplier<Boolean>, private val mySetter: Setter<in Boolean?>) {
private static final class CallbackAccessor {
private final @NotNull Supplier<Boolean> myGetter;
private final @NotNull Setter<? super Boolean> mySetter;
private CallbackAccessor(@NotNull Supplier<Boolean> getter, @NotNull Setter<? super Boolean> setter) {
myGetter = getter;
mySetter = setter;
}
public Boolean getValue() {
return myGetter.get();
}
public void setValue(@NotNull Boolean value) {
mySetter.set(value);
}
var value: Boolean
get() = myGetter.get()
set(value) = mySetter.set(value)
}
@ApiStatus.Internal
static class BeanField {
internal class BeanField(
private val myAccessor: CallbackAccessor,
internal val title: @NlsContexts.Checkbox String,
) {
private final @NotNull CallbackAccessor myAccessor;
private final @NotNull @NlsContexts.Checkbox String myTitle;
private @Nullable JCheckBox myComponent;
val component: JCheckBox by lazy { JCheckBox(this.title) }
private BeanField(@NotNull CallbackAccessor accessor, @NotNull @NlsContexts.Checkbox String title) {
myAccessor = accessor;
myTitle = title;
fun isModified(): Boolean {
val componentValue = this.componentValue
val beanValue = myAccessor.value
return !Comparing.equal<Any?>(componentValue, beanValue)
}
@NotNull
JCheckBox getComponent() {
if (myComponent == null) {
myComponent = createComponent();
fun apply() {
myAccessor.value = this.componentValue
}
fun reset() {
this.componentValue = myAccessor.value
}
private var componentValue: Boolean
get() = component.isSelected
set(value) = component.setSelected(value)
internal var accessorValue: Boolean
get() = myAccessor.value
set(value) {
myAccessor.value = value
}
return myComponent;
}
private @NotNull JCheckBox createComponent() {
return new JCheckBox(myTitle);
}
boolean isModified() {
final Object componentValue = getComponentValue();
final Object beanValue = myAccessor.getValue();
return !Comparing.equal(componentValue, beanValue);
}
void apply() {
myAccessor.setValue(getComponentValue());
}
void reset() {
setComponentValue(myAccessor.getValue());
}
private Boolean getComponentValue() {
return getComponent().isSelected();
}
private void setComponentValue(@NotNull Boolean value) {
getComponent().setSelected(value);
}
private @NotNull String getTitle() {
return myTitle;
}
private void setAccessorValue(boolean value) {
myAccessor.setValue(value);
}
private boolean getAccessorValue() {
return myAccessor.getValue();
}
}
private final List<BeanField> myFields = new ArrayList<>();
protected ConfigurableBuilder() {
}
private val myFields = mutableListOf<BeanField>()
/**
* Adds check box with given {@code title}.
* Initial checkbox value is obtained from {@code getter}.
* After the apply, the value from the check box is written back to model via {@code setter}.
* Adds check box with given `title`.
* Initial checkbox value is obtained from `getter`.
* After the apply, the value from the check box is written back to model via `setter`.
*/
protected void checkBox(@NotNull @NlsContexts.Checkbox String title, @NotNull Getter<@NotNull Boolean> getter, @NotNull Setter<? super Boolean> setter) {
myFields.add(new BeanField(new CallbackAccessor(getter, setter), title));
protected open fun checkBox(@NlsContexts.Checkbox title: @NlsContexts.Checkbox String, getter: Getter<Boolean>, setter: Setter<in Boolean?>) {
myFields.add(BeanField(CallbackAccessor(getter, setter), title))
}
@Override
public @Unmodifiable @NotNull List<OptionDescription> getOptionDescriptors(@NotNull String configurableId,
@NotNull Function<? super String, @NlsContexts.Command String> nameConverter) {
return ContainerUtil.map(myFields, box -> new BooleanOptionDescription(nameConverter.apply(box.getTitle()), configurableId) {
@Override
public boolean isOptionEnabled() {
return box.getAccessorValue();
}
override fun getOptionDescriptors(
configurableId: String,
nameConverter: Function<in String?, String?>,
): List<OptionDescription> {
return myFields.map { box ->
object : BooleanOptionDescription(nameConverter.apply(box.title), configurableId) {
override fun isOptionEnabled(): Boolean {
return box.accessorValue
}
@Override
public void setOptionState(boolean enabled) {
box.setAccessorValue(enabled);
override fun setOptionState(enabled: Boolean) {
box.accessorValue = enabled
}
}
});
}
}
@Override
public void createContent(@NotNull Panel builder) {
ConfigurableBuilderHelper.buildFieldsPanel(builder, myFields);
override fun Panel.createContent() {
for (field in myFields) {
row {
cell(field.component)
.onApply { field.apply() }
.onIsModified { field.isModified() }
.onReset { field.reset() }
UIUtil.applyDeprecatedBackground(field.component)
}
}
}
@ApiStatus.Internal
public static @Nullable String getConfigurableTitle(@NotNull UnnamedConfigurable configurable) {
if (configurable instanceof BeanConfigurable<?>) {
return ((BeanConfigurable<?>)configurable).getTitle();
companion object {
@ApiStatus.Internal
@JvmStatic
fun getConfigurableTitle(configurable: UnnamedConfigurable): String? {
if (configurable is BeanConfigurable<*>) {
return configurable.title
}
return null
}
return null;
}
}
@@ -4,29 +4,12 @@ package com.intellij.openapi.options
import com.intellij.openapi.ui.DialogPanel
import com.intellij.ui.dsl.builder.Panel
import com.intellij.ui.dsl.builder.panel
import com.intellij.util.ui.UIUtil
import org.jetbrains.annotations.ApiStatus
import javax.swing.JComponent
@ApiStatus.Internal
class ConfigurableBuilderHelper {
companion object {
@JvmStatic
@ApiStatus.ScheduledForRemoval
@ApiStatus.Internal
@Deprecated("Will be removed")
@JvmName("buildFieldsPanel")
internal fun Panel.buildFieldsPanel(fields: List<ConfigurableBuilder.BeanField>) {
for (field in fields) {
row {
cell(field.component)
.onApply { field.apply() }
.onIsModified { field.isModified }
.onReset { field.reset() }
UIUtil.applyDeprecatedBackground(field.component)
}
}
}
@JvmStatic
@ApiStatus.Internal