Merge pull request #1515 from ManfredKarrer/app-startup

This will be a series of small scale and low risk changes for improving startup
This commit is contained in:
Chris Beams 2018-04-18 13:31:46 +02:00
commit 4e57a9ee55
No known key found for this signature in database
GPG key ID: 3D214F8F5BC5ED73
18 changed files with 250 additions and 383 deletions

View file

@ -27,6 +27,7 @@ import bisq.desktop.main.funds.transactions.TradableRepository;
import bisq.desktop.main.funds.transactions.TransactionAwareTradableFactory;
import bisq.desktop.main.funds.transactions.TransactionListItemFactory;
import bisq.desktop.main.offer.offerbook.OfferBook;
import bisq.desktop.main.overlays.notifications.NotificationCenter;
import bisq.desktop.main.overlays.windows.TorNetworkSettingsWindow;
import bisq.desktop.util.BSFormatter;
import bisq.desktop.util.BsqFormatter;
@ -42,29 +43,27 @@ import org.springframework.core.env.Environment;
import com.google.inject.Singleton;
import com.google.inject.name.Names;
import javafx.stage.Stage;
import java.util.ResourceBundle;
public class DesktopModule extends AppModule {
private final Stage primaryStage;
public DesktopModule(Environment environment, Stage primaryStage) {
public DesktopModule(Environment environment) {
super(environment);
this.primaryStage = primaryStage;
}
@Override
protected void configure() {
bind(InjectorViewFactory.class).in(Singleton.class);
bind(ViewFactory.class).to(InjectorViewFactory.class);
bind(CachingViewLoader.class).in(Singleton.class);
bind(ResourceBundle.class).toInstance(Res.getResourceBundle());
bind(ViewLoader.class).to(FxmlViewLoader.class).in(Singleton.class);
bind(CachingViewLoader.class).in(Singleton.class);
bind(Navigation.class).in(Singleton.class);
bind(NotificationCenter.class).in(Singleton.class);
bind(OfferBook.class).in(Singleton.class);
bind(BSFormatter.class).in(Singleton.class);
@ -73,8 +72,6 @@ public class DesktopModule extends AppModule {
bind(Transitions.class).in(Singleton.class);
bind(Stage.class).toInstance(primaryStage);
bind(TradableRepository.class).in(Singleton.class);
bind(TransactionListItemFactory.class).in(Singleton.class);
bind(TransactionAwareTradableFactory.class).in(Singleton.class);

View file

@ -18,11 +18,9 @@
package bisq.desktop.app;
import bisq.desktop.SystemTray;
import bisq.desktop.common.UITimer;
import bisq.desktop.common.view.CachingViewLoader;
import bisq.desktop.common.view.View;
import bisq.desktop.common.view.ViewLoader;
import bisq.desktop.common.view.guice.InjectorViewFactory;
import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.main.MainView;
import bisq.desktop.main.debug.DebugView;
@ -32,38 +30,25 @@ import bisq.desktop.main.overlays.windows.FilterWindow;
import bisq.desktop.main.overlays.windows.ManualPayoutTxWindow;
import bisq.desktop.main.overlays.windows.SendAlertMessageWindow;
import bisq.desktop.main.overlays.windows.ShowWalletDataWindow;
import bisq.desktop.setup.DesktopPersistedDataHost;
import bisq.desktop.util.ImageUtil;
import bisq.core.alert.AlertManager;
import bisq.core.app.AppOptionKeys;
import bisq.core.app.BisqEnvironment;
import bisq.core.arbitration.ArbitratorManager;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.WalletService;
import bisq.core.btc.wallet.WalletsManager;
import bisq.core.btc.wallet.WalletsSetup;
import bisq.core.dao.DaoSetup;
import bisq.core.filter.FilterManager;
import bisq.core.locale.Res;
import bisq.core.offer.OpenOfferManager;
import bisq.core.setup.CorePersistedDataHost;
import bisq.core.setup.CoreSetup;
import bisq.core.trade.TradeManager;
import bisq.network.p2p.P2PService;
import bisq.common.UserThread;
import bisq.common.app.DevEnv;
import bisq.common.handlers.ResultHandler;
import bisq.common.proto.persistable.PersistedDataHost;
import bisq.common.setup.CommonSetup;
import bisq.common.setup.GracefulShutDownHandler;
import bisq.common.setup.UncaughtExceptionHandler;
import bisq.common.storage.Storage;
import bisq.common.util.Profiler;
import bisq.common.util.Utilities;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.name.Names;
@ -71,7 +56,6 @@ import com.google.inject.name.Names;
import org.reactfx.EventStreams;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.stage.Modality;
import javafx.stage.Stage;
@ -89,60 +73,56 @@ import javafx.scene.layout.StackPane;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Logger;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import static bisq.desktop.util.Layout.INITIAL_SCENE_HEIGHT;
import static bisq.desktop.util.Layout.INITIAL_SCENE_WIDTH;
public class BisqApp extends Application {
private static final Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(BisqApp.class);
@Slf4j
public class BisqApp extends Application implements UncaughtExceptionHandler {
private static final long LOG_MEMORY_PERIOD_MIN = 10;
@Setter
private static Consumer<Application> appLaunchedHandler;
@Getter
private static Runnable shutDownHandler;
private static BisqEnvironment bisqEnvironment;
public static Runnable shutDownHandler;
private static Stage primaryStage;
protected static void setEnvironment(BisqEnvironment bisqEnvironment) {
BisqApp.bisqEnvironment = bisqEnvironment;
}
private BisqAppModule bisqAppModule;
@Setter
private Injector injector;
@Setter
private GracefulShutDownHandler gracefulShutDownHandler;
private Stage stage;
private boolean popupOpened;
private Scene scene;
private final List<String> corruptedDatabaseFiles = new ArrayList<>();
private boolean shutDownRequested;
public BisqApp() {
shutDownHandler = this::stop;
}
///////////////////////////////////////////////////////////////////////////////////////////
// JavaFx Application implementation
///////////////////////////////////////////////////////////////////////////////////////////
// NOTE: This method is not called on the JavaFX Application Thread.
@Override
public void init() {
UserThread.setExecutor(Platform::runLater);
UserThread.setTimerClass(UITimer.class);
shutDownHandler = this::stop;
CommonSetup.setup(this::showErrorPopup);
CoreSetup.setup(bisqEnvironment);
}
@SuppressWarnings("PointlessBooleanExpression")
@Override
public void start(Stage stage) {
BisqApp.primaryStage = stage;
this.stage = stage;
appLaunchedHandler.accept(this);
}
public void startApplication() {
try {
bisqAppModule = new BisqAppModule(bisqEnvironment, primaryStage);
injector = Guice.createInjector(bisqAppModule);
injector.getInstance(InjectorViewFactory.class).setInjector(injector);
PersistedDataHost.apply(CorePersistedDataHost.getPersistedDataHosts(injector));
PersistedDataHost.apply(DesktopPersistedDataHost.getPersistedDataHosts(injector));
DevEnv.setup(injector);
MainView mainView = loadMainView(injector);
scene = createAndConfigScene(mainView, injector);
setupStage(scene);
@ -154,10 +134,74 @@ public class BisqApp extends Application {
UserThread.runPeriodically(() -> Profiler.printSystemLoad(log), LOG_MEMORY_PERIOD_MIN, TimeUnit.MINUTES);
} catch (Throwable throwable) {
log.error("Error during app init", throwable);
showErrorPopup(throwable, false);
handleUncaughtException(throwable, false);
}
}
@Override
public void stop() {
if (!shutDownRequested) {
new Popup<>().headLine(Res.get("popup.shutDownInProgress.headline"))
.backgroundInfo(Res.get("popup.shutDownInProgress.msg"))
.hideCloseButton()
.useAnimation(false)
.show();
UserThread.runAfter(() -> {
gracefulShutDownHandler.gracefulShutDown(() -> {
log.debug("App shutdown complete");
});
}, 200, TimeUnit.MILLISECONDS);
shutDownRequested = true;
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// UncaughtExceptionHandler implementation
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void handleUncaughtException(Throwable throwable, boolean doShutDown) {
if (!shutDownRequested) {
if (scene == null) {
log.warn("Scene not available yet, we create a new scene. The bug might be caused by an exception in a constructor or by a circular dependency in guice. throwable=" + throwable.toString());
scene = new Scene(new StackPane(), 1000, 650);
scene.getStylesheets().setAll(
"/bisq/desktop/bisq.css",
"/bisq/desktop/images.css");
stage.setScene(scene);
stage.show();
}
try {
try {
if (!popupOpened) {
String message = throwable.getMessage();
popupOpened = true;
if (message != null)
new Popup<>().error(message).onClose(() -> popupOpened = false).show();
else
new Popup<>().error(throwable.toString()).onClose(() -> popupOpened = false).show();
}
} catch (Throwable throwable3) {
log.error("Error at displaying Throwable.");
throwable3.printStackTrace();
}
if (doShutDown)
stop();
} catch (Throwable throwable2) {
// If printStackTrace cause a further exception we don't pass the throwable to the Popup.
log.error(throwable2.toString());
if (doShutDown)
stop();
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private Scene createAndConfigScene(MainView mainView, Injector injector) {
Scene scene = new Scene(mainView.getRoot(), INITIAL_SCENE_WIDTH, INITIAL_SCENE_HEIGHT);
scene.getStylesheets().setAll(
@ -170,19 +214,19 @@ public class BisqApp extends Application {
private void setupStage(Scene scene) {
// configure the system tray
SystemTray.create(primaryStage, shutDownHandler);
SystemTray.create(stage, shutDownHandler);
primaryStage.setOnCloseRequest(event -> {
stage.setOnCloseRequest(event -> {
event.consume();
stop();
});
// configure the primary stage
primaryStage.setTitle(bisqEnvironment.getRequiredProperty(AppOptionKeys.APP_NAME_KEY));
primaryStage.setScene(scene);
primaryStage.setMinWidth(1020);
primaryStage.setMinHeight(620);
String appName = injector.getInstance(Key.get(String.class, Names.named(AppOptionKeys.APP_NAME_KEY)));
stage.setTitle(appName);
stage.setScene(scene);
stage.setMinWidth(1020);
stage.setMinHeight(620);
// on windows the title icon is also used as task bar icon in a larger size
// on Linux no title icon is supported but also a large task bar icon is derived from that title icon
@ -194,10 +238,10 @@ public class BisqApp extends Application {
else
iconPath = "/images/task_bar_icon_linux.png";
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream(iconPath)));
stage.getIcons().add(new Image(getClass().getResourceAsStream(iconPath)));
// make the UI visible
primaryStage.show();
stage.show();
}
private MainView loadMainView(Injector injector) {
@ -278,42 +322,6 @@ public class BisqApp extends Application {
emptyWalletWindow.show();
}
private void showErrorPopup(Throwable throwable, boolean doShutDown) {
if (!shutDownRequested) {
if (scene == null) {
log.warn("Scene not available yet, we create a new scene. The bug might be caused by an exception in a constructor or by a circular dependency in guice. throwable=" + throwable.toString());
scene = new Scene(new StackPane(), 1000, 650);
scene.getStylesheets().setAll(
"/bisq/desktop/bisq.css",
"/bisq/desktop/images.css");
primaryStage.setScene(scene);
primaryStage.show();
}
try {
try {
if (!popupOpened) {
String message = throwable.getMessage();
popupOpened = true;
if (message != null)
new Popup<>().error(message).onClose(() -> popupOpened = false).show();
else
new Popup<>().error(throwable.toString()).onClose(() -> popupOpened = false).show();
}
} catch (Throwable throwable3) {
log.error("Error at displaying Throwable.");
throwable3.printStackTrace();
}
if (doShutDown)
stop();
} catch (Throwable throwable2) {
// If printStackTrace cause a further exception we don't pass the throwable to the Popup.
log.error(throwable2.toString());
if (doShutDown)
stop();
}
}
}
// Used for debugging trade process
private void showDebugWindow(Scene scene, Injector injector) {
ViewLoader viewLoader = injector.getInstance(ViewLoader.class);
@ -325,8 +333,8 @@ public class BisqApp extends Application {
stage.initModality(Modality.NONE);
stage.initStyle(StageStyle.UTILITY);
stage.initOwner(scene.getWindow());
stage.setX(primaryStage.getX() + primaryStage.getWidth() + 10);
stage.setY(primaryStage.getY());
stage.setX(this.stage.getX() + this.stage.getWidth() + 10);
stage.setY(this.stage.getY());
stage.show();
}
@ -349,8 +357,8 @@ public class BisqApp extends Application {
stage.initModality(Modality.NONE);
stage.initStyle(StageStyle.UTILITY);
stage.initOwner(scene.getWindow());
stage.setX(primaryStage.getX() + primaryStage.getWidth() + 10);
stage.setY(primaryStage.getY());
stage.setX(this.stage.getX() + this.stage.getWidth() + 10);
stage.setY(this.stage.getY());
stage.setWidth(200);
stage.setHeight(100);
stage.show();
@ -368,59 +376,4 @@ public class BisqApp extends Application {
.show();
}
}
@SuppressWarnings("CodeBlock2Expr")
@Override
public void stop() {
if (!shutDownRequested) {
new Popup<>().headLine(Res.get("popup.shutDownInProgress.headline"))
.backgroundInfo(Res.get("popup.shutDownInProgress.msg"))
.hideCloseButton()
.useAnimation(false)
.show();
//noinspection CodeBlock2Expr
UserThread.runAfter(() -> {
gracefulShutDown(() -> {
log.debug("App shutdown complete");
System.exit(0);
});
}, 200, TimeUnit.MILLISECONDS);
shutDownRequested = true;
}
}
private void gracefulShutDown(ResultHandler resultHandler) {
try {
if (injector != null) {
injector.getInstance(ArbitratorManager.class).shutDown();
injector.getInstance(TradeManager.class).shutDown();
injector.getInstance(DaoSetup.class).shutDown();
//noinspection CodeBlock2Expr
injector.getInstance(OpenOfferManager.class).shutDown(() -> {
injector.getInstance(P2PService.class).shutDown(() -> {
injector.getInstance(WalletsSetup.class).shutDownComplete.addListener((ov, o, n) -> {
bisqAppModule.close(injector);
log.debug("Graceful shutdown completed");
resultHandler.handleResult();
});
injector.getInstance(WalletsSetup.class).shutDown();
injector.getInstance(BtcWalletService.class).shutDown();
injector.getInstance(BsqWalletService.class).shutDown();
});
});
// we wait max 20 sec.
UserThread.runAfter(() -> {
log.warn("Timeout triggered resultHandler");
resultHandler.handleResult();
}, 20);
} else {
log.warn("injector == null triggered resultHandler");
UserThread.runAfter(resultHandler::handleResult, 1);
}
} catch (Throwable t) {
log.error("App shutdown failed with exception");
t.printStackTrace();
System.exit(1);
}
}
}

View file

@ -17,60 +17,99 @@
package bisq.desktop.app;
import bisq.core.app.AppOptionKeys;
import bisq.core.app.BisqEnvironment;
import bisq.desktop.common.UITimer;
import bisq.desktop.common.view.guice.InjectorViewFactory;
import bisq.desktop.setup.DesktopPersistedDataHost;
import bisq.core.app.BisqExecutable;
import bisq.common.util.Utilities;
import bisq.common.UserThread;
import bisq.common.app.AppModule;
import bisq.common.proto.persistable.PersistedDataHost;
import bisq.common.setup.CommonSetup;
import joptsimple.OptionException;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import com.google.inject.Injector;
import static bisq.core.app.BisqEnvironment.DEFAULT_APP_NAME;
import static bisq.core.app.BisqEnvironment.DEFAULT_USER_DATA_DIR;
import javafx.application.Application;
import javafx.application.Platform;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class BisqAppMain extends BisqExecutable {
static {
Utilities.removeCryptographyRestrictions();
}
private BisqApp application;
public static void main(String[] args) throws Exception {
// We don't want to do the full argument parsing here as that might easily change in update versions
// So we only handle the absolute minimum which is APP_NAME, APP_DATA_DIR_KEY and USER_DATA_DIR
OptionParser parser = new OptionParser();
parser.allowsUnrecognizedOptions();
parser.accepts(AppOptionKeys.USER_DATA_DIR_KEY, description("User data directory", DEFAULT_USER_DATA_DIR))
.withRequiredArg();
parser.accepts(AppOptionKeys.APP_NAME_KEY, description("Application name", DEFAULT_APP_NAME))
.withRequiredArg();
if (BisqExecutable.setupInitialOptionParser(args)) {
// For some reason the JavaFX launch process results in us losing the thread context class loader: reset it.
// In order to work around a bug in JavaFX 8u25 and below, you must include the following code as the first line of your realMain method:
Thread.currentThread().setContextClassLoader(BisqAppMain.class.getClassLoader());
OptionSet options;
try {
options = parser.parse(args);
} catch (OptionException ex) {
System.out.println("error: " + ex.getMessage());
System.out.println();
parser.printHelpOn(System.out);
System.exit(EXIT_FAILURE);
return;
new BisqAppMain().execute(args);
}
BisqEnvironment bisqEnvironment = getBisqEnvironment(options);
}
// need to call that before bisqAppMain().execute(args)
initAppDir(bisqEnvironment.getProperty(AppOptionKeys.APP_DATA_DIR_KEY));
// For some reason the JavaFX launch process results in us losing the thread context class loader: reset it.
// In order to work around a bug in JavaFX 8u25 and below, you must include the following code as the first line of your realMain method:
Thread.currentThread().setContextClassLoader(BisqAppMain.class.getClassLoader());
///////////////////////////////////////////////////////////////////////////////////////////
// First synchronous execution tasks
///////////////////////////////////////////////////////////////////////////////////////////
new BisqAppMain().execute(args);
@Override
protected void configUserThread() {
UserThread.setExecutor(Platform::runLater);
UserThread.setTimerClass(UITimer.class);
}
@Override
protected void doExecute(OptionSet options) {
BisqApp.setEnvironment(getBisqEnvironment(options));
javafx.application.Application.launch(BisqApp.class);
protected void launchApplication() {
BisqApp.setAppLaunchedHandler(application -> {
BisqAppMain.this.application = (BisqApp) application;
// Map to user thread!
UserThread.execute(this::onApplicationLaunched);
});
Application.launch(BisqApp.class);
}
///////////////////////////////////////////////////////////////////////////////////////////
// As application is a JavaFX application we need to wait for onApplicationLaunched
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void onApplicationLaunched() {
super.onApplicationLaunched();
application.setGracefulShutDownHandler(this);
CommonSetup.setup(application);
}
///////////////////////////////////////////////////////////////////////////////////////////
// We continue with a series of synchronous execution tasks
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected AppModule getModule() {
return new BisqAppModule(bisqEnvironment);
}
@Override
protected void applyInjector() {
super.applyInjector();
application.setInjector(injector);
injector.getInstance(InjectorViewFactory.class).setInjector(injector);
}
@Override
protected void setupPersistedDataHosts(Injector injector) {
super.setupPersistedDataHosts(injector);
PersistedDataHost.apply(DesktopPersistedDataHost.getPersistedDataHosts(injector));
}
@Override
protected void startApplication() {
// We need to be in user thread! We mapped at launchApplication already...
application.startApplication();
}
}

View file

@ -18,140 +18,30 @@
package bisq.desktop.app;
import bisq.desktop.DesktopModule;
import bisq.desktop.common.view.CachingViewLoader;
import bisq.desktop.main.overlays.notifications.NotificationCenter;
import bisq.core.alert.AlertModule;
import bisq.core.app.AppOptionKeys;
import bisq.core.app.BisqEnvironment;
import bisq.core.arbitration.ArbitratorModule;
import bisq.core.btc.BitcoinModule;
import bisq.core.dao.DaoModule;
import bisq.core.filter.FilterModule;
import bisq.core.network.p2p.seed.DefaultSeedNodeRepository;
import bisq.core.network.p2p.seed.SeedNodeAddressLookup;
import bisq.core.offer.OfferModule;
import bisq.core.proto.network.CoreNetworkProtoResolver;
import bisq.core.proto.persistable.CorePersistenceProtoResolver;
import bisq.core.trade.TradeModule;
import bisq.core.user.Preferences;
import bisq.core.user.User;
import bisq.core.app.CoreModule;
import bisq.network.crypto.EncryptionServiceModule;
import bisq.network.p2p.P2PModule;
import bisq.network.p2p.network.BridgeAddressProvider;
import bisq.network.p2p.seed.SeedNodeRepository;
import bisq.common.Clock;
import bisq.common.CommonOptionKeys;
import bisq.common.app.AppModule;
import bisq.common.crypto.KeyRing;
import bisq.common.crypto.KeyStorage;
import bisq.common.proto.network.NetworkProtoResolver;
import bisq.common.proto.persistable.PersistenceProtoResolver;
import bisq.common.storage.Storage;
import org.springframework.core.env.Environment;
import com.google.inject.Singleton;
import com.google.inject.name.Names;
import javafx.stage.Stage;
import java.io.File;
import static com.google.inject.name.Names.named;
public class BisqAppModule extends AppModule {
private final Stage primaryStage;
public BisqAppModule(Environment environment, Stage primaryStage) {
public BisqAppModule(Environment environment) {
super(environment);
this.primaryStage = primaryStage;
}
@Override
protected void configure() {
bind(BisqEnvironment.class).toInstance((BisqEnvironment) environment);
bind(CachingViewLoader.class).in(Singleton.class);
bind(KeyStorage.class).in(Singleton.class);
bind(KeyRing.class).in(Singleton.class);
bind(User.class).in(Singleton.class);
bind(NotificationCenter.class).in(Singleton.class);
bind(Clock.class).in(Singleton.class);
bind(Preferences.class).in(Singleton.class);
bind(BridgeAddressProvider.class).to(Preferences.class).in(Singleton.class);
bind(SeedNodeAddressLookup.class).in(Singleton.class);
bind(SeedNodeRepository.class).to(DefaultSeedNodeRepository.class).in(Singleton.class);
File storageDir = new File(environment.getRequiredProperty(Storage.STORAGE_DIR));
bind(File.class).annotatedWith(named(Storage.STORAGE_DIR)).toInstance(storageDir);
File keyStorageDir = new File(environment.getRequiredProperty(KeyStorage.KEY_STORAGE_DIR));
bind(File.class).annotatedWith(named(KeyStorage.KEY_STORAGE_DIR)).toInstance(keyStorageDir);
bind(NetworkProtoResolver.class).to(CoreNetworkProtoResolver.class).in(Singleton.class);
bind(PersistenceProtoResolver.class).to(CorePersistenceProtoResolver.class).in(Singleton.class);
Boolean useDevPrivilegeKeys = environment.getProperty(AppOptionKeys.USE_DEV_PRIVILEGE_KEYS, Boolean.class, false);
bind(boolean.class).annotatedWith(Names.named(AppOptionKeys.USE_DEV_PRIVILEGE_KEYS)).toInstance(useDevPrivilegeKeys);
Boolean useDevMode = environment.getProperty(CommonOptionKeys.USE_DEV_MODE, Boolean.class, false);
bind(boolean.class).annotatedWith(Names.named(CommonOptionKeys.USE_DEV_MODE)).toInstance(useDevMode);
// ordering is used for shut down sequence
install(tradeModule());
install(encryptionServiceModule());
install(arbitratorModule());
install(offerModule());
install(p2pModule());
install(bitcoinModule());
install(daoModule());
install(guiModule());
install(alertModule());
install(filterModule());
install(coreModule());
install(desktopModule());
}
private TradeModule tradeModule() {
return new TradeModule(environment);
private CoreModule coreModule() {
return new CoreModule(environment);
}
private EncryptionServiceModule encryptionServiceModule() {
return new EncryptionServiceModule(environment);
}
private ArbitratorModule arbitratorModule() {
return new ArbitratorModule(environment);
}
private AlertModule alertModule() {
return new AlertModule(environment);
}
private FilterModule filterModule() {
return new FilterModule(environment);
}
private OfferModule offerModule() {
return new OfferModule(environment);
}
private P2PModule p2pModule() {
return new P2PModule(environment);
}
private BitcoinModule bitcoinModule() {
return new BitcoinModule(environment);
}
private DaoModule daoModule() {
return new DaoModule(environment);
}
private DesktopModule guiModule() {
return new DesktopModule(environment, primaryStage);
private DesktopModule desktopModule() {
return new DesktopModule(environment);
}
}

View file

@ -53,7 +53,6 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
private final OpenOfferManager openOfferManager;
private final TradeManager tradeManager;
private final AccountAgeWitnessService accountAgeWitnessService;
private final Stage stage;
final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList();
private final SetChangeListener<PaymentAccount> setChangeListener;
private final String accountsFileName = "AltcoinPaymentAccounts";
@ -65,14 +64,12 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
OpenOfferManager openOfferManager,
TradeManager tradeManager,
AccountAgeWitnessService accountAgeWitnessService,
Stage stage,
PersistenceProtoResolver persistenceProtoResolver) {
this.user = user;
this.preferences = preferences;
this.openOfferManager = openOfferManager;
this.tradeManager = tradeManager;
this.accountAgeWitnessService = accountAgeWitnessService;
this.stage = stage;
this.persistenceProtoResolver = persistenceProtoResolver;
setChangeListener = change -> fillAndSortPaymentAccounts();
}
@ -143,7 +140,7 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
user.setCurrentPaymentAccount(paymentAccount);
}
public void exportAccounts() {
public void exportAccounts(Stage stage) {
if (user.getPaymentAccounts() != null) {
ArrayList<PaymentAccount> accounts = new ArrayList<>(user.getPaymentAccounts().stream()
.filter(paymentAccount -> paymentAccount instanceof CryptoCurrencyAccount)
@ -152,7 +149,7 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
}
}
public void importAccounts() {
public void importAccounts(Stage stage) {
GUIUtil.importAccounts(user, accountsFileName, preferences, stage, persistenceProtoResolver);
}
}

View file

@ -46,6 +46,8 @@ import bisq.common.util.Tuple3;
import javax.inject.Inject;
import javafx.stage.Stage;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
@ -114,8 +116,8 @@ public class AltCoinAccountsView extends ActivatableViewAndModel<GridPane, AltCo
paymentAccountsListView.setItems(model.getPaymentAccounts());
paymentAccountsListView.getSelectionModel().selectedItemProperty().addListener(paymentAccountChangeListener);
addAccountButton.setOnAction(event -> addNewAccount());
exportButton.setOnAction(event -> model.dataModel.exportAccounts());
importButton.setOnAction(event -> model.dataModel.importAccounts());
exportButton.setOnAction(event -> model.dataModel.exportAccounts((Stage) root.getScene().getWindow()));
importButton.setOnAction(event -> model.dataModel.importAccounts((Stage) root.getScene().getWindow()));
}
@Override

View file

@ -36,7 +36,6 @@ import bisq.common.util.Utilities;
import javax.inject.Inject;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
@ -60,7 +59,6 @@ import javax.annotation.Nullable;
public class BackupView extends ActivatableView<GridPane, Void> {
private final File dataDir, logFile;
private int gridRow = 0;
private final Stage stage;
private final Preferences preferences;
private Button selectBackupDir, backupNow;
private TextField backUpLocationTextField;
@ -73,9 +71,8 @@ public class BackupView extends ActivatableView<GridPane, Void> {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private BackupView(Stage stage, Preferences preferences, BisqEnvironment environment) {
private BackupView(Preferences preferences, BisqEnvironment environment) {
super();
this.stage = stage;
this.preferences = preferences;
dataDir = new File(environment.getProperty(AppOptionKeys.APP_DATA_DIR_KEY));
logFile = new File(Paths.get(dataDir.getPath(), "bisq.log").toString());
@ -124,7 +121,7 @@ public class BackupView extends ActivatableView<GridPane, Void> {
directoryChooser.setInitialDirectory(new File(path));
directoryChooser.setTitle(Res.get("account.backup.selectLocation"));
try {
File dir = directoryChooser.showDialog(stage);
File dir = directoryChooser.showDialog(root.getScene().getWindow());
if (dir != null) {
applyBackupDirectory(dir.getAbsolutePath());
}

View file

@ -54,7 +54,6 @@ class FiatAccountsDataModel extends ActivatableDataModel {
private final OpenOfferManager openOfferManager;
private final TradeManager tradeManager;
private final AccountAgeWitnessService accountAgeWitnessService;
private final Stage stage;
final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList();
private final SetChangeListener<PaymentAccount> setChangeListener;
private final String accountsFileName = "FiatPaymentAccounts";
@ -66,14 +65,12 @@ class FiatAccountsDataModel extends ActivatableDataModel {
OpenOfferManager openOfferManager,
TradeManager tradeManager,
AccountAgeWitnessService accountAgeWitnessService,
Stage stage,
PersistenceProtoResolver persistenceProtoResolver) {
this.user = user;
this.preferences = preferences;
this.openOfferManager = openOfferManager;
this.tradeManager = tradeManager;
this.accountAgeWitnessService = accountAgeWitnessService;
this.stage = stage;
this.persistenceProtoResolver = persistenceProtoResolver;
setChangeListener = change -> fillAndSortPaymentAccounts();
}
@ -149,7 +146,7 @@ class FiatAccountsDataModel extends ActivatableDataModel {
user.setCurrentPaymentAccount(paymentAccount);
}
public void exportAccounts() {
public void exportAccounts(Stage stage) {
if (user.getPaymentAccounts() != null) {
ArrayList<PaymentAccount> accounts = new ArrayList<>(user.getPaymentAccounts().stream()
.filter(paymentAccount -> !(paymentAccount instanceof CryptoCurrencyAccount))
@ -158,7 +155,7 @@ class FiatAccountsDataModel extends ActivatableDataModel {
}
}
public void importAccounts() {
public void importAccounts(Stage stage) {
GUIUtil.importAccounts(user, accountsFileName, preferences, stage, persistenceProtoResolver);
}
}

View file

@ -17,18 +17,6 @@
package bisq.desktop.main.account.content.fiataccounts;
import bisq.common.UserThread;
import bisq.common.util.Tuple2;
import bisq.common.util.Tuple3;
import bisq.core.app.BisqEnvironment;
import bisq.core.locale.Res;
import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.ClearXchangeAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountFactory;
import bisq.core.payment.WesternUnionAccount;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.util.validation.InputValidator;
import bisq.desktop.common.view.ActivatableViewAndModel;
import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipButton;
@ -80,9 +68,27 @@ import bisq.desktop.util.validation.USPostalMoneyOrderValidator;
import bisq.desktop.util.validation.UpholdValidator;
import bisq.desktop.util.validation.VenmoValidator;
import bisq.desktop.util.validation.WeChatPayValidator;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.geometry.VPos;
import bisq.core.app.BisqEnvironment;
import bisq.core.locale.Res;
import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.ClearXchangeAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountFactory;
import bisq.core.payment.WesternUnionAccount;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.util.validation.InputValidator;
import bisq.common.UserThread;
import bisq.common.util.Tuple2;
import bisq.common.util.Tuple3;
import org.bitcoinj.core.Coin;
import javax.inject.Inject;
import javafx.stage.Stage;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
@ -92,20 +98,21 @@ import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.text.TextAlignment;
import javafx.geometry.VPos;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.util.Callback;
import javafx.util.StringConverter;
import org.bitcoinj.core.Coin;
import javax.inject.Inject;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static bisq.desktop.util.FormBuilder.add2ButtonsAfterGroup;
import static bisq.desktop.util.FormBuilder.add3ButtonsAfterGroup;
import static bisq.desktop.util.FormBuilder.addLabelComboBox;
import static bisq.desktop.util.FormBuilder.addLabelListView;
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
import static bisq.desktop.util.FormBuilder.*;
@FxmlView
public class FiatAccountsView extends ActivatableViewAndModel<GridPane, FiatAccountsViewModel> {
@ -201,8 +208,8 @@ public class FiatAccountsView extends ActivatableViewAndModel<GridPane, FiatAcco
paymentAccountsListView.setItems(model.getPaymentAccounts());
paymentAccountsListView.getSelectionModel().selectedItemProperty().addListener(paymentAccountChangeListener);
addAccountButton.setOnAction(event -> addNewAccount());
exportButton.setOnAction(event -> model.dataModel.exportAccounts());
importButton.setOnAction(event -> model.dataModel.importAccounts());
exportButton.setOnAction(event -> model.dataModel.exportAccounts((Stage) root.getScene().getWindow()));
importButton.setOnAction(event -> model.dataModel.importAccounts((Stage) root.getScene().getWindow()));
}
@Override

View file

@ -37,18 +37,16 @@ import com.google.inject.name.Named;
import javax.inject.Inject;
import javafx.stage.Stage;
@FxmlView
public class ArbitratorDisputeView extends TraderDisputeView {
@Inject
public ArbitratorDisputeView(DisputeManager disputeManager, KeyRing keyRing, TradeManager tradeManager, Stage stage,
public ArbitratorDisputeView(DisputeManager disputeManager, KeyRing keyRing, TradeManager tradeManager,
BSFormatter formatter, DisputeSummaryWindow disputeSummaryWindow,
PrivateNotificationManager privateNotificationManager,
ContractWindow contractWindow, TradeDetailsWindow tradeDetailsWindow,
P2PService p2PService, @Named(AppOptionKeys.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys) {
super(disputeManager, keyRing, tradeManager, stage, formatter,
super(disputeManager, keyRing, tradeManager, formatter,
disputeSummaryWindow, privateNotificationManager, contractWindow,
tradeDetailsWindow, p2PService, useDevPrivilegeKeys);
}

View file

@ -68,7 +68,6 @@ import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
@ -138,7 +137,6 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
private final DisputeManager disputeManager;
protected final KeyRing keyRing;
private final TradeManager tradeManager;
private final Stage stage;
protected final BSFormatter formatter;
private final DisputeSummaryWindow disputeSummaryWindow;
private final PrivateNotificationManager privateNotificationManager;
@ -186,7 +184,6 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
public TraderDisputeView(DisputeManager disputeManager,
KeyRing keyRing,
TradeManager tradeManager,
Stage stage,
BSFormatter formatter,
DisputeSummaryWindow disputeSummaryWindow,
PrivateNotificationManager privateNotificationManager,
@ -197,7 +194,6 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
this.disputeManager = disputeManager;
this.keyRing = keyRing;
this.tradeManager = tradeManager;
this.stage = stage;
this.formatter = formatter;
this.disputeSummaryWindow = disputeSummaryWindow;
this.privateNotificationManager = privateNotificationManager;
@ -560,7 +556,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
fileChooser.setTitle(Res.get("support.openFile", maxSizeInKB));
/* if (Utilities.isUnix())
fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));*/
File result = fileChooser.showOpenDialog(stage);
File result = fileChooser.showOpenDialog(root.getScene().getWindow());
if (result != null) {
try {
URL url = result.toURI().toURL();
@ -596,7 +592,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
fileChooser.setInitialFileName(attachment.getFileName());
/* if (Utilities.isUnix())
fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));*/
File file = fileChooser.showSaveDialog(stage);
File file = fileChooser.showSaveDialog(root.getScene().getWindow());
if (file != null) {
try (FileOutputStream fileOutputStream = new FileOutputStream(file.getAbsolutePath())) {
fileOutputStream.write(attachment.getBytes());

View file

@ -112,7 +112,6 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
private final BSFormatter formatter;
private final Preferences preferences;
private final TradeDetailsWindow tradeDetailsWindow;
private final Stage stage;
private final OfferDetailsWindow offerDetailsWindow;
@SuppressWarnings("deprecation")
private WalletEventListener walletEventListener;
@ -130,7 +129,6 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
BSFormatter formatter,
Preferences preferences,
TradeDetailsWindow tradeDetailsWindow,
Stage stage,
OfferDetailsWindow offerDetailsWindow,
DisplayedTransactionsFactory displayedTransactionsFactory) {
this.btcWalletService = btcWalletService;
@ -139,7 +137,6 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
this.formatter = formatter;
this.preferences = preferences;
this.tradeDetailsWindow = tradeDetailsWindow;
this.stage = stage;
this.offerDetailsWindow = offerDetailsWindow;
this.displayedTransactions = displayedTransactionsFactory.create();
this.sortedDisplayedTransactions = displayedTransactions.asSortedList();
@ -260,7 +257,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
};
GUIUtil.exportCSV("transactions.csv", headerConverter, contentConverter,
new TransactionsListItem(), sortedDisplayedTransactions, stage);
new TransactionsListItem(), sortedDisplayedTransactions, (Stage) root.getScene().getWindow());
});
}

View file

@ -391,7 +391,7 @@ public abstract class Overlay<T extends Overlay> {
public T useShutDownButton() {
this.actionButtonText = Res.get("shared.shutDown");
this.actionHandlerOptional = Optional.of(BisqApp.shutDownHandler::run);
this.actionHandlerOptional = Optional.of(BisqApp.getShutDownHandler()::run);
//noinspection unchecked
return (T) this;
}

View file

@ -96,7 +96,7 @@ public class TacWindow extends Overlay<TacWindow> {
message(text);
actionButtonText(Res.get("tacWindow.agree"));
closeButtonText(Res.get("tacWindow.disagree"));
onClose(BisqApp.shutDownHandler::run);
onClose(BisqApp.getShutDownHandler()::run);
super.show();
}

View file

@ -86,7 +86,6 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
private final BSFormatter formatter;
private final TradeDetailsWindow tradeDetailsWindow;
private final PrivateNotificationManager privateNotificationManager;
private final Stage stage;
private SortedList<ClosedTradableListItem> sortedList;
@Inject
@ -95,7 +94,6 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
Preferences preferences,
TradeDetailsWindow tradeDetailsWindow,
PrivateNotificationManager privateNotificationManager,
Stage stage,
BSFormatter formatter,
@Named(AppOptionKeys.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys) {
super(model);
@ -103,7 +101,6 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
this.preferences = preferences;
this.tradeDetailsWindow = tradeDetailsWindow;
this.privateNotificationManager = privateNotificationManager;
this.stage = stage;
this.preferences = preferences;
this.formatter = formatter;
this.useDevPrivilegeKeys = useDevPrivilegeKeys;
@ -211,7 +208,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
};
GUIUtil.exportCSV("tradeHistory.csv", headerConverter, contentConverter,
new ClosedTradableListItem(null), sortedList, stage);
new ClosedTradableListItem(null), sortedList, (Stage) root.getScene().getWindow());
});
}

View file

@ -256,7 +256,7 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
.actionButtonText(Res.get("shared.applyAndShutDown"))
.onAction(() -> {
preferences.setUseTorForBitcoinJ(selected);
UserThread.runAfter(BisqApp.shutDownHandler::run, 500, TimeUnit.MILLISECONDS);
UserThread.runAfter(BisqApp.getShutDownHandler()::run, 500, TimeUnit.MILLISECONDS);
})
.closeButtonText(Res.get("shared.cancel"))
.onClose(() -> useTorForBtcJCheckBox.setSelected(!selected))

View file

@ -655,7 +655,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Activatab
new Popup().warning(Res.get("settings.net.needRestart"))
.onAction(() -> {
bisqEnvironment.saveBaseCryptoNetwork(selectBaseCurrencyNetworkComboBox.getSelectionModel().getSelectedItem());
UserThread.runAfter(BisqApp.shutDownHandler::run, 500, TimeUnit.MILLISECONDS);
UserThread.runAfter(BisqApp.getShutDownHandler()::run, 500, TimeUnit.MILLISECONDS);
})
.actionButtonText(Res.get("shared.shutDown"))
.closeButtonText(Res.get("shared.cancel"))

View file

@ -462,7 +462,7 @@ public class GUIUtil {
.actionButtonText(Res.get("shared.shutDown"))
.onAction(() -> {
preferences.setResyncSpvRequested(true);
UserThread.runAfter(BisqApp.shutDownHandler::run, 100, TimeUnit.MILLISECONDS);
UserThread.runAfter(BisqApp.getShutDownHandler()::run, 100, TimeUnit.MILLISECONDS);
})
.hideCloseButton()
.show();