IDEA-173109 Typing settings repository URL triggers path alert

This commit is contained in:
Vladimir Krivosheev
2017-08-08 12:39:15 +02:00
parent e2eabfc490
commit 76262309fa
7 changed files with 46 additions and 56 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -62,5 +62,6 @@ fun showJetBrainsAccountDialog(parent: Component, project: Project? = null): Dia
if (!userName.isNullOrBlank()) {
PasswordSafe.getInstance().set(CredentialAttributes(ErrorReportConfigurable.SERVICE_NAME, userName), Credentials(userName, if (rememberCheckBox.isSelected) passwordField.password else null))
}
return@dialog true
}
}
@@ -141,7 +141,7 @@ fun dialog(title: String,
parent: Component? = null,
errorText: String? = null,
modality: IdeModalityType = IdeModalityType.IDE,
ok: (() -> Unit)? = null): DialogWrapper {
ok: (() -> Boolean)? = null): DialogWrapper {
return object: DialogWrapper(project, parent, true, modality) {
init {
setTitle(title)
@@ -161,12 +161,9 @@ fun dialog(title: String,
override fun getPreferredFocusedComponent() = focusedComponent
override fun doOKAction() {
ok?.let {
if (okAction.isEnabled) {
it()
}
if (okAction.isEnabled && (ok == null || ok())) {
super.doOKAction()
}
super.doOKAction()
}
}
}
@@ -16,7 +16,7 @@ action.CommitToIcs.text=Commit to Settings Repository
init.dialog.message=There is no Settings Repository in the {0}, would you like to create a new one in this location?
init.dialog.title=Create Settings Repository
specify.absolute.path.dialog.message=Please specify absolute path
specify.absolute.path.dialog.message=Path is not absolute
init.failed.title=Cannot Init Repository
init.failed.message=Failed to init repository: {0}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,16 +20,18 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.TextBrowseFolderListener;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.DocumentAdapter;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
/**
* We do not use DialogWrapper validation because UI is awful (located below the field with the same font).
* To fix https://youtrack.jetbrains.com/issue/IDEA-173109 "Typing settings repository URL triggers path alert",
* we simply do validation on button action (and never disable button).
*/
public class IcsSettingsPanel extends DialogWrapper {
private JPanel panel;
private TextFieldWithBrowseButton urlTextField;
@@ -49,15 +51,6 @@ public class IcsSettingsPanel extends DialogWrapper {
}
});
urlTextField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent e) {
UpstreamEditorKt.updateSyncButtonState(StringUtil.nullize(urlTextField.getText()), syncActions);
}
});
UpstreamEditorKt.updateSyncButtonState(StringUtil.nullize(urlTextField.getText()), syncActions);
setTitle(IcsBundleKt.icsMessage("settings.panel.title"));
setResizable(false);
init();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import java.nio.file.Path
import java.nio.file.Paths
interface RepositoryService {
fun checkUrl(uriString: String, suggestToCreate: Boolean, project: Project? = null): Boolean {
fun checkUrl(uriString: String, project: Project? = null): Boolean {
val uri = URIish(uriString)
val isFile: Boolean
if (uri.scheme == URLUtil.FILE_PROTOCOL) {
@@ -50,8 +50,7 @@ interface RepositoryService {
val file = Paths.get(if (url.endsWith(suffix)) url.substring(0, url.length - suffix.length) else url)
if (file.exists()) {
if (!file.isDirectory()) {
//noinspection DialogTitleCapitalization
Messages.showErrorDialog(project, "Specified path is not a directory", "Specified Path is Invalid")
Messages.showErrorDialog(project, "Path is not a directory", "")
return false
}
else if (isValidRepository(file)) {
@@ -68,13 +67,13 @@ interface RepositoryService {
.yesText("Create")
.project(project)
.isYes) {
try {
return try {
createBareRepository(file)
return true
true
}
catch (e: IOException) {
Messages.showErrorDialog(project, icsMessage("init.failed.message", e.message), icsMessage("init.failed.title"))
return false
false
}
}
else {
@@ -20,23 +20,21 @@ import com.intellij.openapi.diagnostic.runAndLogException
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
import com.intellij.openapi.options.ConfigurableUi
import com.intellij.openapi.progress.runModalTask
import com.intellij.openapi.ui.DialogBuilder
import com.intellij.openapi.ui.TextBrowseFolderListener
import com.intellij.openapi.ui.TextFieldWithBrowseButton
import com.intellij.ui.DocumentAdapter
import com.intellij.ui.components.dialog
import com.intellij.ui.layout.*
import com.intellij.util.Function
import com.intellij.util.containers.ContainerUtil
import com.intellij.util.io.delete
import com.intellij.util.io.exists
import com.intellij.util.text.nullize
import com.intellij.util.text.trimMiddle
import com.intellij.util.ui.FormBuilder
import com.intellij.util.ui.table.TableModelEditor
import gnu.trove.THashSet
import org.jetbrains.settingsRepository.git.asProgressMonitor
import org.jetbrains.settingsRepository.git.cloneBare
import javax.swing.JTextField
import javax.swing.event.DocumentEvent
private val COLUMNS = arrayOf(object : TableModelEditor.EditableColumnInfo<ReadonlySource, Boolean>() {
override fun getColumnClass() = Boolean::class.java
@@ -62,19 +60,25 @@ internal fun createReadOnlySourcesEditor(): ConfigurableUi<IcsSettings> {
override fun getItemClass() = ReadonlySource::class.java
override fun edit(item: ReadonlySource, mutator: Function<ReadonlySource, ReadonlySource>, isAdd: Boolean) {
val dialogBuilder = DialogBuilder()
val urlField = TextFieldWithBrowseButton(JTextField(20))
urlField.addBrowseFolderListener(TextBrowseFolderListener(FileChooserDescriptorFactory.createSingleFolderDescriptor()))
urlField.textField.document.addDocumentListener(object : DocumentAdapter() {
override fun textChanged(event: DocumentEvent) {
dialogBuilder.setOkActionEnabled(checkUrl(urlField.text.nullize()))
}
})
dialogBuilder.title("Add read-only source").resizable(false).centerPanel(FormBuilder.createFormBuilder().addLabeledComponent("URL:", urlField).panel).setPreferredFocusComponent(urlField)
if (dialogBuilder.showAndGet()) {
mutator.`fun`(item).url = urlField.text
val panel = panel {
row("URL:") {
urlField()
}
}
dialog(title = "Add read-only source", panel = panel, focusedComponent = urlField) {
val url = urlField.text.nullize(true)
if (!validateUrl(url, null)) {
return@dialog false
}
mutator.`fun`(item).url = url
return@dialog true
}
.show()
}
override fun applyEdited(oldItem: ReadonlySource, newItem: ReadonlySource) {
@@ -23,7 +23,6 @@ import com.intellij.openapi.ui.Messages
import com.intellij.openapi.ui.TextFieldWithBrowseButton
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.text.StringUtil
import com.intellij.util.ArrayUtil
import com.intellij.util.text.nullize
import org.jetbrains.settingsRepository.actions.NOTIFICATION_GROUP
import java.awt.Container
@@ -31,26 +30,23 @@ import java.awt.event.ActionEvent
import javax.swing.AbstractAction
import javax.swing.Action
internal fun checkUrl(url: String?): Boolean {
try {
return url != null && url.length > 1 && icsManager.repositoryService.checkUrl(url, false)
}
catch (e: Throwable) {
fun validateUrl(url: String?, project: Project?): Boolean {
if (url == null) {
Messages.showErrorDialog(project, "URL is empty", "")
return false
}
}
fun updateSyncButtonState(url: String?, syncActions: Array<Action>) {
val enabled = checkUrl(url)
for (syncAction in syncActions) {
syncAction.isEnabled = enabled
if (!icsManager.repositoryService.checkUrl(url, project)) {
return false
}
return true
}
fun createMergeActions(project: Project?, urlTextField: TextFieldWithBrowseButton, dialogParent: Container, okAction: (() -> Unit)): Array<Action> {
var syncTypes = SyncType.values()
if (SystemInfo.isMac) {
syncTypes = ArrayUtil.reverseArray(syncTypes)
syncTypes = syncTypes.reversedArray()
}
val icsManager = icsManager
@@ -59,8 +55,8 @@ fun createMergeActions(project: Project?, urlTextField: TextFieldWithBrowseButto
val syncType = syncTypes[it]
object : AbstractAction(icsMessage("action.${if (syncType == SyncType.MERGE) "Merge" else (if (syncType == SyncType.OVERWRITE_LOCAL) "ResetToTheirs" else "ResetToMy")}Settings.text")) {
private fun saveRemoteRepositoryUrl(): Boolean {
val url = urlTextField.text.nullize()
if (url != null && !icsManager.repositoryService.checkUrl(url, true, project)) {
val url = urlTextField.text.nullize(true)
if (!validateUrl(url, project)) {
return false
}
@@ -71,7 +67,7 @@ fun createMergeActions(project: Project?, urlTextField: TextFieldWithBrowseButto
}
override fun actionPerformed(event: ActionEvent) {
ActionsCollector.getInstance().record("Ics." + getValue(Action.NAME))
ActionsCollector.getInstance().record("Ics.${getValue(Action.NAME)}")
val repositoryWillBeCreated = !icsManager.repositoryManager.isRepositoryExists()
var upstreamSet = false
try {