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).
This commit is contained in:
Ilya.Kazakevich
2018-10-02 18:11:30 +03:00
parent 34897cb119
commit 38646a75c4
3 changed files with 45 additions and 3 deletions
@@ -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<PathMappingSettings.PathMapping>? = 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
@@ -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
*/
@@ -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<PathMappingSettings.PathMapping>? = null
/**
* Synchronizes project.