diff --git a/build.gradle b/build.gradle index 4bfe2a78..1ff9893c 100644 --- a/build.gradle +++ b/build.gradle @@ -28,6 +28,7 @@ dependencies { exclude group: 'org.hamcrest' exclude group: 'junit' } + implementation('com.google.guava:guava:28.2-jre') implementation('org.fxmisc.richtext:richtextfx:0.10.4') implementation('no.tornado:tornadofx-controls:1.0.4') implementation('org.controlsfx:controlsfx:11.0.1' ) { @@ -56,7 +57,7 @@ jlink { requires 'javafx.base'; } - options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages', '--ignore-signing-information'] + options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages', '--ignore-signing-information', '--exclude-files', '**.png'] launcher { name = 'sparrow' jvmArgs = ["--add-opens=javafx.graphics/com.sun.javafx.css=org.controlsfx.controls"] @@ -75,7 +76,6 @@ jlink { } if (org.gradle.internal.os.OperatingSystem.current().macOsX) { imageOptions += ['--icon', 'src/main/resources/sparrow.icns'] - installerType = "dmg" } } diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java index 4a895564..964119cf 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppController.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java @@ -1,18 +1,19 @@ package com.sparrowwallet.sparrow; +import com.google.common.eventbus.Subscribe; import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.drongo.psbt.PSBT; import com.sparrowwallet.drongo.psbt.PSBTParseException; +import com.sparrowwallet.sparrow.event.TabEvent; +import com.sparrowwallet.sparrow.event.TransactionTabChangedEvent; +import com.sparrowwallet.sparrow.event.TransactionTabSelectedEvent; import com.sparrowwallet.sparrow.transaction.TransactionController; -import com.sparrowwallet.sparrow.transaction.TransactionListener; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; -import javafx.scene.control.Alert; -import javafx.scene.control.Tab; -import javafx.scene.control.TabPane; +import javafx.scene.control.*; import javafx.stage.FileChooser; import javafx.stage.Stage; @@ -23,6 +24,10 @@ import java.net.URL; import java.util.ResourceBundle; public class AppController implements Initializable { + private static final String TRANSACTION_TAB_TYPE = "transaction"; + + @FXML + private CheckMenuItem showTxHex; @FXML private TabPane tabs; @@ -33,14 +38,15 @@ public class AppController implements Initializable { } void initializeView() { - tabs.getSelectionModel().selectedItemProperty().addListener((observable, old_val, new_val) -> { - String tabName = new_val.getText(); - if(tabs.getScene() != null) { - Stage tabStage = (Stage)tabs.getScene().getWindow(); - tabStage.setTitle("Sparrow - " + tabName); + tabs.getSelectionModel().selectedItemProperty().addListener((observable, old_val, selectedTab) -> { + String tabType = (String)selectedTab.getUserData(); + if(tabType.equals(TRANSACTION_TAB_TYPE)) { + EventManager.get().post(new TransactionTabSelectedEvent(selectedTab)); } }); + showTxHex.setSelected(true); + addExampleTxTabs(); } @@ -99,6 +105,11 @@ public class AppController implements Initializable { } } + public void showTxHex(ActionEvent event) { + CheckMenuItem item = (CheckMenuItem)event.getSource(); + EventManager.get().post(new TransactionTabChangedEvent(tabs.getSelectionModel().getSelectedItem(), item.isSelected())); + } + private void addExampleTxTabs() { addTransactionTab("p2pkh", "01000000019c2e0f24a03e72002a96acedb12a632e72b6b74c05dc3ceab1fe78237f886c48010000006a47304402203da9d487be5302a6d69e02a861acff1da472885e43d7528ed9b1b537a8e2cac9022002d1bca03a1e9715a99971bafe3b1852b7a4f0168281cbd27a220380a01b3307012102c9950c622494c2e9ff5a003e33b690fe4832477d32c2d256c67eab8bf613b34effffffff02b6f50500000000001976a914bdf63990d6dc33d705b756e13dd135466c06b3b588ac845e0201000000001976a9145fb0e9755a3424efd2ba0587d20b1e98ee29814a88ac06241559", null); addTransactionTab("p2sh", "0100000003a5ee1a0fd80dfbc3142df136ab56e082b799c13aa977c048bdf8f61bd158652c000000006b48304502203b0160de302cded63589a88214fe499a25aa1d86a2ea09129945cd632476a12c022100c77727daf0718307e184d55df620510cf96d4b5814ae3258519c0482c1ca82fa0121024f4102c1f1cf662bf99f2b034eb03edd4e6c96793cb9445ff519aab580649120ffffffff0fce901eb7b7551ba5f414735ff93b83a2a57403df11059ec88245fba2aaf1a0000000006a47304402204089adb8a1de1a9e22aa43b94d54f1e54dc9bea745d57df1a633e03dd9ede3c2022037d1e53e911ed7212186028f2e085f70524930e22eb6184af090ba4ab779a5b90121030644cb394bf381dbec91680bdf1be1986ad93cfb35603697353199fb285a119effffffff0fce901eb7b7551ba5f414735ff93b83a2a57403df11059ec88245fba2aaf1a0010000009300493046022100a07b2821f96658c938fa9c68950af0e69f3b2ce5f8258b3a6ad254d4bc73e11e022100e82fab8df3f7e7a28e91b3609f91e8ebf663af3a4dc2fd2abd954301a5da67e701475121022afc20bf379bc96a2f4e9e63ffceb8652b2b6a097f63fbee6ecec2a49a48010e2103a767c7221e9f15f870f1ad9311f5ab937d79fcaeee15bb2c722bca515581b4c052aeffffffff02a3b81b00000000001976a914ea00917f128f569cbdf79da5efcd9001671ab52c88ac80969800000000001976a9143dec0ead289be1afa8da127a7dbdd425a05e25f688ac00000000", null); @@ -131,6 +142,7 @@ public class AppController implements Initializable { private Tab addTransactionTab(String name, Transaction transaction, PSBT psbt) { try { Tab tab = new Tab(name); + tab.setUserData(TRANSACTION_TAB_TYPE); tab.setClosable(true); FXMLLoader transactionLoader = new FXMLLoader(getClass().getResource("transaction/transaction.fxml")); tab.setContent(transactionLoader.load()); @@ -148,4 +160,16 @@ public class AppController implements Initializable { throw new RuntimeException(e); } } + + @Subscribe + public void tabSelected(TabEvent event) { + Tab selectedTab = event.getTab(); + String tabType = (String)selectedTab.getUserData(); + + String tabName = selectedTab.getText(); + if(tabs.getScene() != null) { + Stage tabStage = (Stage)tabs.getScene().getWindow(); + tabStage.setTitle("Sparrow - " + tabName); + } + } } diff --git a/src/main/java/com/sparrowwallet/sparrow/EventManager.java b/src/main/java/com/sparrowwallet/sparrow/EventManager.java index e369f156..c6dcb74a 100644 --- a/src/main/java/com/sparrowwallet/sparrow/EventManager.java +++ b/src/main/java/com/sparrowwallet/sparrow/EventManager.java @@ -1,32 +1,13 @@ package com.sparrowwallet.sparrow; -import com.sparrowwallet.drongo.protocol.Transaction; -import com.sparrowwallet.sparrow.transaction.TransactionListener; - -import java.util.ArrayList; -import java.util.List; +import com.google.common.eventbus.EventBus; public class EventManager { - private List listenerList = new ArrayList<>(); - private static EventManager SINGLETON = new EventManager(); + private static EventBus SINGLETON = new EventBus(); private EventManager() {} - public void subscribe(TransactionListener listener) { - listenerList.add(listener); - } - - public void unsubscribe(TransactionListener listener) { - listenerList.remove(listener); - } - - public void notify(Transaction transaction) { - for (TransactionListener listener : listenerList) { - listener.updated(transaction); - } - } - - public static EventManager get() { + public static EventBus get() { return SINGLETON; } } diff --git a/src/main/java/com/sparrowwallet/sparrow/event/TabEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/TabEvent.java new file mode 100644 index 00000000..680c7203 --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/event/TabEvent.java @@ -0,0 +1,15 @@ +package com.sparrowwallet.sparrow.event; + +import javafx.scene.control.Tab; + +public class TabEvent { + private Tab tab; + + public TabEvent(Tab tab) { + this.tab = tab; + } + + public Tab getTab() { + return tab; + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/event/TransactionChangedEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/TransactionChangedEvent.java new file mode 100644 index 00000000..4b8b8dbb --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/event/TransactionChangedEvent.java @@ -0,0 +1,15 @@ +package com.sparrowwallet.sparrow.event; + +import com.sparrowwallet.drongo.protocol.Transaction; + +public class TransactionChangedEvent { + private Transaction transaction; + + public TransactionChangedEvent(Transaction transaction) { + this.transaction = transaction; + } + + public Transaction getTransaction() { + return transaction; + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/event/TransactionTabChangedEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/TransactionTabChangedEvent.java new file mode 100644 index 00000000..c14af158 --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/event/TransactionTabChangedEvent.java @@ -0,0 +1,16 @@ +package com.sparrowwallet.sparrow.event; + +import javafx.scene.control.Tab; + +public class TransactionTabChangedEvent extends TabEvent { + private boolean txHexVisible; + + public TransactionTabChangedEvent(Tab tab, boolean txHexVisible) { + super(tab); + this.txHexVisible = txHexVisible; + } + + public boolean isTxHexVisible() { + return txHexVisible; + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/event/TransactionTabSelectedEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/TransactionTabSelectedEvent.java new file mode 100644 index 00000000..1233e80d --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/event/TransactionTabSelectedEvent.java @@ -0,0 +1,9 @@ +package com.sparrowwallet.sparrow.event; + +import javafx.scene.control.Tab; + +public class TransactionTabSelectedEvent extends TabEvent { + public TransactionTabSelectedEvent(Tab tab) { + super(tab); + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java index 564a5165..16a97013 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java @@ -4,18 +4,20 @@ import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.control.IdLabel; import com.sparrowwallet.sparrow.control.CopyableLabel; +import com.sparrowwallet.sparrow.event.TransactionChangedEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.*; import tornadofx.control.DateTimePicker; import tornadofx.control.Field; import tornadofx.control.Fieldset; +import com.google.common.eventbus.Subscribe; import java.net.URL; import java.time.*; import java.util.ResourceBundle; -public class HeadersController extends TransactionFormController implements Initializable, TransactionListener { +public class HeadersController extends TransactionFormController implements Initializable { public static final String LOCKTIME_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; private HeadersForm headersForm; @@ -76,7 +78,7 @@ public class HeadersController extends TransactionFormController implements Init @Override public void initialize(URL location, ResourceBundle resources) { - EventManager.get().subscribe(this); + EventManager.get().register(this); } void setModel(HeadersForm form) { @@ -92,7 +94,7 @@ public class HeadersController extends TransactionFormController implements Init version.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 2, (int)tx.getVersion())); version.valueProperty().addListener((obs, oldValue, newValue) -> { tx.setVersion(newValue); - EventManager.get().notify(tx); + EventManager.get().post(new TransactionChangedEvent(tx)); }); String type = "Legacy"; @@ -113,7 +115,7 @@ public class HeadersController extends TransactionFormController implements Init locktimeFieldset.getChildren().remove(locktimeNoneField); locktimeFieldset.getChildren().add(locktimeNoneField); tx.setLocktime(0); - EventManager.get().notify(tx); + EventManager.get().post(new TransactionChangedEvent(tx)); } else if(selection.equals("block")) { locktimeFieldset.getChildren().remove(locktimeDateField); locktimeFieldset.getChildren().remove(locktimeBlockField); @@ -122,7 +124,7 @@ public class HeadersController extends TransactionFormController implements Init Integer block = locktimeBlock.getValue(); if(block != null) { tx.setLocktime(block); - EventManager.get().notify(tx); + EventManager.get().post(new TransactionChangedEvent(tx)); } } else { locktimeFieldset.getChildren().remove(locktimeBlockField); @@ -133,7 +135,7 @@ public class HeadersController extends TransactionFormController implements Init if(date != null) { locktimeDate.setDateTimeValue(date); tx.setLocktime(date.toEpochSecond(OffsetDateTime.now(ZoneId.systemDefault()).getOffset())); - EventManager.get().notify(tx); + EventManager.get().post(new TransactionChangedEvent(tx)); } } } @@ -158,13 +160,13 @@ public class HeadersController extends TransactionFormController implements Init locktimeBlock.valueProperty().addListener((obs, oldValue, newValue) -> { tx.setLocktime(newValue); - EventManager.get().notify(tx); + EventManager.get().post(new TransactionChangedEvent(tx)); }); locktimeDate.setFormat(LOCKTIME_DATE_FORMAT); locktimeDate.dateTimeValueProperty().addListener((obs, oldValue, newValue) -> { tx.setLocktime(newValue.toEpochSecond(OffsetDateTime.now(ZoneId.systemDefault()).getOffset())); - EventManager.get().notify(tx); + EventManager.get().post(new TransactionChangedEvent(tx)); }); size.setText(tx.getSize() + " B"); @@ -188,15 +190,16 @@ public class HeadersController extends TransactionFormController implements Init id.setText(headersForm.getTransaction().calculateTxId(false).toString()); } - @Override - public void updated(Transaction transaction) { - updateTxId(); - - boolean locktimeEnabled = headersForm.getTransaction().isLocktimeSequenceEnabled(); - locktimeNoneType.setDisable(!locktimeEnabled); - locktimeBlockType.setDisable(!locktimeEnabled); - locktimeBlock.setDisable(!locktimeEnabled); - locktimeDateType.setDisable(!locktimeEnabled); - locktimeDate.setDisable(!locktimeEnabled); + @Subscribe + public void transactionChanged(TransactionChangedEvent event) { + if(headersForm.getTransaction().equals(event.getTransaction())) { + updateTxId(); + boolean locktimeEnabled = headersForm.getTransaction().isLocktimeSequenceEnabled(); + locktimeNoneType.setDisable(!locktimeEnabled); + locktimeBlockType.setDisable(!locktimeEnabled); + locktimeBlock.setDisable(!locktimeEnabled); + locktimeDateType.setDisable(!locktimeEnabled); + locktimeDate.setDisable(!locktimeEnabled); + } } } diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/InputController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/InputController.java index cf1250f2..c7b1c065 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/InputController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/InputController.java @@ -9,6 +9,7 @@ import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.control.IdLabel; import com.sparrowwallet.sparrow.control.CopyableLabel; import com.sparrowwallet.sparrow.control.RelativeTimelockSpinner; +import com.sparrowwallet.sparrow.event.TransactionChangedEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.*; @@ -243,12 +244,12 @@ public class InputController extends TransactionFormController implements Initia locktimeToggleGroup.selectToggle(locktimeAbsoluteType); } else if(txInput.isAbsoluteTimeLocked()) { txInput.setSequenceNumber(TransactionInput.SEQUENCE_RBF_ENABLED); - EventManager.get().notify(transaction); + EventManager.get().post(new TransactionChangedEvent(transaction)); } } else { if(txInput.isAbsoluteTimeLocked()) { txInput.setSequenceNumber(TransactionInput.SEQUENCE_LOCKTIME_DISABLED - 1); - EventManager.get().notify(transaction); + EventManager.get().post(new TransactionChangedEvent(transaction)); } else if(txInput.isRelativeTimeLocked()) { locktimeToggleGroup.selectToggle(locktimeAbsoluteType); } @@ -268,7 +269,7 @@ public class InputController extends TransactionFormController implements Initia locktimeAbsoluteField.setDisable(true); txInput.setSequenceNumber(TransactionInput.SEQUENCE_LOCKTIME_DISABLED); rbf.setSelected(false); - EventManager.get().notify(transaction); + EventManager.get().post(new TransactionChangedEvent(transaction)); } else if(selection.equals("absolute")) { locktimeFieldset.getChildren().removeAll(locktimeRelativeField, locktimeAbsoluteField); locktimeFieldset.getChildren().add(locktimeAbsoluteField); @@ -279,7 +280,7 @@ public class InputController extends TransactionFormController implements Initia } else { txInput.setSequenceNumber(TransactionInput.SEQUENCE_LOCKTIME_DISABLED - 1); } - EventManager.get().notify(transaction); + EventManager.get().post(new TransactionChangedEvent(transaction)); } else { locktimeFieldset.getChildren().removeAll(locktimeRelativeField, locktimeAbsoluteField); locktimeFieldset.getChildren().add(locktimeRelativeField); @@ -348,7 +349,7 @@ public class InputController extends TransactionFormController implements Initia long value = locktimeRelativeSeconds.getValue().toSeconds() / TransactionInput.RELATIVE_TIMELOCK_SECONDS_INCREMENT; txInput.setSequenceNumber((value & TransactionInput.RELATIVE_TIMELOCK_VALUE_MASK) | TransactionInput.RELATIVE_TIMELOCK_TYPE_FLAG); } - EventManager.get().notify(transaction); + EventManager.get().post(new TransactionChangedEvent(transaction)); } public void setModel(InputForm form) { diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/TransactionController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/TransactionController.java index 4582fc43..9b99d2ae 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/TransactionController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/TransactionController.java @@ -1,11 +1,15 @@ package com.sparrowwallet.sparrow.transaction; +import com.google.common.eventbus.Subscribe; import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.protocol.*; import com.sparrowwallet.drongo.psbt.PSBT; import com.sparrowwallet.drongo.psbt.PSBTInput; import com.sparrowwallet.drongo.psbt.PSBTOutput; import com.sparrowwallet.sparrow.EventManager; +import com.sparrowwallet.sparrow.event.TransactionChangedEvent; +import com.sparrowwallet.sparrow.event.TransactionTabChangedEvent; +import com.sparrowwallet.sparrow.event.TransactionTabSelectedEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.Node; @@ -15,6 +19,7 @@ import javafx.scene.control.TreeView; import javafx.scene.control.cell.TextFieldTreeCell; import javafx.scene.layout.Pane; import javafx.util.StringConverter; +import org.controlsfx.control.MasterDetailPane; import org.fxmisc.richtext.CodeArea; import java.io.ByteArrayOutputStream; @@ -22,7 +27,13 @@ import java.io.IOException; import java.net.URL; import java.util.ResourceBundle; -public class TransactionController implements Initializable, TransactionListener { +public class TransactionController implements Initializable { + + @FXML + private Node tabContent; + + @FXML + private MasterDetailPane transactionMasterDetail; @FXML private TreeView txtree; @@ -40,7 +51,7 @@ public class TransactionController implements Initializable, TransactionListener @Override public void initialize(URL location, ResourceBundle resources) { - EventManager.get().subscribe(this); + EventManager.get().register(this); } private void initializeView() { @@ -56,9 +67,9 @@ public class TransactionController implements Initializable, TransactionListener InputsForm inputsForm = (psbt == null ? new InputsForm(transaction) : new InputsForm(psbt)); TreeItem inputsItem = new TreeItem<>(inputsForm); inputsItem.setExpanded(true); - for(TransactionInput txInput : transaction.getInputs()) { + for (TransactionInput txInput : transaction.getInputs()) { PSBTInput psbtInput = null; - if(psbt != null && psbt.getPsbtInputs().size() > txInput.getIndex()) { + if (psbt != null && psbt.getPsbtInputs().size() > txInput.getIndex()) { psbtInput = psbt.getPsbtInputs().get(txInput.getIndex()); } InputForm inputForm = (psbt == null ? new InputForm(transaction, txInput) : new InputForm(psbt, psbtInput)); @@ -69,9 +80,9 @@ public class TransactionController implements Initializable, TransactionListener OutputsForm outputsForm = (psbt == null ? new OutputsForm(transaction) : new OutputsForm(psbt)); TreeItem outputsItem = new TreeItem<>(outputsForm); outputsItem.setExpanded(true); - for(TransactionOutput txOutput : transaction.getOutputs()) { + for (TransactionOutput txOutput : transaction.getOutputs()) { PSBTOutput psbtOutput = null; - if(psbt != null && psbt.getPsbtOutputs().size() > txOutput.getIndex()) { + if (psbt != null && psbt.getPsbtOutputs().size() > txOutput.getIndex()) { psbtOutput = psbt.getPsbtOutputs().get(txOutput.getIndex()); } OutputForm outputForm = (psbt == null ? new OutputForm(transaction, txOutput) : new OutputForm(psbt, psbtOutput)); @@ -83,7 +94,7 @@ public class TransactionController implements Initializable, TransactionListener rootItem.getChildren().add(outputsItem); txtree.setRoot(rootItem); - txtree.setCellFactory(p -> new TextFieldTreeCell<>(new StringConverter(){ + txtree.setCellFactory(p -> new TextFieldTreeCell<>(new StringConverter() { @Override public String toString(TransactionForm transactionForm) { return transactionForm.toString(); @@ -102,18 +113,18 @@ public class TransactionController implements Initializable, TransactionListener txpane.getChildren().clear(); txpane.getChildren().add(node); - if(node instanceof Parent) { - Parent parent = (Parent)node; + if (node instanceof Parent) { + Parent parent = (Parent) node; txhex.getStylesheets().clear(); txhex.getStylesheets().addAll(parent.getStylesheets()); selectedInputIndex = -1; selectedOutputIndex = -1; - if(transactionForm instanceof InputForm) { - InputForm inputForm = (InputForm)transactionForm; + if (transactionForm instanceof InputForm) { + InputForm inputForm = (InputForm) transactionForm; selectedInputIndex = inputForm.getTransactionInput().getIndex(); - } else if(transactionForm instanceof OutputForm) { - OutputForm outputForm = (OutputForm)transactionForm; + } else if (transactionForm instanceof OutputForm) { + OutputForm outputForm = (OutputForm) transactionForm; selectedOutputIndex = outputForm.getTransactionOutput().getIndex(); } @@ -135,7 +146,7 @@ public class TransactionController implements Initializable, TransactionListener ByteArrayOutputStream baos = new ByteArrayOutputStream(); transaction.bitcoinSerializeToStream(baos); hex = Utils.bytesToHex(baos.toByteArray()); - } catch(IOException e) { + } catch (IOException e) { throw new IllegalStateException("Can't happen"); } @@ -144,7 +155,7 @@ public class TransactionController implements Initializable, TransactionListener //Version cursor = addText(hex, cursor, 8, "version"); - if(transaction.hasWitnesses()) { + if (transaction.hasWitnesses()) { //Segwit marker cursor = addText(hex, cursor, 2, "segwit-marker"); //Segwit flag @@ -153,43 +164,43 @@ public class TransactionController implements Initializable, TransactionListener //Number of inputs VarInt numInputs = new VarInt(transaction.getInputs().size()); - cursor = addText(hex, cursor, numInputs.getSizeInBytes()*2, "num-inputs"); + cursor = addText(hex, cursor, numInputs.getSizeInBytes() * 2, "num-inputs"); //Inputs for (int i = 0; i < transaction.getInputs().size(); i++) { TransactionInput input = transaction.getInputs().get(i); - cursor = addText(hex, cursor, 32*2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "hash")); - cursor = addText(hex, cursor, 4*2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "index")); + cursor = addText(hex, cursor, 32 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "hash")); + cursor = addText(hex, cursor, 4 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "index")); VarInt scriptLen = new VarInt(input.getScriptBytes().length); - cursor = addText(hex, cursor, scriptLen.getSizeInBytes()*2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "sigscript-length")); - cursor = addText(hex, cursor, (int)scriptLen.value*2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "sigscript")); - cursor = addText(hex, cursor, 4*2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "sequence")); + cursor = addText(hex, cursor, scriptLen.getSizeInBytes() * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "sigscript-length")); + cursor = addText(hex, cursor, (int) scriptLen.value * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "sigscript")); + cursor = addText(hex, cursor, 4 * 2, "input-" + getIndexedStyleClass(i, selectedInputIndex, "sequence")); } //Number of outputs VarInt numOutputs = new VarInt(transaction.getOutputs().size()); - cursor = addText(hex, cursor, numOutputs.getSizeInBytes()*2, "num-outputs"); + cursor = addText(hex, cursor, numOutputs.getSizeInBytes() * 2, "num-outputs"); //Outputs for (int i = 0; i < transaction.getOutputs().size(); i++) { TransactionOutput output = transaction.getOutputs().get(i); - cursor = addText(hex, cursor, 8*2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "value")); + cursor = addText(hex, cursor, 8 * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "value")); VarInt scriptLen = new VarInt(output.getScriptBytes().length); - cursor = addText(hex, cursor, scriptLen.getSizeInBytes()*2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "pubkeyscript-length")); - cursor = addText(hex, cursor, (int)scriptLen.value*2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "pubkeyscript")); + cursor = addText(hex, cursor, scriptLen.getSizeInBytes() * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "pubkeyscript-length")); + cursor = addText(hex, cursor, (int) scriptLen.value * 2, "output-" + getIndexedStyleClass(i, selectedOutputIndex, "pubkeyscript")); } - if(transaction.hasWitnesses()) { + if (transaction.hasWitnesses()) { for (int i = 0; i < transaction.getInputs().size(); i++) { TransactionInput input = transaction.getInputs().get(i); - if(input.hasWitness()) { + if (input.hasWitness()) { TransactionWitness witness = input.getWitness(); VarInt witnessCount = new VarInt(witness.getPushCount()); - cursor = addText(hex, cursor, witnessCount.getSizeInBytes()*2, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "count")); - for(byte[] push : witness.getPushes()) { + cursor = addText(hex, cursor, witnessCount.getSizeInBytes() * 2, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "count")); + for (byte[] push : witness.getPushes()) { VarInt witnessLen = new VarInt(push.length); - cursor = addText(hex, cursor, witnessLen.getSizeInBytes()*2, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "length")); - cursor = addText(hex, cursor, (int)witnessLen.value*2, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "data")); + cursor = addText(hex, cursor, witnessLen.getSizeInBytes() * 2, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "length")); + cursor = addText(hex, cursor, (int) witnessLen.value * 2, "witness-" + getIndexedStyleClass(i, selectedInputIndex, "data")); } } } @@ -198,13 +209,13 @@ public class TransactionController implements Initializable, TransactionListener //Locktime cursor = addText(hex, cursor, 8, "locktime"); - if(cursor != hex.length()) { + if (cursor != hex.length()) { throw new IllegalStateException("Cursor position does not match transaction serialisation " + cursor + ": " + hex.length()); } } private String getIndexedStyleClass(int iterableIndex, int selectedIndex, String styleClass) { - if(selectedIndex == -1 || selectedIndex == iterableIndex) { + if (selectedIndex == -1 || selectedIndex == iterableIndex) { return styleClass; } @@ -212,7 +223,7 @@ public class TransactionController implements Initializable, TransactionListener } private int addText(String hex, int cursor, int length, String styleClass) { - txhex.append(hex.substring(cursor, cursor+=length), styleClass); + txhex.append(hex.substring(cursor, cursor += length), styleClass); return cursor; } @@ -229,9 +240,21 @@ public class TransactionController implements Initializable, TransactionListener initializeView(); } - @Override - public void updated(Transaction transaction) { - refreshTxHex(); - txtree.refresh(); + @Subscribe + public void transactionChanged(TransactionChangedEvent event) { + if (event.getTransaction().equals(transaction)) { + refreshTxHex(); + txtree.refresh(); + } + } + + @Subscribe + public void tabSelected(TransactionTabSelectedEvent event) { + + } + + @Subscribe + public void tabChanged(TransactionTabChangedEvent event) { + transactionMasterDetail.setShowDetailNode(event.isTxHexVisible()); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/TransactionListener.java b/src/main/java/com/sparrowwallet/sparrow/transaction/TransactionListener.java deleted file mode 100644 index 9106b724..00000000 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/TransactionListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.sparrowwallet.sparrow.transaction; - -import com.sparrowwallet.drongo.protocol.Transaction; - -public interface TransactionListener { - void updated(Transaction transaction); -} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 5011b334..5bd4b964 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -6,5 +6,6 @@ open module com.sparrowwallet.sparrow { requires org.fxmisc.richtext; requires tornadofx.controls; requires com.sparrowwallet.drongo; + requires com.google.common; requires flowless; } \ No newline at end of file diff --git a/src/main/resources/com/sparrowwallet/sparrow/app.fxml b/src/main/resources/com/sparrowwallet/sparrow/app.fxml index 6a34319f..a9fa5323 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/app.fxml +++ b/src/main/resources/com/sparrowwallet/sparrow/app.fxml @@ -2,6 +2,7 @@ + @@ -18,6 +19,11 @@ + + + + + @@ -27,6 +33,6 @@ -