mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
save psbts in binary format by default, add file submenu item for base64
This commit is contained in:
parent
5d91f033c0
commit
08edc04c6d
3 changed files with 88 additions and 41 deletions
|
@ -50,7 +50,10 @@ import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.input.*;
|
import javafx.scene.input.*;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.stage.*;
|
import javafx.stage.FileChooser;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import javafx.stage.StageStyle;
|
||||||
|
import javafx.stage.Window;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import org.controlsfx.control.Notifications;
|
import org.controlsfx.control.Notifications;
|
||||||
import org.controlsfx.control.StatusBar;
|
import org.controlsfx.control.StatusBar;
|
||||||
|
@ -64,7 +67,6 @@ import java.net.URL;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static com.sparrowwallet.sparrow.AppServices.*;
|
import static com.sparrowwallet.sparrow.AppServices.*;
|
||||||
|
@ -81,6 +83,9 @@ public class AppController implements Initializable {
|
||||||
@FXML
|
@FXML
|
||||||
private MenuItem saveTransaction;
|
private MenuItem saveTransaction;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Menu savePSBT;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private MenuItem exportWallet;
|
private MenuItem exportWallet;
|
||||||
|
|
||||||
|
@ -243,6 +248,7 @@ public class AppController implements Initializable {
|
||||||
openWalletsInNewWindows.setSelected(Config.get().isOpenWalletsInNewWindows());
|
openWalletsInNewWindows.setSelected(Config.get().isOpenWalletsInNewWindows());
|
||||||
hideEmptyUsedAddresses.setSelected(Config.get().isHideEmptyUsedAddresses());
|
hideEmptyUsedAddresses.setSelected(Config.get().isHideEmptyUsedAddresses());
|
||||||
showTxHex.setSelected(Config.get().isShowTransactionHex());
|
showTxHex.setSelected(Config.get().isShowTransactionHex());
|
||||||
|
savePSBT.visibleProperty().bind(saveTransaction.visibleProperty().not());
|
||||||
exportWallet.setDisable(true);
|
exportWallet.setDisable(true);
|
||||||
refreshWallet.disableProperty().bind(Bindings.or(exportWallet.disableProperty(), Bindings.or(serverToggle.disableProperty(), AppServices.onlineProperty().not())));
|
refreshWallet.disableProperty().bind(Bindings.or(exportWallet.disableProperty(), Bindings.or(serverToggle.disableProperty(), AppServices.onlineProperty().not())));
|
||||||
|
|
||||||
|
@ -482,45 +488,27 @@ public class AppController implements Initializable {
|
||||||
TransactionTabData transactionTabData = (TransactionTabData)tabData;
|
TransactionTabData transactionTabData = (TransactionTabData)tabData;
|
||||||
Transaction transaction = transactionTabData.getTransaction();
|
Transaction transaction = transactionTabData.getTransaction();
|
||||||
|
|
||||||
//Save a transaction if the PSBT is null or transaction has already been extracted, otherwise save PSBT
|
|
||||||
//The PSBT's transaction is not altered with transaction extraction, but the extracted transaction is stored in TransactionData
|
|
||||||
boolean saveTx = (transactionTabData.getPsbt() == null || transactionTabData.getPsbt().getTransaction() != transaction);
|
|
||||||
|
|
||||||
Stage window = new Stage();
|
Stage window = new Stage();
|
||||||
FileChooser fileChooser = new FileChooser();
|
FileChooser fileChooser = new FileChooser();
|
||||||
fileChooser.setTitle("Save " + (saveTx ? "Transaction" : "PSBT"));
|
fileChooser.setTitle("Save Transaction");
|
||||||
|
|
||||||
String fileName = selectedTab.getText();
|
String fileName = ((Label)selectedTab.getGraphic()).getText();
|
||||||
if(fileName != null && !fileName.isEmpty()) {
|
if(fileName != null && !fileName.isEmpty()) {
|
||||||
if(transactionTabData.getPsbt() != null) {
|
if(fileName.endsWith(".psbt")) {
|
||||||
if(!fileName.endsWith(".psbt")) {
|
fileName = fileName.substring(0, fileName.length() - ".psbt".length());
|
||||||
fileName += ".psbt";
|
}
|
||||||
}
|
|
||||||
} else if(!fileName.endsWith(".txn")) {
|
|
||||||
fileName += ".txn";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(saveTx && fileName.endsWith(".psbt")) {
|
if(!fileName.endsWith(".txn")) {
|
||||||
fileName = fileName.replace(".psbt", "") + ".txn";
|
fileName += ".txn";
|
||||||
}
|
}
|
||||||
|
|
||||||
fileChooser.setInitialFileName(fileName);
|
fileChooser.setInitialFileName(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
File file = fileChooser.showSaveDialog(window);
|
File file = fileChooser.showSaveDialog(window);
|
||||||
if(file != null) {
|
if(file != null) {
|
||||||
if(!saveTx && !file.getName().toLowerCase().endsWith(".psbt")) {
|
try(PrintWriter writer = new PrintWriter(file, StandardCharsets.UTF_8)) {
|
||||||
file = new File(file.getAbsolutePath() + ".psbt");
|
writer.print(Utils.bytesToHex(transaction.bitcoinSerialize()));
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
try(PrintWriter writer = new PrintWriter(file, StandardCharsets.UTF_8)) {
|
|
||||||
if(saveTx) {
|
|
||||||
writer.print(Utils.bytesToHex(transaction.bitcoinSerialize()));
|
|
||||||
} else {
|
|
||||||
writer.print(transactionTabData.getPsbt().toBase64String());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
log.error("Error saving transaction", e);
|
log.error("Error saving transaction", e);
|
||||||
AppServices.showErrorDialog("Error saving transaction", "Cannot write to " + file.getAbsolutePath());
|
AppServices.showErrorDialog("Error saving transaction", "Cannot write to " + file.getAbsolutePath());
|
||||||
|
@ -529,6 +517,58 @@ public class AppController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void savePSBTBinary(ActionEvent event) {
|
||||||
|
savePSBT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void savePSBTText(ActionEvent event) {
|
||||||
|
savePSBT(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void savePSBT(boolean asText) {
|
||||||
|
Tab selectedTab = tabs.getSelectionModel().getSelectedItem();
|
||||||
|
TabData tabData = (TabData)selectedTab.getUserData();
|
||||||
|
if(tabData.getType() == TabData.TabType.TRANSACTION) {
|
||||||
|
TransactionTabData transactionTabData = (TransactionTabData)tabData;
|
||||||
|
|
||||||
|
Stage window = new Stage();
|
||||||
|
FileChooser fileChooser = new FileChooser();
|
||||||
|
fileChooser.setTitle("Save PSBT");
|
||||||
|
|
||||||
|
String fileName = ((Label)selectedTab.getGraphic()).getText();
|
||||||
|
if(fileName != null && !fileName.isEmpty()) {
|
||||||
|
if(!fileName.endsWith(".psbt")) {
|
||||||
|
fileName += ".psbt";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(asText) {
|
||||||
|
fileName += ".txt";
|
||||||
|
}
|
||||||
|
|
||||||
|
fileChooser.setInitialFileName(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = fileChooser.showSaveDialog(window);
|
||||||
|
if(file != null) {
|
||||||
|
if(!asText && !file.getName().toLowerCase().endsWith(".psbt")) {
|
||||||
|
file = new File(file.getAbsolutePath() + ".psbt");
|
||||||
|
}
|
||||||
|
|
||||||
|
try(FileOutputStream outputStream = new FileOutputStream(file)) {
|
||||||
|
if(asText) {
|
||||||
|
PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
|
||||||
|
writer.print(transactionTabData.getPsbt().toBase64String());
|
||||||
|
writer.flush();
|
||||||
|
} else {
|
||||||
|
outputStream.write(transactionTabData.getPsbt().serialize());
|
||||||
|
}
|
||||||
|
} catch(IOException e) {
|
||||||
|
log.error("Error saving PSBT", e);
|
||||||
|
AppServices.showErrorDialog("Error saving PSBT", "Cannot write to " + file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<WalletTabData> getOpenWalletTabData() {
|
public List<WalletTabData> getOpenWalletTabData() {
|
||||||
List<WalletTabData> openWalletTabData = new ArrayList<>();
|
List<WalletTabData> openWalletTabData = new ArrayList<>();
|
||||||
|
@ -1065,7 +1105,7 @@ public class AppController implements Initializable {
|
||||||
//As per BIP174, combine PSBTs with matching transactions so long as they are not yet finalized
|
//As per BIP174, combine PSBTs with matching transactions so long as they are not yet finalized
|
||||||
transactionTabData.getPsbt().combine(psbt);
|
transactionTabData.getPsbt().combine(psbt);
|
||||||
if(name != null && !name.isEmpty()) {
|
if(name != null && !name.isEmpty()) {
|
||||||
tab.setText(name);
|
((Label)tab.getGraphic()).setText(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventManager.get().post(new PSBTCombinedEvent(transactionTabData.getPsbt()));
|
EventManager.get().post(new PSBTCombinedEvent(transactionTabData.getPsbt()));
|
||||||
|
@ -1080,7 +1120,7 @@ public class AppController implements Initializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name != null && !name.isEmpty()) {
|
if(name != null && !name.isEmpty()) {
|
||||||
tab.setText(name);
|
((Label)tab.getGraphic()).setText(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventManager.get().post(new PSBTFinalizedEvent(transactionTabData.getPsbt()));
|
EventManager.get().post(new PSBTFinalizedEvent(transactionTabData.getPsbt()));
|
||||||
|
@ -1268,15 +1308,19 @@ public class AppController implements Initializable {
|
||||||
if(event instanceof TransactionTabSelectedEvent) {
|
if(event instanceof TransactionTabSelectedEvent) {
|
||||||
TransactionTabSelectedEvent txTabEvent = (TransactionTabSelectedEvent)event;
|
TransactionTabSelectedEvent txTabEvent = (TransactionTabSelectedEvent)event;
|
||||||
TransactionTabData transactionTabData = txTabEvent.getTransactionTabData();
|
TransactionTabData transactionTabData = txTabEvent.getTransactionTabData();
|
||||||
saveTransaction.setDisable(false);
|
if(transactionTabData.getPsbt() == null || transactionTabData.getPsbt().getTransaction() != transactionTabData.getTransaction()) {
|
||||||
saveTransaction.setText("Save " + (transactionTabData.getPsbt() == null || transactionTabData.getPsbt().getTransaction() != transactionTabData.getTransaction() ? "Transaction..." : "PSBT..."));
|
saveTransaction.setVisible(true);
|
||||||
|
saveTransaction.setDisable(false);
|
||||||
|
} else {
|
||||||
|
saveTransaction.setVisible(false);
|
||||||
|
}
|
||||||
exportWallet.setDisable(true);
|
exportWallet.setDisable(true);
|
||||||
showTxHex.setDisable(false);
|
showTxHex.setDisable(false);
|
||||||
} else if(event instanceof WalletTabSelectedEvent) {
|
} else if(event instanceof WalletTabSelectedEvent) {
|
||||||
WalletTabSelectedEvent walletTabEvent = (WalletTabSelectedEvent)event;
|
WalletTabSelectedEvent walletTabEvent = (WalletTabSelectedEvent)event;
|
||||||
WalletTabData walletTabData = walletTabEvent.getWalletTabData();
|
WalletTabData walletTabData = walletTabEvent.getWalletTabData();
|
||||||
|
saveTransaction.setVisible(true);
|
||||||
saveTransaction.setDisable(true);
|
saveTransaction.setDisable(true);
|
||||||
saveTransaction.setText("Save Transaction...");
|
|
||||||
exportWallet.setDisable(walletTabData.getWallet() == null || !walletTabData.getWallet().isValid());
|
exportWallet.setDisable(walletTabData.getWallet() == null || !walletTabData.getWallet().isValid());
|
||||||
showTxHex.setDisable(true);
|
showTxHex.setDisable(true);
|
||||||
}
|
}
|
||||||
|
@ -1290,7 +1334,8 @@ public class AppController implements Initializable {
|
||||||
if(tabData instanceof TransactionTabData) {
|
if(tabData instanceof TransactionTabData) {
|
||||||
TransactionTabData transactionTabData = (TransactionTabData)tabData;
|
TransactionTabData transactionTabData = (TransactionTabData)tabData;
|
||||||
if(transactionTabData.getTransaction() == event.getFinalTransaction()) {
|
if(transactionTabData.getTransaction() == event.getFinalTransaction()) {
|
||||||
saveTransaction.setText("Save Transaction...");
|
saveTransaction.setVisible(true);
|
||||||
|
saveTransaction.setDisable(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -680,10 +680,8 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
file = new File(file.getAbsolutePath() + ".psbt");
|
file = new File(file.getAbsolutePath() + ".psbt");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try(FileOutputStream outputStream = new FileOutputStream(file)) {
|
||||||
try(PrintWriter writer = new PrintWriter(file, StandardCharsets.UTF_8)) {
|
outputStream.write(headersForm.getPsbt().serialize());
|
||||||
writer.print(headersForm.getPsbt().toBase64String());
|
|
||||||
}
|
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
log.error("Error saving PSBT", e);
|
log.error("Error saving PSBT", e);
|
||||||
AppServices.showErrorDialog("Error saving PSBT", "Cannot write to " + file.getAbsolutePath());
|
AppServices.showErrorDialog("Error saving PSBT", "Cannot write to " + file.getAbsolutePath());
|
||||||
|
|
|
@ -27,6 +27,10 @@
|
||||||
</items>
|
</items>
|
||||||
</Menu>
|
</Menu>
|
||||||
<MenuItem fx:id="saveTransaction" mnemonicParsing="false" text="Save Transaction..." accelerator="Shortcut+S" onAction="#saveTransaction"/>
|
<MenuItem fx:id="saveTransaction" mnemonicParsing="false" text="Save Transaction..." accelerator="Shortcut+S" onAction="#saveTransaction"/>
|
||||||
|
<Menu fx:id="savePSBT" mnemonicParsing="false" text="Save PSBT">
|
||||||
|
<MenuItem text="As Binary..." onAction="#savePSBTBinary" accelerator="Shortcut+S"/>
|
||||||
|
<MenuItem text="As Base64..." onAction="#savePSBTText"/>
|
||||||
|
</Menu>
|
||||||
<SeparatorMenuItem />
|
<SeparatorMenuItem />
|
||||||
<MenuItem mnemonicParsing="false" text="Import Wallet..." onAction="#importWallet"/>
|
<MenuItem mnemonicParsing="false" text="Import Wallet..." onAction="#importWallet"/>
|
||||||
<MenuItem fx:id="exportWallet" mnemonicParsing="false" text="Export Wallet..." onAction="#exportWallet"/>
|
<MenuItem fx:id="exportWallet" mnemonicParsing="false" text="Export Wallet..." onAction="#exportWallet"/>
|
||||||
|
|
Loading…
Reference in a new issue