walletfx: Introduce OverlayWindowController interface

Rationale:

1. Stronger typing makes code more readable and refactorable
2. Eliminates “automatic” reflection in MainController
3. Makes overlayUI field in implementing classes private
4. Is a step towards further refactoring and reusability
This commit is contained in:
Sean Gilligan 2021-09-19 12:34:52 -07:00
parent 17aeea2d75
commit 44ca7f6689
7 changed files with 73 additions and 26 deletions

View File

@ -0,0 +1,28 @@
/*
* Copyright by the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.walletfx.overlay;
import wallettemplate.MainController;
/**
* Interface for controllers displayed via OverlayWindow.OverlayUI
*/
public interface OverlayWindowController<T> {
/**
* @param ui The overlay UI (node, controller pair)
*/
void setOverlayUI(MainController.OverlayUI<? extends OverlayWindowController<T>> ui);
}

View File

@ -36,12 +36,12 @@ import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.util.Duration;
import org.bitcoinj.walletfx.overlay.OverlayWindowController;
import org.bitcoinj.walletfx.utils.GuiUtils;
import org.bitcoinj.walletfx.utils.TextFieldValidator;
import wallettemplate.controls.ClickableBitcoinAddress;
import wallettemplate.controls.NotificationBarPane;
import org.bitcoinj.walletfx.utils.BitcoinUIModel;
import org.bitcoinj.walletfx.utils.GuiUtils;
import org.bitcoinj.walletfx.utils.easing.EasingMode;
import org.bitcoinj.walletfx.utils.easing.ElasticInterpolator;
@ -170,7 +170,7 @@ public class MainController {
return model.getDownloadProgressTracker();
}
public class OverlayUI<T> {
public class OverlayUI<T extends OverlayWindowController<T>> {
public Node ui;
public T controller;
@ -219,22 +219,18 @@ public class MainController {
}
@Nullable
private OverlayUI currentOverlay;
private OverlayUI<? extends OverlayWindowController<?>> currentOverlay;
public <T> OverlayUI<T> overlayUI(Node node, T controller) {
public <T extends OverlayWindowController<T>> OverlayUI<T> overlayUI(Node node, T controller) {
checkGuiThread();
OverlayUI<T> pair = new OverlayUI<>(node, controller);
// Auto-magically set the overlayUI member, if it's there.
try {
controller.getClass().getField("overlayUI").set(controller, pair);
} catch (IllegalAccessException | NoSuchFieldException ignored) {
}
controller.setOverlayUI(pair);
pair.show();
return pair;
}
/** Loads the FXML file with the given name, blurs out the main UI and puts this one on top. */
public <T> OverlayUI<T> overlayUI(String name) {
public <T extends OverlayWindowController<T>> OverlayUI<T> overlayUI(String name) {
try {
checkGuiThread();
// Load the UI from disk.
@ -243,13 +239,7 @@ public class MainController {
Pane ui = loader.load();
T controller = loader.getController();
OverlayUI<T> pair = new OverlayUI<>(ui, controller);
// Auto-magically set the overlayUI member, if it's there.
try {
if (controller != null)
controller.getClass().getField("overlayUI").set(controller, pair);
} catch (IllegalAccessException | NoSuchFieldException ignored) {
ignored.printStackTrace();
}
controller.setOverlayUI(pair);
pair.show();
return pair;
} catch (IOException e) {

View File

@ -29,6 +29,7 @@ import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import org.bitcoinj.walletfx.overlay.OverlayWindowController;
import org.bouncycastle.crypto.params.KeyParameter;
import wallettemplate.controls.BitcoinAddressValidator;
import org.bitcoinj.walletfx.utils.TextFieldValidator;
@ -39,7 +40,7 @@ import static org.bitcoinj.walletfx.utils.GuiUtils.*;
import javax.annotation.Nullable;
public class SendMoneyController {
public class SendMoneyController implements OverlayWindowController<SendMoneyController> {
public Button sendBtn;
public Button cancelBtn;
public TextField address;
@ -47,11 +48,16 @@ public class SendMoneyController {
public TextField amountEdit;
public Label btcLabel;
public MainController.OverlayUI overlayUI;
private MainController.OverlayUI<? extends OverlayWindowController<SendMoneyController>> overlayUI;
private Wallet.SendResult sendResult;
private KeyParameter aesKey;
@Override
public void setOverlayUI(MainController.OverlayUI<? extends OverlayWindowController<SendMoneyController>> ui) {
overlayUI = ui;
}
// Called by FXMLLoader
public void initialize() {
Coin balance = Main.bitcoin.wallet().getBalance();

View File

@ -30,6 +30,7 @@ import javafx.scene.control.ProgressIndicator;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import org.bitcoinj.walletfx.overlay.OverlayWindowController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.bouncycastle.crypto.params.KeyParameter;
@ -44,7 +45,7 @@ import static org.bitcoinj.walletfx.utils.GuiUtils.*;
* User interface for entering a password on demand, e.g. to send money. Also used when encrypting a wallet. Shows a
* progress meter as we scrypt the password.
*/
public class WalletPasswordController {
public class WalletPasswordController implements OverlayWindowController<WalletPasswordController> {
private static final Logger log = LoggerFactory.getLogger(WalletPasswordController.class);
@FXML HBox buttonsBox;
@ -54,10 +55,15 @@ public class WalletPasswordController {
@FXML GridPane widgetGrid;
@FXML Label explanationLabel;
public MainController.OverlayUI overlayUI;
private MainController.OverlayUI<? extends OverlayWindowController<WalletPasswordController>> overlayUI;
private SimpleObjectProperty<KeyParameter> aesKey = new SimpleObjectProperty<>();
@Override
public void setOverlayUI(MainController.OverlayUI<? extends OverlayWindowController<WalletPasswordController>> ui) {
overlayUI = ui;
}
public void initialize() {
progressMeter.setOpacity(0);
Platform.runLater(pass1::requestFocus);

View File

@ -23,6 +23,7 @@ import javafx.scene.control.*;
import javafx.scene.layout.*;
import org.bitcoinj.crypto.*;
import org.bitcoinj.wallet.*;
import org.bitcoinj.walletfx.overlay.OverlayWindowController;
import org.slf4j.*;
import org.bouncycastle.crypto.params.*;
@ -34,7 +35,7 @@ import java.util.concurrent.*;
import org.bitcoinj.walletfx.utils.KeyDerivationTasks;
import static org.bitcoinj.walletfx.utils.GuiUtils.*;
public class WalletSetPasswordController {
public class WalletSetPasswordController implements OverlayWindowController<WalletSetPasswordController> {
private static final Logger log = LoggerFactory.getLogger(WalletSetPasswordController.class);
public PasswordField pass1, pass2;
@ -43,7 +44,7 @@ public class WalletSetPasswordController {
public Button closeButton;
public Label explanationLabel;
public MainController.OverlayUI overlayUI;
private MainController.OverlayUI<? extends OverlayWindowController<WalletSetPasswordController>> overlayUI;
// These params were determined empirically on a top-range (as of 2014) MacBook Pro with native scrypt support,
// using the scryptenc command line tool from the original scrypt distribution, given a memory limit of 40mb.
public static final Protos.ScryptParameters SCRYPT_PARAMETERS = Protos.ScryptParameters.newBuilder()
@ -53,6 +54,11 @@ public class WalletSetPasswordController {
.setSalt(ByteString.copyFrom(KeyCrypterScrypt.randomSalt()))
.build();
@Override
public void setOverlayUI(MainController.OverlayUI<? extends OverlayWindowController<WalletSetPasswordController>> ui) {
overlayUI = ui;
}
public void initialize() {
progressMeter.setOpacity(0);
}

View File

@ -28,6 +28,7 @@ import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TextArea;
import org.bitcoinj.walletfx.overlay.OverlayWindowController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.bouncycastle.crypto.params.KeyParameter;
@ -47,7 +48,7 @@ import static org.bitcoinj.walletfx.utils.GuiUtils.informationalAlert;
import static org.bitcoinj.walletfx.utils.WTUtils.didThrow;
import static org.bitcoinj.walletfx.utils.WTUtils.unchecked;
public class WalletSettingsController {
public class WalletSettingsController implements OverlayWindowController<WalletSettingsController> {
private static final Logger log = LoggerFactory.getLogger(WalletSettingsController.class);
@FXML Button passwordButton;
@ -55,10 +56,15 @@ public class WalletSettingsController {
@FXML TextArea wordsArea;
@FXML Button restoreButton;
public MainController.OverlayUI overlayUI;
private MainController.OverlayUI<? extends OverlayWindowController<WalletSettingsController>> overlayUI;
private KeyParameter aesKey;
@Override
public void setOverlayUI(MainController.OverlayUI<? extends OverlayWindowController<WalletSettingsController>> ui) {
overlayUI = ui;
}
// Note: NOT called by FXMLLoader!
public void initialize(@Nullable KeyParameter aesKey) {
DeterministicSeed seed = Main.bitcoin.wallet().getKeyChainSeed();

View File

@ -42,6 +42,7 @@ import javafx.scene.layout.Pane;
import org.bitcoinj.core.Address;
import org.bitcoinj.uri.BitcoinURI;
import org.bitcoinj.walletfx.overlay.OverlayWindowController;
import wallettemplate.Main;
import org.bitcoinj.walletfx.utils.GuiUtils;
import org.bitcoinj.walletfx.utils.QRCodeImages;
@ -57,7 +58,7 @@ import static javafx.beans.binding.Bindings.convert;
* address looks like a blue hyperlink. Next to it there are two icons, one that copies to the clipboard and another
* that shows a QRcode.
*/
public class ClickableBitcoinAddress extends AnchorPane {
public class ClickableBitcoinAddress extends AnchorPane implements OverlayWindowController<ClickableBitcoinAddress> {
@FXML protected Label addressLabel;
@FXML protected ContextMenu addressMenu;
@FXML protected Label copyWidget;
@ -66,6 +67,10 @@ public class ClickableBitcoinAddress extends AnchorPane {
protected SimpleObjectProperty<Address> address = new SimpleObjectProperty<>();
private final StringExpression addressStr;
@Override
public void setOverlayUI(MainController.OverlayUI<? extends OverlayWindowController<ClickableBitcoinAddress>> ui) {
}
public ClickableBitcoinAddress() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("bitcoin_address.fxml"));