introduce wallet subtabs

This commit is contained in:
Craig Raw 2021-07-30 09:46:42 +02:00
parent fc9cdaabb4
commit 02d3817cb1
5 changed files with 129 additions and 64 deletions

View file

@ -40,6 +40,7 @@ import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.Parent; import javafx.scene.Parent;
import javafx.scene.Scene; import javafx.scene.Scene;
@ -218,8 +219,8 @@ public class AppController implements Initializable {
EventManager.get().post(new OpenWalletsEvent(tabs.getScene().getWindow(), getOpenWalletTabData())); EventManager.get().post(new OpenWalletsEvent(tabs.getScene().getWindow(), getOpenWalletTabData()));
} }
List<WalletTabData> closedWalletTabs = c.getRemoved().stream().map(tab -> (TabData)tab.getUserData()) List<WalletTabData> closedWalletTabs = c.getRemoved().stream().filter(tab -> tab.getUserData() instanceof WalletTabData)
.filter(tabData -> tabData.getType() == TabData.TabType.WALLET).map(tabData -> (WalletTabData)tabData).collect(Collectors.toList()); .flatMap(tab -> ((TabPane)tab.getContent()).getTabs().stream().map(subTab -> (WalletTabData)subTab.getUserData())).collect(Collectors.toList());
if(!closedWalletTabs.isEmpty()) { if(!closedWalletTabs.isEmpty()) {
EventManager.get().post(new WalletTabsClosedEvent(closedWalletTabs)); EventManager.get().post(new WalletTabsClosedEvent(closedWalletTabs));
} }
@ -619,9 +620,11 @@ public class AppController implements Initializable {
List<WalletTabData> openWalletTabData = new ArrayList<>(); List<WalletTabData> openWalletTabData = new ArrayList<>();
for(Tab tab : tabs.getTabs()) { for(Tab tab : tabs.getTabs()) {
TabData tabData = (TabData)tab.getUserData(); if(tab.getUserData() instanceof WalletTabData) {
if(tabData.getType() == TabData.TabType.WALLET) { TabPane subTabs = (TabPane)tab.getContent();
openWalletTabData.add((WalletTabData)tabData); for(Tab subTab : subTabs.getTabs()) {
openWalletTabData.add((WalletTabData)subTab.getUserData());
}
} }
} }
@ -640,11 +643,14 @@ public class AppController implements Initializable {
public void selectTab(Wallet wallet) { public void selectTab(Wallet wallet) {
for(Tab tab : tabs.getTabs()) { for(Tab tab : tabs.getTabs()) {
TabData tabData = (TabData) tab.getUserData(); if(tab.getUserData() instanceof WalletTabData) {
if(tabData.getType() == TabData.TabType.WALLET) { TabPane subTabs = (TabPane)tab.getContent();
WalletTabData walletTabData = (WalletTabData) tabData; for(Tab subTab : subTabs.getTabs()) {
WalletTabData walletTabData = (WalletTabData)subTab.getUserData();
if(walletTabData.getWallet() == wallet) { if(walletTabData.getWallet() == wallet) {
tabs.getSelectionModel().select(tab); tabs.getSelectionModel().select(tab);
subTabs.getSelectionModel().select(subTab);
}
} }
} }
} }
@ -950,14 +956,16 @@ public class AppController implements Initializable {
//Close existing wallet first if open //Close existing wallet first if open
for(Iterator<Tab> iter = tabs.getTabs().iterator(); iter.hasNext(); ) { for(Iterator<Tab> iter = tabs.getTabs().iterator(); iter.hasNext(); ) {
Tab tab = iter.next(); Tab tab = iter.next();
TabData tabData = (TabData)tab.getUserData(); if(tab.getUserData() instanceof WalletTabData) {
if(tabData.getType() == TabData.TabType.WALLET) { TabPane subTabs = (TabPane)tab.getContent();
WalletTabData walletTabData = (WalletTabData) tabData; for(Tab subTab : subTabs.getTabs()) {
WalletTabData walletTabData = (WalletTabData)subTab.getUserData();
if(walletTabData.getStorage().getWalletFile().equals(walletFile)) { if(walletTabData.getStorage().getWalletFile().equals(walletFile)) {
iter.remove(); iter.remove();
} }
} }
} }
}
walletFile.delete(); walletFile.delete();
} }
@ -1016,11 +1024,9 @@ public class AppController implements Initializable {
} }
public void exportWallet(ActionEvent event) { public void exportWallet(ActionEvent event) {
Tab selectedTab = tabs.getSelectionModel().getSelectedItem(); WalletForm selectedWalletForm = getSelectedWalletForm();
TabData tabData = (TabData)selectedTab.getUserData(); if(selectedWalletForm != null) {
if(tabData.getType() == TabData.TabType.WALLET) { WalletExportDialog dlg = new WalletExportDialog(selectedWalletForm.getWallet());
WalletTabData walletTabData = (WalletTabData)tabData;
WalletExportDialog dlg = new WalletExportDialog(walletTabData.getWallet());
Optional<Wallet> wallet = dlg.showAndWait(); Optional<Wallet> wallet = dlg.showAndWait();
if(wallet.isPresent()) { if(wallet.isPresent()) {
//Successful export //Successful export
@ -1035,10 +1041,9 @@ public class AppController implements Initializable {
public void signVerifyMessage(ActionEvent event) { public void signVerifyMessage(ActionEvent event) {
MessageSignDialog messageSignDialog = null; MessageSignDialog messageSignDialog = null;
Tab tab = tabs.getSelectionModel().getSelectedItem(); WalletForm selectedWalletForm = getSelectedWalletForm();
if(tab != null && tab.getUserData() instanceof WalletTabData) { if(selectedWalletForm != null) {
WalletTabData walletTabData = (WalletTabData)tab.getUserData(); Wallet wallet = selectedWalletForm.getWallet();
Wallet wallet = walletTabData.getWallet();
if(wallet.getKeystores().size() == 1 && if(wallet.getKeystores().size() == 1 &&
(wallet.getKeystores().get(0).hasPrivateKey() || wallet.getKeystores().get(0).getSource() == KeystoreSource.HW_USB)) { (wallet.getKeystores().get(0).hasPrivateKey() || wallet.getKeystores().get(0).getSource() == KeystoreSource.HW_USB)) {
//Can sign and verify //Can sign and verify
@ -1055,11 +1060,9 @@ public class AppController implements Initializable {
} }
public void sendToMany(ActionEvent event) { public void sendToMany(ActionEvent event) {
Tab selectedTab = tabs.getSelectionModel().getSelectedItem(); WalletForm selectedWalletForm = getSelectedWalletForm();
TabData tabData = (TabData)selectedTab.getUserData(); if(selectedWalletForm != null) {
if(tabData.getType() == TabData.TabType.WALLET) { Wallet wallet = selectedWalletForm.getWallet();
WalletTabData walletTabData = (WalletTabData) tabData;
Wallet wallet = walletTabData.getWallet();
BitcoinUnit bitcoinUnit = Config.get().getBitcoinUnit(); BitcoinUnit bitcoinUnit = Config.get().getBitcoinUnit();
if(bitcoinUnit == BitcoinUnit.AUTO) { if(bitcoinUnit == BitcoinUnit.AUTO) {
bitcoinUnit = wallet.getAutoUnit(); bitcoinUnit = wallet.getAutoUnit();
@ -1081,16 +1084,14 @@ public class AppController implements Initializable {
} }
public void refreshWallet(ActionEvent event) { public void refreshWallet(ActionEvent event) {
Tab selectedTab = tabs.getSelectionModel().getSelectedItem(); WalletForm selectedWalletForm = getSelectedWalletForm();
TabData tabData = (TabData)selectedTab.getUserData(); if(selectedWalletForm != null) {
if(tabData.getType() == TabData.TabType.WALLET) { Wallet wallet = selectedWalletForm.getWallet();
WalletTabData walletTabData = (WalletTabData) tabData;
Wallet wallet = walletTabData.getWallet();
Wallet pastWallet = wallet.copy(); Wallet pastWallet = wallet.copy();
walletTabData.getStorage().backupTempWallet(); selectedWalletForm.getStorage().backupTempWallet();
wallet.clearHistory(); wallet.clearHistory();
AppServices.clearTransactionHistoryCache(wallet); AppServices.clearTransactionHistoryCache(wallet);
EventManager.get().post(new WalletHistoryClearedEvent(wallet, pastWallet, walletTabData.getWalletForm().getWalletId())); EventManager.get().post(new WalletHistoryClearedEvent(wallet, pastWallet, selectedWalletForm.getWalletId()));
} }
} }
@ -1118,7 +1119,7 @@ public class AppController implements Initializable {
} }
public void addWalletTab(Storage storage, Wallet wallet, Wallet backupWallet) { public void addWalletTab(Storage storage, Wallet wallet, Wallet backupWallet) {
try { if(wallet.isMasterWallet()) {
String name = storage.getWalletName(wallet); String name = storage.getWalletName(wallet);
if(!name.equals(wallet.getName())) { if(!name.equals(wallet.getName())) {
wallet.setName(name); wallet.setName(name);
@ -1133,8 +1134,46 @@ public class AppController implements Initializable {
tab.setGraphic(tabLabel); tab.setGraphic(tabLabel);
tab.setContextMenu(getTabContextMenu(tab)); tab.setContextMenu(getTabContextMenu(tab));
tab.setClosable(true); tab.setClosable(true);
TabPane subTabs = new TabPane();
subTabs.setSide(Side.RIGHT);
subTabs.getStyleClass().add("master-only");
tab.setContent(subTabs);
subTabs.getSelectionModel().selectedItemProperty().addListener((observable, old_val, selectedTab) -> {
if(selectedTab != null) {
EventManager.get().post(new WalletTabSelectedEvent(tab));
}
});
WalletForm walletForm = addWalletSubTab(subTabs, storage, wallet, backupWallet);
TabData tabData = new WalletTabData(TabData.TabType.WALLET, walletForm);
tab.setUserData(tabData);
tabs.getTabs().add(tab);
tabs.getSelectionModel().select(tab);
} else {
for(Tab walletTab : tabs.getTabs()) {
TabData tabData = (TabData)walletTab.getUserData();
if(tabData instanceof WalletTabData) {
WalletTabData walletTabData = (WalletTabData)tabData;
if(walletTabData.getWallet() == wallet.getMasterWallet()) {
TabPane subTabs = (TabPane)walletTab.getContent();
subTabs.getStyleClass().remove("master-only");
addWalletSubTab(subTabs, storage, wallet, backupWallet);
}
}
}
}
}
public WalletForm addWalletSubTab(TabPane subTabs, Storage storage, Wallet wallet, Wallet backupWallet) {
try {
Tab subTab = new Tab(wallet.getName());
subTab.setClosable(false);
FXMLLoader walletLoader = new FXMLLoader(getClass().getResource("wallet/wallet.fxml")); FXMLLoader walletLoader = new FXMLLoader(getClass().getResource("wallet/wallet.fxml"));
tab.setContent(walletLoader.load()); subTab.setContent(walletLoader.load());
WalletController controller = walletLoader.getController(); WalletController controller = walletLoader.getController();
EventManager.get().post(new WalletOpeningEvent(storage, wallet)); EventManager.get().post(new WalletOpeningEvent(storage, wallet));
@ -1145,15 +1184,30 @@ public class AppController implements Initializable {
controller.setWalletForm(walletForm); controller.setWalletForm(walletForm);
TabData tabData = new WalletTabData(TabData.TabType.WALLET, walletForm); TabData tabData = new WalletTabData(TabData.TabType.WALLET, walletForm);
tab.setUserData(tabData); subTab.setUserData(tabData);
tabs.getTabs().add(tab); subTabs.getTabs().add(subTab);
tabs.getSelectionModel().select(tab); subTabs.getSelectionModel().select(subTab);
return walletForm;
} catch(IOException e) { } catch(IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public WalletForm getSelectedWalletForm() {
Tab selectedTab = tabs.getSelectionModel().getSelectedItem();
TabData tabData = (TabData)selectedTab.getUserData();
if(tabData instanceof WalletTabData) {
TabPane subTabs = (TabPane)selectedTab.getContent();
Tab selectedSubTab = subTabs.getSelectionModel().getSelectedItem();
WalletTabData subWalletTabData = (WalletTabData)selectedSubTab.getUserData();
return subWalletTabData.getWalletForm();
}
return null;
}
public void openExamples(ActionEvent event) { public void openExamples(ActionEvent event) {
try { try {
addTransactionTab("p2pkh", null, "01000000019c2e0f24a03e72002a96acedb12a632e72b6b74c05dc3ceab1fe78237f886c48010000006a47304402203da9d487be5302a6d69e02a861acff1da472885e43d7528ed9b1b537a8e2cac9022002d1bca03a1e9715a99971bafe3b1852b7a4f0168281cbd27a220380a01b3307012102c9950c622494c2e9ff5a003e33b690fe4832477d32c2d256c67eab8bf613b34effffffff02b6f50500000000001976a914bdf63990d6dc33d705b756e13dd135466c06b3b588ac845e0201000000001976a9145fb0e9755a3424efd2ba0587d20b1e98ee29814a88ac06241559"); addTransactionTab("p2pkh", null, "01000000019c2e0f24a03e72002a96acedb12a632e72b6b74c05dc3ceab1fe78237f886c48010000006a47304402203da9d487be5302a6d69e02a861acff1da472885e43d7528ed9b1b537a8e2cac9022002d1bca03a1e9715a99971bafe3b1852b7a4f0168281cbd27a220380a01b3307012102c9950c622494c2e9ff5a003e33b690fe4832477d32c2d256c67eab8bf613b34effffffff02b6f50500000000001976a914bdf63990d6dc33d705b756e13dd135466c06b3b588ac845e0201000000001976a9145fb0e9755a3424efd2ba0587d20b1e98ee29814a88ac06241559");
@ -1507,11 +1561,9 @@ public class AppController implements Initializable {
@Subscribe @Subscribe
public void walletAddressesChanged(WalletAddressesChangedEvent event) { public void walletAddressesChanged(WalletAddressesChangedEvent event) {
Tab tab = tabs.getSelectionModel().getSelectedItem(); WalletForm selectedWalletForm = getSelectedWalletForm();
TabData tabData = (TabData)tab.getUserData(); if(selectedWalletForm != null) {
if(tabData instanceof WalletTabData) { if(selectedWalletForm.getWalletId().equals(event.getWalletId())) {
WalletTabData walletTabData = (WalletTabData)tabData;
if(walletTabData.getWalletForm().getWalletId().equals(event.getWalletId())) {
exportWallet.setDisable(!event.getWallet().isValid()); exportWallet.setDisable(!event.getWallet().isValid());
} }
} }
@ -1827,28 +1879,34 @@ public class AppController implements Initializable {
public void viewWallet(ViewWalletEvent event) { public void viewWallet(ViewWalletEvent event) {
if(tabs.getScene().getWindow().equals(event.getWindow())) { if(tabs.getScene().getWindow().equals(event.getWindow())) {
for(Tab tab : tabs.getTabs()) { for(Tab tab : tabs.getTabs()) {
TabData tabData = (TabData) tab.getUserData(); if(tab.getUserData() instanceof WalletTabData) {
if(tabData.getType() == TabData.TabType.WALLET) { TabPane subTabs = (TabPane)tab.getContent();
WalletTabData walletTabData = (WalletTabData) tabData; for(Tab subTab : subTabs.getTabs()) {
WalletTabData walletTabData = (WalletTabData)subTab.getUserData();
if(event.getStorage().getWalletId(event.getWallet()).equals(walletTabData.getWalletForm().getWalletId())) { if(event.getStorage().getWalletId(event.getWallet()).equals(walletTabData.getWalletForm().getWalletId())) {
tabs.getSelectionModel().select(tab); tabs.getSelectionModel().select(tab);
subTabs.getSelectionModel().select(subTab);
return; return;
} }
} }
} }
}
for(Tab tab : tabs.getTabs()) { for(Tab tab : tabs.getTabs()) {
TabData tabData = (TabData) tab.getUserData(); if(tab.getUserData() instanceof WalletTabData) {
if(tabData.getType() == TabData.TabType.WALLET) { TabPane subTabs = (TabPane)tab.getContent();
WalletTabData walletTabData = (WalletTabData) tabData; for(Tab subTab : subTabs.getTabs()) {
WalletTabData walletTabData = (WalletTabData)subTab.getUserData();
if(event.getStorage().getWalletFile().equals(walletTabData.getStorage().getWalletFile())) { if(event.getStorage().getWalletFile().equals(walletTabData.getStorage().getWalletFile())) {
tabs.getSelectionModel().select(tab); tabs.getSelectionModel().select(tab);
subTabs.getSelectionModel().select(subTab);
return; return;
} }
} }
} }
} }
} }
}
@Subscribe @Subscribe
public void viewTransaction(ViewTransactionEvent event) { public void viewTransaction(ViewTransactionEvent event) {

View file

@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.sparrow.WalletTabData; import com.sparrowwallet.sparrow.WalletTabData;
import javafx.scene.control.Tab; import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
public class WalletTabSelectedEvent extends TabSelectedEvent { public class WalletTabSelectedEvent extends TabSelectedEvent {
public WalletTabSelectedEvent(Tab tab) { public WalletTabSelectedEvent(Tab tab) {
@ -9,6 +10,8 @@ public class WalletTabSelectedEvent extends TabSelectedEvent {
} }
public WalletTabData getWalletTabData() { public WalletTabData getWalletTabData() {
return (WalletTabData)getTabData(); TabPane subTabs = (TabPane)getTab().getContent();
Tab subTab = subTabs.getSelectionModel().getSelectedItem();
return (WalletTabData)subTab.getUserData();
} }
} }

View file

@ -14,7 +14,6 @@ import javafx.scene.Node;
import javafx.scene.control.Toggle; import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleButton; import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup; import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import java.io.IOException; import java.io.IOException;
@ -22,9 +21,6 @@ import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
public class WalletController extends WalletFormController implements Initializable { public class WalletController extends WalletFormController implements Initializable {
@FXML
private BorderPane tabContent;
@FXML @FXML
private StackPane walletPane; private StackPane walletPane;

View file

@ -24,6 +24,14 @@
-fx-text-fill: rgb(202, 18, 67); -fx-text-fill: rgb(202, 18, 67);
} }
.master-only {
-fx-tab-max-height: 0;
}
.master-only .tab-header-area {
visibility: hidden;
}
.status-bar .status-label { .status-bar .status-label {
-fx-alignment: center-left; -fx-alignment: center-left;
} }

View file

@ -8,7 +8,7 @@
<?import org.controlsfx.glyphfont.Glyph?> <?import org.controlsfx.glyphfont.Glyph?>
<?import com.sparrowwallet.sparrow.wallet.Function?> <?import com.sparrowwallet.sparrow.wallet.Function?>
<BorderPane fx:id="tabContent" stylesheets="@wallet.css, @../general.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.wallet.WalletController"> <BorderPane stylesheets="@wallet.css, @../general.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.sparrowwallet.sparrow.wallet.WalletController">
<left> <left>
<VBox styleClass="list-menu"> <VBox styleClass="list-menu">
<ToggleButton VBox.vgrow="ALWAYS" text="Transactions" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity"> <ToggleButton VBox.vgrow="ALWAYS" text="Transactions" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity">