diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java index 2bf87e93..3162bd5d 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppController.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java @@ -40,6 +40,7 @@ import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; import javafx.geometry.Pos; +import javafx.geometry.Side; import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.Scene; @@ -218,8 +219,8 @@ public class AppController implements Initializable { EventManager.get().post(new OpenWalletsEvent(tabs.getScene().getWindow(), getOpenWalletTabData())); } - List closedWalletTabs = c.getRemoved().stream().map(tab -> (TabData)tab.getUserData()) - .filter(tabData -> tabData.getType() == TabData.TabType.WALLET).map(tabData -> (WalletTabData)tabData).collect(Collectors.toList()); + List closedWalletTabs = c.getRemoved().stream().filter(tab -> tab.getUserData() instanceof WalletTabData) + .flatMap(tab -> ((TabPane)tab.getContent()).getTabs().stream().map(subTab -> (WalletTabData)subTab.getUserData())).collect(Collectors.toList()); if(!closedWalletTabs.isEmpty()) { EventManager.get().post(new WalletTabsClosedEvent(closedWalletTabs)); } @@ -619,9 +620,11 @@ public class AppController implements Initializable { List openWalletTabData = new ArrayList<>(); for(Tab tab : tabs.getTabs()) { - TabData tabData = (TabData)tab.getUserData(); - if(tabData.getType() == TabData.TabType.WALLET) { - openWalletTabData.add((WalletTabData)tabData); + if(tab.getUserData() instanceof WalletTabData) { + TabPane subTabs = (TabPane)tab.getContent(); + for(Tab subTab : subTabs.getTabs()) { + openWalletTabData.add((WalletTabData)subTab.getUserData()); + } } } @@ -640,11 +643,14 @@ public class AppController implements Initializable { public void selectTab(Wallet wallet) { for(Tab tab : tabs.getTabs()) { - TabData tabData = (TabData) tab.getUserData(); - if(tabData.getType() == TabData.TabType.WALLET) { - WalletTabData walletTabData = (WalletTabData) tabData; - if(walletTabData.getWallet() == wallet) { - tabs.getSelectionModel().select(tab); + if(tab.getUserData() instanceof WalletTabData) { + TabPane subTabs = (TabPane)tab.getContent(); + for(Tab subTab : subTabs.getTabs()) { + WalletTabData walletTabData = (WalletTabData)subTab.getUserData(); + if(walletTabData.getWallet() == wallet) { + tabs.getSelectionModel().select(tab); + subTabs.getSelectionModel().select(subTab); + } } } } @@ -950,11 +956,13 @@ public class AppController implements Initializable { //Close existing wallet first if open for(Iterator iter = tabs.getTabs().iterator(); iter.hasNext(); ) { Tab tab = iter.next(); - TabData tabData = (TabData)tab.getUserData(); - if(tabData.getType() == TabData.TabType.WALLET) { - WalletTabData walletTabData = (WalletTabData) tabData; - if(walletTabData.getStorage().getWalletFile().equals(walletFile)) { - iter.remove(); + if(tab.getUserData() instanceof WalletTabData) { + TabPane subTabs = (TabPane)tab.getContent(); + for(Tab subTab : subTabs.getTabs()) { + WalletTabData walletTabData = (WalletTabData)subTab.getUserData(); + if(walletTabData.getStorage().getWalletFile().equals(walletFile)) { + iter.remove(); + } } } } @@ -1016,11 +1024,9 @@ public class AppController implements Initializable { } public void exportWallet(ActionEvent event) { - Tab selectedTab = tabs.getSelectionModel().getSelectedItem(); - TabData tabData = (TabData)selectedTab.getUserData(); - if(tabData.getType() == TabData.TabType.WALLET) { - WalletTabData walletTabData = (WalletTabData)tabData; - WalletExportDialog dlg = new WalletExportDialog(walletTabData.getWallet()); + WalletForm selectedWalletForm = getSelectedWalletForm(); + if(selectedWalletForm != null) { + WalletExportDialog dlg = new WalletExportDialog(selectedWalletForm.getWallet()); Optional wallet = dlg.showAndWait(); if(wallet.isPresent()) { //Successful export @@ -1035,10 +1041,9 @@ public class AppController implements Initializable { public void signVerifyMessage(ActionEvent event) { MessageSignDialog messageSignDialog = null; - Tab tab = tabs.getSelectionModel().getSelectedItem(); - if(tab != null && tab.getUserData() instanceof WalletTabData) { - WalletTabData walletTabData = (WalletTabData)tab.getUserData(); - Wallet wallet = walletTabData.getWallet(); + WalletForm selectedWalletForm = getSelectedWalletForm(); + if(selectedWalletForm != null) { + Wallet wallet = selectedWalletForm.getWallet(); if(wallet.getKeystores().size() == 1 && (wallet.getKeystores().get(0).hasPrivateKey() || wallet.getKeystores().get(0).getSource() == KeystoreSource.HW_USB)) { //Can sign and verify @@ -1055,11 +1060,9 @@ public class AppController implements Initializable { } public void sendToMany(ActionEvent event) { - Tab selectedTab = tabs.getSelectionModel().getSelectedItem(); - TabData tabData = (TabData)selectedTab.getUserData(); - if(tabData.getType() == TabData.TabType.WALLET) { - WalletTabData walletTabData = (WalletTabData) tabData; - Wallet wallet = walletTabData.getWallet(); + WalletForm selectedWalletForm = getSelectedWalletForm(); + if(selectedWalletForm != null) { + Wallet wallet = selectedWalletForm.getWallet(); BitcoinUnit bitcoinUnit = Config.get().getBitcoinUnit(); if(bitcoinUnit == BitcoinUnit.AUTO) { bitcoinUnit = wallet.getAutoUnit(); @@ -1081,16 +1084,14 @@ public class AppController implements Initializable { } public void refreshWallet(ActionEvent event) { - Tab selectedTab = tabs.getSelectionModel().getSelectedItem(); - TabData tabData = (TabData)selectedTab.getUserData(); - if(tabData.getType() == TabData.TabType.WALLET) { - WalletTabData walletTabData = (WalletTabData) tabData; - Wallet wallet = walletTabData.getWallet(); + WalletForm selectedWalletForm = getSelectedWalletForm(); + if(selectedWalletForm != null) { + Wallet wallet = selectedWalletForm.getWallet(); Wallet pastWallet = wallet.copy(); - walletTabData.getStorage().backupTempWallet(); + selectedWalletForm.getStorage().backupTempWallet(); wallet.clearHistory(); 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) { - try { + if(wallet.isMasterWallet()) { String name = storage.getWalletName(wallet); if(!name.equals(wallet.getName())) { wallet.setName(name); @@ -1133,8 +1134,46 @@ public class AppController implements Initializable { tab.setGraphic(tabLabel); tab.setContextMenu(getTabContextMenu(tab)); 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")); - tab.setContent(walletLoader.load()); + subTab.setContent(walletLoader.load()); WalletController controller = walletLoader.getController(); EventManager.get().post(new WalletOpeningEvent(storage, wallet)); @@ -1145,15 +1184,30 @@ public class AppController implements Initializable { controller.setWalletForm(walletForm); TabData tabData = new WalletTabData(TabData.TabType.WALLET, walletForm); - tab.setUserData(tabData); + subTab.setUserData(tabData); - tabs.getTabs().add(tab); - tabs.getSelectionModel().select(tab); + subTabs.getTabs().add(subTab); + subTabs.getSelectionModel().select(subTab); + + return walletForm; } catch(IOException 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) { try { addTransactionTab("p2pkh", null, "01000000019c2e0f24a03e72002a96acedb12a632e72b6b74c05dc3ceab1fe78237f886c48010000006a47304402203da9d487be5302a6d69e02a861acff1da472885e43d7528ed9b1b537a8e2cac9022002d1bca03a1e9715a99971bafe3b1852b7a4f0168281cbd27a220380a01b3307012102c9950c622494c2e9ff5a003e33b690fe4832477d32c2d256c67eab8bf613b34effffffff02b6f50500000000001976a914bdf63990d6dc33d705b756e13dd135466c06b3b588ac845e0201000000001976a9145fb0e9755a3424efd2ba0587d20b1e98ee29814a88ac06241559"); @@ -1507,11 +1561,9 @@ public class AppController implements Initializable { @Subscribe public void walletAddressesChanged(WalletAddressesChangedEvent event) { - Tab tab = tabs.getSelectionModel().getSelectedItem(); - TabData tabData = (TabData)tab.getUserData(); - if(tabData instanceof WalletTabData) { - WalletTabData walletTabData = (WalletTabData)tabData; - if(walletTabData.getWalletForm().getWalletId().equals(event.getWalletId())) { + WalletForm selectedWalletForm = getSelectedWalletForm(); + if(selectedWalletForm != null) { + if(selectedWalletForm.getWalletId().equals(event.getWalletId())) { exportWallet.setDisable(!event.getWallet().isValid()); } } @@ -1827,23 +1879,29 @@ public class AppController implements Initializable { public void viewWallet(ViewWalletEvent event) { if(tabs.getScene().getWindow().equals(event.getWindow())) { for(Tab tab : tabs.getTabs()) { - TabData tabData = (TabData) tab.getUserData(); - if(tabData.getType() == TabData.TabType.WALLET) { - WalletTabData walletTabData = (WalletTabData) tabData; - if(event.getStorage().getWalletId(event.getWallet()).equals(walletTabData.getWalletForm().getWalletId())) { - tabs.getSelectionModel().select(tab); - return; + if(tab.getUserData() instanceof WalletTabData) { + TabPane subTabs = (TabPane)tab.getContent(); + for(Tab subTab : subTabs.getTabs()) { + WalletTabData walletTabData = (WalletTabData)subTab.getUserData(); + if(event.getStorage().getWalletId(event.getWallet()).equals(walletTabData.getWalletForm().getWalletId())) { + tabs.getSelectionModel().select(tab); + subTabs.getSelectionModel().select(subTab); + return; + } } } } for(Tab tab : tabs.getTabs()) { - TabData tabData = (TabData) tab.getUserData(); - if(tabData.getType() == TabData.TabType.WALLET) { - WalletTabData walletTabData = (WalletTabData) tabData; - if(event.getStorage().getWalletFile().equals(walletTabData.getStorage().getWalletFile())) { - tabs.getSelectionModel().select(tab); - return; + if(tab.getUserData() instanceof WalletTabData) { + TabPane subTabs = (TabPane)tab.getContent(); + for(Tab subTab : subTabs.getTabs()) { + WalletTabData walletTabData = (WalletTabData)subTab.getUserData(); + if(event.getStorage().getWalletFile().equals(walletTabData.getStorage().getWalletFile())) { + tabs.getSelectionModel().select(tab); + subTabs.getSelectionModel().select(subTab); + return; + } } } } diff --git a/src/main/java/com/sparrowwallet/sparrow/event/WalletTabSelectedEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/WalletTabSelectedEvent.java index e5ff2081..ea9f3905 100644 --- a/src/main/java/com/sparrowwallet/sparrow/event/WalletTabSelectedEvent.java +++ b/src/main/java/com/sparrowwallet/sparrow/event/WalletTabSelectedEvent.java @@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.event; import com.sparrowwallet.sparrow.WalletTabData; import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; public class WalletTabSelectedEvent extends TabSelectedEvent { public WalletTabSelectedEvent(Tab tab) { @@ -9,6 +10,8 @@ public class WalletTabSelectedEvent extends TabSelectedEvent { } public WalletTabData getWalletTabData() { - return (WalletTabData)getTabData(); + TabPane subTabs = (TabPane)getTab().getContent(); + Tab subTab = subTabs.getSelectionModel().getSelectedItem(); + return (WalletTabData)subTab.getUserData(); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/WalletController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/WalletController.java index 95406bc8..fd61fc0e 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/WalletController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/WalletController.java @@ -14,7 +14,6 @@ import javafx.scene.Node; import javafx.scene.control.Toggle; import javafx.scene.control.ToggleButton; import javafx.scene.control.ToggleGroup; -import javafx.scene.layout.BorderPane; import javafx.scene.layout.StackPane; import java.io.IOException; @@ -22,9 +21,6 @@ import java.net.URL; import java.util.ResourceBundle; public class WalletController extends WalletFormController implements Initializable { - @FXML - private BorderPane tabContent; - @FXML private StackPane walletPane; diff --git a/src/main/resources/com/sparrowwallet/sparrow/app.css b/src/main/resources/com/sparrowwallet/sparrow/app.css index 996c266f..1c917887 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/app.css +++ b/src/main/resources/com/sparrowwallet/sparrow/app.css @@ -24,6 +24,14 @@ -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 { -fx-alignment: center-left; } diff --git a/src/main/resources/com/sparrowwallet/sparrow/wallet/wallet.fxml b/src/main/resources/com/sparrowwallet/sparrow/wallet/wallet.fxml index 86c426b7..da9e2a14 100644 --- a/src/main/resources/com/sparrowwallet/sparrow/wallet/wallet.fxml +++ b/src/main/resources/com/sparrowwallet/sparrow/wallet/wallet.fxml @@ -8,7 +8,7 @@ - +