From fb89f087f090a861cd237f126ba3f8a32a5f541a Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Thu, 28 Aug 2014 18:24:42 +0200 Subject: [PATCH] fixed app dir problem with update to gradle. --- .idea/copyright/Bitsquare_Affero_GPLv3.xml | 9 -- .idea/copyright/profiles_settings.xml | 2 +- Development-notes.md | 23 +++ src/main/java/io/bitsquare/BitSquare.java | 9 +- .../java/io/bitsquare/btc/WalletFacade.java | 7 +- .../bitsquare/gui/trade/TradeController.java | 6 +- ...fferCodeBehind.java => CreateOfferCB.java} | 136 +++++++++--------- ...OfferPresenter.java => CreateOfferPM.java} | 14 +- .../trade/createoffer/CreateOfferView.fxml | 2 +- .../trade/orderbook/OrderBookController.java | 4 +- .../io/bitsquare/gui/util/BSFormatter.java | 1 + src/main/java/io/bitsquare/msg/P2PNode.java | 33 ++--- .../io/bitsquare/util/AppDirectoryUtil.java | 98 ------------- src/main/java/io/bitsquare/util/FileUtil.java | 6 +- .../java/lighthouse/files/AppDirectory.java | 56 ++++++++ src/main/resources/logback.xml | 32 ++--- .../java/io/bitsquare/BitSquareTestSuite.java | 4 +- ...senterTest.java => CreateOfferPMTest.java} | 6 +- 18 files changed, 206 insertions(+), 242 deletions(-) delete mode 100644 .idea/copyright/Bitsquare_Affero_GPLv3.xml create mode 100644 Development-notes.md rename src/main/java/io/bitsquare/gui/trade/createoffer/{CreateOfferCodeBehind.java => CreateOfferCB.java} (62%) rename src/main/java/io/bitsquare/gui/trade/createoffer/{CreateOfferPresenter.java => CreateOfferPM.java} (98%) delete mode 100644 src/main/java/io/bitsquare/util/AppDirectoryUtil.java create mode 100644 src/main/java/lighthouse/files/AppDirectory.java rename src/test/java/io/bitsquare/gui/trade/createoffer/{CreateOfferPresenterTest.java => CreateOfferPMTest.java} (96%) diff --git a/.idea/copyright/Bitsquare_Affero_GPLv3.xml b/.idea/copyright/Bitsquare_Affero_GPLv3.xml deleted file mode 100644 index 20bcc836bb..0000000000 --- a/.idea/copyright/Bitsquare_Affero_GPLv3.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml index f6fb94b193..e7bedf3377 100644 --- a/.idea/copyright/profiles_settings.xml +++ b/.idea/copyright/profiles_settings.xml @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/Development-notes.md b/Development-notes.md new file mode 100644 index 0000000000..b4737c4954 --- /dev/null +++ b/Development-notes.md @@ -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) diff --git a/src/main/java/io/bitsquare/BitSquare.java b/src/main/java/io/bitsquare/BitSquare.java index feffbf3996..48afa01d6b 100644 --- a/src/main/java/io/bitsquare/BitSquare.java +++ b/src/main/java/io/bitsquare/BitSquare.java @@ -28,14 +28,12 @@ import io.bitsquare.persistence.Persistence; import io.bitsquare.settings.Settings; import io.bitsquare.user.User; import io.bitsquare.util.AWTSystemTray; -import io.bitsquare.util.AppDirectoryUtil; import com.google.common.base.Throwables; import com.google.inject.Guice; import com.google.inject.Injector; -import java.io.File; import java.io.IOException; import java.util.Arrays; @@ -48,6 +46,8 @@ import javafx.stage.Stage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import lighthouse.files.AppDirectory; + public class BitSquare extends Application { private static final Logger log = LoggerFactory.getLogger(BitSquare.class); @@ -61,7 +61,7 @@ public class BitSquare extends Application { public static void main(String[] args) { Profiler.init(); 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); } @@ -82,8 +82,7 @@ public class BitSquare extends Application { Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> Popups.handleUncaughtExceptions (Throwables.getRootCause(throwable))); - AppDirectoryUtil.setStorageDirectory( - new File(AppDirectoryUtil.getApplicationDirectory().getCanonicalPath() + "/data")); + AppDirectory.initAppDir(APP_NAME); // currently there is not SystemTray support for java fx (planned for version 3) so we use the old AWT AWTSystemTray.createSystemTray(primaryStage); diff --git a/src/main/java/io/bitsquare/btc/WalletFacade.java b/src/main/java/io/bitsquare/btc/WalletFacade.java index 47a270962b..dba1ebc6ca 100644 --- a/src/main/java/io/bitsquare/btc/WalletFacade.java +++ b/src/main/java/io/bitsquare/btc/WalletFacade.java @@ -22,7 +22,6 @@ import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.btc.listeners.ConfidenceListener; import io.bitsquare.crypto.CryptoFacade; import io.bitsquare.persistence.Persistence; -import io.bitsquare.util.AppDirectoryUtil; import com.google.bitcoin.core.Address; import com.google.bitcoin.core.AddressFormatException; @@ -78,6 +77,8 @@ import javafx.util.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import lighthouse.files.AppDirectory; + import static com.google.bitcoin.script.ScriptOpCodes.OP_RETURN; /** @@ -139,7 +140,7 @@ public class WalletFacade { Threading.USER_THREAD = Platform::runLater; // 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 protected void onSetupCompleted() { // 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); Serializable serializable = persistence.read(this, "addressEntryList"); - List persistedAddressEntryList = (List) serializable; if (serializable instanceof List) { + List persistedAddressEntryList = (List) serializable; for (AddressEntry persistedAddressEntry : persistedAddressEntryList) { persistedAddressEntry.setDeterministicKey( (DeterministicKey) wallet.findKeyFromPubHash(persistedAddressEntry.getPubKeyHash())); diff --git a/src/main/java/io/bitsquare/gui/trade/TradeController.java b/src/main/java/io/bitsquare/gui/trade/TradeController.java index cfec85a2d4..9cecebcad2 100644 --- a/src/main/java/io/bitsquare/gui/trade/TradeController.java +++ b/src/main/java/io/bitsquare/gui/trade/TradeController.java @@ -22,7 +22,7 @@ import io.bitsquare.gui.CachedViewController; import io.bitsquare.gui.NavigationItem; import io.bitsquare.gui.ViewController; 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.takeoffer.TakeOfferController; import io.bitsquare.trade.Direction; @@ -46,7 +46,7 @@ public class TradeController extends CachedViewController { private static final Logger log = LoggerFactory.getLogger(TradeController.class); protected OrderBookController orderBookController; - protected CreateOfferCodeBehind createOfferCodeBehind; + protected CreateOfferCB createOfferCodeBehind; protected TakeOfferController takeOfferController; protected GuiceFXMLLoader orderBookLoader; @@ -76,7 +76,7 @@ public class TradeController extends CachedViewController { // TODO find better solution // Textfield focus out triggers validation, use runLater as quick fix... ((TabPane) root).getSelectionModel().selectedIndexProperty().addListener((observableValue) -> - Platform.runLater(() -> ValidatingTextField.hidePopover())); + Platform.runLater(ValidatingTextField::hidePopover)); } diff --git a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCodeBehind.java b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCB.java similarity index 62% rename from src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCodeBehind.java rename to src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCB.java index f3215fbe64..32ea66359d 100644 --- a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCodeBehind.java +++ b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCB.java @@ -43,31 +43,34 @@ import org.slf4j.Logger; 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): *

- * 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 *

- * - Setup binding from Presenter to View elements (also bidirectional - Inputs). Binding are only to presenters - * properties, not logical bindings or cross-view element bindings. - * - Listen to UI events (Action) from View and call method in Presenter. - * - Is entry node for hierarchical view graphs. Passes method calls to Presenter. Calls methods on sub views. + * - Creates presentation model and passes model from Guice injection to the presenter. Does not hold any reference to the model. + * //TODO is there a better way for DI of model? + * - Setup binding from presenter to view elements (also bidirectional - used for input data). Binding are only to plain + * 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. - * - Non declarative (dynamic) view definitions (if it gets larger, then user a ViewBuilder) - * - Has no logic and no state, only view elements and a presenter reference! + * - Can contain non-declarative (dynamic) view definitions (if it gets larger, then use a dedicated ViewBuilder) *

* View: - * - Mostly declared in FXML. Dynamic parts are declared in Controller. If more view elements need to be defined in - * code then use ViewBuilder. + * - Typically declared in FXML. Dynamic parts are declared in Controller. If more view elements need to be defined in + * code then use a ViewBuilder. *

- * Optional ViewBuilder: - * - Replacement for FXML view definitions. + * ViewBuilder (optional): + * - Additionally or instead of FXML view. If no FXML then controller setup need to be handles by ViewBuilder. *

* Note: Don't assign the root node as it is defined in the base class! */ -public class CreateOfferCodeBehind extends CachedViewController { - private static final Logger log = LoggerFactory.getLogger(CreateOfferCodeBehind.class); +public class CreateOfferCB extends CachedViewController { + 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 ValidatingTextField amountTextField, minAmountTextField, priceTextField, volumeTextField; @@ -86,8 +89,8 @@ public class CreateOfferCodeBehind extends CachedViewController { /////////////////////////////////////////////////////////////////////////////////////////// @Inject - public CreateOfferCodeBehind(CreateOfferModel model) { - presenter = new CreateOfferPresenter(model); + public CreateOfferCB(CreateOfferModel model) { + pm = new CreateOfferPM(model); } @@ -99,17 +102,18 @@ public class CreateOfferCodeBehind extends CachedViewController { public void initialize(URL url, ResourceBundle rb) { super.initialize(url, rb); - presenter.onViewInitialized(); + pm.onViewInitialized(); - balanceTextField.setup(presenter.getWalletFacade(), presenter.address.get()); + balanceTextField.setup(pm.getWalletFacade(), pm.address.get()); } @Override public void deactivate() { super.deactivate(); - presenter.deactivate(); + pm.deactivate(); + //TODO check that again ((TradeController) parentController).onCreateOfferViewRemoved(); } @@ -117,7 +121,7 @@ public class CreateOfferCodeBehind extends CachedViewController { public void activate() { super.activate(); - presenter.activate(); + pm.activate(); setupBindings(); setupListeners(); @@ -130,7 +134,7 @@ public class CreateOfferCodeBehind extends CachedViewController { /////////////////////////////////////////////////////////////////////////////////////////// public void setOrderBookFilter(OrderBookFilter orderBookFilter) { - presenter.setOrderBookFilter(orderBookFilter); + pm.setOrderBookFilter(orderBookFilter); } @@ -140,12 +144,12 @@ public class CreateOfferCodeBehind extends CachedViewController { @FXML public void onPlaceOffer() { - presenter.placeOffer(); + pm.placeOffer(); } @FXML public void onClose() { - presenter.close(); + pm.close(); TabPane tabPane = ((TabPane) (root.getParent().getParent())); tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem()); @@ -158,26 +162,26 @@ public class CreateOfferCodeBehind extends CachedViewController { private void setupListeners() { volumeTextField.focusedProperty().addListener((o, oldValue, newValue) -> { - presenter.onFocusOutVolumeTextField(oldValue, newValue, volumeTextField.getText()); - volumeTextField.setText(presenter.volume.get()); + pm.onFocusOutVolumeTextField(oldValue, newValue, volumeTextField.getText()); + volumeTextField.setText(pm.volume.get()); }); amountTextField.focusedProperty().addListener((o, oldValue, newValue) -> { - presenter.onFocusOutAmountTextField(oldValue, newValue); - amountTextField.setText(presenter.amount.get()); + pm.onFocusOutAmountTextField(oldValue, newValue); + amountTextField.setText(pm.amount.get()); }); priceTextField.focusedProperty().addListener((o, oldValue, newValue) -> { - presenter.onFocusOutPriceTextField(oldValue, newValue); - priceTextField.setText(presenter.price.get()); + pm.onFocusOutPriceTextField(oldValue, newValue); + priceTextField.setText(pm.price.get()); }); minAmountTextField.focusedProperty().addListener((o, oldValue, newValue) -> { - presenter.onFocusOutMinAmountTextField(oldValue, newValue); - minAmountTextField.setText(presenter.minAmount.get()); + pm.onFocusOutMinAmountTextField(oldValue, newValue); + minAmountTextField.setText(pm.minAmount.get()); }); - presenter.needsInputValidation.addListener((o, oldValue, newValue) -> { + pm.needsInputValidation.addListener((o, oldValue, newValue) -> { if (newValue) { amountTextField.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) { Popups.openWarningPopup("Warning", "The amount you have entered exceeds the number of allowed decimal" + " 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) { Popups.openWarningPopup("Warning", "The amount you have entered exceeds the number of allowed decimal" + " 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) { 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."); - presenter.showWarningInvalidBtcFractions.set(false); - volumeTextField.setText(presenter.volume.get()); + pm.showWarningInvalidBtcFractions.set(false); + volumeTextField.setText(pm.volume.get()); } }); - presenter.requestPlaceOfferFailed.addListener((o, oldValue, newValue) -> { + pm.requestPlaceOfferFailed.addListener((o, oldValue, newValue) -> { if (newValue) { Popups.openErrorPopup("Error", "An error occurred when placing the offer.\n" + - presenter.requestPlaceOfferErrorMessage); - presenter.requestPlaceOfferFailed.set(false); + pm.requestPlaceOfferErrorMessage); + pm.requestPlaceOfferFailed.set(false); } }); } private void setupBindings() { - buyLabel.textProperty().bind(presenter.directionLabel); - amountTextField.textProperty().bindBidirectional(presenter.amount); - priceTextField.textProperty().bindBidirectional(presenter.price); - volumeTextField.textProperty().bindBidirectional(presenter.volume); + buyLabel.textProperty().bind(pm.directionLabel); + amountTextField.textProperty().bindBidirectional(pm.amount); + priceTextField.textProperty().bindBidirectional(pm.price); + volumeTextField.textProperty().bindBidirectional(pm.volume); - minAmountTextField.textProperty().bindBidirectional(presenter.minAmount); - collateralLabel.textProperty().bind(presenter.collateralLabel); - collateralTextField.textProperty().bind(presenter.collateral); - totalToPayTextField.textProperty().bind(presenter.totalToPay); + minAmountTextField.textProperty().bindBidirectional(pm.minAmount); + collateralLabel.textProperty().bind(pm.collateralLabel); + collateralTextField.textProperty().bind(pm.collateral); + totalToPayTextField.textProperty().bind(pm.totalToPay); - addressTextField.amountAsCoinProperty().bind(presenter.totalToPayAsCoin); - addressTextField.paymentLabelProperty().bind(presenter.paymentLabel); - addressTextField.addressProperty().bind(presenter.addressAsString); + addressTextField.amountAsCoinProperty().bind(pm.totalToPayAsCoin); + addressTextField.paymentLabelProperty().bind(pm.paymentLabel); + addressTextField.addressProperty().bind(pm.addressAsString); - bankAccountTypeTextField.textProperty().bind(presenter.bankAccountType); - bankAccountCurrencyTextField.textProperty().bind(presenter.bankAccountCurrency); - bankAccountCountyTextField.textProperty().bind(presenter.bankAccountCounty); + bankAccountTypeTextField.textProperty().bind(pm.bankAccountType); + bankAccountCurrencyTextField.textProperty().bind(pm.bankAccountCurrency); + bankAccountCountyTextField.textProperty().bind(pm.bankAccountCounty); - acceptedCountriesTextField.textProperty().bind(presenter.acceptedCountries); - acceptedLanguagesTextField.textProperty().bind(presenter.acceptedLanguages); - totalFeesTextField.textProperty().bind(presenter.totalFees); - transactionIdTextField.textProperty().bind(presenter.transactionId); + acceptedCountriesTextField.textProperty().bind(pm.acceptedCountries); + acceptedLanguagesTextField.textProperty().bind(pm.acceptedLanguages); + totalFeesTextField.textProperty().bind(pm.totalFees); + transactionIdTextField.textProperty().bind(pm.transactionId); - placeOfferButton.visibleProperty().bind(presenter.isPlaceOfferButtonVisible); - placeOfferButton.disableProperty().bind(presenter.isPlaceOfferButtonDisabled); - closeButton.visibleProperty().bind(presenter.isCloseButtonVisible); + placeOfferButton.visibleProperty().bind(pm.isPlaceOfferButtonVisible); + placeOfferButton.disableProperty().bind(pm.isPlaceOfferButtonDisabled); + closeButton.visibleProperty().bind(pm.isCloseButtonVisible); //TODO /* progressIndicator.visibleProperty().bind(viewModel.isOfferPlacedScreen); @@ -280,8 +284,8 @@ public class CreateOfferCodeBehind extends CachedViewController { ValidationHelper.setupMinAmountInRangeOfAmountValidation(amountTextField, minAmountTextField, - presenter.amount, - presenter.minAmount, + pm.amount, + pm.minAmount, amountValidator, minAmountValidator); } diff --git a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPresenter.java b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPM.java similarity index 98% rename from src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPresenter.java rename to src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPM.java index 55197fe580..34fb3024b3 100644 --- a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPresenter.java +++ b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPM.java @@ -43,18 +43,18 @@ import static io.bitsquare.gui.util.BSFormatter.*; import static javafx.beans.binding.Bindings.createStringBinding; /** - * Presenter: + * Presentation model: * Knows Model, does not know the View (CodeBehind) *

* - Holds data and state of the View (formatting,...) * - Receive user input via method calls from CodeBehind. * - Validates input, applies business logic and converts input to Model. - * - Format model data to properties used for binding from the view. - * - Listen to updates from Model via Bindings. - * - Is testable + * - Format model data to properties used for binding from the view (The view setup the bindings). + * - Listen to updates from Model via Bindings (The PM setup the bindings to the model). + * - Can be used for unit testing */ -class CreateOfferPresenter { - private static final Logger log = LoggerFactory.getLogger(CreateOfferPresenter.class); +class CreateOfferPM { + private static final Logger log = LoggerFactory.getLogger(CreateOfferPM.class); private CreateOfferModel model; @@ -95,7 +95,7 @@ class CreateOfferPresenter { // Constructor /////////////////////////////////////////////////////////////////////////////////////////// - CreateOfferPresenter(CreateOfferModel model) { + CreateOfferPM(CreateOfferModel model) { this.model = model; } diff --git a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferView.fxml b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferView.fxml index c4cdbbc64c..8439862973 100644 --- a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferView.fxml +++ b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferView.fxml @@ -25,7 +25,7 @@ - diff --git a/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookController.java b/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookController.java index 3cec5d9b0c..a54d446498 100644 --- a/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookController.java +++ b/src/main/java/io/bitsquare/gui/trade/orderbook/OrderBookController.java @@ -25,7 +25,7 @@ import io.bitsquare.gui.MainController; import io.bitsquare.gui.NavigationItem; import io.bitsquare.gui.ViewController; 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.util.BSFormatter; import io.bitsquare.gui.util.ImageUtil; @@ -229,7 +229,7 @@ public class OrderBookController extends CachedViewController { createOfferButton.setDisable(true); ViewController nextController = parentController.loadViewAndGetChildController(NavigationItem.CREATE_OFFER); if (nextController != null) - ((CreateOfferCodeBehind) nextController).setOrderBookFilter(orderBookFilter); + ((CreateOfferCB) nextController).setOrderBookFilter(orderBookFilter); } else { showRegistrationDialog(); diff --git a/src/main/java/io/bitsquare/gui/util/BSFormatter.java b/src/main/java/io/bitsquare/gui/util/BSFormatter.java index 51ac15f401..649f404552 100644 --- a/src/main/java/io/bitsquare/gui/util/BSFormatter.java +++ b/src/main/java/io/bitsquare/gui/util/BSFormatter.java @@ -70,6 +70,7 @@ public class BSFormatter { static { //useMilliBitFormat(true); + setLocale(Locale.US); } diff --git a/src/main/java/io/bitsquare/msg/P2PNode.java b/src/main/java/io/bitsquare/msg/P2PNode.java index 954cd36762..779ca5ff33 100644 --- a/src/main/java/io/bitsquare/msg/P2PNode.java +++ b/src/main/java/io/bitsquare/msg/P2PNode.java @@ -17,9 +17,6 @@ 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.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -61,6 +58,8 @@ import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; 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 * for instance the IP address periodically. @@ -70,12 +69,8 @@ import org.slf4j.LoggerFactory; public class P2PNode { private static final Logger log = LoggerFactory.getLogger(P2PNode.class); - private Thread bootstrapToLocalhostThread; - private Thread bootstrapToServerThread; - private KeyPair keyPair; private final Boolean useDiskStorage; - private final SeedNodeAddress.StaticSeedNodeAddresses defaultStaticSeedNodeAddresses; private MessageBroker messageBroker; private PeerAddress storedPeerAddress; @@ -90,11 +85,9 @@ public class P2PNode { @Inject public P2PNode(BootstrappedPeerFactory bootstrappedPeerFactory, - @Named("useDiskStorage") Boolean useDiskStorage, - @Named("defaultSeedNode") SeedNodeAddress.StaticSeedNodeAddresses defaultStaticSeedNodeAddresses) { + @Named("useDiskStorage") Boolean useDiskStorage) { this.bootstrappedPeerFactory = bootstrappedPeerFactory; this.useDiskStorage = useDiskStorage; - this.defaultStaticSeedNodeAddresses = defaultStaticSeedNodeAddresses; } // for unit testing @@ -105,7 +98,6 @@ public class P2PNode { messageBroker = (message, peerAddress) -> { }; useDiskStorage = false; - defaultStaticSeedNodeAddresses = SeedNodeAddress.StaticSeedNodeAddresses.LOCALHOST; } @@ -300,20 +292,13 @@ public class P2PNode { private void useDiscStorage(boolean useDiscStorage) { if (useDiscStorage) { - try { - - File path = new File(AppDirectoryUtil.getStorageDirectory().getCanonicalPath() + "/" + BitSquare - .getAppName() + "_tomP2P"); - if (!path.exists()) { - 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(); + File path = new File(AppDirectory.dir().toFile() + "/tomP2P"); + if (!path.exists()) { + boolean created = path.mkdir(); + if (!created) + throw new RuntimeException("Could not create the directory '" + path + "'"); } + storage = new StorageDisk(Number160.ZERO, path, new DSASignatureFactory()); } else { storage = new StorageMemory(); diff --git a/src/main/java/io/bitsquare/util/AppDirectoryUtil.java b/src/main/java/io/bitsquare/util/AppDirectoryUtil.java deleted file mode 100644 index b3404d0b5b..0000000000 --- a/src/main/java/io/bitsquare/util/AppDirectoryUtil.java +++ /dev/null @@ -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 . - */ - -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 + "'"); - } - } -} - diff --git a/src/main/java/io/bitsquare/util/FileUtil.java b/src/main/java/io/bitsquare/util/FileUtil.java index b30fb77df1..e0525f4911 100644 --- a/src/main/java/io/bitsquare/util/FileUtil.java +++ b/src/main/java/io/bitsquare/util/FileUtil.java @@ -25,15 +25,17 @@ import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import lighthouse.files.AppDirectory; + public class FileUtil { private static final Logger log = LoggerFactory.getLogger(FileUtil.class); 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 { - 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 { diff --git a/src/main/java/lighthouse/files/AppDirectory.java b/src/main/java/lighthouse/files/AppDirectory.java new file mode 100644 index 0000000000..5d293aa2a3 --- /dev/null +++ b/src/main/java/lighthouse/files/AppDirectory.java @@ -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); + } +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index f2e3399472..7de15700eb 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -31,24 +31,24 @@ - + diff --git a/src/test/java/io/bitsquare/BitSquareTestSuite.java b/src/test/java/io/bitsquare/BitSquareTestSuite.java index dd8d997d18..d14acbdd7a 100644 --- a/src/test/java/io/bitsquare/BitSquareTestSuite.java +++ b/src/test/java/io/bitsquare/BitSquareTestSuite.java @@ -18,7 +18,7 @@ package io.bitsquare; 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.BitSquareConverterTest; import io.bitsquare.gui.util.BitSquareNumberValidatorTest; @@ -36,7 +36,7 @@ import org.junit.runners.Suite; P2PNodeTest.class, FiatValidatorTest.class, RestrictionsTest.class, - CreateOfferPresenterTest.class, + CreateOfferPMTest.class, BSFormatterTest.class }) diff --git a/src/test/java/io/bitsquare/gui/trade/createoffer/CreateOfferPresenterTest.java b/src/test/java/io/bitsquare/gui/trade/createoffer/CreateOfferPMTest.java similarity index 96% rename from src/test/java/io/bitsquare/gui/trade/createoffer/CreateOfferPresenterTest.java rename to src/test/java/io/bitsquare/gui/trade/createoffer/CreateOfferPMTest.java index d2a87f6f6b..500bc9d438 100644 --- a/src/test/java/io/bitsquare/gui/trade/createoffer/CreateOfferPresenterTest.java +++ b/src/test/java/io/bitsquare/gui/trade/createoffer/CreateOfferPMTest.java @@ -33,8 +33,8 @@ import org.slf4j.LoggerFactory; import static org.junit.Assert.*; -public class CreateOfferPresenterTest { - private static final Logger log = LoggerFactory.getLogger(CreateOfferPresenterTest.class); +public class CreateOfferPMTest { + private static final Logger log = LoggerFactory.getLogger(CreateOfferPMTest.class); @Test public void testBindings() { @@ -43,7 +43,7 @@ public class CreateOfferPresenterTest { BSFormatter.setLocale(Locale.US); BSFormatter.setFiatCurrencyCode("USD"); - CreateOfferPresenter presenter = new CreateOfferPresenter(model); + CreateOfferPM presenter = new CreateOfferPM(model); presenter.onViewInitialized(); model.collateralAsLong.set(100);