diff --git a/plugins/svn4idea/resources/META-INF/plugin.xml b/plugins/svn4idea/resources/META-INF/plugin.xml
index 6f81edf8f561..9e0c2bc6707d 100644
--- a/plugins/svn4idea/resources/META-INF/plugin.xml
+++ b/plugins/svn4idea/resources/META-INF/plugin.xml
@@ -140,7 +140,7 @@
-
diff --git a/plugins/svn4idea/resources/messages/SvnBundle.properties b/plugins/svn4idea/resources/messages/SvnBundle.properties
index 74cb6bd7c244..97e07e1c3104 100644
--- a/plugins/svn4idea/resources/messages/SvnBundle.properties
+++ b/plugins/svn4idea/resources/messages/SvnBundle.properties
@@ -279,8 +279,8 @@ dialog.title.select.path.to.subversion.executable=Subversion
label.select.path.to.subversion.executable=Select path to Subversion executable (1.7+)
label.path.to.svn.executable=Path to Subversion executable:
command.line.interactive.mode.title=Enable interactive mode
-command.line.interactive.mode.description=Emulates the behavior when Subversion commands are executed directly from the terminal (in the interactive mode).
\
- This is required to handle password/passphrase prompts for svn+ssh repositories, and trust invalid server certificates for https repositories.
+command.line.interactive.mode.description=Emulates the behavior when Subversion commands are executed directly from the terminal (in the interactive mode).
\
+ This is required to handle password/passphrase prompts for svn+ssh repositories, and trust invalid server certificates for https repositories.
non.english.locale.detected.warning=A non-English locale is used.
ssh.settings.executable.label=SSH executable\:
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/GeneralSettingsPanel.form b/plugins/svn4idea/src/org/jetbrains/idea/svn/GeneralSettingsPanel.form
deleted file mode 100644
index 6ddaf9550eaf..000000000000
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/GeneralSettingsPanel.form
+++ /dev/null
@@ -1,128 +0,0 @@
-
-
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/GeneralSettingsPanel.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/GeneralSettingsPanel.java
deleted file mode 100644
index 337e9248ab28..000000000000
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/GeneralSettingsPanel.java
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
-package org.jetbrains.idea.svn;
-
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
-import com.intellij.openapi.options.ConfigurableUi;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.TextFieldWithBrowseButton;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
-import com.intellij.ui.components.JBCheckBox;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.idea.svn.auth.SvnAuthenticationNotifier;
-
-import javax.swing.*;
-import java.util.Objects;
-
-import static org.jetbrains.idea.svn.SvnBundle.message;
-import static org.jetbrains.idea.svn.SvnUtil.USER_CONFIGURATION_PATH;
-
-public class GeneralSettingsPanel implements ConfigurableUi, Disposable {
-
- private final @NotNull Project myProject;
-
- private JPanel myMainPanel;
-
- private JCheckBox myUseCustomConfigurationDirectory;
- private TextFieldWithBrowseButton myConfigurationDirectoryText;
- private JButton myClearAuthButton;
- private JBCheckBox myRunUnderTerminal;
- private TextFieldWithBrowseButton myCommandLineClient;
-
- public GeneralSettingsPanel(@NotNull Project project) {
- myProject = project;
-
- myUseCustomConfigurationDirectory.addActionListener(e -> {
- boolean enabled = myUseCustomConfigurationDirectory.isSelected();
- myConfigurationDirectoryText.setEnabled(enabled);
- myConfigurationDirectoryText.setEditable(enabled);
- SvnConfiguration configuration = SvnConfiguration.getInstance(myProject);
- String path = configuration.getConfigurationDirectory();
- if (!enabled || path == null) {
- myConfigurationDirectoryText.setText(USER_CONFIGURATION_PATH.getValue().toString());
- }
- else {
- myConfigurationDirectoryText.setText(path);
- }
- });
- myCommandLineClient.addBrowseFolderListener(project, FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor()
- .withTitle(message("dialog.title.select.path.to.subversion.executable"))
- .withDescription(message("label.select.path.to.subversion.executable")));
- myClearAuthButton.addActionListener(
- e -> SvnAuthenticationNotifier.clearAuthenticationCache(myProject, myMainPanel, myConfigurationDirectoryText.getText()));
- myConfigurationDirectoryText.addActionListener(e -> {
- @NonNls String path = myConfigurationDirectoryText.getText().trim();
- SvnConfigurable.selectConfigurationDirectory(path, s -> myConfigurationDirectoryText.setText(s), myProject, myMainPanel);
- });
- }
-
- @Override
- public @NotNull JComponent getComponent() {
- return myMainPanel;
- }
-
- @Override
- public void reset(@NotNull SvnConfiguration configuration) {
- String path = configuration.getConfigurationDirectory();
- if (configuration.isUseDefaultConfiguration() || path == null) {
- path = USER_CONFIGURATION_PATH.getValue().toString();
- }
- myConfigurationDirectoryText.setText(path);
- myUseCustomConfigurationDirectory.setSelected(!configuration.isUseDefaultConfiguration());
-
- boolean enabled = myUseCustomConfigurationDirectory.isSelected();
- myConfigurationDirectoryText.setEnabled(enabled);
- myConfigurationDirectoryText.setEditable(enabled);
-
- myRunUnderTerminal.setSelected(configuration.isRunUnderTerminal());
- final SvnApplicationSettings applicationSettings17 = SvnApplicationSettings.getInstance();
- myCommandLineClient.setText(applicationSettings17.getCommandLinePath());
- }
-
- @Override
- public boolean isModified(@NotNull SvnConfiguration configuration) {
- if (configuration.isUseDefaultConfiguration() == myUseCustomConfigurationDirectory.isSelected()) {
- return true;
- }
- if (configuration.isRunUnderTerminal() != myRunUnderTerminal.isSelected()) return true;
- final SvnApplicationSettings applicationSettings17 = SvnApplicationSettings.getInstance();
- if (!Objects.equals(applicationSettings17.getCommandLinePath(), myCommandLineClient.getText().trim())) return true;
- if (!configuration.getConfigurationDirectory().equals(myConfigurationDirectoryText.getText().trim())) return true;
-
- return false;
- }
-
- @Override
- public void apply(@NotNull SvnConfiguration configuration) {
- configuration.setConfigurationDirParameters(!myUseCustomConfigurationDirectory.isSelected(), myConfigurationDirectoryText.getText());
-
- final SvnVcs vcs17 = SvnVcs.getInstance(myProject);
-
- final SvnApplicationSettings applicationSettings17 = SvnApplicationSettings.getInstance();
- boolean reloadWorkingCopies = !StringUtil.equals(applicationSettings17.getCommandLinePath(), myCommandLineClient.getText().trim());
- configuration.setRunUnderTerminal(myRunUnderTerminal.isSelected());
-
- applicationSettings17.setCommandLinePath(myCommandLineClient.getText().trim());
- boolean isClientValid = vcs17.checkCommandLineVersion();
- if (!myProject.isDefault() && isClientValid && reloadWorkingCopies) {
- vcs17.invokeRefreshSvnRoots();
- VcsDirtyScopeManager.getInstance(myProject).markEverythingDirty();
- }
- }
-
- @Override
- public void dispose() {
- }
-
- private void createUIComponents() {
- myCommandLineClient = new TextFieldWithBrowseButton(null, this);
- myConfigurationDirectoryText = new TextFieldWithBrowseButton(null, this);
- }
-}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/GeneralSvnConfigurable.kt b/plugins/svn4idea/src/org/jetbrains/idea/svn/GeneralSvnConfigurable.kt
new file mode 100644
index 000000000000..e805fcec1706
--- /dev/null
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/GeneralSvnConfigurable.kt
@@ -0,0 +1,141 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package org.jetbrains.idea.svn
+
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
+import com.intellij.openapi.options.BoundSearchableConfigurable
+import com.intellij.openapi.options.Configurable.NoScroll
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.ui.DialogPanel
+import com.intellij.openapi.ui.TextFieldWithBrowseButton
+import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager
+import com.intellij.ui.components.JBCheckBox
+import com.intellij.ui.dsl.builder.AlignX
+import com.intellij.ui.dsl.builder.RightGap
+import com.intellij.ui.dsl.builder.bindSelected
+import com.intellij.ui.dsl.builder.panel
+import com.intellij.ui.layout.selected
+import com.intellij.util.Consumer
+import org.jetbrains.annotations.NonNls
+import org.jetbrains.idea.svn.auth.SvnAuthenticationNotifier
+
+internal class GeneralSvnConfigurable(private val project: Project) : BoundSearchableConfigurable(
+ SvnConfigurable.getGroupDisplayName(),
+ SvnConfigurable.HELP_ID,
+ SvnConfigurable.ID
+), NoScroll, Disposable {
+
+ private val commandLineClient = TextFieldWithBrowseButton(null, this)
+ private val configurationDirectoryText = TextFieldWithBrowseButton(null, this)
+ private lateinit var useCustomConfigurationDirectory: JBCheckBox
+
+ init {
+ commandLineClient.addBrowseFolderListener(project, FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor()
+ .withTitle(SvnBundle.message("dialog.title.select.path.to.subversion.executable"))
+ .withDescription(SvnBundle.message("label.select.path.to.subversion.executable")))
+ }
+
+ override fun createPanel(): DialogPanel {
+ val settings = SvnConfiguration.getInstance(project)
+ lateinit var result: DialogPanel
+
+ result = panel {
+ row(SvnBundle.message("label.path.to.svn.executable")) {
+ val applicationSettings17 = SvnApplicationSettings.getInstance()
+ cell(commandLineClient)
+ .align(AlignX.FILL)
+ .onReset {
+ commandLineClient.setText(applicationSettings17.commandLinePath)
+ }.onApply {
+ applicationSettings17.commandLinePath = commandLineClient.getText().trim()
+ }.onIsModified {
+ applicationSettings17.commandLinePath != commandLineClient.getText().trim()
+ }
+ }
+
+ row {
+ checkBox(SvnBundle.message("command.line.interactive.mode.title"))
+ .comment(SvnBundle.message("command.line.interactive.mode.description"))
+ .bindSelected(settings::isRunUnderTerminal, settings::setRunUnderTerminal)
+ }
+
+ row {
+ useCustomConfigurationDirectory = checkBox(SvnBundle.message("settings.use.custom.directory"))
+ .onChanged {
+ val configuration = SvnConfiguration.getInstance(project)
+ val path = configuration.getConfigurationDirectory()
+ if (!useCustomConfigurationDirectory.isSelected || path == null) {
+ configurationDirectoryText.setText(SvnUtil.USER_CONFIGURATION_PATH.getValue().toString())
+ }
+ else {
+ configurationDirectoryText.setText(path)
+ }
+ }.gap(RightGap.SMALL)
+ .component
+
+ cell(configurationDirectoryText)
+ .align(AlignX.FILL)
+ .enabledIf(useCustomConfigurationDirectory.selected)
+ }
+
+ row {
+ label("")
+ }.resizableRow()
+
+ row {
+ button(SvnBundle.message("button.text.clear.authentication.cache")) {
+ SvnAuthenticationNotifier.clearAuthenticationCache(project, result, configurationDirectoryText.getText())
+ }.commentRight(SvnBundle.message("label.text.delete.stored.credentials"))
+ }
+ }
+
+ configurationDirectoryText.addActionListener { _ ->
+ @NonNls val path = configurationDirectoryText.getText().trim()
+ SvnConfigurable.selectConfigurationDirectory(path, Consumer { s: String? -> configurationDirectoryText.setText(s) }, project, result)
+ }
+
+ return result
+ }
+
+ override fun apply() {
+ val settings = SvnConfiguration.getInstance(project)
+ val applicationSettings17 = SvnApplicationSettings.getInstance()
+ val oldCommandLinePath = applicationSettings17.commandLinePath
+
+ super.apply()
+
+ settings.setConfigurationDirParameters(!useCustomConfigurationDirectory.isSelected, configurationDirectoryText.getText())
+
+ val vcs17 = SvnVcs.getInstance(project)
+ val isClientValid = vcs17.checkCommandLineVersion()
+ if (!project.isDefault && isClientValid && oldCommandLinePath != applicationSettings17.commandLinePath) {
+ vcs17.invokeRefreshSvnRoots()
+ VcsDirtyScopeManager.getInstance(project).markEverythingDirty()
+ }
+ }
+
+ override fun isModified(): Boolean {
+ val settings = SvnConfiguration.getInstance(project)
+ if (settings.isUseDefaultConfiguration == useCustomConfigurationDirectory.isSelected
+ || settings.getConfigurationDirectory() != configurationDirectoryText.getText().trim()) {
+ return true
+ }
+
+ return super.isModified()
+ }
+
+ override fun reset() {
+ super.reset()
+
+ val settings = SvnConfiguration.getInstance(project)
+ var path = settings.getConfigurationDirectory()
+ if (settings.isUseDefaultConfiguration || path == null) {
+ path = SvnUtil.USER_CONFIGURATION_PATH.getValue().toString()
+ }
+ configurationDirectoryText.setText(path)
+ useCustomConfigurationDirectory.setSelected(!settings.isUseDefaultConfiguration)
+ }
+
+ override fun dispose() {
+ }
+}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java
index df2605f67f0d..19cad7ae02ab 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java
@@ -62,12 +62,6 @@ public abstract class SvnConfigurable extends ConfigurableBase new GeneralSettingsPanel(project), HELP_ID);
- }
- }
-
public static class Ssh extends SvnConfigurable {
public Ssh(@NotNull Project project) {
super(project, "SSH", message("configurable.name.svn.ssh"), () -> new SshSettingsPanel(project));