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