mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 13:16:44 +00:00
generate border wallets grid from seed words
This commit is contained in:
parent
faa5a11c94
commit
6063b02113
6 changed files with 259 additions and 15 deletions
|
@ -27,6 +27,7 @@ import java.io.FileInputStream;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -34,6 +35,8 @@ import java.util.stream.Collectors;
|
||||||
public class MnemonicGridDialog extends Dialog<List<String>> {
|
public class MnemonicGridDialog extends Dialog<List<String>> {
|
||||||
private final SpreadsheetView spreadsheetView;
|
private final SpreadsheetView spreadsheetView;
|
||||||
|
|
||||||
|
private final int GRID_COLUMN_COUNT = 16;
|
||||||
|
|
||||||
private final BooleanProperty initializedProperty = new SimpleBooleanProperty(false);
|
private final BooleanProperty initializedProperty = new SimpleBooleanProperty(false);
|
||||||
private final BooleanProperty wordsSelectedProperty = new SimpleBooleanProperty(false);
|
private final BooleanProperty wordsSelectedProperty = new SimpleBooleanProperty(false);
|
||||||
|
|
||||||
|
@ -43,11 +46,11 @@ public class MnemonicGridDialog extends Dialog<List<String>> {
|
||||||
setTitle("Border Wallets Grid");
|
setTitle("Border Wallets Grid");
|
||||||
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
|
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
|
||||||
dialogPane.getStylesheets().add(AppServices.class.getResource("grid.css").toExternalForm());
|
dialogPane.getStylesheets().add(AppServices.class.getResource("grid.css").toExternalForm());
|
||||||
dialogPane.setHeaderText("Load a Border Wallets PDF, and select 11 or 23 words in the grid.\nThe order of selection is important!");
|
dialogPane.setHeaderText("Load a Border Wallets PDF, or generate a grid from a BIP39 seed.\nThen select 11 or 23 words in a pattern on the grid. Note the order of selection is important!");
|
||||||
javafx.scene.image.Image image = new Image("/image/border-wallets.png");
|
javafx.scene.image.Image image = new Image("/image/border-wallets.png");
|
||||||
dialogPane.setGraphic(new ImageView(image));
|
dialogPane.setGraphic(new ImageView(image));
|
||||||
|
|
||||||
String[][] emptyWordGrid = new String[128][16];
|
String[][] emptyWordGrid = new String[128][GRID_COLUMN_COUNT];
|
||||||
Grid grid = getGrid(emptyWordGrid);
|
Grid grid = getGrid(emptyWordGrid);
|
||||||
|
|
||||||
spreadsheetView = new SpreadsheetView(grid);
|
spreadsheetView = new SpreadsheetView(grid);
|
||||||
|
@ -87,9 +90,15 @@ public class MnemonicGridDialog extends Dialog<List<String>> {
|
||||||
|
|
||||||
dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
|
dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
|
||||||
|
|
||||||
final ButtonType loadCsvButtonType = new javafx.scene.control.ButtonType("Load PDF", ButtonBar.ButtonData.LEFT);
|
final ButtonType loadCsvButtonType = new javafx.scene.control.ButtonType("Load PDF...", ButtonBar.ButtonData.LEFT);
|
||||||
dialogPane.getButtonTypes().add(loadCsvButtonType);
|
dialogPane.getButtonTypes().add(loadCsvButtonType);
|
||||||
|
|
||||||
|
final ButtonType generateButtonType = new javafx.scene.control.ButtonType("Generate Grid...", ButtonBar.ButtonData.HELP);
|
||||||
|
dialogPane.getButtonTypes().add(generateButtonType);
|
||||||
|
|
||||||
|
final ButtonType clearButtonType = new javafx.scene.control.ButtonType("Clear Selection", ButtonBar.ButtonData.OTHER);
|
||||||
|
dialogPane.getButtonTypes().add(clearButtonType);
|
||||||
|
|
||||||
Button okButton = (Button)dialogPane.lookupButton(ButtonType.OK);
|
Button okButton = (Button)dialogPane.lookupButton(ButtonType.OK);
|
||||||
okButton.disableProperty().bind(Bindings.not(Bindings.and(initializedProperty, wordsSelectedProperty)));
|
okButton.disableProperty().bind(Bindings.not(Bindings.and(initializedProperty, wordsSelectedProperty)));
|
||||||
|
|
||||||
|
@ -166,6 +175,24 @@ public class MnemonicGridDialog extends Dialog<List<String>> {
|
||||||
return words;
|
return words;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String[][] toGrid(List<String> words) {
|
||||||
|
String[][] grid = new String[words.size()/GRID_COLUMN_COUNT][GRID_COLUMN_COUNT];
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
int col = 0;
|
||||||
|
for(String word : words) {
|
||||||
|
String abbr = word.length() < 4 ? word : word.substring(0, 4);
|
||||||
|
grid[row][col] = abbr;
|
||||||
|
col++;
|
||||||
|
if(col >= GRID_COLUMN_COUNT) {
|
||||||
|
col = 0;
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
|
||||||
private class MnemonicGridDialogPane extends DialogPane {
|
private class MnemonicGridDialogPane extends DialogPane {
|
||||||
@Override
|
@Override
|
||||||
protected Node createButton(ButtonType buttonType) {
|
protected Node createButton(ButtonType buttonType) {
|
||||||
|
@ -198,6 +225,36 @@ public class MnemonicGridDialog extends Dialog<List<String>> {
|
||||||
});
|
});
|
||||||
|
|
||||||
button = loadButton;
|
button = loadButton;
|
||||||
|
} else if(buttonType.getButtonData() == ButtonBar.ButtonData.HELP) {
|
||||||
|
Button generateButton = new Button(buttonType.getText());
|
||||||
|
final ButtonBar.ButtonData buttonData = buttonType.getButtonData();
|
||||||
|
ButtonBar.setButtonData(generateButton, buttonData);
|
||||||
|
generateButton.setOnAction(event -> {
|
||||||
|
SeedEntryDialog seedEntryDialog = new SeedEntryDialog(12);
|
||||||
|
Optional<List<String>> optWords = seedEntryDialog.showAndWait();
|
||||||
|
if(optWords.isPresent()) {
|
||||||
|
List<String> mnemonicWords = optWords.get();
|
||||||
|
List<String> shuffledWordList = shuffle(mnemonicWords);
|
||||||
|
String[][] wordGrid = toGrid(shuffledWordList);
|
||||||
|
spreadsheetView.setGrid(getGrid(wordGrid));
|
||||||
|
initializedProperty.set(true);
|
||||||
|
|
||||||
|
if(seedEntryDialog.isGenerated()) {
|
||||||
|
//TODO: Save grid PDF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
button = generateButton;
|
||||||
|
} else if(buttonType.getButtonData() == ButtonBar.ButtonData.OTHER) {
|
||||||
|
Button clearButton = new Button(buttonType.getText());
|
||||||
|
final ButtonBar.ButtonData buttonData = buttonType.getButtonData();
|
||||||
|
ButtonBar.setButtonData(clearButton, buttonData);
|
||||||
|
clearButton.setOnAction(event -> {
|
||||||
|
spreadsheetView.getSelectionModel().clearSelection();
|
||||||
|
});
|
||||||
|
|
||||||
|
button = clearButton;
|
||||||
} else {
|
} else {
|
||||||
button = super.createButton(buttonType);
|
button = super.createButton(buttonType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.sparrowwallet.sparrow.control;
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.wallet.DeterministicSeed;
|
|
||||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
import com.sparrowwallet.drongo.wallet.WalletModel;
|
import com.sparrowwallet.drongo.wallet.WalletModel;
|
||||||
import javafx.beans.property.SimpleListProperty;
|
import javafx.beans.property.SimpleListProperty;
|
||||||
|
@ -25,7 +24,7 @@ public class MnemonicKeystoreDisplayPane extends MnemonicKeystorePane {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node getMnemonicWordsEntry(int numWords, boolean editPassphrase) {
|
protected Node getMnemonicWordsEntry(int numWords, boolean showPassphrase, boolean editPassphrase) {
|
||||||
VBox vBox = new VBox();
|
VBox vBox = new VBox();
|
||||||
vBox.setSpacing(10);
|
vBox.setSpacing(10);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.wallet.Bip39MnemonicCode;
|
||||||
|
import com.sparrowwallet.drongo.wallet.DeterministicSeed;
|
||||||
|
import com.sparrowwallet.drongo.wallet.MnemonicException;
|
||||||
|
import com.sparrowwallet.drongo.wallet.WalletModel;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MnemonicKeystoreEntryPane extends MnemonicKeystorePane {
|
||||||
|
private final BooleanProperty validProperty = new SimpleBooleanProperty(false);
|
||||||
|
|
||||||
|
private boolean generated;
|
||||||
|
|
||||||
|
public MnemonicKeystoreEntryPane(int numWords) {
|
||||||
|
super(DeterministicSeed.Type.BIP39.getName(), "Enter seed words", "", "image/" + WalletModel.SEED.getType() + ".png");
|
||||||
|
showHideLink.setVisible(false);
|
||||||
|
buttonBox.getChildren().clear();
|
||||||
|
|
||||||
|
defaultWordSizeProperty.set(numWords);
|
||||||
|
setDescription("Generate new or enter existing");
|
||||||
|
showHideLink.setVisible(false);
|
||||||
|
setContent(getMnemonicWordsEntry(numWords, false, true));
|
||||||
|
setExpanded(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Node> createRightButtons() {
|
||||||
|
Button button = new Button("Next");
|
||||||
|
button.setVisible(false);
|
||||||
|
return List.of(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onWordChange(boolean empty, boolean validWords, boolean validChecksum) {
|
||||||
|
if(!empty && validWords) {
|
||||||
|
try {
|
||||||
|
Bip39MnemonicCode.INSTANCE.check(wordEntriesProperty.get());
|
||||||
|
validChecksum = true;
|
||||||
|
} catch(MnemonicException e) {
|
||||||
|
invalidLabel.setText("Invalid checksum");
|
||||||
|
invalidLabel.setTooltip(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validProperty.set(validChecksum);
|
||||||
|
validLabel.setVisible(validChecksum);
|
||||||
|
invalidLabel.setVisible(!validChecksum && !empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateNew() {
|
||||||
|
int mnemonicSeedLength = wordEntriesProperty.get().size() * 11;
|
||||||
|
int entropyLength = mnemonicSeedLength - (mnemonicSeedLength/33);
|
||||||
|
|
||||||
|
SecureRandom secureRandom;
|
||||||
|
try {
|
||||||
|
secureRandom = SecureRandom.getInstanceStrong();
|
||||||
|
} catch(NoSuchAlgorithmException e) {
|
||||||
|
secureRandom = new SecureRandom();
|
||||||
|
}
|
||||||
|
|
||||||
|
DeterministicSeed deterministicSeed = new DeterministicSeed(secureRandom, entropyLength, "");
|
||||||
|
displayMnemonicCode(deterministicSeed);
|
||||||
|
generated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayMnemonicCode(DeterministicSeed deterministicSeed) {
|
||||||
|
setDescription("Write down these words");
|
||||||
|
showHideLink.setVisible(false);
|
||||||
|
|
||||||
|
for (int i = 0; i < wordsPane.getChildren().size(); i++) {
|
||||||
|
WordEntry wordEntry = (WordEntry)wordsPane.getChildren().get(i);
|
||||||
|
wordEntry.getEditor().setText(deterministicSeed.getMnemonicCode().get(i));
|
||||||
|
wordEntry.getEditor().setEditable(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return validProperty.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanProperty validProperty() {
|
||||||
|
return validProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGenerated() {
|
||||||
|
return generated;
|
||||||
|
}
|
||||||
|
}
|
|
@ -223,7 +223,7 @@ public class MnemonicKeystoreImportPane extends MnemonicKeystorePane {
|
||||||
private void confirmBackup() {
|
private void confirmBackup() {
|
||||||
setDescription("Confirm backup by re-entering words");
|
setDescription("Confirm backup by re-entering words");
|
||||||
showHideLink.setVisible(false);
|
showHideLink.setVisible(false);
|
||||||
setContent(getMnemonicWordsEntry(wordEntriesProperty.get().size(), false));
|
setContent(getMnemonicWordsEntry(wordEntriesProperty.get().size(), true, false));
|
||||||
setExpanded(true);
|
setExpanded(true);
|
||||||
backButton.setVisible(true);
|
backButton.setVisible(true);
|
||||||
generateButton.setVisible(false);
|
generateButton.setVisible(false);
|
||||||
|
|
|
@ -81,7 +81,7 @@ public class MnemonicKeystorePane extends TitledDescriptionPane {
|
||||||
enterMnemonicButton.getItems().add(item);
|
enterMnemonicButton.getItems().add(item);
|
||||||
}
|
}
|
||||||
enterMnemonicButton.getItems().add(new SeparatorMenuItem());
|
enterMnemonicButton.getItems().add(new SeparatorMenuItem());
|
||||||
MenuItem gridItem = new MenuItem("Border Wallets...");
|
MenuItem gridItem = new MenuItem("Border Wallets Grid...");
|
||||||
gridItem.setOnAction(event -> {
|
gridItem.setOnAction(event -> {
|
||||||
showGrid();
|
showGrid();
|
||||||
});
|
});
|
||||||
|
@ -100,7 +100,7 @@ public class MnemonicKeystorePane extends TitledDescriptionPane {
|
||||||
Optional<List<String>> optWords = mnemonicGridDialog.showAndWait();
|
Optional<List<String>> optWords = mnemonicGridDialog.showAndWait();
|
||||||
if(optWords.isPresent()) {
|
if(optWords.isPresent()) {
|
||||||
List<String> words = optWords.get();
|
List<String> words = optWords.get();
|
||||||
setContent(getMnemonicWordsEntry(words.size() + 1, true));
|
setContent(getMnemonicWordsEntry(words.size() + 1, true, true));
|
||||||
setExpanded(true);
|
setExpanded(true);
|
||||||
|
|
||||||
for(int i = 0; i < wordsPane.getChildren().size(); i++) {
|
for(int i = 0; i < wordsPane.getChildren().size(); i++) {
|
||||||
|
@ -150,7 +150,7 @@ public class MnemonicKeystorePane extends TitledDescriptionPane {
|
||||||
|
|
||||||
protected void showWordList(DeterministicSeed seed) {
|
protected void showWordList(DeterministicSeed seed) {
|
||||||
List<String> words = seed.getMnemonicCode();
|
List<String> words = seed.getMnemonicCode();
|
||||||
setContent(getMnemonicWordsEntry(words.size(), true));
|
setContent(getMnemonicWordsEntry(words.size(), true, true));
|
||||||
setExpanded(true);
|
setExpanded(true);
|
||||||
|
|
||||||
for(int i = 0; i < wordsPane.getChildren().size(); i++) {
|
for(int i = 0; i < wordsPane.getChildren().size(); i++) {
|
||||||
|
@ -163,11 +163,11 @@ public class MnemonicKeystorePane extends TitledDescriptionPane {
|
||||||
protected void enterMnemonic(int numWords) {
|
protected void enterMnemonic(int numWords) {
|
||||||
setDescription("Generate new or enter existing");
|
setDescription("Generate new or enter existing");
|
||||||
showHideLink.setVisible(false);
|
showHideLink.setVisible(false);
|
||||||
setContent(getMnemonicWordsEntry(numWords, true));
|
setContent(getMnemonicWordsEntry(numWords, true, true));
|
||||||
setExpanded(true);
|
setExpanded(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Node getMnemonicWordsEntry(int numWords, boolean editPassphrase) {
|
protected Node getMnemonicWordsEntry(int numWords, boolean showPassphrase, boolean editPassphrase) {
|
||||||
VBox vBox = new VBox();
|
VBox vBox = new VBox();
|
||||||
vBox.setSpacing(10);
|
vBox.setSpacing(10);
|
||||||
|
|
||||||
|
@ -196,10 +196,12 @@ public class MnemonicKeystorePane extends TitledDescriptionPane {
|
||||||
|
|
||||||
vBox.getChildren().add(wordsPane);
|
vBox.getChildren().add(wordsPane);
|
||||||
|
|
||||||
|
if(showPassphrase) {
|
||||||
PassphraseEntry passphraseEntry = new PassphraseEntry(editPassphrase);
|
PassphraseEntry passphraseEntry = new PassphraseEntry(editPassphrase);
|
||||||
wordEntries.get(wordEntries.size() - 1).setNextField(passphraseEntry.getEditor());
|
wordEntries.get(wordEntries.size() - 1).setNextField(passphraseEntry.getEditor());
|
||||||
passphraseEntry.setPadding(new Insets(0, 26, 10, 10));
|
passphraseEntry.setPadding(new Insets(0, 26, 10, 10));
|
||||||
vBox.getChildren().add(passphraseEntry);
|
vBox.getChildren().add(passphraseEntry);
|
||||||
|
}
|
||||||
|
|
||||||
AnchorPane buttonPane = new AnchorPane();
|
AnchorPane buttonPane = new AnchorPane();
|
||||||
buttonPane.setPadding(new Insets(0, 26, 0, 10));
|
buttonPane.setPadding(new Insets(0, 26, 0, 10));
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
|
import com.sparrowwallet.sparrow.AppServices;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.*;
|
||||||
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SeedEntryDialog extends Dialog<List<String>> {
|
||||||
|
private final MnemonicKeystoreEntryPane keystorePane;
|
||||||
|
|
||||||
|
public SeedEntryDialog(int numWords) {
|
||||||
|
final DialogPane dialogPane = new MnemonicGridDialogPane();
|
||||||
|
setDialogPane(dialogPane);
|
||||||
|
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
|
||||||
|
AppServices.setStageIcon(dialogPane.getScene().getWindow());
|
||||||
|
|
||||||
|
int lines = numWords / 3;
|
||||||
|
int height = lines * 40;
|
||||||
|
|
||||||
|
StackPane stackPane = new StackPane();
|
||||||
|
dialogPane.setContent(stackPane);
|
||||||
|
|
||||||
|
AnchorPane anchorPane = new AnchorPane();
|
||||||
|
ScrollPane scrollPane = new ScrollPane();
|
||||||
|
scrollPane.getStyleClass().add("edge-to-edge");
|
||||||
|
scrollPane.setPrefHeight(104 + height);
|
||||||
|
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||||
|
scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||||
|
anchorPane.getChildren().add(scrollPane);
|
||||||
|
scrollPane.setFitToWidth(true);
|
||||||
|
AnchorPane.setLeftAnchor(scrollPane, 0.0);
|
||||||
|
AnchorPane.setRightAnchor(scrollPane, 0.0);
|
||||||
|
|
||||||
|
Accordion keystoreAccordion = new Accordion();
|
||||||
|
scrollPane.setContent(keystoreAccordion);
|
||||||
|
|
||||||
|
keystorePane = new MnemonicKeystoreEntryPane(numWords);
|
||||||
|
keystorePane.setAnimated(false);
|
||||||
|
keystoreAccordion.getPanes().add(keystorePane);
|
||||||
|
|
||||||
|
stackPane.getChildren().addAll(anchorPane);
|
||||||
|
|
||||||
|
dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
|
||||||
|
|
||||||
|
Button okButton = (Button)dialogPane.lookupButton(ButtonType.OK);
|
||||||
|
okButton.disableProperty().bind(keystorePane.validProperty().not());
|
||||||
|
|
||||||
|
final ButtonType generateButtonType = new javafx.scene.control.ButtonType("Generate New", ButtonBar.ButtonData.LEFT);
|
||||||
|
dialogPane.getButtonTypes().add(generateButtonType);
|
||||||
|
|
||||||
|
setResultConverter((dialogButton) -> {
|
||||||
|
ButtonBar.ButtonData data = dialogButton == null ? null : dialogButton.getButtonData();
|
||||||
|
return data == ButtonBar.ButtonData.OK_DONE ? keystorePane.wordEntriesProperty.get() : null;
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogPane.setPrefWidth(500);
|
||||||
|
dialogPane.setPrefHeight(180 + height);
|
||||||
|
AppServices.moveToActiveWindowScreen(this);
|
||||||
|
|
||||||
|
Platform.runLater(() -> keystoreAccordion.setExpandedPane(keystorePane));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MnemonicGridDialogPane extends DialogPane {
|
||||||
|
@Override
|
||||||
|
protected Node createButton(ButtonType buttonType) {
|
||||||
|
Node button;
|
||||||
|
if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT) {
|
||||||
|
Button generateButton = new Button(buttonType.getText());
|
||||||
|
final ButtonBar.ButtonData buttonData = buttonType.getButtonData();
|
||||||
|
ButtonBar.setButtonData(generateButton, buttonData);
|
||||||
|
generateButton.setOnAction(event -> {
|
||||||
|
keystorePane.generateNew();
|
||||||
|
});
|
||||||
|
|
||||||
|
button = generateButton;
|
||||||
|
} else {
|
||||||
|
button = super.createButton(buttonType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGenerated() {
|
||||||
|
return keystorePane.isGenerated();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue