diff --git a/platform/icons/src/vcs/clone.svg b/platform/icons/src/vcs/clone.svg
new file mode 100644
index 000000000000..285121cfa7f6
--- /dev/null
+++ b/platform/icons/src/vcs/clone.svg
@@ -0,0 +1,6 @@
+
diff --git a/platform/icons/src/vcs/clone_dark.svg b/platform/icons/src/vcs/clone_dark.svg
new file mode 100644
index 000000000000..592210d05523
--- /dev/null
+++ b/platform/icons/src/vcs/clone_dark.svg
@@ -0,0 +1,6 @@
+
diff --git a/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml b/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml
index feccdea73f5b..e4b7b61354f2 100644
--- a/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml
+++ b/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml
@@ -105,6 +105,8 @@
+
diff --git a/platform/platform-resources/src/META-INF/VcsExtensions.xml b/platform/platform-resources/src/META-INF/VcsExtensions.xml
index 3d284e904322..fa94a453efaa 100644
--- a/platform/platform-resources/src/META-INF/VcsExtensions.xml
+++ b/platform/platform-resources/src/META-INF/VcsExtensions.xml
@@ -140,6 +140,11 @@
+
+
diff --git a/platform/platform-resources/src/idea/VcsActions.xml b/platform/platform-resources/src/idea/VcsActions.xml
index 7ef52030259c..18c827e08899 100644
--- a/platform/platform-resources/src/idea/VcsActions.xml
+++ b/platform/platform-resources/src/idea/VcsActions.xml
@@ -346,6 +346,11 @@
icon="AllIcons.Welcome.FromVCS">
+
+
+
+
+ fun getOkButtonText(): String = "Clone"
+}
diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/ui/VcsCloneComponentStub.kt b/platform/vcs-api/src/com/intellij/openapi/vcs/ui/VcsCloneComponentStub.kt
new file mode 100644
index 000000000000..1fb0b99c13bc
--- /dev/null
+++ b/platform/vcs-api/src/com/intellij/openapi/vcs/ui/VcsCloneComponentStub.kt
@@ -0,0 +1,27 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.openapi.vcs.ui
+
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.ui.ValidationInfo
+import com.intellij.openapi.vcs.CheckoutProvider
+import java.awt.FlowLayout
+import javax.swing.JComponent
+import javax.swing.JLabel
+import javax.swing.JPanel
+
+class VcsCloneComponentStub(private val checkoutProvider: CheckoutProvider,
+ private val primaryActionText: String = "Clone") : VcsCloneComponent {
+ override fun getView(): JComponent {
+ val panel = JPanel(FlowLayout(FlowLayout.LEADING))
+ // todo: replace with better help text
+ // todo: or add additional button closer to vcs combo
+ panel.add(JLabel("Click \"$primaryActionText\" to continue"))
+ return panel
+ }
+
+ override fun doClone(project: Project, listener: CheckoutProvider.Listener) = checkoutProvider.doCheckout(project, listener)
+
+ override fun isOkEnabled() = true
+
+ override fun doValidateAll() = emptyList()
+}
\ No newline at end of file
diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/ui/cloneDialog/VcsCloneDialogExtension.kt b/platform/vcs-api/src/com/intellij/openapi/vcs/ui/cloneDialog/VcsCloneDialogExtension.kt
new file mode 100644
index 000000000000..617dc0ba4a17
--- /dev/null
+++ b/platform/vcs-api/src/com/intellij/openapi/vcs/ui/cloneDialog/VcsCloneDialogExtension.kt
@@ -0,0 +1,32 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.openapi.vcs.ui.cloneDialog
+
+import com.intellij.openapi.extensions.ExtensionPointName
+import com.intellij.openapi.project.Project
+import javax.swing.Icon
+
+/**
+ * Extension point that provide an ability to add integration with specific cloud repository hosting/service (e.g "GitHub", "BitBucket", etc)
+ */
+interface VcsCloneDialogExtension {
+ companion object {
+ val EP_NAME =
+ ExtensionPointName.create("com.intellij.openapi.vcs.ui.cloneDialog.VcsCloneDialogExtension")
+ }
+
+ /**
+ * Visible name of extension (e.g. "Repository URL", "GitHub", etc)
+ */
+ fun getName(): String
+
+ /**
+ * Visible icon of extension
+ */
+ fun getIcon(): Icon
+
+ /**
+ * Builds [VcsCloneDialogExtensionComponent] that would be displayed on center of get-from-vcs dialog when extension is selected.
+ * Will be called lazily and once on first choosing of extension.
+ */
+ fun createMainComponent(project: Project): VcsCloneDialogExtensionComponent
+}
\ No newline at end of file
diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/ui/cloneDialog/VcsCloneDialogExtensionComponent.kt b/platform/vcs-api/src/com/intellij/openapi/vcs/ui/cloneDialog/VcsCloneDialogExtensionComponent.kt
new file mode 100644
index 000000000000..305e7ab6e3fa
--- /dev/null
+++ b/platform/vcs-api/src/com/intellij/openapi/vcs/ui/cloneDialog/VcsCloneDialogExtensionComponent.kt
@@ -0,0 +1,48 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.openapi.vcs.ui.cloneDialog
+
+import com.intellij.openapi.ui.ValidationInfo
+import javax.swing.JComponent
+
+/**
+ * Main component for get-from-vcs extensions.
+ * It's responsible for:
+ * 1. Providing extension-specific UI for get-from-vcs dialog by [getView]
+ * 2. handling commands that would be provided from top-level [com.intellij.openapi.ui.DialogWrapper]
+ */
+interface VcsCloneDialogExtensionComponent {
+
+ /**
+ * Return main [JComponent] that will be displayed in center of get-from-vcs dialog when extension is selected.
+ *
+ * It is called once when extension is selected first time
+ */
+ fun getView(): JComponent
+
+ /**
+ * Checks that is possible to perform ok action in current state of component
+ *
+ * Would be called form [com.intellij.openapi.ui.DialogWrapper.isOKActionEnabled] when extension is selected
+ */
+ fun isOkEnabled(): Boolean
+
+ /**
+ * Perform primary clone/checkout action.
+ * would be called from [com.intellij.openapi.ui.DialogWrapper.doOKAction] when extension is selected
+ *
+ * @see com.intellij.openapi.ui.DialogWrapper.doOKAction
+ */
+ fun doOk()
+
+ /**
+ * would be called from [com.intellij.openapi.ui.DialogWrapper.doValidateAll] when extension is selected
+ *
+ * @see com.intellij.openapi.ui.DialogWrapper.doValidateAll
+ */
+ fun doValidateAll(): List
+
+ /**
+ * Text that represents dialog primary action
+ */
+ fun getOkButtonText(): String = "Clone"
+}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/GetFromVcsAction.java b/platform/vcs-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/GetFromVcsAction.java
index 99eebe2fd174..bd8a356bf8d9 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/GetFromVcsAction.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/GetFromVcsAction.java
@@ -3,12 +3,17 @@ package com.intellij.openapi.wm.impl.welcomeScreen;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vcs.CheckoutProvider;
import com.intellij.openapi.vcs.checkout.CheckoutActionGroup;
import com.intellij.ui.UIBundle;
import org.jetbrains.annotations.NotNull;
-public class GetFromVcsAction extends WelcomePopupAction{
+/**
+ * @deprecated superseded by {@link RunVcsCloneDialogAction}
+ */
+@Deprecated
+public class GetFromVcsAction extends WelcomePopupAction {
@Override
protected void fillActions(DefaultActionGroup group) {
@@ -32,6 +37,7 @@ public class GetFromVcsAction extends WelcomePopupAction{
@Override
public void update(@NotNull AnActionEvent e) {
+ e.getPresentation().setVisible(!Registry.is("vcs.use.new.clone.dialog"));
e.getPresentation().setEnabled(CheckoutProvider.EXTENSION_POINT_NAME.hasAnyExtensions());
}
}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RunVcsCloneDialogAction.kt b/platform/vcs-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RunVcsCloneDialogAction.kt
new file mode 100644
index 000000000000..526d6ce2e565
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RunVcsCloneDialogAction.kt
@@ -0,0 +1,25 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.openapi.wm.impl.welcomeScreen
+
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.actionSystem.CommonDataKeys
+import com.intellij.openapi.project.DumbAwareAction
+import com.intellij.openapi.project.ProjectManager
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.openapi.vcs.CheckoutProvider
+import com.intellij.util.ui.cloneDialog.VcsCloneDialog
+
+class RunVcsCloneDialogAction : DumbAwareAction("Get from Version Control") {
+
+ override fun update(e: AnActionEvent) {
+ e.presentation.isEnabled = CheckoutProvider.EXTENSION_POINT_NAME.hasAnyExtensions()
+ e.presentation.isVisible = Registry.`is`("vcs.use.new.clone.dialog")
+ }
+
+ override fun actionPerformed(e: AnActionEvent) {
+ val project = e.getData(CommonDataKeys.PROJECT) ?: ProjectManager.getInstance().defaultProject
+ VcsCloneDialog.Builder(project)
+ .forExtension()
+ .showAndGet()
+ }
+}
diff --git a/platform/vcs-impl/src/com/intellij/util/ui/cloneDialog/RepositoryUrlCloneDialogExtension.kt b/platform/vcs-impl/src/com/intellij/util/ui/cloneDialog/RepositoryUrlCloneDialogExtension.kt
new file mode 100644
index 000000000000..4a15fcc402d5
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/util/ui/cloneDialog/RepositoryUrlCloneDialogExtension.kt
@@ -0,0 +1,98 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.util.ui.cloneDialog
+
+import com.intellij.icons.AllIcons
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.ui.ComboBox
+import com.intellij.openapi.ui.ValidationInfo
+import com.intellij.openapi.vcs.CheckoutProvider
+import com.intellij.openapi.vcs.ProjectLevelVcsManager
+import com.intellij.openapi.vcs.ui.VcsCloneComponent
+import com.intellij.openapi.vcs.ui.cloneDialog.VcsCloneDialogExtension
+import com.intellij.openapi.vcs.ui.cloneDialog.VcsCloneDialogExtensionComponent
+import com.intellij.ui.SimpleListCellRenderer
+import com.intellij.ui.layout.*
+import com.intellij.util.ui.JBUI
+import com.intellij.util.ui.UIUtil
+import java.awt.BorderLayout
+import java.awt.CardLayout
+import java.awt.event.ItemEvent
+import java.util.*
+import javax.swing.Icon
+import javax.swing.JPanel
+
+class RepositoryUrlCloneDialogExtension : VcsCloneDialogExtension {
+ override fun getIcon(): Icon = AllIcons.Welcome.FromVCS
+
+ override fun getName() = "Repository URL"
+
+ override fun createMainComponent(project: Project): RepositoryUrlMainExtensionComponent {
+ return RepositoryUrlMainExtensionComponent(project)
+ }
+
+ class RepositoryUrlMainExtensionComponent(private val project: Project) : VcsCloneDialogExtensionComponent {
+ private val vcsComponents = HashMap()
+ private val cardLayout = CardLayout()
+ private val mainPanel = JPanel(BorderLayout())
+ private val comboBox: ComboBox = ComboBox().apply {
+ renderer = SimpleListCellRenderer.create("") { it.vcsName.removePrefix("_") }
+ }
+
+ init {
+ mainPanel.border = JBUI.Borders.emptyRight(UIUtil.DEFAULT_VGAP)
+ val northPanel = panel {
+ row("Version control:") { comboBox() }
+ }
+ mainPanel.add(northPanel, BorderLayout.NORTH)
+
+ val centerPanel = JPanel(cardLayout)
+ mainPanel.add(centerPanel, BorderLayout.CENTER)
+
+ comboBox.addItemListener { e: ItemEvent ->
+ if (e.stateChange == ItemEvent.SELECTED) {
+ val provider = e.item as CheckoutProvider
+ cardLayout.show(centerPanel, provider.vcsName)
+ }
+ }
+
+ for (checkoutProvider in CheckoutProvider.EXTENSION_POINT_NAME.extensions) {
+ comboBox.addItem(checkoutProvider)
+ val vcsComponent = checkoutProvider.buildVcsCloneComponent(project)
+ vcsComponents[checkoutProvider.vcsName] = vcsComponent
+ val view = vcsComponent.getView()
+ centerPanel.add(view, checkoutProvider.vcsName)
+ }
+ }
+
+ override fun getView() = mainPanel
+
+ override fun getOkButtonText(): String {
+ return getCurrentVcsComponent()?.getOkButtonText() ?: "Clone"
+ }
+
+ fun openForVcs(clazz: Class): RepositoryUrlMainExtensionComponent {
+ comboBox.selectedItem = CheckoutProvider.EXTENSION_POINT_NAME.findExtension(clazz)
+ return this
+ }
+
+ override fun doOk() {
+ val listener = ProjectLevelVcsManager.getInstance(project).compositeCheckoutListener
+ getCurrentVcsComponent()?.doClone(project, listener)
+ }
+
+ override fun isOkEnabled(): Boolean {
+ return getCurrentVcsComponent()?.isOkEnabled() ?: true
+ }
+
+ override fun doValidateAll(): List {
+ return getCurrentVcsComponent()?.doValidateAll() ?: emptyList()
+ }
+
+ private fun getCurrentVcsComponent() = vcsComponents[getCurrentVcsName()]
+
+ private fun getCurrentVcsName(): String {
+ val checkoutProvider = comboBox.selectedItem as CheckoutProvider
+ return checkoutProvider.vcsName
+ }
+ }
+}
diff --git a/platform/vcs-impl/src/com/intellij/util/ui/cloneDialog/VcsCloneDialog.kt b/platform/vcs-impl/src/com/intellij/util/ui/cloneDialog/VcsCloneDialog.kt
new file mode 100644
index 000000000000..18804b96f934
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/util/ui/cloneDialog/VcsCloneDialog.kt
@@ -0,0 +1,123 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.util.ui.cloneDialog
+
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.ui.DialogWrapper
+import com.intellij.openapi.ui.ValidationInfo
+import com.intellij.openapi.vcs.CheckoutProvider
+import com.intellij.openapi.vcs.ui.cloneDialog.VcsCloneDialogExtension
+import com.intellij.openapi.vcs.ui.cloneDialog.VcsCloneDialogExtensionComponent
+import com.intellij.openapi.wm.impl.welcomeScreen.FlatWelcomeFrame
+import com.intellij.openapi.wm.impl.welcomeScreen.FlatWelcomeFrame.getSeparatorColor
+import com.intellij.ui.CollectionListModel
+import com.intellij.ui.ScrollPaneFactory
+import com.intellij.ui.ScrollingUtil
+import com.intellij.ui.border.CustomLineBorder
+import com.intellij.util.ui.JBEmptyBorder
+import com.intellij.util.ui.JBInsets
+import com.intellij.util.ui.JBUI
+import com.intellij.util.ui.UIUtil
+import com.intellij.util.ui.cloneDialog.RepositoryUrlCloneDialogExtension.RepositoryUrlMainExtensionComponent
+import java.awt.CardLayout
+import java.util.*
+import javax.swing.JComponent
+import javax.swing.JPanel
+import javax.swing.ScrollPaneConstants
+import javax.swing.event.ListSelectionListener
+
+/**
+ * Top-level UI-component for new clone/checkout dialog
+ */
+internal class VcsCloneDialog private constructor(private val project: Project,
+ initialExtensionClass: Class,
+ private var initialVcs: Class? = null) : DialogWrapper(project) {
+ private lateinit var extensionList: VcsCloneDialogExtensionList
+ private val cardLayout = CardLayout()
+ private val mainPanel = JPanel(cardLayout)
+ private val extensionComponents: MutableMap = HashMap()
+
+ init {
+ init()
+ title = "Get From Version Control"
+ JBUI.size(FlatWelcomeFrame.MAX_DEFAULT_WIDTH, FlatWelcomeFrame.DEFAULT_HEIGHT).let {
+ rootPane.minimumSize = it
+ rootPane.preferredSize = it
+ }
+
+ val withoutRightInset = UIUtil.PANEL_REGULAR_INSETS.let {
+ // use empty right inset to align the scroll bar to the edge of panel
+ JBInsets(it.top, it.left, it.bottom, 0)
+ }
+ mainPanel.border = JBEmptyBorder(withoutRightInset)
+
+ VcsCloneDialogExtension.EP_NAME.findExtension(initialExtensionClass)?.let {
+ ScrollingUtil.selectItem(extensionList, it)
+ }
+ }
+
+ override fun getStyle() = DialogStyle.COMPACT
+
+ override fun createCenterPanel(): JComponent {
+ val extensions = VcsCloneDialogExtension.EP_NAME.extensionList
+ val listModel = CollectionListModel(extensions)
+
+ extensionList = VcsCloneDialogExtensionList(listModel).apply {
+ addListSelectionListener(ListSelectionListener { e ->
+ val source = e.source as VcsCloneDialogExtensionList
+ switchComponent(source.selectedValue)
+ })
+ }
+ val scrollableList = ScrollPaneFactory.createScrollPane(extensionList, true).apply {
+ border = CustomLineBorder(getSeparatorColor(), JBUI.insetsRight(1))
+ }
+ return JBUI.Panels.simplePanel()
+ .addToCenter(mainPanel)
+ .addToLeft(scrollableList).apply {
+ border = CustomLineBorder(getSeparatorColor(), JBUI.insetsBottom(1))
+ }
+ }
+
+ override fun isOKActionEnabled(): Boolean {
+ return getSelectedComponent()?.isOkEnabled() ?: false
+ }
+
+ override fun doOKAction() {
+ getSelectedComponent()?.doOk()
+ }
+
+ override fun doValidateAll(): List {
+ return getSelectedComponent()?.doValidateAll() ?: emptyList()
+ }
+
+ private fun switchComponent(extension: VcsCloneDialogExtension) {
+ val extensionId = extension.javaClass.name
+ val mainComponent = extensionComponents.getOrPut(extensionId, {
+ val component = extension.createMainComponent(project)
+ val scrollableMainPanel = ScrollPaneFactory.createScrollPane(component.getView(), true)
+ scrollableMainPanel.verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
+ scrollableMainPanel.horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
+ mainPanel.add(scrollableMainPanel, extensionId)
+ component
+ })
+
+ setOKButtonText(mainComponent.getOkButtonText())
+ if (mainComponent is RepositoryUrlMainExtensionComponent) {
+ initialVcs?.let { mainComponent.openForVcs(it) }
+ }
+ cardLayout.show(mainPanel, extensionId)
+ }
+
+ private fun getSelectedComponent(): VcsCloneDialogExtensionComponent? {
+ return extensionComponents[extensionList.selectedValue.javaClass.name]
+ }
+
+ class Builder(private val project: Project) {
+ fun forExtension(clazz: Class = RepositoryUrlCloneDialogExtension::class.java): VcsCloneDialog {
+ return VcsCloneDialog(project, clazz, null)
+ }
+
+ fun forVcs(clazz: Class): VcsCloneDialog {
+ return VcsCloneDialog(project, RepositoryUrlCloneDialogExtension::class.java, clazz)
+ }
+ }
+}
\ No newline at end of file
diff --git a/platform/vcs-impl/src/com/intellij/util/ui/cloneDialog/VcsCloneDialogExtensionList.kt b/platform/vcs-impl/src/com/intellij/util/ui/cloneDialog/VcsCloneDialogExtensionList.kt
new file mode 100644
index 000000000000..6417d035e5aa
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/util/ui/cloneDialog/VcsCloneDialogExtensionList.kt
@@ -0,0 +1,47 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.util.ui.cloneDialog
+
+import com.intellij.openapi.vcs.ui.cloneDialog.VcsCloneDialogExtension
+import com.intellij.ui.ScrollingUtil
+import com.intellij.ui.SingleSelectionModel
+import com.intellij.ui.components.JBList
+import com.intellij.util.ui.ListUiUtil
+import com.intellij.util.ui.UIUtil
+import java.awt.Component
+import java.awt.FlowLayout
+import javax.swing.*
+import javax.swing.border.EmptyBorder
+
+class VcsCloneDialogExtensionList(listModel: ListModel) : JBList(listModel) {
+ init {
+ selectionModel = SingleSelectionModel()
+ cellRenderer = Renderer()
+
+ ScrollingUtil.installActions(this)
+ }
+
+ class Renderer : ListCellRenderer {
+ val component = VcsCloneDialogExtensionListItem
+ val wrapper: JComponent
+
+ init {
+ wrapper = JPanel(FlowLayout(FlowLayout.LEADING)).apply {
+ border = EmptyBorder(UIUtil.PANEL_REGULAR_INSETS)
+ add(component)
+ }
+ }
+
+ override fun getListCellRendererComponent(list: JList,
+ value: VcsCloneDialogExtension,
+ index: Int,
+ isSelected: Boolean,
+ cellHasFocus: Boolean): Component {
+ component.setTitle(value.getName())
+ component.setTitleForeground(ListUiUtil.WithTallRow.foreground(list, isSelected))
+ component.setIcon(value.getIcon())
+ UIUtil.setBackgroundRecursively(wrapper, ListUiUtil.WithTallRow.background(list, isSelected))
+ return wrapper
+ }
+ }
+}
+
diff --git a/platform/vcs-impl/src/com/intellij/util/ui/cloneDialog/VcsCloneDialogExtensionListItem.kt b/platform/vcs-impl/src/com/intellij/util/ui/cloneDialog/VcsCloneDialogExtensionListItem.kt
new file mode 100644
index 000000000000..3598996f7fa3
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/util/ui/cloneDialog/VcsCloneDialogExtensionListItem.kt
@@ -0,0 +1,48 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.util.ui.cloneDialog
+
+import com.intellij.util.IconUtil
+import com.intellij.util.ui.GridBag
+import com.intellij.util.ui.JBUI
+import com.intellij.util.ui.UIUtil
+import java.awt.Color
+import java.awt.GridBagLayout
+import javax.swing.Icon
+import javax.swing.JComponent
+import javax.swing.JLabel
+
+
+object VcsCloneDialogExtensionListItem : JComponent() {
+
+ private val iconLabel: JLabel = JLabel()
+ private val titleLabel: JLabel = JLabel()
+
+ init {
+ layout = GridBagLayout()
+
+ var gbc = GridBag().next()
+ .insetRight(UIUtil.DEFAULT_VGAP)
+ .anchor(GridBag.LINE_START)
+ .fillCellNone()
+ add(iconLabel, gbc)
+
+ gbc = gbc.next()
+ .insets(JBUI.emptyInsets())
+ .anchor(GridBag.BELOW_BASELINE_LEADING)
+ .fillCellHorizontally()
+ titleLabel.font = JBUI.Fonts.label().asBold()
+ add(titleLabel, gbc)
+ }
+
+ fun setTitle(title: String) {
+ titleLabel.text = title
+ }
+
+ fun setIcon(icon: Icon) {
+ iconLabel.icon = IconUtil.scale(icon, null, 22.0f/icon.iconHeight) // scale is chosen so that the size of icon corresponds the design
+ }
+
+ fun setTitleForeground(foreground: Color) {
+ titleLabel.foreground = foreground
+ }
+}
\ No newline at end of file