fixed app dir problem with update to gradle.

This commit is contained in:
Manfred Karrer 2014-08-28 18:24:42 +02:00
parent fb7397eb48
commit fb89f087f0
18 changed files with 206 additions and 242 deletions

View file

@ -1,9 +0,0 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="This file is part of Bitsquare.&#10;&#10;Bitsquare is free software: you can redistribute it and/or modify it&#10;under the terms of the GNU Affero General Public License as published by&#10;the Free Software Foundation, either version 3 of the License, or (at&#10;your option) any later version.&#10;&#10;Bitsquare is distributed in the hope that it will be useful, but WITHOUT&#10;ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or&#10;FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public&#10;License for more details.&#10;&#10;You should have received a copy of the GNU Affero General Public License&#10;along with Bitsquare. If not, see &lt;http://www.gnu.org/licenses/&gt;." />
<option name="keyword" value="GNU Affero General Public License" />
<option name="allowReplaceKeyword" value="" />
<option name="myName" value="Bitsquare Affero GPLv3" />
<option name="myLocal" value="true" />
</copyright>
</component>

View file

@ -1,3 +1,3 @@
<component name="CopyrightManager"> <component name="CopyrightManager">
<settings default="Bitsquare Affero GPLv3" /> <settings default="" />
</component> </component>

23
Development-notes.md Normal file
View file

@ -0,0 +1,23 @@
## UI Architecure pattern:
We use the Presentation Model pattern which has some similarities with MVVM (Silverlight, WPF) as we use data
bindings, though there are differences in the way the view and the "code behind" is organized (different framework
support).
We don't use the term controller for the JavaFX controller it has too much association with the classical MVC
controller.
View: FXML or code based View
CodeBehind (CB): JavaFX controller associated with FXML View
Presentation Model (PM)
Model: Domain data
* State is stored in the presenter.
* Logic is stored in presenter.
* Presenter represents a abstract view of the UI.
* Presenter is not aware of the view.
* View is aware of the presenter.
* View is completely isolated from the model.
## References:
[Presentation Model](http://martinfowler.com/eaaDev/PresentationModel.html)
[Model View ViewModel - MVVM](http://msdn.microsoft.com/en-us/magazine/dd419663.aspx)

View file

@ -28,14 +28,12 @@ import io.bitsquare.persistence.Persistence;
import io.bitsquare.settings.Settings; import io.bitsquare.settings.Settings;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import io.bitsquare.util.AWTSystemTray; import io.bitsquare.util.AWTSystemTray;
import io.bitsquare.util.AppDirectoryUtil;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
@ -48,6 +46,8 @@ import javafx.stage.Stage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import lighthouse.files.AppDirectory;
public class BitSquare extends Application { public class BitSquare extends Application {
private static final Logger log = LoggerFactory.getLogger(BitSquare.class); private static final Logger log = LoggerFactory.getLogger(BitSquare.class);
@ -61,7 +61,7 @@ public class BitSquare extends Application {
public static void main(String[] args) { public static void main(String[] args) {
Profiler.init(); Profiler.init();
Profiler.printMsgWithTime("BitSquare.main called with args " + Arrays.asList(args).toString()); Profiler.printMsgWithTime("BitSquare.main called with args " + Arrays.asList(args).toString());
if (args != null && args.length > 0) APP_NAME = args[0]; if (args.length > 0) APP_NAME = APP_NAME + "_" + args[0];
launch(args); launch(args);
} }
@ -82,8 +82,7 @@ public class BitSquare extends Application {
Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> Popups.handleUncaughtExceptions Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> Popups.handleUncaughtExceptions
(Throwables.getRootCause(throwable))); (Throwables.getRootCause(throwable)));
AppDirectoryUtil.setStorageDirectory( AppDirectory.initAppDir(APP_NAME);
new File(AppDirectoryUtil.getApplicationDirectory().getCanonicalPath() + "/data"));
// currently there is not SystemTray support for java fx (planned for version 3) so we use the old AWT // currently there is not SystemTray support for java fx (planned for version 3) so we use the old AWT
AWTSystemTray.createSystemTray(primaryStage); AWTSystemTray.createSystemTray(primaryStage);

View file

@ -22,7 +22,6 @@ import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.listeners.ConfidenceListener; import io.bitsquare.btc.listeners.ConfidenceListener;
import io.bitsquare.crypto.CryptoFacade; import io.bitsquare.crypto.CryptoFacade;
import io.bitsquare.persistence.Persistence; import io.bitsquare.persistence.Persistence;
import io.bitsquare.util.AppDirectoryUtil;
import com.google.bitcoin.core.Address; import com.google.bitcoin.core.Address;
import com.google.bitcoin.core.AddressFormatException; import com.google.bitcoin.core.AddressFormatException;
@ -78,6 +77,8 @@ import javafx.util.Pair;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import lighthouse.files.AppDirectory;
import static com.google.bitcoin.script.ScriptOpCodes.OP_RETURN; import static com.google.bitcoin.script.ScriptOpCodes.OP_RETURN;
/** /**
@ -139,7 +140,7 @@ public class WalletFacade {
Threading.USER_THREAD = Platform::runLater; Threading.USER_THREAD = Platform::runLater;
// If seed is non-null it means we are restoring from backup. // If seed is non-null it means we are restoring from backup.
walletAppKit = new WalletAppKit(params, AppDirectoryUtil.getStorageDirectory(), WALLET_PREFIX) { walletAppKit = new WalletAppKit(params, AppDirectory.dir().toFile(), WALLET_PREFIX) {
@Override @Override
protected void onSetupCompleted() { protected void onSetupCompleted() {
// Don't make the user wait for confirmations for now, as the intention is they're sending it // Don't make the user wait for confirmations for now, as the intention is they're sending it
@ -223,8 +224,8 @@ public class WalletFacade {
wallet.addEventListener(walletEventListener); wallet.addEventListener(walletEventListener);
Serializable serializable = persistence.read(this, "addressEntryList"); Serializable serializable = persistence.read(this, "addressEntryList");
List<AddressEntry> persistedAddressEntryList = (List<AddressEntry>) serializable;
if (serializable instanceof List) { if (serializable instanceof List) {
List<AddressEntry> persistedAddressEntryList = (List<AddressEntry>) serializable;
for (AddressEntry persistedAddressEntry : persistedAddressEntryList) { for (AddressEntry persistedAddressEntry : persistedAddressEntryList) {
persistedAddressEntry.setDeterministicKey( persistedAddressEntry.setDeterministicKey(
(DeterministicKey) wallet.findKeyFromPubHash(persistedAddressEntry.getPubKeyHash())); (DeterministicKey) wallet.findKeyFromPubHash(persistedAddressEntry.getPubKeyHash()));

View file

@ -22,7 +22,7 @@ import io.bitsquare.gui.CachedViewController;
import io.bitsquare.gui.NavigationItem; import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.ViewController; import io.bitsquare.gui.ViewController;
import io.bitsquare.gui.components.ValidatingTextField; import io.bitsquare.gui.components.ValidatingTextField;
import io.bitsquare.gui.trade.createoffer.CreateOfferCodeBehind; import io.bitsquare.gui.trade.createoffer.CreateOfferCB;
import io.bitsquare.gui.trade.orderbook.OrderBookController; import io.bitsquare.gui.trade.orderbook.OrderBookController;
import io.bitsquare.gui.trade.takeoffer.TakeOfferController; import io.bitsquare.gui.trade.takeoffer.TakeOfferController;
import io.bitsquare.trade.Direction; import io.bitsquare.trade.Direction;
@ -46,7 +46,7 @@ public class TradeController extends CachedViewController {
private static final Logger log = LoggerFactory.getLogger(TradeController.class); private static final Logger log = LoggerFactory.getLogger(TradeController.class);
protected OrderBookController orderBookController; protected OrderBookController orderBookController;
protected CreateOfferCodeBehind createOfferCodeBehind; protected CreateOfferCB createOfferCodeBehind;
protected TakeOfferController takeOfferController; protected TakeOfferController takeOfferController;
protected GuiceFXMLLoader orderBookLoader; protected GuiceFXMLLoader orderBookLoader;
@ -76,7 +76,7 @@ public class TradeController extends CachedViewController {
// TODO find better solution // TODO find better solution
// Textfield focus out triggers validation, use runLater as quick fix... // Textfield focus out triggers validation, use runLater as quick fix...
((TabPane) root).getSelectionModel().selectedIndexProperty().addListener((observableValue) -> ((TabPane) root).getSelectionModel().selectedIndexProperty().addListener((observableValue) ->
Platform.runLater(() -> ValidatingTextField.hidePopover())); Platform.runLater(ValidatingTextField::hidePopover));
} }

View file

@ -43,31 +43,34 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Code behind (FXML Controller is part of View, not a classical MVC controller): * Code behind (We don't call it controller as controller is associated with the classical MVC controller):
* <p> * <p>
* Creates Presenter and passes Model from DI to Presenter. Does not hold a reference to Model * - Knows the presentation model, does not know the model
* - Has no logic and no state
* <p> * <p>
* - Setup binding from Presenter to View elements (also bidirectional - Inputs). Binding are only to presenters * - Creates presentation model and passes model from Guice injection to the presenter. Does not hold any reference to the model.
* properties, not logical bindings or cross-view element bindings. * //TODO is there a better way for DI of model?
* - Listen to UI events (Action) from View and call method in Presenter. * - Setup binding from presenter to view elements (also bidirectional - used for input data). Binding are only to plain
* - Is entry node for hierarchical view graphs. Passes method calls to Presenter. Calls methods on sub views. * presenter properties. There are no logical bindings or cross-view element bindings.
* - Listens to UI events (Actions) from view and calls method in presentation model.
* - Is entry node for view graph and responsible for navigation and creation of new views.
* - Passes application API method calls to Presenter. Calls application methods on sub views.
* - Handle lifecycle and self removal from scene graph. * - Handle lifecycle and self removal from scene graph.
* - Non declarative (dynamic) view definitions (if it gets larger, then user a ViewBuilder) * - Can contain non-declarative (dynamic) view definitions (if it gets larger, then use a dedicated ViewBuilder)
* - Has no logic and no state, only view elements and a presenter reference!
* <p> * <p>
* View: * View:
* - Mostly declared in FXML. Dynamic parts are declared in Controller. If more view elements need to be defined in * - Typically declared in FXML. Dynamic parts are declared in Controller. If more view elements need to be defined in
* code then use ViewBuilder. * code then use a ViewBuilder.
* <p> * <p>
* Optional ViewBuilder: * ViewBuilder (optional):
* - Replacement for FXML view definitions. * - Additionally or instead of FXML view. If no FXML then controller setup need to be handles by ViewBuilder.
* <p> * <p>
* Note: Don't assign the root node as it is defined in the base class! * Note: Don't assign the root node as it is defined in the base class!
*/ */
public class CreateOfferCodeBehind extends CachedViewController { public class CreateOfferCB extends CachedViewController {
private static final Logger log = LoggerFactory.getLogger(CreateOfferCodeBehind.class); private static final Logger log = LoggerFactory.getLogger(CreateOfferCB.class);
private final CreateOfferPresenter presenter; private final CreateOfferPM pm;
@FXML private Label buyLabel, confirmationLabel, txTitleLabel, collateralLabel; @FXML private Label buyLabel, confirmationLabel, txTitleLabel, collateralLabel;
@FXML private ValidatingTextField amountTextField, minAmountTextField, priceTextField, volumeTextField; @FXML private ValidatingTextField amountTextField, minAmountTextField, priceTextField, volumeTextField;
@ -86,8 +89,8 @@ public class CreateOfferCodeBehind extends CachedViewController {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public CreateOfferCodeBehind(CreateOfferModel model) { public CreateOfferCB(CreateOfferModel model) {
presenter = new CreateOfferPresenter(model); pm = new CreateOfferPM(model);
} }
@ -99,17 +102,18 @@ public class CreateOfferCodeBehind extends CachedViewController {
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle rb) {
super.initialize(url, rb); super.initialize(url, rb);
presenter.onViewInitialized(); pm.onViewInitialized();
balanceTextField.setup(presenter.getWalletFacade(), presenter.address.get()); balanceTextField.setup(pm.getWalletFacade(), pm.address.get());
} }
@Override @Override
public void deactivate() { public void deactivate() {
super.deactivate(); super.deactivate();
presenter.deactivate(); pm.deactivate();
//TODO check that again
((TradeController) parentController).onCreateOfferViewRemoved(); ((TradeController) parentController).onCreateOfferViewRemoved();
} }
@ -117,7 +121,7 @@ public class CreateOfferCodeBehind extends CachedViewController {
public void activate() { public void activate() {
super.activate(); super.activate();
presenter.activate(); pm.activate();
setupBindings(); setupBindings();
setupListeners(); setupListeners();
@ -130,7 +134,7 @@ public class CreateOfferCodeBehind extends CachedViewController {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void setOrderBookFilter(OrderBookFilter orderBookFilter) { public void setOrderBookFilter(OrderBookFilter orderBookFilter) {
presenter.setOrderBookFilter(orderBookFilter); pm.setOrderBookFilter(orderBookFilter);
} }
@ -140,12 +144,12 @@ public class CreateOfferCodeBehind extends CachedViewController {
@FXML @FXML
public void onPlaceOffer() { public void onPlaceOffer() {
presenter.placeOffer(); pm.placeOffer();
} }
@FXML @FXML
public void onClose() { public void onClose() {
presenter.close(); pm.close();
TabPane tabPane = ((TabPane) (root.getParent().getParent())); TabPane tabPane = ((TabPane) (root.getParent().getParent()));
tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem()); tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem());
@ -158,26 +162,26 @@ public class CreateOfferCodeBehind extends CachedViewController {
private void setupListeners() { private void setupListeners() {
volumeTextField.focusedProperty().addListener((o, oldValue, newValue) -> { volumeTextField.focusedProperty().addListener((o, oldValue, newValue) -> {
presenter.onFocusOutVolumeTextField(oldValue, newValue, volumeTextField.getText()); pm.onFocusOutVolumeTextField(oldValue, newValue, volumeTextField.getText());
volumeTextField.setText(presenter.volume.get()); volumeTextField.setText(pm.volume.get());
}); });
amountTextField.focusedProperty().addListener((o, oldValue, newValue) -> { amountTextField.focusedProperty().addListener((o, oldValue, newValue) -> {
presenter.onFocusOutAmountTextField(oldValue, newValue); pm.onFocusOutAmountTextField(oldValue, newValue);
amountTextField.setText(presenter.amount.get()); amountTextField.setText(pm.amount.get());
}); });
priceTextField.focusedProperty().addListener((o, oldValue, newValue) -> { priceTextField.focusedProperty().addListener((o, oldValue, newValue) -> {
presenter.onFocusOutPriceTextField(oldValue, newValue); pm.onFocusOutPriceTextField(oldValue, newValue);
priceTextField.setText(presenter.price.get()); priceTextField.setText(pm.price.get());
}); });
minAmountTextField.focusedProperty().addListener((o, oldValue, newValue) -> { minAmountTextField.focusedProperty().addListener((o, oldValue, newValue) -> {
presenter.onFocusOutMinAmountTextField(oldValue, newValue); pm.onFocusOutMinAmountTextField(oldValue, newValue);
minAmountTextField.setText(presenter.minAmount.get()); minAmountTextField.setText(pm.minAmount.get());
}); });
presenter.needsInputValidation.addListener((o, oldValue, newValue) -> { pm.needsInputValidation.addListener((o, oldValue, newValue) -> {
if (newValue) { if (newValue) {
amountTextField.reValidate(); amountTextField.reValidate();
minAmountTextField.reValidate(); minAmountTextField.reValidate();
@ -186,67 +190,67 @@ public class CreateOfferCodeBehind extends CachedViewController {
} }
}); });
presenter.showWarningInvalidBtcDecimalPlaces.addListener((o, oldValue, newValue) -> { pm.showWarningInvalidBtcDecimalPlaces.addListener((o, oldValue, newValue) -> {
if (newValue) { if (newValue) {
Popups.openWarningPopup("Warning", "The amount you have entered exceeds the number of allowed decimal" + Popups.openWarningPopup("Warning", "The amount you have entered exceeds the number of allowed decimal" +
" places.\nThe amount has been adjusted to 4 decimal places."); " places.\nThe amount has been adjusted to 4 decimal places.");
presenter.showWarningInvalidBtcDecimalPlaces.set(false); pm.showWarningInvalidBtcDecimalPlaces.set(false);
} }
}); });
presenter.showWarningInvalidFiatDecimalPlaces.addListener((o, oldValue, newValue) -> { pm.showWarningInvalidFiatDecimalPlaces.addListener((o, oldValue, newValue) -> {
if (newValue) { if (newValue) {
Popups.openWarningPopup("Warning", "The amount you have entered exceeds the number of allowed decimal" + Popups.openWarningPopup("Warning", "The amount you have entered exceeds the number of allowed decimal" +
" places.\nThe amount has been adjusted to 2 decimal places."); " places.\nThe amount has been adjusted to 2 decimal places.");
presenter.showWarningInvalidFiatDecimalPlaces.set(false); pm.showWarningInvalidFiatDecimalPlaces.set(false);
} }
}); });
presenter.showWarningInvalidBtcFractions.addListener((o, oldValue, newValue) -> { pm.showWarningInvalidBtcFractions.addListener((o, oldValue, newValue) -> {
if (newValue) { if (newValue) {
Popups.openWarningPopup("Warning", "The total volume you have entered leads to invalid fractional " + Popups.openWarningPopup("Warning", "The total volume you have entered leads to invalid fractional " +
"Bitcoin amounts.\nThe amount has been adjusted and a new total volume be calculated from it."); "Bitcoin amounts.\nThe amount has been adjusted and a new total volume be calculated from it.");
presenter.showWarningInvalidBtcFractions.set(false); pm.showWarningInvalidBtcFractions.set(false);
volumeTextField.setText(presenter.volume.get()); volumeTextField.setText(pm.volume.get());
} }
}); });
presenter.requestPlaceOfferFailed.addListener((o, oldValue, newValue) -> { pm.requestPlaceOfferFailed.addListener((o, oldValue, newValue) -> {
if (newValue) { if (newValue) {
Popups.openErrorPopup("Error", "An error occurred when placing the offer.\n" + Popups.openErrorPopup("Error", "An error occurred when placing the offer.\n" +
presenter.requestPlaceOfferErrorMessage); pm.requestPlaceOfferErrorMessage);
presenter.requestPlaceOfferFailed.set(false); pm.requestPlaceOfferFailed.set(false);
} }
}); });
} }
private void setupBindings() { private void setupBindings() {
buyLabel.textProperty().bind(presenter.directionLabel); buyLabel.textProperty().bind(pm.directionLabel);
amountTextField.textProperty().bindBidirectional(presenter.amount); amountTextField.textProperty().bindBidirectional(pm.amount);
priceTextField.textProperty().bindBidirectional(presenter.price); priceTextField.textProperty().bindBidirectional(pm.price);
volumeTextField.textProperty().bindBidirectional(presenter.volume); volumeTextField.textProperty().bindBidirectional(pm.volume);
minAmountTextField.textProperty().bindBidirectional(presenter.minAmount); minAmountTextField.textProperty().bindBidirectional(pm.minAmount);
collateralLabel.textProperty().bind(presenter.collateralLabel); collateralLabel.textProperty().bind(pm.collateralLabel);
collateralTextField.textProperty().bind(presenter.collateral); collateralTextField.textProperty().bind(pm.collateral);
totalToPayTextField.textProperty().bind(presenter.totalToPay); totalToPayTextField.textProperty().bind(pm.totalToPay);
addressTextField.amountAsCoinProperty().bind(presenter.totalToPayAsCoin); addressTextField.amountAsCoinProperty().bind(pm.totalToPayAsCoin);
addressTextField.paymentLabelProperty().bind(presenter.paymentLabel); addressTextField.paymentLabelProperty().bind(pm.paymentLabel);
addressTextField.addressProperty().bind(presenter.addressAsString); addressTextField.addressProperty().bind(pm.addressAsString);
bankAccountTypeTextField.textProperty().bind(presenter.bankAccountType); bankAccountTypeTextField.textProperty().bind(pm.bankAccountType);
bankAccountCurrencyTextField.textProperty().bind(presenter.bankAccountCurrency); bankAccountCurrencyTextField.textProperty().bind(pm.bankAccountCurrency);
bankAccountCountyTextField.textProperty().bind(presenter.bankAccountCounty); bankAccountCountyTextField.textProperty().bind(pm.bankAccountCounty);
acceptedCountriesTextField.textProperty().bind(presenter.acceptedCountries); acceptedCountriesTextField.textProperty().bind(pm.acceptedCountries);
acceptedLanguagesTextField.textProperty().bind(presenter.acceptedLanguages); acceptedLanguagesTextField.textProperty().bind(pm.acceptedLanguages);
totalFeesTextField.textProperty().bind(presenter.totalFees); totalFeesTextField.textProperty().bind(pm.totalFees);
transactionIdTextField.textProperty().bind(presenter.transactionId); transactionIdTextField.textProperty().bind(pm.transactionId);
placeOfferButton.visibleProperty().bind(presenter.isPlaceOfferButtonVisible); placeOfferButton.visibleProperty().bind(pm.isPlaceOfferButtonVisible);
placeOfferButton.disableProperty().bind(presenter.isPlaceOfferButtonDisabled); placeOfferButton.disableProperty().bind(pm.isPlaceOfferButtonDisabled);
closeButton.visibleProperty().bind(presenter.isCloseButtonVisible); closeButton.visibleProperty().bind(pm.isCloseButtonVisible);
//TODO //TODO
/* progressIndicator.visibleProperty().bind(viewModel.isOfferPlacedScreen); /* progressIndicator.visibleProperty().bind(viewModel.isOfferPlacedScreen);
@ -280,8 +284,8 @@ public class CreateOfferCodeBehind extends CachedViewController {
ValidationHelper.setupMinAmountInRangeOfAmountValidation(amountTextField, ValidationHelper.setupMinAmountInRangeOfAmountValidation(amountTextField,
minAmountTextField, minAmountTextField,
presenter.amount, pm.amount,
presenter.minAmount, pm.minAmount,
amountValidator, amountValidator,
minAmountValidator); minAmountValidator);
} }

View file

@ -43,18 +43,18 @@ import static io.bitsquare.gui.util.BSFormatter.*;
import static javafx.beans.binding.Bindings.createStringBinding; import static javafx.beans.binding.Bindings.createStringBinding;
/** /**
* Presenter: * Presentation model:
* Knows Model, does not know the View (CodeBehind) * Knows Model, does not know the View (CodeBehind)
* <p> * <p>
* - Holds data and state of the View (formatting,...) * - Holds data and state of the View (formatting,...)
* - Receive user input via method calls from CodeBehind. * - Receive user input via method calls from CodeBehind.
* - Validates input, applies business logic and converts input to Model. * - Validates input, applies business logic and converts input to Model.
* - Format model data to properties used for binding from the view. * - Format model data to properties used for binding from the view (The view setup the bindings).
* - Listen to updates from Model via Bindings. * - Listen to updates from Model via Bindings (The PM setup the bindings to the model).
* - Is testable * - Can be used for unit testing
*/ */
class CreateOfferPresenter { class CreateOfferPM {
private static final Logger log = LoggerFactory.getLogger(CreateOfferPresenter.class); private static final Logger log = LoggerFactory.getLogger(CreateOfferPM.class);
private CreateOfferModel model; private CreateOfferModel model;
@ -95,7 +95,7 @@ class CreateOfferPresenter {
// Constructor // Constructor
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
CreateOfferPresenter(CreateOfferModel model) { CreateOfferPM(CreateOfferModel model) {
this.model = model; this.model = model;
} }

View file

@ -25,7 +25,7 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<AnchorPane fx:id="root" fx:controller="io.bitsquare.gui.trade.createoffer.CreateOfferCodeBehind" <AnchorPane fx:id="root" fx:controller="io.bitsquare.gui.trade.createoffer.CreateOfferCB"
prefHeight="500" prefWidth="800" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" prefHeight="500" prefWidth="800" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0"
AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0"
xmlns:fx="http://javafx.com/fxml"> xmlns:fx="http://javafx.com/fxml">

View file

@ -25,7 +25,7 @@ import io.bitsquare.gui.MainController;
import io.bitsquare.gui.NavigationItem; import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.ViewController; import io.bitsquare.gui.ViewController;
import io.bitsquare.gui.components.Popups; import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.trade.createoffer.CreateOfferCodeBehind; import io.bitsquare.gui.trade.createoffer.CreateOfferCB;
import io.bitsquare.gui.trade.takeoffer.TakeOfferController; import io.bitsquare.gui.trade.takeoffer.TakeOfferController;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.ImageUtil; import io.bitsquare.gui.util.ImageUtil;
@ -229,7 +229,7 @@ public class OrderBookController extends CachedViewController {
createOfferButton.setDisable(true); createOfferButton.setDisable(true);
ViewController nextController = parentController.loadViewAndGetChildController(NavigationItem.CREATE_OFFER); ViewController nextController = parentController.loadViewAndGetChildController(NavigationItem.CREATE_OFFER);
if (nextController != null) if (nextController != null)
((CreateOfferCodeBehind) nextController).setOrderBookFilter(orderBookFilter); ((CreateOfferCB) nextController).setOrderBookFilter(orderBookFilter);
} }
else { else {
showRegistrationDialog(); showRegistrationDialog();

View file

@ -70,6 +70,7 @@ public class BSFormatter {
static { static {
//useMilliBitFormat(true); //useMilliBitFormat(true);
setLocale(Locale.US);
} }

View file

@ -17,9 +17,6 @@
package io.bitsquare.msg; package io.bitsquare.msg;
import io.bitsquare.BitSquare;
import io.bitsquare.util.AppDirectoryUtil;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
@ -61,6 +58,8 @@ import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import lighthouse.files.AppDirectory;
/** /**
* The fully bootstrapped P2PNode which is responsible himself for his availability in the messaging system. It saves * The fully bootstrapped P2PNode which is responsible himself for his availability in the messaging system. It saves
* for instance the IP address periodically. * for instance the IP address periodically.
@ -70,12 +69,8 @@ import org.slf4j.LoggerFactory;
public class P2PNode { public class P2PNode {
private static final Logger log = LoggerFactory.getLogger(P2PNode.class); private static final Logger log = LoggerFactory.getLogger(P2PNode.class);
private Thread bootstrapToLocalhostThread;
private Thread bootstrapToServerThread;
private KeyPair keyPair; private KeyPair keyPair;
private final Boolean useDiskStorage; private final Boolean useDiskStorage;
private final SeedNodeAddress.StaticSeedNodeAddresses defaultStaticSeedNodeAddresses;
private MessageBroker messageBroker; private MessageBroker messageBroker;
private PeerAddress storedPeerAddress; private PeerAddress storedPeerAddress;
@ -90,11 +85,9 @@ public class P2PNode {
@Inject @Inject
public P2PNode(BootstrappedPeerFactory bootstrappedPeerFactory, public P2PNode(BootstrappedPeerFactory bootstrappedPeerFactory,
@Named("useDiskStorage") Boolean useDiskStorage, @Named("useDiskStorage") Boolean useDiskStorage) {
@Named("defaultSeedNode") SeedNodeAddress.StaticSeedNodeAddresses defaultStaticSeedNodeAddresses) {
this.bootstrappedPeerFactory = bootstrappedPeerFactory; this.bootstrappedPeerFactory = bootstrappedPeerFactory;
this.useDiskStorage = useDiskStorage; this.useDiskStorage = useDiskStorage;
this.defaultStaticSeedNodeAddresses = defaultStaticSeedNodeAddresses;
} }
// for unit testing // for unit testing
@ -105,7 +98,6 @@ public class P2PNode {
messageBroker = (message, peerAddress) -> { messageBroker = (message, peerAddress) -> {
}; };
useDiskStorage = false; useDiskStorage = false;
defaultStaticSeedNodeAddresses = SeedNodeAddress.StaticSeedNodeAddresses.LOCALHOST;
} }
@ -300,20 +292,13 @@ public class P2PNode {
private void useDiscStorage(boolean useDiscStorage) { private void useDiscStorage(boolean useDiscStorage) {
if (useDiscStorage) { if (useDiscStorage) {
try { File path = new File(AppDirectory.dir().toFile() + "/tomP2P");
if (!path.exists()) {
File path = new File(AppDirectoryUtil.getStorageDirectory().getCanonicalPath() + "/" + BitSquare boolean created = path.mkdir();
.getAppName() + "_tomP2P"); if (!created)
if (!path.exists()) { throw new RuntimeException("Could not create the directory '" + path + "'");
boolean created = path.mkdir();
if (!created)
throw new RuntimeException("Could not create the directory '" + path + "'");
}
storage = new StorageDisk(Number160.ZERO, path, new DSASignatureFactory());
} catch (IOException e) {
e.printStackTrace();
} }
storage = new StorageDisk(Number160.ZERO, path, new DSASignatureFactory());
} }
else { else {
storage = new StorageMemory(); storage = new StorageMemory();

View file

@ -1,98 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.util;
import java.io.File;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AppDirectoryUtil {
private static final Logger log = LoggerFactory.getLogger(AppDirectoryUtil.class);
private static File storageDirectory;
static {
useApplicationDirectory();
log.info("Default application data directory = " + storageDirectory);
}
public static File getStorageDirectory() {
return storageDirectory;
}
public static void setStorageDirectory(File directory) {
storageDirectory = directory;
log.info("User defined application data directory = " + directory);
createDirIfNotExists();
}
public static void useApplicationDirectory() {
setStorageDirectory(getApplicationDirectory());
}
public static void useSystemApplicationDataDirectory() {
setStorageDirectory(getSystemApplicationDataDirectory());
}
public static File getApplicationDirectory() {
File executionRoot =
new File(AppDirectoryUtil.class.getProtectionDomain().getCodeSource().getLocation().getFile());
try {
log.trace("executionRoot " + executionRoot.getCanonicalPath());
// check if it is packed into a mac app (e.g.: "$HOME/Desktop/bitsquare.app/Contents/Java/bitsquare.jar")
if (executionRoot.getCanonicalPath().endsWith(".app/Contents/Java/bitsquare.jar") &&
System.getProperty("os.name").startsWith("Mac"))
return executionRoot.getParentFile().getParentFile().getParentFile().getParentFile();
else if (executionRoot.getCanonicalPath().endsWith(File.separator + "target" + File.separator + "classes"))
return executionRoot.getParentFile(); // dev e.g.:
// $HOME/Documents/_intellij/bitsquare/target/classes -> use target as root
else if (executionRoot.getCanonicalPath().endsWith(File.separator + "bitsquare.jar"))
return executionRoot.getParentFile(); // dev with jar e.g.:
// $HOME/Documents/_intellij/bitsquare/out/artifacts/bitsquare2/bitsquare.jar -> use target as root
else
return executionRoot;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public static File getSystemApplicationDataDirectory() {
String osName = System.getProperty("os.name");
if (osName != null && osName.startsWith("Windows"))
return new File(System.getenv("APPDATA") + File.separator + "BitSquare");
else if (osName != null && osName.startsWith("Mac"))
return new File(System.getProperty("user.home") + "/Library/Application Support/BitSquare");
else
return new File(System.getProperty("user.home") + File.separator + "BitSquare");
}
private static void createDirIfNotExists() {
if (!storageDirectory.exists()) {
boolean created = storageDirectory.mkdir();
if (!created)
throw new RuntimeException(
"Could not create the application data directory of '" + storageDirectory + "'");
}
}
}

View file

@ -25,15 +25,17 @@ import java.io.IOException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import lighthouse.files.AppDirectory;
public class FileUtil { public class FileUtil {
private static final Logger log = LoggerFactory.getLogger(FileUtil.class); private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
public static File getFile(String name, String suffix) { public static File getFile(String name, String suffix) {
return new File(AppDirectoryUtil.getStorageDirectory(), name + "." + suffix); return new File(AppDirectory.dir().toFile(), name + "." + suffix);
} }
public static File getTempFile(String prefix) throws IOException { public static File getTempFile(String prefix) throws IOException {
return File.createTempFile("temp_" + prefix, null, AppDirectoryUtil.getStorageDirectory()); return File.createTempFile("temp_" + prefix, null, AppDirectory.dir().toFile());
} }
public static void writeTempFileToFile(File tempFile, File file) throws IOException { public static void writeTempFileToFile(File tempFile, File file) throws IOException {

View file

@ -0,0 +1,56 @@
package lighthouse.files;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static com.google.common.base.Preconditions.checkNotNull;
// TODO update to open source file when its released
/** Manages the directory where the app stores all its files. */
public class AppDirectory {
public static Path getUserDataDir() {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
return Paths.get(System.getenv("APPDATA"));
} else if (os.contains("mac")) {
return Paths.get(System.getProperty("user.home"), "Library", "Application Support");
} else {
// Linux and other similar systems, we hope (not Android).
return Paths.get(System.getProperty("user.home"), ".local", "share");
}
}
public static Path getUserDataDir(String appName) {
return getUserDataDir().resolve(appName);
}
public static Path initAppDir(String appName) throws IOException {
AppDirectory.appName = appName;
Path dir = dir();
if (!Files.exists(dir))
Files.createDirectory(dir);
else if (!Files.isWritable(dir))
throw new IOException("App directory is not writeable");
return dir;
}
private static String appName;
private static Path dir;
public static Path dir() {
if (dir == null)
return getUserDataDir(appName);
else
return dir;
}
public static void overrideAppDir(Path newDir) {
dir = checkNotNull(newDir);
}
}

View file

@ -31,24 +31,24 @@
<logger name="io.netty.channel" level="WARN"/> <logger name="io.netty.channel" level="WARN"/>
<logger name="io.netty.buffer" level="WARN"/> <logger name="io.netty.buffer" level="WARN"/>
<!--
<logger name="io.bitsquare.gui.ViewController" level="OFF"/> <logger name="io.bitsquare.gui.ViewController" level="OFF"/>
<logger name="io.bitsquare.gui.CachedViewController" level="OFF"/> <logger name="io.bitsquare.gui.CachedViewController" level="OFF"/>
<logger name="io.bitsquare.gui.util.Profiler" level="OFF"/> <logger name="io.bitsquare.gui.util.Profiler" level="OFF"/>
<!--
<logger name="com.google.bitcoin.core.Wallet" level="OFF"/> <logger name="com.google.bitcoin.core.Wallet" level="OFF"/>
<logger name="com.google.bitcoin.core.MemoryPool" level="OFF"/> <logger name="com.google.bitcoin.core.MemoryPool" level="OFF"/>
<logger name="com.google.bitcoin.net.discovery.DnsDiscovery" level="OFF"/> <logger name="com.google.bitcoin.net.discovery.DnsDiscovery" level="OFF"/>
<logger name="com.google.bitcoin.core.DownloadListener" level="OFF"/> <logger name="com.google.bitcoin.core.DownloadListener" level="OFF"/>
<logger name="com.google.bitcoin.core.TransactionOutput" level="OFF"/> <logger name="com.google.bitcoin.core.TransactionOutput" level="OFF"/>
<logger name="com.google.bitcoin.core.BitcoinSerializer" level="OFF"/> <logger name="com.google.bitcoin.core.BitcoinSerializer" level="OFF"/>
<logger name="com.google.bitcoin.core.Peer" level="OFF"/> <logger name="com.google.bitcoin.core.Peer" level="OFF"/>
<logger name="com.google.bitcoin.core.PeerGroup" level="OFF"/> <logger name="com.google.bitcoin.core.PeerGroup" level="OFF"/>
<logger name="com.google.bitcoin.core.PeerSocketHandler" level="OFF"/> <logger name="com.google.bitcoin.core.PeerSocketHandler" level="OFF"/>
<logger name="com.google.bitcoin.net.NioClientManager" level="OFF"/> <logger name="com.google.bitcoin.net.NioClientManager" level="OFF"/>
<logger name="com.google.bitcoin.net.ConnectionHandler" level="OFF"/> <logger name="com.google.bitcoin.net.ConnectionHandler" level="OFF"/>
--> -->
</configuration> </configuration>

View file

@ -18,7 +18,7 @@
package io.bitsquare; package io.bitsquare;
import io.bitsquare.btc.RestrictionsTest; import io.bitsquare.btc.RestrictionsTest;
import io.bitsquare.gui.trade.createoffer.CreateOfferPresenterTest; import io.bitsquare.gui.trade.createoffer.CreateOfferPMTest;
import io.bitsquare.gui.util.BSFormatterTest; import io.bitsquare.gui.util.BSFormatterTest;
import io.bitsquare.gui.util.BitSquareConverterTest; import io.bitsquare.gui.util.BitSquareConverterTest;
import io.bitsquare.gui.util.BitSquareNumberValidatorTest; import io.bitsquare.gui.util.BitSquareNumberValidatorTest;
@ -36,7 +36,7 @@ import org.junit.runners.Suite;
P2PNodeTest.class, P2PNodeTest.class,
FiatValidatorTest.class, FiatValidatorTest.class,
RestrictionsTest.class, RestrictionsTest.class,
CreateOfferPresenterTest.class, CreateOfferPMTest.class,
BSFormatterTest.class BSFormatterTest.class
}) })

View file

@ -33,8 +33,8 @@ import org.slf4j.LoggerFactory;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class CreateOfferPresenterTest { public class CreateOfferPMTest {
private static final Logger log = LoggerFactory.getLogger(CreateOfferPresenterTest.class); private static final Logger log = LoggerFactory.getLogger(CreateOfferPMTest.class);
@Test @Test
public void testBindings() { public void testBindings() {
@ -43,7 +43,7 @@ public class CreateOfferPresenterTest {
BSFormatter.setLocale(Locale.US); BSFormatter.setLocale(Locale.US);
BSFormatter.setFiatCurrencyCode("USD"); BSFormatter.setFiatCurrencyCode("USD");
CreateOfferPresenter presenter = new CreateOfferPresenter(model); CreateOfferPM presenter = new CreateOfferPM(model);
presenter.onViewInitialized(); presenter.onViewInitialized();
model.collateralAsLong.set(100); model.collateralAsLong.set(100);