[clonedialog] Introduce new clone dialog and its API

New API is designed to provide two abilities for implementators:
1. Extending clone dialog with custom external components (e.g. for some cloud VCS hosting providers, like Github,
Bitbucket, GitLab, etc).
For each new extensions it is required to implement `VcsCloneDialogExtension` and `VcsCloneDialogExtensionComponent`
interfaces.

2. Extending the existing "Repository URL" clone dialog component with UI for clone process initiating for any VCS based
on `CheckoutProvider`.
It is required to implement `com.intellij.openapi.vcs.CheckoutProvider#buildVcsCloneComponent`.

GitOrigin-RevId: 997db50dca810cdf802c0c7bf6aabc3a9c523a6b
This commit is contained in:
Aleksandr Krasilnikov
2019-07-02 06:52:16 +03:00
committed by intellij-monorepo-bot
parent b77f28e5f1
commit 5803710c02
18 changed files with 516 additions and 1 deletions
+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<rect width="2" height="8.386" x="7.532" y="3.269" fill="#6E6E6E" transform="rotate(45 8.532 7.462)"/>
<polygon fill="#6E6E6E" points="4 5 11 12 4 12"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 297 B

+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<rect width="2" height="8.386" x="7.532" y="3.269" fill="#AFB1B3" transform="rotate(45 8.532 7.462)"/>
<polygon fill="#AFB1B3" points="4 5 11 12 4 12"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 297 B

@@ -105,6 +105,8 @@
<extensionPoint name="vcsRepositoryInitializer" interface="com.intellij.vcs.VcsRepositoryInitializer"/>
<extensionPoint name="openapi.vcs.changes.vcsPreservingExecutor"
interface="com.intellij.openapi.vcs.changes.VcsPreservingExecutor"/>
<extensionPoint qualifiedName="com.intellij.openapi.vcs.ui.cloneDialog.VcsCloneDialogExtension"
interface="com.intellij.openapi.vcs.ui.cloneDialog.VcsCloneDialogExtension"/>
</extensionPoints>
</idea-plugin>
@@ -140,6 +140,11 @@
<nonProjectFileWritingAccessExtension implementation="com.intellij.openapi.vcs.changes.IgnoredFileWritingAccessExtension"/>
<statistics.applicationUsagesCollector implementation="com.intellij.openapi.vcs.statistics.VcsApplicationOptionsUsagesCollector"/>
<openapi.vcs.ui.cloneDialog.VcsCloneDialogExtension
id="com.intellij.util.ui.cloneDialog.RepositoryUrlCloneDialogExtension"
implementation="com.intellij.util.ui.cloneDialog.RepositoryUrlCloneDialogExtension"
order="first"/>
</extensions>
<applicationListeners>
@@ -346,6 +346,11 @@
icon="AllIcons.Welcome.FromVCS">
<add-to-group group-id="WelcomeScreen.QuickStart" anchor="first"/>
</action>
<action id="WelcomeScreen.NewGetFromVcs" class="com.intellij.openapi.wm.impl.welcomeScreen.RunVcsCloneDialogAction"
icon="AllIcons.Vcs.Clone"
internal="true">
<add-to-group group-id="WelcomeScreen.QuickStart" anchor="last"/>
</action>
<action id="Vcs.CopyRevisionNumberAction" class="com.intellij.openapi.vcs.history.actions.CopyRevisionNumberAction"
text="Copy Revision Number" description="Copy short revision numbers of selected commits to the clipboard"
@@ -534,6 +534,10 @@ vcs.process.externally.added.files.description=Process externally added files. A
vcs.propose.add.ignored.directories.to.exclude=false
vcs.propose.add.ignored.directories.to.exclude.description=Show notification with proposal to add ignored (but not excluded) directories to exclude.
vcs.use.new.clone.dialog=false
vcs.use.new.clone.dialog.description=Use new clone dialog
vcs.use.new.clone.dialog.restartRequired=true
psi.incremental.reparse.depth.limit=1000
psi.deferIconLoading=true
@@ -3133,6 +3133,7 @@ public class AllIcons {
/** 16x16 */ public static final Icon Arrow_right = load("/vcs/arrow_right.svg");
/** 16x16 */ public static final Icon Branch = load("/vcs/branch.svg");
/** 16x16 */ public static final Icon Changelist = load("/vcs/changelist.svg");
/** 16x16 */ public static final Icon Clone = load("/vcs/clone.svg");
/** 16x16 */ public static final Icon CommitNode = load("/vcs/commitNode.svg");
/** 16x16 */ public static final Icon Equal = load("/vcs/equal.svg");
/** 16x16 */ public static final Icon Folders = load("/vcs/folders.svg");
@@ -17,6 +17,8 @@ package com.intellij.openapi.vcs;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.ui.VcsCloneComponent;
import com.intellij.openapi.vcs.ui.VcsCloneComponentStub;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -49,4 +51,9 @@ public interface CheckoutProvider {
return getTextWithoutMnemonicEscaping(o1.getVcsName()).compareTo(getTextWithoutMnemonicEscaping(o2.getVcsName()));
}
}
@NotNull
default VcsCloneComponent buildVcsCloneComponent(@NotNull Project project) {
return new VcsCloneComponentStub(this, "Clone");
}
}
@@ -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.vcs.ui
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.ValidationInfo
import com.intellij.openapi.vcs.CheckoutProvider
import javax.swing.JComponent
/**
* Provides UI and dialog action handling for specific VCS
*/
interface VcsCloneComponent {
/**
* Component that would be placed on center of dialog panel
*/
fun getView(): JComponent
fun doClone(project: Project, listener: CheckoutProvider.Listener)
fun isOkEnabled(): Boolean
fun doValidateAll(): List<ValidationInfo>
fun getOkButtonText(): String = "Clone"
}
@@ -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<ValidationInfo>()
}
@@ -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<VcsCloneDialogExtension>("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
}
@@ -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<ValidationInfo>
/**
* Text that represents dialog primary action
*/
fun getOkButtonText(): String = "Clone"
}
@@ -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());
}
}
@@ -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()
}
}
@@ -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<String, VcsCloneComponent>()
private val cardLayout = CardLayout()
private val mainPanel = JPanel(BorderLayout())
private val comboBox: ComboBox<CheckoutProvider> = ComboBox<CheckoutProvider>().apply {
renderer = SimpleListCellRenderer.create<CheckoutProvider>("") { 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<out CheckoutProvider>): 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<ValidationInfo> {
return getCurrentVcsComponent()?.doValidateAll() ?: emptyList()
}
private fun getCurrentVcsComponent() = vcsComponents[getCurrentVcsName()]
private fun getCurrentVcsName(): String {
val checkoutProvider = comboBox.selectedItem as CheckoutProvider
return checkoutProvider.vcsName
}
}
}
@@ -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<out VcsCloneDialogExtension>,
private var initialVcs: Class<out CheckoutProvider>? = null) : DialogWrapper(project) {
private lateinit var extensionList: VcsCloneDialogExtensionList
private val cardLayout = CardLayout()
private val mainPanel = JPanel(cardLayout)
private val extensionComponents: MutableMap<String, VcsCloneDialogExtensionComponent> = 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<VcsCloneDialogExtension>(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<ValidationInfo> {
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<out VcsCloneDialogExtension> = RepositoryUrlCloneDialogExtension::class.java): VcsCloneDialog {
return VcsCloneDialog(project, clazz, null)
}
fun forVcs(clazz: Class<out CheckoutProvider>): VcsCloneDialog {
return VcsCloneDialog(project, RepositoryUrlCloneDialogExtension::class.java, clazz)
}
}
}
@@ -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<VcsCloneDialogExtension>) : JBList<VcsCloneDialogExtension>(listModel) {
init {
selectionModel = SingleSelectionModel()
cellRenderer = Renderer()
ScrollingUtil.installActions(this)
}
class Renderer : ListCellRenderer<VcsCloneDialogExtension> {
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<out VcsCloneDialogExtension>,
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
}
}
}
@@ -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
}
}