From 767077c764f44ba195a9335c0d55618cf6176e58 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Thu, 1 Sep 2016 16:34:42 +0100 Subject: [PATCH] explorer: Add Low level events viewer for tx screen asd --- .../com/r3corda/client/fxutils/ChosenList.kt | 4 +- .../model/GatheredTransactionDataModel.kt | 23 +++++++++--- .../r3corda/explorer/ui/SingleRowSelection.kt | 6 +++ .../r3corda/explorer/ui/TableViewUtilities.kt | 7 ++++ .../explorer/ui/TreeTableViewUtilities.kt | 8 ++++ .../com/r3corda/explorer/views/CashViewer.kt | 33 ++++++----------- .../explorer/views/TransactionViewer.kt | 37 ++++++++++++++++++- .../explorer/views/TransactionViewer.fxml | 12 +++++- 8 files changed, 98 insertions(+), 32 deletions(-) create mode 100644 explorer/src/main/kotlin/com/r3corda/explorer/ui/SingleRowSelection.kt diff --git a/client/src/main/kotlin/com/r3corda/client/fxutils/ChosenList.kt b/client/src/main/kotlin/com/r3corda/client/fxutils/ChosenList.kt index 1c33e2a3bb..d686f1dba3 100644 --- a/client/src/main/kotlin/com/r3corda/client/fxutils/ChosenList.kt +++ b/client/src/main/kotlin/com/r3corda/client/fxutils/ChosenList.kt @@ -21,7 +21,7 @@ import javafx.collections.ObservableListBase * The above will create a list that chooses and delegates to the appropriate filtered list based on the type of filter. */ class ChosenList( - private val chosenListObservable: ObservableValue> + private val chosenListObservable: ObservableValue> ): ObservableListBase() { private var currentList = chosenListObservable.value @@ -48,7 +48,7 @@ class ChosenList( } } - private fun pick(list: ObservableList) { + private fun pick(list: ObservableList) { currentList.removeListener(listener) list.addListener(listener) beginChange() diff --git a/client/src/main/kotlin/com/r3corda/client/model/GatheredTransactionDataModel.kt b/client/src/main/kotlin/com/r3corda/client/model/GatheredTransactionDataModel.kt index fe9209358b..58355f3330 100644 --- a/client/src/main/kotlin/com/r3corda/client/model/GatheredTransactionDataModel.kt +++ b/client/src/main/kotlin/com/r3corda/client/model/GatheredTransactionDataModel.kt @@ -7,6 +7,7 @@ import com.r3corda.node.services.monitor.TransactionBuildResult import com.r3corda.node.utilities.AddOrRemove import javafx.beans.property.SimpleObjectProperty import javafx.beans.value.ObservableValue +import javafx.collections.FXCollections import javafx.collections.ObservableList import rx.Observable import java.time.Instant @@ -20,6 +21,7 @@ interface GatheredTransactionData { val transaction: ObservableValue val status: ObservableValue val lastUpdate: ObservableValue + val allEvents: ObservableList } sealed class TransactionCreateStatus(val message: String?) { @@ -42,7 +44,8 @@ data class GatheredTransactionDataWritable( override val protocolStatus: SimpleObjectProperty = SimpleObjectProperty(null), override val transaction: SimpleObjectProperty = SimpleObjectProperty(null), override val status: SimpleObjectProperty = SimpleObjectProperty(null), - override val lastUpdate: SimpleObjectProperty + override val lastUpdate: SimpleObjectProperty, + override val allEvents: ObservableList = FXCollections.observableArrayList() ) : GatheredTransactionData /** @@ -74,7 +77,7 @@ class GatheredTransactionDataModel { } is ServiceToClientEvent.OutputState -> {} is ServiceToClientEvent.StateMachine -> { - newFiberIdTransactionStateOrModify(transactionStates, + newFiberIdTransactionStateOrModify(transactionStates, serviceToClientEvent, fiberId = serviceToClientEvent.fiberId, lastUpdate = serviceToClientEvent.time, tweak = { @@ -87,7 +90,7 @@ class GatheredTransactionDataModel { ) } is ServiceToClientEvent.Progress -> { - newFiberIdTransactionStateOrModify(transactionStates, + newFiberIdTransactionStateOrModify(transactionStates, serviceToClientEvent, fiberId = serviceToClientEvent.fiberId, lastUpdate = serviceToClientEvent.time, tweak = { @@ -97,7 +100,7 @@ class GatheredTransactionDataModel { } is ServiceToClientEvent.TransactionBuild -> { val state = serviceToClientEvent.state - newUuidTransactionStateOrModify(transactionStates, + newUuidTransactionStateOrModify(transactionStates, serviceToClientEvent, uuid = serviceToClientEvent.id, fiberId = when (state) { is TransactionBuildResult.ProtocolStarted -> state.fiberId @@ -124,27 +127,32 @@ class GatheredTransactionDataModel { companion object { private fun newFiberIdTransactionStateOrModify( transactionStates: ObservableList, + event: ServiceToClientEvent, fiberId: Long, lastUpdate: Instant, tweak: GatheredTransactionDataWritable.() -> Unit ) { val index = transactionStates.indexOfFirst { it.fiberId.value == fiberId } - if (index < 0) { + val state = if (index < 0) { val newState = GatheredTransactionDataWritable( fiberId = SimpleObjectProperty(fiberId), lastUpdate = SimpleObjectProperty(lastUpdate) ) tweak(newState) transactionStates.add(newState) + newState } else { val existingState = transactionStates[index] existingState.lastUpdate.set(lastUpdate) tweak(existingState) + existingState } + state.allEvents.add(event) } private fun newUuidTransactionStateOrModify( transactionStates: ObservableList, + event: ServiceToClientEvent, uuid: UUID, fiberId: Long?, lastUpdate: Instant, @@ -153,7 +161,7 @@ class GatheredTransactionDataModel { val index = transactionStates.indexOfFirst { it.uuid.value == uuid || (fiberId != null && it.fiberId.value == fiberId) } - if (index < 0) { + val state = if (index < 0) { val newState = GatheredTransactionDataWritable( uuid = SimpleObjectProperty(uuid), fiberId = SimpleObjectProperty(fiberId), @@ -161,11 +169,14 @@ class GatheredTransactionDataModel { ) tweak(newState) transactionStates.add(newState) + newState } else { val existingState = transactionStates[index] existingState.lastUpdate.set(lastUpdate) tweak(existingState) + existingState } + state.allEvents.add(event) } } diff --git a/explorer/src/main/kotlin/com/r3corda/explorer/ui/SingleRowSelection.kt b/explorer/src/main/kotlin/com/r3corda/explorer/ui/SingleRowSelection.kt new file mode 100644 index 0000000000..2de9d6a2c0 --- /dev/null +++ b/explorer/src/main/kotlin/com/r3corda/explorer/ui/SingleRowSelection.kt @@ -0,0 +1,6 @@ +package com.r3corda.explorer.ui + +sealed class SingleRowSelection { + class None : SingleRowSelection() + class Selected(val node: A) : SingleRowSelection() +} diff --git a/explorer/src/main/kotlin/com/r3corda/explorer/ui/TableViewUtilities.kt b/explorer/src/main/kotlin/com/r3corda/explorer/ui/TableViewUtilities.kt index 0936cd4c92..b877c81596 100644 --- a/explorer/src/main/kotlin/com/r3corda/explorer/ui/TableViewUtilities.kt +++ b/explorer/src/main/kotlin/com/r3corda/explorer/ui/TableViewUtilities.kt @@ -47,3 +47,10 @@ fun Formatter.toTableCellFactory() = Callback, Tabl } } +fun TableView.singleRowSelection() = Bindings.createObjectBinding({ + if (selectionModel.selectedItems.size == 0) { + SingleRowSelection.None() + } else { + SingleRowSelection.Selected(selectionModel.selectedItems[0]) + } +}, arrayOf(selectionModel.selectedItems)) diff --git a/explorer/src/main/kotlin/com/r3corda/explorer/ui/TreeTableViewUtilities.kt b/explorer/src/main/kotlin/com/r3corda/explorer/ui/TreeTableViewUtilities.kt index 3c5b439d39..d3cd6ec8b4 100644 --- a/explorer/src/main/kotlin/com/r3corda/explorer/ui/TreeTableViewUtilities.kt +++ b/explorer/src/main/kotlin/com/r3corda/explorer/ui/TreeTableViewUtilities.kt @@ -47,3 +47,11 @@ fun Formatter.toTreeTableCellFactory() = Callback TreeTableView.singleRowSelection() = Bindings.createObjectBinding({ + if (selectionModel.selectedItems.size == 0) { + SingleRowSelection.None() + } else { + SingleRowSelection.Selected(selectionModel.selectedItems[0].value) + } +}, arrayOf(selectionModel.selectedItems)) diff --git a/explorer/src/main/kotlin/com/r3corda/explorer/views/CashViewer.kt b/explorer/src/main/kotlin/com/r3corda/explorer/views/CashViewer.kt index 05ff74d279..f6d2f8aa07 100644 --- a/explorer/src/main/kotlin/com/r3corda/explorer/views/CashViewer.kt +++ b/explorer/src/main/kotlin/com/r3corda/explorer/views/CashViewer.kt @@ -14,7 +14,9 @@ import com.r3corda.explorer.formatters.AmountFormatter import com.r3corda.explorer.formatters.NumberFormatter import com.r3corda.explorer.model.ReportingCurrencyModel import com.r3corda.explorer.model.SettingsModel +import com.r3corda.explorer.ui.SingleRowSelection import com.r3corda.explorer.ui.setColumnPrefWidthPolicy +import com.r3corda.explorer.ui.singleRowSelection import com.r3corda.explorer.ui.toTreeTableCellFactory import javafx.beans.binding.Bindings import javafx.beans.property.ReadOnlyObjectWrapper @@ -172,18 +174,7 @@ class CashViewer : View() { treeItem } - sealed class ViewerNodeSelection { - object None : ViewerNodeSelection() - class Selected(val node: ViewerNode) : ViewerNodeSelection() - } - - val selectedViewerNode = Bindings.createObjectBinding({ - if (cashViewerTable.selectionModel.selectedItems.size == 0) { - ViewerNodeSelection.None - } else { - ViewerNodeSelection.Selected(cashViewerTable.selectionModel.selectedItems[0].value) - } - }, arrayOf(cashViewerTable.selectionModel.selectedItems)) + val selectedViewerNode = cashViewerTable.singleRowSelection() data class StateRow ( val originated: LocalDateTime, @@ -221,10 +212,10 @@ class CashViewer : View() { } private val noSelectionStates = FXCollections.observableArrayList>() - private val selectedViewerNodeStates = ChosenList(EasyBind.map(selectedViewerNode) { selection -> + private val selectedViewerNodeStates = ChosenList>(EasyBind.map(selectedViewerNode) { selection -> when (selection) { - CashViewer.ViewerNodeSelection.None -> noSelectionStates - is CashViewer.ViewerNodeSelection.Selected -> + is SingleRowSelection.None -> noSelectionStates + is SingleRowSelection.Selected -> when (selection.node) { CashViewer.ViewerNode.Root -> noSelectionStates is CashViewer.ViewerNode.IssuerNode -> selection.node.states @@ -236,8 +227,8 @@ class CashViewer : View() { private val noSelectionSumEquiv = EasyBind.map(reportingCurrency) { Amount(0, it) } private val selectedViewerNodeSumEquiv = EasyBind.monadic(selectedViewerNode).flatMap { selection -> when (selection) { - ViewerNodeSelection.None -> noSelectionSumEquiv - is ViewerNodeSelection.Selected -> + is SingleRowSelection.None -> noSelectionSumEquiv + is SingleRowSelection.Selected -> when (selection.node) { ViewerNode.Root -> noSelectionSumEquiv is ViewerNode.IssuerNode -> selection.node.sumEquivAmount @@ -252,10 +243,10 @@ class CashViewer : View() { private val onlyLeftPaneShown = FXCollections.observableArrayList(leftPane) private val bothPanesShown = FXCollections.observableArrayList(leftPane, rightPane) - private val panesShown = ChosenList(EasyBind.map(selectedViewerNode) { + private val panesShown = ChosenList(EasyBind.map(selectedViewerNode) { when (it) { - CashViewer.ViewerNodeSelection.None -> onlyLeftPaneShown - is CashViewer.ViewerNodeSelection.Selected -> bothPanesShown + is SingleRowSelection.None -> onlyLeftPaneShown + is SingleRowSelection.Selected -> bothPanesShown } }) @@ -271,7 +262,7 @@ class CashViewer : View() { Bindings.bindContent(topSplitPane.items, panesShown) rightPane.visibleProperty().bind(EasyBind.map(selectedViewerNode) { - it != ViewerNodeSelection.None + it !is SingleRowSelection.None }) totalPositionsLabel.textProperty().bind(Bindings.createStringBinding({ diff --git a/explorer/src/main/kotlin/com/r3corda/explorer/views/TransactionViewer.kt b/explorer/src/main/kotlin/com/r3corda/explorer/views/TransactionViewer.kt index 1a1d04f1f2..b4499eb669 100644 --- a/explorer/src/main/kotlin/com/r3corda/explorer/views/TransactionViewer.kt +++ b/explorer/src/main/kotlin/com/r3corda/explorer/views/TransactionViewer.kt @@ -1,5 +1,6 @@ package com.r3corda.explorer.views +import com.r3corda.client.fxutils.ChosenList import com.r3corda.client.model.* import com.r3corda.contracts.asset.Cash import com.r3corda.core.contracts.Amount @@ -8,10 +9,15 @@ import com.r3corda.core.contracts.withoutIssuer import com.r3corda.core.transactions.SignedTransaction import com.r3corda.explorer.formatters.AmountFormatter import com.r3corda.explorer.model.ReportingCurrencyModel +import com.r3corda.explorer.ui.SingleRowSelection import com.r3corda.explorer.ui.setColumnPrefWidthPolicy +import com.r3corda.explorer.ui.singleRowSelection import com.r3corda.explorer.ui.toTableCellFactory +import com.r3corda.node.services.monitor.ServiceToClientEvent import javafx.beans.binding.Bindings +import javafx.beans.property.ReadOnlyObjectWrapper import javafx.beans.value.ObservableValue +import javafx.collections.FXCollections import javafx.collections.ObservableList import javafx.geometry.Insets import javafx.scene.control.Label @@ -31,6 +37,7 @@ import java.util.* class TransactionViewer: View() { override val root: VBox by fxml() + // Top half (transactions table) private val transactionViewTable: TableView by fxid("TransactionViewTable") private val transactionViewTransactionId: TableColumn by fxid("TransactionViewTransactionId") private val transactionViewOriginator: TableColumn by fxid("TransactionViewOriginator") @@ -39,6 +46,11 @@ class TransactionViewer: View() { private val transactionViewCommandTypes: TableColumn by fxid("TransactionViewCommandTypes") private val transactionViewTotalValueEquiv: TableColumn> by fxid("TransactionViewTotalValueEquiv") + // Bottom half (details) + private val lowLevelEventsTable: TableView by fxid("LowLevelEventsTable") + private val lowLevelEventsTimestamp: TableColumn by fxid("LowLevelEventsTimestamp") + private val lowLevelEventsEvent: TableColumn by fxid("LowLevelEventsEvent") + private val gatheredTransactionDataList: ObservableList by observableListReadOnly(GatheredTransactionDataModel::gatheredTransactionDataList) private val reportingExchange: ObservableValue) -> Amount>> @@ -51,7 +63,8 @@ class TransactionViewer: View() { val statusUpdated: ObservableValue, val commandTypes: ObservableValue>>, val viewTotalValueEquiv: ObservableValue?>, - val transaction: ObservableValue + val transaction: ObservableValue, + val allEvents: ObservableList ) private val viewerNodes = EasyBind.map(gatheredTransactionDataList) { @@ -78,7 +91,8 @@ class TransactionViewer: View() { viewTotalValueEquiv = EasyBind.combine(reportingExchange, it.transaction) { exchange, transaction -> transaction?.let { calculateTotalEquiv(exchange.first, exchange.second, transaction) } }, - transaction = it.transaction + transaction = it.transaction, + allEvents = it.allEvents ) } @@ -92,7 +106,18 @@ class TransactionViewer: View() { ) } + private val selectedViewerNode = transactionViewTable.singleRowSelection() + + private val noLowLevelEvents = FXCollections.emptyObservableList() + private val lowLevelEvents = ChosenList(EasyBind.map(selectedViewerNode) { + when (it) { + is SingleRowSelection.None -> noLowLevelEvents + is SingleRowSelection.Selected -> it.node.allEvents + } + }) + init { + // Transaction table Bindings.bindContent(transactionViewTable.items, viewerNodes) transactionViewTable.setColumnPrefWidthPolicy { tableWidthWithoutPaddingAndBorder, column -> @@ -146,5 +171,13 @@ class TransactionViewer: View() { } transactionViewTotalValueEquiv.setCellValueFactory> { it.value.viewTotalValueEquiv } transactionViewTotalValueEquiv.cellFactory = AmountFormatter.comma.toTableCellFactory() + + // Low level events + Bindings.bindContent(lowLevelEventsTable.items, lowLevelEvents) + lowLevelEventsTimestamp.setCellValueFactory { ReadOnlyObjectWrapper(it.value.time) } + lowLevelEventsEvent.setCellValueFactory { ReadOnlyObjectWrapper(it.value) } + lowLevelEventsTable.setColumnPrefWidthPolicy { tableWidthWithoutPaddingAndBorder, column -> + Math.floor(tableWidthWithoutPaddingAndBorder.toDouble() / lowLevelEventsTable.columns.size).toInt() + } } } diff --git a/explorer/src/main/resources/com/r3corda/explorer/views/TransactionViewer.fxml b/explorer/src/main/resources/com/r3corda/explorer/views/TransactionViewer.fxml index ed7bb9434b..3cecf1e2e4 100644 --- a/explorer/src/main/resources/com/r3corda/explorer/views/TransactionViewer.fxml +++ b/explorer/src/main/resources/com/r3corda/explorer/views/TransactionViewer.fxml @@ -32,7 +32,7 @@ - + @@ -156,6 +156,16 @@ + + + + + + + + + +