Craig Raw
2 years ago
6 changed files with 204 additions and 69 deletions
@ -0,0 +1,75 @@ |
|||||
|
package com.sparrowwallet.sparrow.io; |
||||
|
|
||||
|
import com.google.zxing.BarcodeFormat; |
||||
|
import com.google.zxing.WriterException; |
||||
|
import com.google.zxing.client.j2se.MatrixToImageConfig; |
||||
|
import com.google.zxing.client.j2se.MatrixToImageWriter; |
||||
|
import com.google.zxing.common.BitMatrix; |
||||
|
import com.google.zxing.qrcode.QRCodeWriter; |
||||
|
import com.lowagie.text.*; |
||||
|
import com.lowagie.text.Font; |
||||
|
import com.lowagie.text.Image; |
||||
|
import com.lowagie.text.pdf.PdfWriter; |
||||
|
import com.sparrowwallet.hummingbird.UR; |
||||
|
import com.sparrowwallet.hummingbird.UREncoder; |
||||
|
import com.sparrowwallet.sparrow.AppServices; |
||||
|
import javafx.embed.swing.SwingFXUtils; |
||||
|
import javafx.stage.FileChooser; |
||||
|
import javafx.stage.Stage; |
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
|
||||
|
import java.awt.*; |
||||
|
import java.io.*; |
||||
|
|
||||
|
public class PdfUtils { |
||||
|
private static final Logger log = LoggerFactory.getLogger(PdfUtils.class); |
||||
|
|
||||
|
private static final int QR_WIDTH = 480; |
||||
|
private static final int QR_HEIGHT = 480; |
||||
|
|
||||
|
public static void saveOutputDescriptor(String walletName, String outputDescriptor, UR ur) { |
||||
|
Stage window = new Stage(); |
||||
|
FileChooser fileChooser = new FileChooser(); |
||||
|
fileChooser.setTitle("Save PDF"); |
||||
|
fileChooser.setInitialFileName(walletName + ".pdf"); |
||||
|
AppServices.moveToActiveWindowScreen(window, 800, 450); |
||||
|
File file = fileChooser.showSaveDialog(window); |
||||
|
if(file != null) { |
||||
|
try(Document document = new Document()) { |
||||
|
document.setMargins(36, 36, 48, 36); |
||||
|
PdfWriter.getInstance(document, new FileOutputStream(file)); |
||||
|
document.open(); |
||||
|
|
||||
|
Font titleFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 16, Color.BLACK); |
||||
|
Chunk title = new Chunk("Output descriptor for " + walletName, titleFont); |
||||
|
document.add(title); |
||||
|
|
||||
|
UREncoder urEncoder = new UREncoder(ur, 2000, 10, 0); |
||||
|
String fragment = urEncoder.nextPart(); |
||||
|
if(urEncoder.isSinglePart()) { |
||||
|
Image image = Image.getInstance(SwingFXUtils.fromFXImage(getQrCode(fragment), null), Color.WHITE); |
||||
|
document.add(image); |
||||
|
} |
||||
|
|
||||
|
Font descriptorFont = FontFactory.getFont(FontFactory.COURIER, 14, Color.BLACK); |
||||
|
Paragraph descriptor = new Paragraph(outputDescriptor, descriptorFont); |
||||
|
document.add(descriptor); |
||||
|
} catch(Exception e) { |
||||
|
log.error("Error creating descriptor PDF", e); |
||||
|
AppServices.showErrorDialog("Error creating PDF", e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static javafx.scene.image.Image getQrCode(String fragment) throws IOException, WriterException { |
||||
|
QRCodeWriter qrCodeWriter = new QRCodeWriter(); |
||||
|
BitMatrix qrMatrix = qrCodeWriter.encode(fragment, BarcodeFormat.QR_CODE, QR_WIDTH, QR_HEIGHT); |
||||
|
|
||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
||||
|
MatrixToImageWriter.writeToStream(qrMatrix, "PNG", baos, new MatrixToImageConfig()); |
||||
|
|
||||
|
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); |
||||
|
return new javafx.scene.image.Image(bais); |
||||
|
} |
||||
|
} |
@ -0,0 +1,90 @@ |
|||||
|
package com.sparrowwallet.sparrow.wallet; |
||||
|
|
||||
|
import com.sparrowwallet.drongo.wallet.Wallet; |
||||
|
import com.sparrowwallet.hummingbird.UR; |
||||
|
import com.sparrowwallet.sparrow.AppServices; |
||||
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; |
||||
|
import com.sparrowwallet.sparrow.io.PdfUtils; |
||||
|
import javafx.scene.Node; |
||||
|
import javafx.scene.control.*; |
||||
|
import javafx.scene.layout.HBox; |
||||
|
import javafx.scene.layout.Priority; |
||||
|
import org.controlsfx.glyphfont.Glyph; |
||||
|
|
||||
|
public class MultisigBackupDialog extends Dialog<String> { |
||||
|
private final Wallet wallet; |
||||
|
private final String descriptor; |
||||
|
private final UR ur; |
||||
|
|
||||
|
private final TextArea textArea; |
||||
|
|
||||
|
public MultisigBackupDialog(Wallet wallet, String descriptor, UR ur) { |
||||
|
this.wallet = wallet; |
||||
|
this.descriptor = descriptor; |
||||
|
this.ur = ur; |
||||
|
|
||||
|
setTitle("Backup Multisig Wallet?"); |
||||
|
|
||||
|
DialogPane dialogPane = new MultisigBackupDialogPane(); |
||||
|
dialogPane.setHeaderText("To restore this multisig wallet, you need at least " + wallet.getDefaultPolicy().getNumSignaturesRequired() + " seeds and ALL of the xpubs!\n" + |
||||
|
"It is recommended to backup either this wallet file, or the wallet output descriptor.\n\n" + |
||||
|
"The wallet output descriptor contains all the xpubs and is shown below.\n" + |
||||
|
"Alternatively, use the Export button below to export the Sparrow wallet file."); |
||||
|
setDialogPane(dialogPane); |
||||
|
|
||||
|
dialogPane.getStyleClass().addAll("alert", "warning"); |
||||
|
|
||||
|
HBox hbox = new HBox(); |
||||
|
this.textArea = new TextArea(descriptor); |
||||
|
this.textArea.setMaxWidth(Double.MAX_VALUE); |
||||
|
this.textArea.setWrapText(true); |
||||
|
this.textArea.getStyleClass().add("fixed-width"); |
||||
|
this.textArea.setEditable(false); |
||||
|
hbox.getChildren().add(textArea); |
||||
|
HBox.setHgrow(this.textArea, Priority.ALWAYS); |
||||
|
|
||||
|
dialogPane.setContent(hbox); |
||||
|
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm()); |
||||
|
AppServices.setStageIcon(dialogPane.getScene().getWindow()); |
||||
|
|
||||
|
dialogPane.getStyleClass().add("text-input-dialog"); |
||||
|
dialogPane.getButtonTypes().add(ButtonType.OK); |
||||
|
|
||||
|
final ButtonType qrButtonType = new javafx.scene.control.ButtonType("Save PDF...", ButtonBar.ButtonData.LEFT); |
||||
|
dialogPane.getButtonTypes().add(qrButtonType); |
||||
|
|
||||
|
dialogPane.setPrefWidth(700); |
||||
|
dialogPane.setPrefHeight(350); |
||||
|
AppServices.moveToActiveWindowScreen(this); |
||||
|
} |
||||
|
|
||||
|
private class MultisigBackupDialogPane extends DialogPane { |
||||
|
@Override |
||||
|
protected Node createButton(ButtonType buttonType) { |
||||
|
Node button; |
||||
|
if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT) { |
||||
|
Button pdfButton = new Button(buttonType.getText()); |
||||
|
pdfButton.setGraphicTextGap(5); |
||||
|
pdfButton.setGraphic(getGlyph(FontAwesome5.Glyph.FILE_PDF)); |
||||
|
|
||||
|
final ButtonBar.ButtonData buttonData = buttonType.getButtonData(); |
||||
|
ButtonBar.setButtonData(pdfButton, buttonData); |
||||
|
pdfButton.setOnAction(event -> { |
||||
|
PdfUtils.saveOutputDescriptor(wallet.getFullDisplayName(), descriptor, ur); |
||||
|
}); |
||||
|
|
||||
|
button = pdfButton; |
||||
|
} else { |
||||
|
button = super.createButton(buttonType); |
||||
|
} |
||||
|
|
||||
|
return button; |
||||
|
} |
||||
|
|
||||
|
private Glyph getGlyph(FontAwesome5.Glyph glyphName) { |
||||
|
Glyph glyph = new Glyph(FontAwesome5.FONT_NAME, glyphName); |
||||
|
glyph.setFontSize(11); |
||||
|
return glyph; |
||||
|
} |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue