Kotlin UI DSL:

* Top and bottom paddings for note row (explanation text) now conforms to our guideline (bigger than before).
* For all JPasswordField new automatic rule is used: width `250`. If you have `growPolicy = GrowPolicy.SHORT_TEXT` for password fields, now you can remove this unnecessary flag.
* grow policy SHORT_TEXT changed: maxWidth now 250 instead of 210.

Kotlin UI DSL is covered by tests, so, in case of regressions, please contact me to add missed test case.

Currently, Kotlin UI DSL (`noteRow`) doesn't check that your text has a correct width, it is your responsibility to insert `\n` if need.
This commit is contained in:
Vladimir Krivosheev
2018-03-22 13:07:57 +01:00
parent ece0fabce6
commit 81bd3606e1
7 changed files with 87 additions and 58 deletions
@@ -201,7 +201,7 @@ internal class PasswordSafeConfigurableUi : ConfigurableUi<PasswordSafeSettings>
)
}
row("Master Password:") {
keePassMasterPassword(growPolicy = GrowPolicy.SHORT_TEXT)
keePassMasterPassword()
}
if (!SystemInfo.isWindows) {
row { hint("Stored using weak encryption. It is recommended to store on encrypted volume for additional security.") }
@@ -26,8 +26,8 @@ fun showJetBrainsAccountDialog(parent: Component, project: Project? = null): Dia
val rememberCheckBox = CheckBox(CommonBundle.message("checkbox.remember.password"), selected = credentials?.userName == null || !credentials.password.isNullOrEmpty())
val panel = panel {
noteRow("Login to JetBrains Account to get notified when the submitted\nexceptions are fixed.")
row("Username:") { userField() }
noteRow("Login to JetBrains Account to get notified\nwhen the submitted exceptions are fixed.")
row("Username:") { userField(growPolicy = GrowPolicy.SHORT_TEXT) }
row("Password:") { passwordField() }
row {
rememberCheckBox()
@@ -12,7 +12,8 @@ import javax.swing.JLabel
internal const val HORIZONTAL_GAP = 10
internal const val VERTICAL_GAP = 5
fun createLayoutBuilder() = LayoutBuilder(MigLayoutBuilder())
@PublishedApi
internal fun createLayoutBuilder() = LayoutBuilder(MigLayoutBuilder())
interface LayoutBuilderImpl {
fun newRow(label: JLabel? = null, buttonGroup: ButtonGroup? = null, separated: Boolean = false): Row
@@ -214,8 +214,6 @@ private fun addGrowIfNeed(cc: CC, component: Component) {
component is JPasswordField -> {
applyGrowPolicy(cc, GrowPolicy.SHORT_TEXT)
cc.grow(0f)
cc.width("210!")
}
component is JTextComponent || component is SeparatorComponent || component is ComponentWithBrowseButton<*> -> {
@@ -0,0 +1,24 @@
rowConstraints: ''
columnConstraints:
count: 2.0
constraints:
- {}
- {grow: 100.0}
componentConstrains:
'JLabel #0':
spanX: 2097051.0
wrap: true
vertical:
gapBefore:
min: {value: 5.0, unit: 2.0}
preferred: {value: 5.0, unit: 2.0}
gapAfter:
min: {value: 10.0, unit: 2.0}
preferred: {value: 10.0, unit: 2.0}
'JLabel #1': {}
'JPasswordField #2':
wrap: true
horizontal:
size:
preferred: {value: 250.0}
'JCheckBox #3': {skip: 1.0, spanX: 2097051.0, wrap: true}
@@ -1,69 +1,62 @@
// Copyright 2000-2018 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.ui.layout
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.ui.components.JBPasswordField
import com.intellij.ui.components.RadioButton
import net.miginfocom.layout.LayoutUtil
import net.miginfocom.swing.MigLayout
import java.awt.BorderLayout
import java.awt.Color
import java.awt.Dimension
import javax.swing.JFrame
import com.intellij.CommonBundle
import com.intellij.ide.BrowserUtil
import com.intellij.testFramework.runInEdtAndWait
import com.intellij.ui.components.CheckBox
import com.intellij.ui.components.dialog
import javax.swing.JPasswordField
import javax.swing.JTextField
object MigLayoutTestApp {
@JvmStatic
fun main(args: Array<String>) {
LayoutUtil.setGlobalDebugMillis(1000)
// LayoutUtil.setGlobalDebugMillis(1000)
val panel = panel {
row { label("Save passwords:") }
runInEdtAndWait {
val passwordField = JPasswordField()
// val panel = panel {
// noteRow("Profiler requires access to the kernel-level API.\nEnter the sudo password to allow this. ")
// row("Sudo password:") { passwordField() }
// row { CheckBox(CommonBundle.message("checkbox.remember.password"), true)() }
// }
buttonGroup {
val panel = panel {
noteRow("Login to JetBrains Account to get notified\nwhen the submitted exceptions are fixed.")
row("Username:") { JTextField()(growPolicy = GrowPolicy.SHORT_TEXT) }
row("Password:") { passwordField() }
row {
RadioButton("In KeePass")()
row("Database:") {
JTextField()()
gearButton(
object : AnAction("Clear") {
override fun actionPerformed(event: AnActionEvent) {
}
},
object : AnAction("Import") {
override fun actionPerformed(event: AnActionEvent) {
}
}
)
}
row("Master Password:") {
JBPasswordField()(growPolicy = GrowPolicy.SHORT_TEXT)
}
row {
hint("Stored using weak encryption.")
CheckBox(CommonBundle.message("checkbox.remember.password"))()
right {
link("Forgot password?") {
BrowserUtil.browse("https://account.jetbrains.com/forgot-password?username=")
}
}
}
row {
RadioButton("Do not save, forget passwords after restart")()
}
row {
hint("Existing KeePass file will be removed.")
}
noteRow("""Do not have an account? <a href="https://account.jetbrains.com/login?signup">Sign Up</a>""")
}
dialog(
title = "Access Required",
panel = panel,
focusedComponent = passwordField,
okActionEnabled = false
) {
return@dialog null
}
.showAndGet()
}
val frame = JFrame()
frame.defaultCloseOperation = JFrame.EXIT_ON_CLOSE
frame.contentPane.add(panel, BorderLayout.CENTER)
frame.contentPane.background = Color.WHITE
frame.background = Color.WHITE
frame.pack()
frame.setLocationRelativeTo(null)
frame.minimumSize = Dimension(512, 256)
frame.isVisible = true
System.out.println(configurationToJson(panel, panel.layout as MigLayout, false))
// val frame = JFrame()
// frame.defaultCloseOperation = JFrame.EXIT_ON_CLOSE
// frame.contentPane.add(panel, BorderLayout.CENTER)
// frame.contentPane.background = Color.WHITE
// frame.background = Color.WHITE
// frame.pack()
// frame.setLocationRelativeTo(null)
// frame.minimumSize = Dimension(512, 256)
// frame.isVisible = true
//
// System.out.println(configurationToJson(panel, panel.layout as MigLayout, false))
}
}
@@ -1,9 +1,11 @@
// Copyright 2000-2018 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.ui.layout
import com.intellij.CommonBundle
import com.intellij.openapi.application.invokeAndWaitIfNeed
import com.intellij.testFramework.PlatformTestUtil
import com.intellij.testFramework.UsefulTestCase
import com.intellij.testFramework.assertions.Assertions
import com.intellij.ui.components.CheckBox
import com.intellij.ui.components.JBPasswordField
import com.intellij.ui.components.RadioButton
@@ -30,6 +32,7 @@ import java.util.concurrent.Callable
import javax.imageio.ImageIO
import javax.swing.JFrame
import javax.swing.JPanel
import javax.swing.JPasswordField
import javax.swing.JTextField
import kotlin.properties.Delegates
@@ -99,6 +102,16 @@ class UiDslTest {
}, "[0, 0, 145, 23], [165, 0, 347, 23], [0, 28, 145, 26], [165, 28, 347, 26]")
}
@Test
fun `note row in the dialog`() {
val passwordField = JPasswordField()
doTest(panel {
noteRow("Profiler requires access to the kernel-level API. Enter the sudo password to allow this. ")
row("Sudo password:") { passwordField() }
row { CheckBox(CommonBundle.message("checkbox.remember.password"), true)() }
}, "[0, 0, 544, 31], [0, 36, 99, 26], [119, 36, 425, 26], [119, 67, 425, 23]")
}
private fun doTest(panel: JPanel, expectedLocations: String) {
val frame = GuiActionRunner.execute(Callable {
LayoutUtil.setGlobalDebugMillis(1000)
@@ -124,7 +137,7 @@ class UiDslTest {
try {
val expectedLayoutDataFile = Paths.get(PlatformTestUtil.getPlatformTestDataPath(), "ui", "layout", "$imageName.yml")
if (expectedLayoutDataFile.exists()) {
com.intellij.testFramework.assertions.Assertions.assertThat(actualLayoutJson).isEqualTo(expectedLayoutDataFile)
Assertions.assertThat(actualLayoutJson).isEqualTo(expectedLayoutDataFile)
}
else {
expectedLayoutDataFile.write(actualLayoutJson)