mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 05:06:45 +00:00
address table improvements
This commit is contained in:
parent
70c4eeaf5e
commit
936d42e7fd
5 changed files with 146 additions and 125 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
||||||
Subproject commit fa30f37e235d20e66fc5864a54f1100540ccbb51
|
Subproject commit 0d56692784f5dfc50197533eb00ccf8e5c42e471
|
|
@ -102,7 +102,7 @@ public class AppController implements Initializable {
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
if(db.hasFiles()) {
|
if(db.hasFiles()) {
|
||||||
for(File file : db.getFiles()) {
|
for(File file : db.getFiles()) {
|
||||||
openFile(file);
|
openTransactionFile(file);
|
||||||
}
|
}
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
|
@ -160,6 +160,8 @@ public class AppController implements Initializable {
|
||||||
if(config.getMode() == Mode.ONLINE && config.getElectrumServer() != null && !config.getElectrumServer().isEmpty()) {
|
if(config.getMode() == Mode.ONLINE && config.getElectrumServer() != null && !config.getElectrumServer().isEmpty()) {
|
||||||
connectionService.start();
|
connectionService.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openWalletFile(new File("/Users/scy/.sparrow/wallets/sparta.json"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ElectrumServer.ConnectionService createConnectionService() {
|
private ElectrumServer.ConnectionService createConnectionService() {
|
||||||
|
@ -202,7 +204,7 @@ public class AppController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openFromFile(ActionEvent event) {
|
public void openTransactionFromFile(ActionEvent event) {
|
||||||
Stage window = new Stage();
|
Stage window = new Stage();
|
||||||
|
|
||||||
FileChooser fileChooser = new FileChooser();
|
FileChooser fileChooser = new FileChooser();
|
||||||
|
@ -215,11 +217,11 @@ public class AppController implements Initializable {
|
||||||
|
|
||||||
File file = fileChooser.showOpenDialog(window);
|
File file = fileChooser.showOpenDialog(window);
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
openFile(file);
|
openTransactionFile(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openFile(File file) {
|
private void openTransactionFile(File file) {
|
||||||
for(Tab tab : tabs.getTabs()) {
|
for(Tab tab : tabs.getTabs()) {
|
||||||
TabData tabData = (TabData)tab.getUserData();
|
TabData tabData = (TabData)tab.getUserData();
|
||||||
if(file.equals(tabData.getFile())) {
|
if(file.equals(tabData.getFile())) {
|
||||||
|
@ -266,7 +268,7 @@ public class AppController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openFromText(ActionEvent event) {
|
public void openTransactionFromText(ActionEvent event) {
|
||||||
TextAreaDialog dialog = new TextAreaDialog();
|
TextAreaDialog dialog = new TextAreaDialog();
|
||||||
dialog.setTitle("Open from text");
|
dialog.setTitle("Open from text");
|
||||||
dialog.getDialogPane().setHeaderText("Paste a transaction or PSBT:");
|
dialog.getDialogPane().setHeaderText("Paste a transaction or PSBT:");
|
||||||
|
@ -325,6 +327,11 @@ public class AppController implements Initializable {
|
||||||
|
|
||||||
File file = fileChooser.showOpenDialog(window);
|
File file = fileChooser.showOpenDialog(window);
|
||||||
if(file != null) {
|
if(file != null) {
|
||||||
|
openWalletFile(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openWalletFile(File file) {
|
||||||
try {
|
try {
|
||||||
Storage storage = new Storage(file);
|
Storage storage = new Storage(file);
|
||||||
FileType fileType = IOUtils.getFileType(file);
|
FileType fileType = IOUtils.getFileType(file);
|
||||||
|
@ -374,7 +381,6 @@ public class AppController implements Initializable {
|
||||||
showErrorDialog("Error Opening Wallet", e.getMessage());
|
showErrorDialog("Error Opening Wallet", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void restorePublicKeysFromSeed(Wallet wallet, Key key) throws MnemonicException {
|
private void restorePublicKeysFromSeed(Wallet wallet, Key key) throws MnemonicException {
|
||||||
if(wallet.containsSeeds()) {
|
if(wallet.containsSeeds()) {
|
||||||
|
|
|
@ -19,7 +19,8 @@ import javafx.scene.control.*;
|
||||||
import javafx.scene.control.cell.TextFieldTreeTableCell;
|
import javafx.scene.control.cell.TextFieldTreeTableCell;
|
||||||
import javafx.scene.input.Clipboard;
|
import javafx.scene.input.Clipboard;
|
||||||
import javafx.scene.input.ClipboardContent;
|
import javafx.scene.input.ClipboardContent;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.input.MouseButton;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
import javafx.scene.text.Font;
|
import javafx.scene.text.Font;
|
||||||
import javafx.util.converter.DefaultStringConverter;
|
import javafx.util.converter.DefaultStringConverter;
|
||||||
import org.controlsfx.glyphfont.FontAwesome;
|
import org.controlsfx.glyphfont.FontAwesome;
|
||||||
|
@ -67,16 +68,26 @@ public class AddressTreeTable extends TreeTableView<Entry> {
|
||||||
amountCol.setSortable(false);
|
amountCol.setSortable(false);
|
||||||
getColumns().add(amountCol);
|
getColumns().add(amountCol);
|
||||||
|
|
||||||
TreeTableColumn<Entry, Entry> actionCol = new TreeTableColumn<>("Actions");
|
|
||||||
actionCol.setCellValueFactory((TreeTableColumn.CellDataFeatures<Entry, Entry> param) -> {
|
|
||||||
return new ReadOnlyObjectWrapper<>(param.getValue().getValue());
|
|
||||||
});
|
|
||||||
actionCol.setCellFactory(p -> new ActionCell());
|
|
||||||
actionCol.setSortable(false);
|
|
||||||
getColumns().add(actionCol);
|
|
||||||
|
|
||||||
setEditable(true);
|
setEditable(true);
|
||||||
setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY);
|
setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
|
|
||||||
|
scrollTo(rootEntry.getNode().getHighestUsedIndex());
|
||||||
|
|
||||||
|
setOnMouseClicked(mouseEvent -> {
|
||||||
|
if(mouseEvent.getButton().equals(MouseButton.PRIMARY)){
|
||||||
|
if(mouseEvent.getClickCount() == 2) {
|
||||||
|
TreeItem<Entry> treeItem = getSelectionModel().getSelectedItem();
|
||||||
|
if(treeItem != null && treeItem.getChildren().isEmpty()) {
|
||||||
|
Entry entry = getSelectionModel().getSelectedItem().getValue();
|
||||||
|
if(entry instanceof NodeEntry) {
|
||||||
|
NodeEntry nodeEntry = (NodeEntry)entry;
|
||||||
|
EventManager.get().post(new ReceiveActionEvent(nodeEntry));
|
||||||
|
Platform.runLater(() -> EventManager.get().post(new ReceiveToEvent(nodeEntry)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void applyRowStyles(TreeTableCell<?, ?> cell, Entry entry) {
|
private static void applyRowStyles(TreeTableCell<?, ?> cell, Entry entry) {
|
||||||
|
@ -100,6 +111,9 @@ public class AddressTreeTable extends TreeTableView<Entry> {
|
||||||
private static class DataCell extends TreeTableCell<Entry, Entry> {
|
private static class DataCell extends TreeTableCell<Entry, Entry> {
|
||||||
public DataCell() {
|
public DataCell() {
|
||||||
super();
|
super();
|
||||||
|
setAlignment(Pos.CENTER_LEFT);
|
||||||
|
setContentDisplay(ContentDisplay.RIGHT);
|
||||||
|
getStyleClass().add("data-cell");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -117,8 +131,21 @@ public class AddressTreeTable extends TreeTableView<Entry> {
|
||||||
NodeEntry nodeEntry = (NodeEntry)entry;
|
NodeEntry nodeEntry = (NodeEntry)entry;
|
||||||
Address address = nodeEntry.getAddress();
|
Address address = nodeEntry.getAddress();
|
||||||
setText(address.toString());
|
setText(address.toString());
|
||||||
setContextMenu(new AddressContextMenu(address));
|
setContextMenu(new AddressContextMenu(address, nodeEntry.getOutputDescriptor()));
|
||||||
|
Tooltip tooltip = new Tooltip();
|
||||||
|
tooltip.setText(nodeEntry.getNode().getDerivationPath());
|
||||||
|
setTooltip(tooltip);
|
||||||
getStyleClass().add("address-cell");
|
getStyleClass().add("address-cell");
|
||||||
|
|
||||||
|
Button receiveButton = new Button("");
|
||||||
|
Glyph receiveGlyph = new Glyph("FontAwesome", FontAwesome.Glyph.ARROW_DOWN);
|
||||||
|
receiveGlyph.setFontSize(12);
|
||||||
|
receiveButton.setGraphic(receiveGlyph);
|
||||||
|
receiveButton.setOnAction(event -> {
|
||||||
|
EventManager.get().post(new ReceiveActionEvent(nodeEntry));
|
||||||
|
Platform.runLater(() -> EventManager.get().post(new ReceiveToEvent(nodeEntry)));
|
||||||
|
});
|
||||||
|
setGraphic(receiveButton);
|
||||||
} else if(entry instanceof HashIndexEntry) {
|
} else if(entry instanceof HashIndexEntry) {
|
||||||
HashIndexEntry hashIndexEntry = (HashIndexEntry)entry;
|
HashIndexEntry hashIndexEntry = (HashIndexEntry)entry;
|
||||||
setText(hashIndexEntry.getDescription());
|
setText(hashIndexEntry.getDescription());
|
||||||
|
@ -126,13 +153,22 @@ public class AddressTreeTable extends TreeTableView<Entry> {
|
||||||
Tooltip tooltip = new Tooltip();
|
Tooltip tooltip = new Tooltip();
|
||||||
tooltip.setText(hashIndexEntry.getHashIndex().toString());
|
tooltip.setText(hashIndexEntry.getHashIndex().toString());
|
||||||
setTooltip(tooltip);
|
setTooltip(tooltip);
|
||||||
|
|
||||||
|
Button viewTransactionButton = new Button("");
|
||||||
|
Glyph searchGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.SEARCH);
|
||||||
|
searchGlyph.setFontSize(12);
|
||||||
|
viewTransactionButton.setGraphic(searchGlyph);
|
||||||
|
viewTransactionButton.setOnAction(event -> {
|
||||||
|
EventManager.get().post(new TransactionViewEvent(hashIndexEntry.getBlockTransaction(), hashIndexEntry));
|
||||||
|
});
|
||||||
|
setGraphic(viewTransactionButton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class AddressContextMenu extends ContextMenu {
|
private static class AddressContextMenu extends ContextMenu {
|
||||||
public AddressContextMenu(Address address) {
|
public AddressContextMenu(Address address, String outputDescriptor) {
|
||||||
MenuItem copyAddress = new MenuItem("Copy Address");
|
MenuItem copyAddress = new MenuItem("Copy Address");
|
||||||
copyAddress.setOnAction(AE -> {
|
copyAddress.setOnAction(AE -> {
|
||||||
hide();
|
hide();
|
||||||
|
@ -149,7 +185,15 @@ public class AddressTreeTable extends TreeTableView<Entry> {
|
||||||
Clipboard.getSystemClipboard().setContent(content);
|
Clipboard.getSystemClipboard().setContent(content);
|
||||||
});
|
});
|
||||||
|
|
||||||
getItems().addAll(copyAddress, copyHex);
|
MenuItem copyOutputDescriptor = new MenuItem("Copy Output Descriptor");
|
||||||
|
copyOutputDescriptor.setOnAction(AE -> {
|
||||||
|
hide();
|
||||||
|
ClipboardContent content = new ClipboardContent();
|
||||||
|
content.putString(outputDescriptor);
|
||||||
|
Clipboard.getSystemClipboard().setContent(content);
|
||||||
|
});
|
||||||
|
|
||||||
|
getItems().addAll(copyAddress, copyHex, copyOutputDescriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,6 +292,7 @@ public class AddressTreeTable extends TreeTableView<Entry> {
|
||||||
public AmountCell() {
|
public AmountCell() {
|
||||||
super();
|
super();
|
||||||
getStyleClass().add("amount-cell");
|
getStyleClass().add("amount-cell");
|
||||||
|
setContentDisplay(ContentDisplay.RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -263,6 +308,19 @@ public class AddressTreeTable extends TreeTableView<Entry> {
|
||||||
String satsValue = String.format(Locale.ENGLISH, "%,d", amount);
|
String satsValue = String.format(Locale.ENGLISH, "%,d", amount);
|
||||||
String btcValue = CoinLabel.getBTCFormat().format(amount.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC";
|
String btcValue = CoinLabel.getBTCFormat().format(amount.doubleValue() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC";
|
||||||
|
|
||||||
|
Entry entry = getTreeTableView().getTreeItem(getIndex()).getValue();
|
||||||
|
if(entry instanceof HashIndexEntry) {
|
||||||
|
Region node = new Region();
|
||||||
|
node.setPrefWidth(10);
|
||||||
|
setGraphic(node);
|
||||||
|
|
||||||
|
if(((HashIndexEntry) entry).getType() == HashIndexEntry.Type.INPUT) {
|
||||||
|
satsValue = "-" + satsValue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setGraphic(null);
|
||||||
|
}
|
||||||
|
|
||||||
Tooltip tooltip = new Tooltip();
|
Tooltip tooltip = new Tooltip();
|
||||||
tooltip.setText(btcValue);
|
tooltip.setText(btcValue);
|
||||||
|
|
||||||
|
@ -271,57 +329,4 @@ public class AddressTreeTable extends TreeTableView<Entry> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ActionCell extends TreeTableCell<Entry, Entry> {
|
|
||||||
private final HBox actionBox;
|
|
||||||
private final Button receiveButton;
|
|
||||||
private final Button viewTransactionButton;
|
|
||||||
|
|
||||||
public ActionCell() {
|
|
||||||
super();
|
|
||||||
getStyleClass().add("action-cell");
|
|
||||||
|
|
||||||
actionBox = new HBox();
|
|
||||||
actionBox.setSpacing(8);
|
|
||||||
actionBox.setAlignment(Pos.CENTER);
|
|
||||||
|
|
||||||
receiveButton = new Button("");
|
|
||||||
Glyph receiveGlyph = new Glyph("FontAwesome", FontAwesome.Glyph.ARROW_DOWN);
|
|
||||||
receiveGlyph.setFontSize(12);
|
|
||||||
receiveButton.setGraphic(receiveGlyph);
|
|
||||||
receiveButton.setOnAction(event -> {
|
|
||||||
NodeEntry nodeEntry = (NodeEntry)getTreeTableView().getTreeItem(getIndex()).getValue();
|
|
||||||
EventManager.get().post(new ReceiveActionEvent(nodeEntry));
|
|
||||||
Platform.runLater(() -> EventManager.get().post(new ReceiveToEvent(nodeEntry)));
|
|
||||||
});
|
|
||||||
|
|
||||||
viewTransactionButton = new Button("");
|
|
||||||
Glyph searchGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.SEARCH);
|
|
||||||
searchGlyph.setFontSize(12);
|
|
||||||
viewTransactionButton.setGraphic(searchGlyph);
|
|
||||||
viewTransactionButton.setOnAction(event -> {
|
|
||||||
HashIndexEntry hashIndexEntry = (HashIndexEntry)getTreeTableView().getTreeItem(getIndex()).getValue();
|
|
||||||
EventManager.get().post(new TransactionViewEvent(hashIndexEntry.getBlockTransaction(), hashIndexEntry));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void updateItem(Entry entry, boolean empty) {
|
|
||||||
super.updateItem(entry, empty);
|
|
||||||
if (empty) {
|
|
||||||
setGraphic(null);
|
|
||||||
} else {
|
|
||||||
applyRowStyles(this, getTreeTableView().getTreeItem(getIndex()).getValue());
|
|
||||||
|
|
||||||
actionBox.getChildren().remove(0, actionBox.getChildren().size());
|
|
||||||
if(entry instanceof NodeEntry) {
|
|
||||||
actionBox.getChildren().add(receiveButton);
|
|
||||||
} else if(entry instanceof HashIndexEntry) {
|
|
||||||
actionBox.getChildren().add(viewTransactionButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
setGraphic(actionBox);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
<MenuItem mnemonicParsing="false" text="Open Wallet..." onAction="#openWallet"/>
|
<MenuItem mnemonicParsing="false" text="Open Wallet..." onAction="#openWallet"/>
|
||||||
<Menu mnemonicParsing="false" text="Open Transaction">
|
<Menu mnemonicParsing="false" text="Open Transaction">
|
||||||
<items>
|
<items>
|
||||||
<MenuItem text="File..." onAction="#openFromFile"/>
|
<MenuItem text="File..." onAction="#openTransactionFromFile"/>
|
||||||
<MenuItem text="From Text..." onAction="#openFromText"/>
|
<MenuItem text="From Text..." onAction="#openTransactionFromText"/>
|
||||||
<MenuItem text="Examples" onAction="#openExamples"/>
|
<MenuItem text="Examples" onAction="#openExamples"/>
|
||||||
</items>
|
</items>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
|
@ -9,15 +9,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.hashindex-row {
|
.hashindex-row {
|
||||||
-fx-background-color: #fafafa;
|
-fx-text-fill: #696c77;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hashindex-row .text {
|
.hashindex-row.spent {
|
||||||
-fx-fill: #696c77;
|
-fx-text-fill: #a0a1a7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hashindex-row.spent .text {
|
.tree-table-row-cell:selected .hashindex-row {
|
||||||
-fx-fill: #a0a1a7;
|
-fx-text-fill: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-cell .text-field {
|
.label-cell .text-field {
|
||||||
|
@ -32,8 +32,18 @@
|
||||||
-fx-strikethrough: true;
|
-fx-strikethrough: true;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-cell .button {
|
.data-cell .button {
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
-fx-pref-height: 18;
|
-fx-pref-height: 18;
|
||||||
-fx-pref-width: 18;
|
-fx-pref-width: 18;
|
||||||
|
-fx-border-width: 0;
|
||||||
|
-fx-background-color: -fx-background;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-cell .button .label .text {
|
||||||
|
-fx-fill: -fx-background;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-cell:hover .button .label .text {
|
||||||
|
-fx-fill: -fx-text-base-color;
|
||||||
}
|
}
|
Loading…
Reference in a new issue