mirror of
https://github.com/corda/corda.git
synced 2025-04-07 11:27:01 +00:00
DemoBench: UI improvements, part uno
This commit is contained in:
parent
87dd99d968
commit
a90b2ba839
@ -48,17 +48,20 @@ data class PhysicalLocation(val coordinate: WorldCoordinate, val description: St
|
||||
* A simple lookup table of city names to their coordinates. Lookups are case insensitive.
|
||||
*/
|
||||
object CityDatabase {
|
||||
private val cityMap = HashMap<String, PhysicalLocation>()
|
||||
private val caseInsensitiveLookups = HashMap<String, PhysicalLocation>()
|
||||
val cityMap = HashMap<String, PhysicalLocation>()
|
||||
|
||||
init {
|
||||
javaClass.getResourceAsStream("cities.txt").bufferedReader().useLines { lines ->
|
||||
for (line in lines) {
|
||||
if (line.startsWith("#")) continue
|
||||
val (name, lng, lat) = line.split('\t')
|
||||
cityMap[name.toLowerCase()] = PhysicalLocation(WorldCoordinate(lat.toDouble(), lng.toDouble()), name)
|
||||
val location = PhysicalLocation(WorldCoordinate(lat.toDouble(), lng.toDouble()), name)
|
||||
caseInsensitiveLookups[name.toLowerCase()] = location
|
||||
cityMap[name] = location
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun get(name: String) = cityMap[name.toLowerCase()]
|
||||
operator fun get(name: String) = caseInsensitiveLookups[name.toLowerCase()]
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import net.corda.demobench.views.DemoBenchView
|
||||
import tornadofx.*
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.charset.StandardCharsets.UTF_8
|
||||
import javax.swing.SwingUtilities
|
||||
import javax.swing.UIManager
|
||||
|
||||
/**
|
||||
* README!
|
||||
|
@ -25,6 +25,7 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() {
|
||||
|
||||
private var baseDir: Path = baseDirFor(ManagementFactory.getRuntimeMXBean().startTime)
|
||||
private val cordaPath: Path = jvm.applicationDir.resolve("corda").resolve("corda.jar")
|
||||
//private val command = arrayOf("/usr/local/bin/fish")
|
||||
private val command = jvm.commandFor(cordaPath).toTypedArray()
|
||||
|
||||
private val nodes = LinkedHashMap<String, NodeConfig>()
|
||||
|
@ -15,7 +15,6 @@ import tornadofx.*
|
||||
import java.util.*
|
||||
|
||||
class DemoBenchView : View("Corda DemoBench") {
|
||||
|
||||
override val root by fxml<Parent>()
|
||||
|
||||
private val profileController by inject<ProfileController>()
|
||||
@ -26,6 +25,7 @@ class DemoBenchView : View("Corda DemoBench") {
|
||||
private val menuSaveAs by fxid<MenuItem>()
|
||||
|
||||
init {
|
||||
importStylesheet("/net/corda/demobench/r3-style.css")
|
||||
importStylesheet("/net/corda/demobench/style.css")
|
||||
|
||||
configureShutdown()
|
||||
|
@ -1,27 +1,34 @@
|
||||
package net.corda.demobench.views
|
||||
|
||||
import javafx.application.Platform
|
||||
import javafx.scene.control.ComboBox
|
||||
import javafx.scene.control.SelectionMode.MULTIPLE
|
||||
import javafx.scene.control.SelectionMode.values
|
||||
import javafx.scene.input.KeyCode
|
||||
import javafx.scene.layout.Pane
|
||||
import javafx.scene.layout.Priority
|
||||
import javafx.stage.FileChooser
|
||||
import javafx.util.converter.NumberStringConverter
|
||||
import net.corda.core.node.CityDatabase
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.demobench.model.*
|
||||
import net.corda.demobench.ui.CloseableTab
|
||||
import org.controlsfx.control.textfield.TextFields
|
||||
import tornadofx.*
|
||||
import java.nio.file.Path
|
||||
import java.text.DecimalFormat
|
||||
import java.util.*
|
||||
|
||||
class NodeTabView : Fragment() {
|
||||
private val cityList = CityDatabase.cityMap.keys.toList().sorted()
|
||||
|
||||
override val root = stackpane {}
|
||||
|
||||
private val main by inject<DemoBenchView>()
|
||||
private val showConfig by param(true)
|
||||
|
||||
private companion object : Component() {
|
||||
const val textWidth = 200.0
|
||||
const val textWidth = 465.0
|
||||
const val numberWidth = 100.0
|
||||
const val maxNameLength = 15
|
||||
|
||||
@ -46,32 +53,28 @@ class NodeTabView : Fragment() {
|
||||
private val nodeTerminalView = find<NodeTerminalView>()
|
||||
private val nodeConfigView = stackpane {
|
||||
isVisible = showConfig
|
||||
styleClass += "config-view"
|
||||
|
||||
form {
|
||||
fieldset("Configuration") {
|
||||
isFillWidth = false
|
||||
|
||||
field("Node Name", op = { nodeNameField() })
|
||||
field("Nearest City", op = { nearestCityField() })
|
||||
field("Legal name") { nodeNameField() }
|
||||
field("Nearest city") { nearestCityField() }
|
||||
}
|
||||
|
||||
/*fieldset("Ports") {
|
||||
field("P2P Port", op = { p2pPortField() })
|
||||
field("RPC port", op = { rpcPortField() })
|
||||
field("Web Port", op = { webPortField() })
|
||||
field("Database Port", op = { databasePortField() })
|
||||
}
|
||||
}*/
|
||||
|
||||
hbox {
|
||||
styleClass.addAll("node-panel")
|
||||
|
||||
fieldset("Services") {
|
||||
styleClass.addAll("services-panel")
|
||||
|
||||
listview(availableServices.observable()) {
|
||||
selectionModel.selectionMode = MULTIPLE
|
||||
model.item.extraServices.set(selectionModel.selectedItems)
|
||||
}
|
||||
}
|
||||
|
||||
fieldset("CorDapps") {
|
||||
hboxConstraints { hGrow = Priority.ALWAYS }
|
||||
styleClass.addAll("cordapps-panel")
|
||||
|
||||
listview(cordapps) {
|
||||
@ -82,23 +85,41 @@ class NodeTabView : Fragment() {
|
||||
key.consume()
|
||||
}
|
||||
}
|
||||
button("Add CorDapp") {
|
||||
setOnAction {
|
||||
val app = (chooser.showOpenDialog(null) ?: return@setOnAction).toPath()
|
||||
if (!cordapps.contains(app)) {
|
||||
cordapps.add(app)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fieldset("Services") {
|
||||
styleClass.addAll("services-panel")
|
||||
|
||||
listview(availableServices.observable()) {
|
||||
selectionModel.selectionMode = MULTIPLE
|
||||
model.item.extraServices.set(selectionModel.selectedItems)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button("Create Node") {
|
||||
setOnAction {
|
||||
if (model.validate()) {
|
||||
launch()
|
||||
main.enableAddNodes()
|
||||
main.enableSaveProfile()
|
||||
hbox {
|
||||
button("Add CorDapp") {
|
||||
setOnAction {
|
||||
val app = (chooser.showOpenDialog(null) ?: return@setOnAction).toPath()
|
||||
if (!cordapps.contains(app)) {
|
||||
cordapps.add(app)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spacer pane.
|
||||
pane {
|
||||
hboxConstraints { hGrow = Priority.ALWAYS }
|
||||
}
|
||||
|
||||
button("Start node") {
|
||||
styleClass += "start-button"
|
||||
setOnAction {
|
||||
if (model.validate()) {
|
||||
launch()
|
||||
main.enableAddNodes()
|
||||
main.enableSaveProfile()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -117,6 +138,7 @@ class NodeTabView : Fragment() {
|
||||
root.add(nodeTerminalView)
|
||||
|
||||
model.legalName.value = if (nodeController.hasNetworkMap()) "" else DUMMY_NOTARY.name
|
||||
model.nearestCity.value = if (nodeController.hasNetworkMap()) "" else "London"
|
||||
model.p2pPort.value = nodeController.nextPort
|
||||
model.rpcPort.value = nodeController.nextPort
|
||||
model.webPort.value = nodeController.nextPort
|
||||
@ -147,13 +169,29 @@ class NodeTabView : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun Pane.nearestCityField() = textfield(model.nearestCity) {
|
||||
// private fun Pane.nearestCityField() = textfield(model.nearestCity) {
|
||||
// minWidth = textWidth
|
||||
// TextFields.bindAutoCompletion(this, CityDatabase.cityMap.keys)
|
||||
// validator(trigger = ValidationTrigger.OnBlur) {
|
||||
// if (it == null || it.trim().isEmpty()) {
|
||||
// error("Nearest city is required")
|
||||
// } else if (CityDatabase[it] == null) {
|
||||
// error("$it is not in our database, sorry")
|
||||
// } else {
|
||||
// null
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun Pane.nearestCityField() = combobox(model.nearestCity, cityList) {
|
||||
minWidth = textWidth
|
||||
validator {
|
||||
if (it == null) {
|
||||
error("Nearest city is required")
|
||||
} else if (it.trim().isEmpty()) {
|
||||
isEditable = true
|
||||
TextFields.bindAutoCompletion(editor, cityList)
|
||||
validator(trigger = ValidationTrigger.OnBlur) {
|
||||
if (it == null || it.trim().isEmpty()) {
|
||||
error("Nearest city is required")
|
||||
} else if (CityDatabase[it] == null) {
|
||||
error("$it is not in our database, sorry")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ class NodeTerminalView : Fragment() {
|
||||
private val webServerController by inject<WebServerController>()
|
||||
|
||||
private val nodeName by fxid<Label>()
|
||||
private val p2pPort by fxid<PropertyLabel>()
|
||||
private val states by fxid<PropertyLabel>()
|
||||
private val transactions by fxid<PropertyLabel>()
|
||||
private val balance by fxid<PropertyLabel>()
|
||||
@ -49,7 +48,6 @@ class NodeTerminalView : Fragment() {
|
||||
|
||||
fun open(config: NodeConfig, onExit: () -> Unit) {
|
||||
nodeName.text = config.legalName
|
||||
p2pPort.value = config.p2pPort.toString()
|
||||
launchWebButton.text = "Launch\nWeb Server\n(Port ${config.webPort})"
|
||||
|
||||
val swingTerminal = SwingNode()
|
||||
@ -177,8 +175,8 @@ class NodeTerminalView : Fragment() {
|
||||
}
|
||||
|
||||
class TerminalSettingsProvider : DefaultSettingsProvider() {
|
||||
override fun getDefaultStyle() = TextStyle(TerminalColor.WHITE, TerminalColor.BLACK)
|
||||
|
||||
override fun getDefaultStyle() = TextStyle(TerminalColor.WHITE, TerminalColor.rgb(50, 50, 50))
|
||||
override fun emulateX11CopyPaste() = true
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
/** Styles that follow the corporate branding guidelines, and which give a web/bootstrap look'n'feel */
|
||||
|
||||
.root-pane {
|
||||
-fx-font-family: sans-serif;
|
||||
-fx-font-size: 14pt;
|
||||
-db-grey: #ddd;
|
||||
}
|
||||
|
||||
.button {
|
||||
-fx-padding: 12px;
|
||||
-fx-border-radius: 4px;
|
||||
}
|
||||
|
||||
.info-button {
|
||||
-fx-base: #5bc0de;
|
||||
-fx-text-fill: white;
|
||||
-fx-border-color: #298dff;
|
||||
-fx-background-color: linear-gradient(to bottom, #70b3ff 0%, #3392ff 100%);
|
||||
}
|
||||
|
||||
.info-button:hover {
|
||||
-fx-background-color: #3392ff;
|
||||
}
|
||||
|
||||
.tab-pane:top > .tab-header-area > .tab-header-background {
|
||||
-fx-background-color: white;
|
||||
-fx-border-color: -db-grey;
|
||||
-fx-border-width: 0 0 1 0;
|
||||
}
|
||||
|
||||
.tab-pane:top > .tab-header-area {
|
||||
-fx-padding: 0.816667em 0 0 8em;
|
||||
}
|
||||
|
||||
.tab .focus-indicator {
|
||||
-fx-border-width: 0, 0, 0;
|
||||
}
|
||||
|
||||
.tab, .tab:selected:hover {
|
||||
-fx-background-color: white;
|
||||
-fx-background-radius: 0;
|
||||
-fx-border-radius: 4px 4px 0 0;
|
||||
-fx-padding: 10px 15px;
|
||||
}
|
||||
|
||||
.tab:selected {
|
||||
-fx-border-width: 1;
|
||||
-fx-border-color: -db-grey -db-grey white -db-grey;
|
||||
}
|
||||
|
||||
.tab:hover {
|
||||
-fx-background-color: -db-grey;
|
||||
-fx-background-radius: 4px 4px 0 0;
|
||||
-fx-cursor: hand;
|
||||
}
|
@ -4,27 +4,38 @@
|
||||
*/
|
||||
|
||||
.header {
|
||||
-fx-background-color: #505050;
|
||||
-fx-padding: 15px;
|
||||
-fx-background-color: white;
|
||||
-fx-padding: 1.5em;
|
||||
-fx-spacing: 20px;
|
||||
}
|
||||
|
||||
.property-label .label {
|
||||
-fx-font-size: 14pt;
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
.add-node-button {
|
||||
-fx-base: red;
|
||||
-fx-text-fill: black;
|
||||
}
|
||||
|
||||
.big-button {
|
||||
-fx-base: #009759;
|
||||
-fx-background-radius: 5px;
|
||||
-fx-opacity: 80%;
|
||||
-fx-font-size: 12pt;
|
||||
}
|
||||
|
||||
.start-button {
|
||||
-fx-base: #26b426;
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
.terminal-gradient-pane {
|
||||
-fx-border-color: black;
|
||||
-fx-border-width: 1 0 0 0;
|
||||
-fx-background-color: linear-gradient(to bottom, black, #323232);
|
||||
}
|
||||
|
||||
.terminal-vbox {
|
||||
-fx-background-color: #323232;
|
||||
}
|
||||
|
||||
.node-panel {
|
||||
-fx-spacing: 20px;
|
||||
-fx-spacing: 1em;
|
||||
-fx-background-color: white;
|
||||
}
|
||||
|
||||
.services-panel {
|
||||
@ -39,5 +50,10 @@
|
||||
|
||||
.list-cell {
|
||||
-fx-control-inner-background: white;
|
||||
-fx-control-inner-background-alt: gainsboro;
|
||||
-fx-control-inner-background-alt: #f7f7f7;
|
||||
}
|
||||
|
||||
.config-view {
|
||||
-fx-background-color: white;
|
||||
-fx-padding: 1em;
|
||||
}
|
||||
|
@ -1,22 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<VBox xmlns="http://javafx.com/javafx/8.0.102" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Menu?>
|
||||
<?import javafx.scene.control.MenuBar?>
|
||||
<?import javafx.scene.control.MenuItem?>
|
||||
<?import javafx.scene.control.TabPane?>
|
||||
<?import javafx.scene.image.Image?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
|
||||
<VBox xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<MenuBar useSystemMenuBar="true">
|
||||
<Menu text="File">
|
||||
<MenuItem fx:id="menuOpen" text="Open"/>
|
||||
<MenuItem fx:id="menuSaveAs" disable="true" text="Save As"/>
|
||||
<MenuItem fx:id="menuOpen" text="Open" />
|
||||
<MenuItem fx:id="menuSaveAs" disable="true" text="Save As" />
|
||||
</Menu>
|
||||
</MenuBar>
|
||||
<StackPane VBox.vgrow="ALWAYS">
|
||||
<TabPane fx:id="nodeTabPane" minHeight="444.0" minWidth="800.0" prefHeight="613.0" prefWidth="1231.0"
|
||||
tabClosingPolicy="UNAVAILABLE" tabMinHeight="30.0"/>
|
||||
<Button fx:id="addNodeButton" mnemonicParsing="false" styleClass="add-node-button" text="Add Node"
|
||||
StackPane.alignment="TOP_RIGHT">
|
||||
<StackPane styleClass="root-pane" VBox.vgrow="ALWAYS">
|
||||
<TabPane fx:id="nodeTabPane" minHeight="444.0" minWidth="800.0" prefHeight="613.0" prefWidth="1231.0" tabClosingPolicy="UNAVAILABLE" tabMinHeight="30.0" />
|
||||
<ImageView fitHeight="40.0" preserveRatio="true" StackPane.alignment="TOP_LEFT">
|
||||
<Image url="@cordalogo-full-trans.png"/>
|
||||
<StackPane.margin>
|
||||
<Insets right="5.0" top="5.0"/>
|
||||
<Insets left="20" top="15.0"/>
|
||||
</StackPane.margin>
|
||||
</ImageView>
|
||||
<Button fx:id="addNodeButton" mnemonicParsing="false" styleClass="info-button" text="Add Node" StackPane.alignment="TOP_RIGHT">
|
||||
<StackPane.margin>
|
||||
<Insets right="25.0" top="10.0" />
|
||||
</StackPane.margin>
|
||||
</Button>
|
||||
</StackPane>
|
||||
|
@ -3,19 +3,17 @@
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import net.corda.demobench.ui.*?>
|
||||
<VBox visible="false" prefHeight="953.0" prefWidth="1363.0" xmlns="http://javafx.com/javafx/8.0.102"
|
||||
xmlns:fx="http://javafx.com/fxml/1">
|
||||
<HBox prefHeight="95.0" prefWidth="800.0" spacing="15.0" styleClass="header">
|
||||
<VBox prefHeight="66.0" prefWidth="296.0" spacing="20.0">
|
||||
<Label fx:id="nodeName" style="-fx-font-size: 40; -fx-text-fill: red;"/>
|
||||
<PropertyLabel fx:id="p2pPort" name="P2P port: "/>
|
||||
<VBox visible="false" prefHeight="953.0" prefWidth="1363.0" xmlns="http://javafx.com/javafx/8.0.102" xmlns:fx="http://javafx.com/fxml/1" styleClass="terminal-vbox">
|
||||
<HBox prefHeight="95.0" prefWidth="800.0" styleClass="header">
|
||||
<VBox prefHeight="66.0" HBox.hgrow="ALWAYS">
|
||||
<Label fx:id="nodeName" style="-fx-font-size: 40; -fx-text-fill: red;" minWidth="NaN"/>
|
||||
</VBox>
|
||||
<VBox prefHeight="93.0" prefWidth="267.0">
|
||||
<PropertyLabel fx:id="states" name="States in vault: "/>
|
||||
<PropertyLabel fx:id="transactions" name="Known transactions: "/>
|
||||
<PropertyLabel fx:id="balance" name="Balance: "/>
|
||||
</VBox>
|
||||
<Pane prefHeight="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS"/>
|
||||
<!--<Pane prefHeight="200.0" prefWidth="200.0"/>-->
|
||||
<Button fx:id="viewDatabaseButton" disable="true" mnemonicParsing="false" prefHeight="92.0" prefWidth="115.0"
|
||||
styleClass="big-button" text="View Database" textAlignment="CENTER"/>
|
||||
<Button fx:id="launchWebButton" disable="true" mnemonicParsing="false" prefHeight="92.0" prefWidth="115.0"
|
||||
@ -23,4 +21,5 @@
|
||||
<Button fx:id="launchExplorerButton" disable="true" mnemonicParsing="false" prefHeight="92.0" prefWidth="115.0"
|
||||
styleClass="big-button" text="Launch Explorer" textAlignment="CENTER"/>
|
||||
</HBox>
|
||||
<Pane minHeight="8" mouseTransparent="true" styleClass="terminal-gradient-pane"/>
|
||||
</VBox>
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
Loading…
x
Reference in New Issue
Block a user