From 38646a75c4a0910c13e3ccdeda6ae46af98352fb Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Tue, 25 Sep 2018 01:14:44 +0300 Subject: [PATCH] PY-31904: "Remote path" for Vagrant is calculated automatically One can't change remote path for Vagrant in PyCharm, so PyProjectSynchronizer now has API to report "default mappings". Once reported, PyAddExistingSdkPanel uses them to update remote path field (which is switched to the readonly mode in this case). --- .../newProject/steps/PyAddExistingSdkPanel.kt | 31 ++++++++++++++++++- .../newProject/steps/PyRemotePathField.java | 5 +++ .../python/remote/PyProjectSynchronizer.kt | 12 +++++-- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/python/python-community-configure/src/com/jetbrains/python/newProject/steps/PyAddExistingSdkPanel.kt b/python/python-community-configure/src/com/jetbrains/python/newProject/steps/PyAddExistingSdkPanel.kt index 3c7029e6085a..5ff1d99b68ac 100644 --- a/python/python-community-configure/src/com/jetbrains/python/newProject/steps/PyAddExistingSdkPanel.kt +++ b/python/python-community-configure/src/com/jetbrains/python/newProject/steps/PyAddExistingSdkPanel.kt @@ -13,6 +13,7 @@ import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.component1 import com.intellij.openapi.util.component2 import com.intellij.openapi.util.text.StringUtil +import com.intellij.util.PathMappingSettings import com.intellij.util.ui.FormBuilder import com.intellij.util.ui.UIUtil import com.jetbrains.python.remote.PyProjectSynchronizer @@ -34,6 +35,12 @@ class PyAddExistingSdkPanel(project: Project?, override val panelName: String = "Existing interpreter" + /** + * Path mappings of current synchronizer. + * Once set, [remotePathField] will be updated on any change of local path passed through mappings + */ + private var defaultMappings: List? = null + override val sdk: Sdk? get() = sdkChooserCombo.comboBox.selectedItem as? Sdk @@ -44,6 +51,7 @@ class PyAddExistingSdkPanel(project: Project?, set(value) { field = value sdkChooserCombo.setNewProjectPath(value) + updateRemotePathIfNeeded() } private val sdkChooserCombo: PythonSdkChooserCombo @@ -101,16 +109,34 @@ class PyAddExistingSdkPanel(project: Project?, } } + private fun update() { val synchronizer = sdk?.projectSynchronizer remotePathField.mainPanel.isVisible = synchronizer != null if (synchronizer != null) { val defaultRemotePath = synchronizer.getDefaultRemotePath() + defaultMappings = synchronizer.getAutoMappings() + assert(defaultRemotePath == null || defaultMappings == null) { "Can't have both: default mappings and default value" } + assert(!(defaultRemotePath?.isEmpty() ?: false)) { "Mappings are empty" } + val textField = remotePathField.textField if (defaultRemotePath != null && StringUtil.isEmpty(textField.text)) { textField.text = defaultRemotePath } } + // DefaultMappings revokes user ability to change mapping by her self, so field is readonly + remotePathField.setReadOnly(defaultMappings != null) + updateRemotePathIfNeeded() + } + + /** + * Remote path should be updated automatically if [defaultMappings] are set. + * See [PyProjectSynchronizer.getAutoMappings]. + */ + private fun updateRemotePathIfNeeded() { + val path = newProjectPath ?: return + val mappings = defaultMappings ?: return + remotePathField.textField.text = mappings.find { it.canReplaceLocal(path) }?.mapToRemote(path) ?: "?" } companion object { @@ -136,7 +162,10 @@ class PyAddExistingSdkPanel(project: Project?, } panel.isVisible = true val wrapper = object : DialogWrapper(true) { - init { init() } + init { + init() + } + override fun createCenterPanel() = panel } return if (wrapper.showAndGet()) supplier.get() else null diff --git a/python/python-community-configure/src/com/jetbrains/python/newProject/steps/PyRemotePathField.java b/python/python-community-configure/src/com/jetbrains/python/newProject/steps/PyRemotePathField.java index 2049a668e471..8cda007de4f1 100644 --- a/python/python-community-configure/src/com/jetbrains/python/newProject/steps/PyRemotePathField.java +++ b/python/python-community-configure/src/com/jetbrains/python/newProject/steps/PyRemotePathField.java @@ -38,6 +38,11 @@ public final class PyRemotePathField { return myMainPanel; } + void setReadOnly(final boolean readOnly) { + myLocationField.setEditable(! readOnly); + myLocationField.getButton().setVisible(! readOnly); + } + /** * Add listener for "browse" button */ diff --git a/python/src/com/jetbrains/python/remote/PyProjectSynchronizer.kt b/python/src/com/jetbrains/python/remote/PyProjectSynchronizer.kt index 35c93bdd4f68..1d636a645b07 100644 --- a/python/src/com/jetbrains/python/remote/PyProjectSynchronizer.kt +++ b/python/src/com/jetbrains/python/remote/PyProjectSynchronizer.kt @@ -17,6 +17,7 @@ package com.jetbrains.python.remote import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project +import com.intellij.util.PathMappingSettings import java.io.File import java.util.function.Consumer @@ -48,12 +49,19 @@ interface PyProjectSynchronizer { fun checkSynchronizationAvailable(syncCheckStrategy: PySyncCheckStrategy): String? /** - * @return if remote box allows user to configure remote path, this method returns default path + * if remote box allows user to configure remote path, this method returns default path * that should be shown to user. - * If returns null, user can't configure remote path and GUI should not provide such ability + * + * Must return null if [getAutoMappings] are not null. */ fun getDefaultRemotePath(): String? + /** + * If remote box does not allow user to configure path mapping then these mappings could be used to automatically convert + * local path to remote path. If set, can't be empty and can't coexist with [getDefaultRemotePath] + */ + fun getAutoMappings(): List? = null + /** * Synchronizes project.