fixed validation bugs and bugs at create order view

This commit is contained in:
Manfred Karrer 2014-08-20 21:55:27 +02:00
parent 844029d967
commit 7e8ee84ed1
19 changed files with 328 additions and 246 deletions

View file

@ -648,7 +648,7 @@ public class WalletFacade
Coin fee = FeePolicy.CREATE_OFFER_FEE.subtract(FeePolicy.TX_FEE); Coin fee = FeePolicy.CREATE_OFFER_FEE.subtract(FeePolicy.TX_FEE);
log.trace("fee: " + fee.toFriendlyString()); log.trace("fee: " + fee.toFriendlyString());
tx.addOutput(fee, feePolicy.getAddressForCreateOfferFee()); tx.addOutput(fee, feePolicy.getAddressForCreateOfferFee());
printInputs("payCreateOfferFee", tx); // printInputs("payCreateOfferFee", tx);
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx); Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
sendRequest.shuffleOutputs = false; sendRequest.shuffleOutputs = false;
// we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to wait for 1 confirmation) // we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to wait for 1 confirmation)

View file

@ -20,7 +20,6 @@ import io.bitsquare.settings.Settings;
import io.bitsquare.storage.Persistence; import io.bitsquare.storage.Persistence;
import io.bitsquare.trade.TradeManager; import io.bitsquare.trade.TradeManager;
import io.bitsquare.trade.orderbook.OrderBook; import io.bitsquare.trade.orderbook.OrderBook;
import io.bitsquare.trade.orderbook.OrderBookFilter;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import javax.inject.Inject; import javax.inject.Inject;
@ -34,7 +33,6 @@ public class BitSquareModule extends AbstractModule
bind(OrderBook.class).asEagerSingleton(); bind(OrderBook.class).asEagerSingleton();
bind(Persistence.class).asEagerSingleton(); bind(Persistence.class).asEagerSingleton();
bind(Settings.class).asEagerSingleton(); bind(Settings.class).asEagerSingleton();
bind(OrderBookFilter.class).asEagerSingleton();
bind(CryptoFacade.class).asEagerSingleton(); bind(CryptoFacade.class).asEagerSingleton();
bind(WalletFacade.class).asEagerSingleton(); bind(WalletFacade.class).asEagerSingleton();

View file

@ -40,8 +40,8 @@ public class GuiceFXMLLoader
{ {
this.url = url; this.url = url;
// useCaching = false;
isCached = useCaching && cachedGUIItems.containsKey(url); isCached = useCaching && cachedGUIItems.containsKey(url);
if (!isCached) if (!isCached)
{ {
loader = new FXMLLoader(url, Localisation.getResourceBundle()); loader = new FXMLLoader(url, Localisation.getResourceBundle());

View file

@ -6,7 +6,6 @@ import io.bitsquare.btc.WalletFacade;
import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.di.GuiceFXMLLoader; import io.bitsquare.di.GuiceFXMLLoader;
import io.bitsquare.gui.components.NetworkSyncPane; import io.bitsquare.gui.components.NetworkSyncPane;
import io.bitsquare.gui.market.MarketController;
import io.bitsquare.gui.orders.OrdersController; import io.bitsquare.gui.orders.OrdersController;
import io.bitsquare.gui.util.ImageUtil; import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.gui.util.Profiler; import io.bitsquare.gui.util.Profiler;
@ -14,7 +13,6 @@ import io.bitsquare.gui.util.Transitions;
import io.bitsquare.msg.BootstrapListener; import io.bitsquare.msg.BootstrapListener;
import io.bitsquare.msg.MessageFacade; import io.bitsquare.msg.MessageFacade;
import io.bitsquare.storage.Persistence; import io.bitsquare.storage.Persistence;
import io.bitsquare.trade.Direction;
import io.bitsquare.trade.TradeManager; import io.bitsquare.trade.TradeManager;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import io.bitsquare.util.AWTSystemTray; import io.bitsquare.util.AWTSystemTray;
@ -332,11 +330,6 @@ public class MainController implements Initializable, NavigationController
controller = loadView(navigationItem); controller = loadView(navigationItem);
if (controller instanceof MarketController)
{
((MarketController) controller).setDirection(navigationItem == NavigationItem.BUY ? Direction.BUY : Direction.SELL);
}
persistence.write(this, "selectedNavigationItem", navigationItem); persistence.write(this, "selectedNavigationItem", navigationItem);
prevToggleButton = toggleButton; prevToggleButton = toggleButton;

View file

@ -6,8 +6,8 @@ public enum NavigationItem
{ {
MAIN("/io/bitsquare/gui/MainView.fxml"), MAIN("/io/bitsquare/gui/MainView.fxml"),
HOME("/io/bitsquare/gui/home/HomeView.fxml", ImageUtil.HOME, ImageUtil.HOME_ACTIVE), HOME("/io/bitsquare/gui/home/HomeView.fxml", ImageUtil.HOME, ImageUtil.HOME_ACTIVE),
BUY("/io/bitsquare/gui/market/MarketView.fxml", ImageUtil.NAV_BUY, ImageUtil.NAV_BUY_ACTIVE), BUY("/io/bitsquare/gui/market/BuyView.fxml", ImageUtil.NAV_BUY, ImageUtil.NAV_BUY_ACTIVE),
SELL("/io/bitsquare/gui/market/MarketView.fxml", ImageUtil.NAV_SELL, ImageUtil.NAV_SELL_ACTIVE), SELL("/io/bitsquare/gui/market/SellView.fxml", ImageUtil.NAV_SELL, ImageUtil.NAV_SELL_ACTIVE),
ORDERS("/io/bitsquare/gui/orders/OrdersView.fxml", ImageUtil.ORDERS, ImageUtil.ORDERS_ACTIVE), ORDERS("/io/bitsquare/gui/orders/OrdersView.fxml", ImageUtil.ORDERS, ImageUtil.ORDERS_ACTIVE),
FUNDS("/io/bitsquare/gui/funds/FundsView.fxml", ImageUtil.FUNDS, ImageUtil.FUNDS_ACTIVE), FUNDS("/io/bitsquare/gui/funds/FundsView.fxml", ImageUtil.FUNDS, ImageUtil.FUNDS_ACTIVE),
MSG("/io/bitsquare/gui/msg/MsgView.fxml", ImageUtil.MSG, ImageUtil.MSG_ACTIVE), MSG("/io/bitsquare/gui/msg/MsgView.fxml", ImageUtil.MSG, ImageUtil.MSG_ACTIVE),

View file

@ -1,7 +1,6 @@
package io.bitsquare.gui.components; package io.bitsquare.gui.components;
import io.bitsquare.gui.util.NumberValidator; import io.bitsquare.gui.util.NumberValidator;
import java.util.LinkedList;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets; import javafx.geometry.Insets;
@ -28,21 +27,26 @@ import org.slf4j.LoggerFactory;
public class ValidatingTextField extends TextField public class ValidatingTextField extends TextField
{ {
private static final Logger log = LoggerFactory.getLogger(ValidatingTextField.class); private static final Logger log = LoggerFactory.getLogger(ValidatingTextField.class);
private static final Effect DEFAULT_EFFECT = new DropShadow(BlurType.GAUSSIAN, Color.RED, 4, 0.0, 0, 0); private static PopOver popOver;
// we hold all error popups any only display the latest one private Effect invalidEffect = new DropShadow(BlurType.GAUSSIAN, Color.RED, 4, 0.0, 0, 0);
private static final LinkedList<PopOver> allErrorPopups = new LinkedList<>();
private Effect invalidEffect = DEFAULT_EFFECT; private final BooleanProperty isValid = new SimpleBooleanProperty(true);
private final BooleanProperty valid = new SimpleBooleanProperty(true);
private NumberValidator numberValidator; private NumberValidator numberValidator;
private boolean validateOnFocusOut = true; private boolean validateOnFocusOut = true;
private boolean needsValidationOnFocusOut; private boolean needsValidationOnFocusOut;
private PopOver popOver;
private Region errorPopupLayoutReference; private Region errorPopupLayoutReference;
private double errorPopOverX;
private double errorPopOverY;
///////////////////////////////////////////////////////////////////////////////////////////
// Static
///////////////////////////////////////////////////////////////////////////////////////////
public static void hidePopover()
{
if (popOver != null)
popOver.hide();
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -52,6 +56,7 @@ public class ValidatingTextField extends TextField
public ValidatingTextField() public ValidatingTextField()
{ {
super(); super();
setupListeners(); setupListeners();
} }
@ -75,19 +80,44 @@ public class ValidatingTextField extends TextField
this.numberValidator = numberValidator; this.numberValidator = numberValidator;
} }
/**
* @param errorPopupLayoutReference The node used as reference for positioning
*/
public void setErrorPopupLayoutReference(Region errorPopupLayoutReference) public void setErrorPopupLayoutReference(Region errorPopupLayoutReference)
{ {
this.errorPopupLayoutReference = errorPopupLayoutReference; this.errorPopupLayoutReference = errorPopupLayoutReference;
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public boolean getIsValid()
{
return isValid.get();
}
public BooleanProperty isValidProperty()
{
return isValid;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Private methods // Private methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void setupListeners() private void setupListeners()
{ {
this.textProperty().addListener((ov, oldValue, newValue) -> { sceneProperty().addListener((ov, oldValue, newValue) -> {
// we got removed from the scene
// lets hide an open popup
if (newValue == null)
hidePopover();
});
textProperty().addListener((ov, oldValue, newValue) -> {
if (numberValidator != null) if (numberValidator != null)
{ {
if (!validateOnFocusOut) if (!validateOnFocusOut)
@ -97,12 +127,12 @@ public class ValidatingTextField extends TextField
} }
}); });
this.focusedProperty().addListener((ov, oldValue, newValue) -> { focusedProperty().addListener((ov, oldValue, newValue) -> {
if (validateOnFocusOut && needsValidationOnFocusOut && !newValue && getScene()!= null && getScene().getWindow().isFocused()) if (validateOnFocusOut && needsValidationOnFocusOut && !newValue && getScene() != null && getScene().getWindow().isFocused())
validate(getText()); validate(getText());
}); });
this.valid.addListener((ov, oldValue, newValue) -> applyEffect(newValue)); isValid.addListener((ov, oldValue, newValue) -> applyEffect(newValue));
} }
private void validate(String input) private void validate(String input)
@ -110,7 +140,7 @@ public class ValidatingTextField extends TextField
if (input != null) if (input != null)
{ {
NumberValidator.ValidationResult validationResult = numberValidator.validate(input); NumberValidator.ValidationResult validationResult = numberValidator.validate(input);
valid.set(validationResult.isValid); isValid.set(validationResult.isValid);
applyErrorMessage(validationResult); applyErrorMessage(validationResult);
} }
} }
@ -119,35 +149,19 @@ public class ValidatingTextField extends TextField
{ {
if (validationResult.isValid) if (validationResult.isValid)
{ {
if (allErrorPopups.contains(popOver)) if (popOver != null)
{ {
allErrorPopups.remove(popOver);
popOver.hide(); popOver.hide();
} }
if (allErrorPopups.size() > 0)
{
PopOver lastPopOver = allErrorPopups.getLast();
lastPopOver.show(getScene().getWindow());
}
popOver = null;
} }
else else
{ {
if (allErrorPopups.size() > 0) if (popOver == null)
{ createErrorPopOver(validationResult.errorMessage);
PopOver lastPopOver = allErrorPopups.getLast(); else
lastPopOver.hide(); setErrorMessage(validationResult.errorMessage);
}
if (allErrorPopups.contains(popOver)) popOver.show(getScene().getWindow(), getErrorPopupPosition().getX(), getErrorPopupPosition().getY());
{
allErrorPopups.remove(popOver);
popOver.hide();
}
popOver = createErrorPopOver(validationResult.errorMessage);
popOver.show(getScene().getWindow(), errorPopOverX, errorPopOverY);
allErrorPopups.add(popOver);
} }
} }
@ -156,30 +170,39 @@ public class ValidatingTextField extends TextField
setEffect(isValid ? null : invalidEffect); setEffect(isValid ? null : invalidEffect);
} }
private PopOver createErrorPopOver(String errorMessage) private Point2D getErrorPopupPosition()
{
Window window = getScene().getWindow();
Point2D point;
double x;
if (errorPopupLayoutReference == null)
{
point = localToScene(0, 0);
x = point.getX() + window.getX() + getWidth() + 20;
}
else
{
point = errorPopupLayoutReference.localToScene(0, 0);
x = point.getX() + window.getX() + errorPopupLayoutReference.getWidth() + 20;
}
double y = point.getY() + window.getY() + Math.floor(getHeight() / 2);
return new Point2D(x, y);
}
private static void setErrorMessage(String errorMessage)
{
((Label) popOver.getContentNode()).setText(errorMessage);
}
private static void createErrorPopOver(String errorMessage)
{ {
Label errorLabel = new Label(errorMessage); Label errorLabel = new Label(errorMessage);
errorLabel.setId("validation-error"); errorLabel.setId("validation-error");
errorLabel.setPadding(new Insets(0, 10, 0, 10)); errorLabel.setPadding(new Insets(0, 10, 0, 10));
PopOver popOver = new PopOver(errorLabel); popOver = new PopOver(errorLabel);
popOver.setAutoFix(true); popOver.setAutoFix(true);
popOver.setDetachedTitle(""); popOver.setDetachedTitle("");
popOver.setArrowIndent(5); popOver.setArrowIndent(5);
Window window = getScene().getWindow();
Point2D point;
if (errorPopupLayoutReference == null)
{
point = localToScene(0, 0);
errorPopOverX = point.getX() + window.getX() + getWidth() + 20;
}
else
{
point = errorPopupLayoutReference.localToScene(0, 0);
errorPopOverX = point.getX() + window.getX() + errorPopupLayoutReference.getWidth() + 20;
}
errorPopOverY = point.getY() + window.getY() + Math.floor(getHeight() / 2);
return popOver;
} }
} }

View file

@ -24,6 +24,7 @@ public class BalanceTextField extends AnchorPane
private WalletFacade walletFacade; private WalletFacade walletFacade;
private ConfidenceListener confidenceListener; private ConfidenceListener confidenceListener;
private BalanceListener balanceListener; private BalanceListener balanceListener;
private Coin balance;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -96,11 +97,21 @@ public class BalanceTextField extends AnchorPane
walletFacade.removeBalanceListener(balanceListener); walletFacade.removeBalanceListener(balanceListener);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public Coin getBalance()
{
return balance;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Private methods // Private methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void updateConfidence(TransactionConfidence confidence) private void updateConfidence(TransactionConfidence confidence)
{ {
if (confidence != null) if (confidence != null)
@ -136,10 +147,12 @@ public class BalanceTextField extends AnchorPane
private void updateBalance(Coin balance) private void updateBalance(Coin balance)
{ {
this.balance = balance;
if (balance != null) if (balance != null)
{ {
//TODO use BitSquareFormatter //TODO use BitSquareFormatter
balanceTextField.setText(balance.toFriendlyString()); balanceTextField.setText(balance.toFriendlyString());
} }
} }
} }

View file

@ -0,0 +1,14 @@
package io.bitsquare.gui.market;
import io.bitsquare.trade.Direction;
public class BuyController extends SellController
{
@Override
protected void applyDirection()
{
//tabPane.getSelectionModel().select(0);
orderBookController.applyDirection(Direction.BUY);
}
}

View file

@ -4,4 +4,4 @@
<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.AnchorPane?>
<TabPane xmlns:fx="http://javafx.com/fxml/1" fx:id="tabPane" AnchorPane.bottomAnchor="0.0" <TabPane xmlns:fx="http://javafx.com/fxml/1" fx:id="tabPane" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"
fx:controller="io.bitsquare.gui.market.MarketController"/> fx:controller="io.bitsquare.gui.market.BuyController"/>

View file

@ -1,135 +0,0 @@
package io.bitsquare.gui.market;
import io.bitsquare.di.GuiceFXMLLoader;
import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.market.orderbook.OrderBookController;
import io.bitsquare.trade.Direction;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
public class MarketController implements Initializable, NavigationController, ChildController
{
private boolean orderbookCreated;
private OrderBookController orderBookController;
@FXML
private TabPane tabPane;
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: Initializable
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void initialize(URL url, ResourceBundle rb)
{
navigateToView(NavigationItem.ORDER_BOOK);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: NavigationController
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public ChildController navigateToView(NavigationItem navigationItem)
{
if (navigationItem == NavigationItem.ORDER_BOOK && orderbookCreated)
{
tabPane.getSelectionModel().select(0);
return null;
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()));
try
{
final Parent view = loader.load();
ChildController childController = loader.getController();
childController.setNavigationController(this);
if (childController instanceof OrderBookController)
{
orderBookController = (OrderBookController) childController;
}
String tabLabel;
switch (navigationItem)
{
case CREATE_OFFER:
tabLabel = "Create offer";
break;
case TAKE_OFFER:
tabLabel = "Take offer";
break;
default:
tabLabel = "Orderbook";
break;
}
final Tab tab = new Tab(tabLabel);
tab.setContent(view);
tabPane.getTabs().add(tab);
if (navigationItem == NavigationItem.ORDER_BOOK)
{
tab.setClosable(false);
orderbookCreated = true;
}
tabPane.getSelectionModel().select(tabPane.getTabs().size() - 1);
return childController;
} catch (IOException e)
{
e.printStackTrace();
}
return null;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: ChildController
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void setNavigationController(NavigationController navigationController)
{
}
@Override
public void cleanup()
{
if (orderBookController != null)
{
orderBookController.cleanup();
orderBookController = null;
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setter
///////////////////////////////////////////////////////////////////////////////////////////
public void setDirection(Direction direction)
{
tabPane.getSelectionModel().select(0);
if (orderBookController != null)
{
orderBookController.setDirection(direction);
}
}
}

View file

@ -0,0 +1,143 @@
package io.bitsquare.gui.market;
import io.bitsquare.di.GuiceFXMLLoader;
import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.components.ValidatingTextField;
import io.bitsquare.gui.market.orderbook.OrderBookController;
import io.bitsquare.trade.Direction;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkArgument;
public class SellController implements Initializable, NavigationController, ChildController
{
private static final Logger log = LoggerFactory.getLogger(SellController.class);
protected OrderBookController orderBookController;
protected GuiceFXMLLoader orderBookLoader;
@FXML
protected TabPane tabPane;
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: Initializable
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void initialize(URL url, ResourceBundle rb)
{
// TODO find better solution
// Textfield focus out triggers validation, use runLater as quick fix...
tabPane.getSelectionModel().selectedIndexProperty().addListener((observableValue) -> Platform.runLater(() -> ValidatingTextField.hidePopover()));
}
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: NavigationController
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public ChildController navigateToView(NavigationItem navigationItem)
{
if (navigationItem == NavigationItem.ORDER_BOOK)
{
return loadOrderBook();
}
else
{
checkArgument(navigationItem.equals(NavigationItem.CREATE_OFFER) || navigationItem.equals(NavigationItem.TAKE_OFFER));
// CreateOffer and TakeOffer must not be cached by GuiceFXMLLoader as we cannot use a view multiple times in different graphs
GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), false);
try
{
final Parent view = loader.load();
ChildController childController = loader.getController();
childController.setNavigationController(this);
String tabLabel = navigationItem.equals(NavigationItem.CREATE_OFFER) ? "Create offer" : "Take offer";
final Tab tab = new Tab(tabLabel);
tab.setContent(view);
tabPane.getTabs().add(tab);
tabPane.getSelectionModel().select(tabPane.getTabs().size() - 1);
return childController;
} catch (IOException e)
{
e.printStackTrace();
log.error(e.getMessage());
}
return null;
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: ChildController
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void setNavigationController(NavigationController navigationController)
{
navigateToView(NavigationItem.ORDER_BOOK);
}
@Override
public void cleanup()
{
if (orderBookController != null)
{
orderBookController.cleanup();
orderBookController = null;
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
protected void applyDirection()
{
orderBookController.applyDirection(Direction.SELL);
}
protected ChildController loadOrderBook()
{
// Orderbook must not be cached by GuiceFXMLLoader as we use 2 instances for sell and buy screens.
if (orderBookLoader == null)
{
orderBookLoader = new GuiceFXMLLoader(getClass().getResource(NavigationItem.ORDER_BOOK.getFxmlUrl()), false);
try
{
final Parent view = orderBookLoader.load();
final Tab tab = new Tab("Orderbook");
tab.setClosable(false);
tab.setContent(view);
tabPane.getTabs().add(tab);
} catch (IOException e)
{
e.printStackTrace();
}
}
orderBookController = orderBookLoader.getController();
orderBookController.setNavigationController(this);
applyDirection();
return orderBookController;
}
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>
<TabPane xmlns:fx="http://javafx.com/fxml/1" fx:id="tabPane" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"
fx:controller="io.bitsquare.gui.market.SellController"/>

View file

@ -77,6 +77,7 @@ public class CreateOfferController implements Initializable, ChildController, Hi
final ViewModel viewModel = new ViewModel(); final ViewModel viewModel = new ViewModel();
private final double collateral; private final double collateral;
private Direction direction; private Direction direction;
private AddressEntry addressEntry;
@FXML private AnchorPane rootContainer; @FXML private AnchorPane rootContainer;
@FXML private Label buyLabel, confirmationLabel, txTitleLabel, collateralLabel; @FXML private Label buyLabel, confirmationLabel, txTitleLabel, collateralLabel;
@ -137,17 +138,13 @@ public class CreateOfferController implements Initializable, ChildController, Hi
@Override @Override
public void initialize(URL url, ResourceBundle rb) public void initialize(URL url, ResourceBundle rb)
{ {
// Node wrappedButton = Borders.wrap(button).etchedBorder().buildAll()
setupBindings(); setupBindings();
setupValidation(); setupValidation();
//TODO //TODO
if (walletFacade.getWallet() != null) if (walletFacade.getWallet() != null)
{ {
AddressEntry addressEntry = walletFacade.getUnusedTradeAddressInfo(); addressEntry = walletFacade.getUnusedTradeAddressInfo();
addressTextField.setAddress(addressEntry.getAddress().toString()); addressTextField.setAddress(addressEntry.getAddress().toString());
balanceTextField.setAddress(addressEntry.getAddress()); balanceTextField.setAddress(addressEntry.getAddress());
@ -215,11 +212,18 @@ public class CreateOfferController implements Initializable, ChildController, Hi
placeOfferButton.visibleProperty().bind(viewModel.isOfferPlacedScreen.not()); placeOfferButton.visibleProperty().bind(viewModel.isOfferPlacedScreen.not());
closeButton.visibleProperty().bind(viewModel.isOfferPlacedScreen); closeButton.visibleProperty().bind(viewModel.isOfferPlacedScreen);
//TODO
/* progressIndicator.visibleProperty().bind(viewModel.isOfferPlacedScreen); /* progressIndicator.visibleProperty().bind(viewModel.isOfferPlacedScreen);
confirmationLabel.visibleProperty().bind(viewModel.isOfferPlacedScreen); confirmationLabel.visibleProperty().bind(viewModel.isOfferPlacedScreen);
txTitleLabel.visibleProperty().bind(viewModel.isOfferPlacedScreen); txTitleLabel.visibleProperty().bind(viewModel.isOfferPlacedScreen);
transactionIdTextField.visibleProperty().bind(viewModel.isOfferPlacedScreen); transactionIdTextField.visibleProperty().bind(viewModel.isOfferPlacedScreen);
*/ */
placeOfferButton.disableProperty().bind(amountTextField.isValidProperty()
.and(minAmountTextField.isValidProperty())
.and(volumeTextField.isValidProperty())
.and(priceTextField.isValidProperty()).not());
} }
private void setupValidation() private void setupValidation()
@ -301,6 +305,15 @@ public class CreateOfferController implements Initializable, ChildController, Hi
@FXML @FXML
public void onPlaceOffer() public void onPlaceOffer()
{
amountTextField.reValidate();
minAmountTextField.reValidate();
volumeTextField.reValidate();
priceTextField.reValidate();
//balanceTextField.getBalance()
if (amountTextField.getIsValid() && minAmountTextField.getIsValid() && volumeTextField.getIsValid() && amountTextField.getIsValid())
{ {
viewModel.isPlaceOfferButtonDisabled.set(true); viewModel.isPlaceOfferButtonDisabled.set(true);
@ -317,6 +330,7 @@ public class CreateOfferController implements Initializable, ChildController, Hi
viewModel.isPlaceOfferButtonDisabled.set(false); viewModel.isPlaceOfferButtonDisabled.set(false);
}); });
} }
}
@FXML @FXML
public void onClose() public void onClose()

View file

@ -7,8 +7,8 @@
<?import javafx.geometry.*?> <?import javafx.geometry.*?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" fx:id="rootContainer" prefHeight="500" prefWidth="800" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" <AnchorPane fx:id="rootContainer" prefHeight="500" prefWidth="800" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0"
AnchorPane.topAnchor="10.0" xmlns="http://javafx.com/javafx/8" fx:controller="io.bitsquare.gui.market.createOffer.CreateOfferController"> AnchorPane.topAnchor="10.0" xmlns="http://javafx.com/javafx/8" fx:controller="io.bitsquare.gui.market.createOffer.CreateOfferController" xmlns:fx="http://javafx.com/fxml/1" >
<GridPane hgap="5.0" vgap="5.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0"> <GridPane hgap="5.0" vgap="5.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0">
@ -63,7 +63,7 @@
<!-- button --> <!-- button -->
<VSpacer GridPane.rowIndex="7" prefHeight="10"/> <VSpacer GridPane.rowIndex="7" prefHeight="10"/>
<Button GridPane.rowIndex="8" GridPane.columnIndex="1" fx:id="placeOfferButton" onAction="#onPlaceOffer" defaultButton="true" text="Place offer"/> <Button GridPane.rowIndex="8" GridPane.columnIndex="1" fx:id="placeOfferButton" onAction="#onPlaceOffer" disable="true" defaultButton="true" text="Place offer"/>
<Button GridPane.rowIndex="8" GridPane.columnIndex="1" fx:id="closeButton" onAction="#onClose" visible="false" defaultButton="true" focusTraversable="false" text="Close"/> <Button GridPane.rowIndex="8" GridPane.columnIndex="1" fx:id="closeButton" onAction="#onClose" visible="false" defaultButton="true" focusTraversable="false" text="Close"/>

View file

@ -92,15 +92,16 @@ public class OrderBookController implements Initializable, ChildController
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
private OrderBookController(OrderBook orderBook, OrderBookFilter orderBookFilter, User user, MessageFacade messageFacade, WalletFacade walletFacade, Settings settings, Persistence persistence) private OrderBookController(OrderBook orderBook, User user, MessageFacade messageFacade, WalletFacade walletFacade, Settings settings, Persistence persistence)
{ {
this.orderBook = orderBook; this.orderBook = orderBook;
this.orderBookFilter = orderBookFilter;
this.user = user; this.user = user;
this.messageFacade = messageFacade; this.messageFacade = messageFacade;
this.walletFacade = walletFacade; this.walletFacade = walletFacade;
this.settings = settings; this.settings = settings;
this.persistence = persistence; this.persistence = persistence;
this.orderBookFilter = new OrderBookFilter();
} }
@ -111,12 +112,15 @@ public class OrderBookController implements Initializable, ChildController
@Override @Override
public void initialize(URL url, ResourceBundle rb) public void initialize(URL url, ResourceBundle rb)
{ {
orderBook.init();
// init table // init table
setCountryColumnCellFactory(); setCountryColumnCellFactory();
setBankAccountTypeColumnCellFactory(); setBankAccountTypeColumnCellFactory();
setDirectionColumnCellFactory(); setDirectionColumnCellFactory();
}
private void init()
{
orderBook.init();
offerList = orderBook.getOfferList(); offerList = orderBook.getOfferList();
offerList.comparatorProperty().bind(orderBookTable.comparatorProperty()); offerList.comparatorProperty().bind(orderBookTable.comparatorProperty());
orderBookTable.setItems(offerList); orderBookTable.setItems(offerList);
@ -178,8 +182,9 @@ public class OrderBookController implements Initializable, ChildController
// Public methods // Public methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void setDirection(Direction direction) public void applyDirection(Direction direction)
{ {
init();
orderBookTable.getSelectionModel().clearSelection(); orderBookTable.getSelectionModel().clearSelection();
price.setText(""); price.setText("");
orderBookFilter.setDirection(direction); orderBookFilter.setDirection(direction);

View file

@ -13,7 +13,7 @@ import org.slf4j.LoggerFactory;
public class BtcValidator extends NumberValidator public class BtcValidator extends NumberValidator
{ {
private static final Logger log = LoggerFactory.getLogger(BtcValidator.class); private static final Logger log = LoggerFactory.getLogger(BtcValidator.class);
private ValidationResult overriddenValidationResult; private ValidationResult externalValidationResult;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -23,6 +23,9 @@ public class BtcValidator extends NumberValidator
@Override @Override
public ValidationResult validate(String input) public ValidationResult validate(String input)
{ {
if (externalValidationResult != null)
return externalValidationResult;
ValidationResult result = validateIfNotEmpty(input); ValidationResult result = validateIfNotEmpty(input);
if (result.isValid) if (result.isValid)
{ {
@ -38,23 +41,21 @@ public class BtcValidator extends NumberValidator
.and(validateIfNotExceedsMaxBtcValue(input)); .and(validateIfNotExceedsMaxBtcValue(input));
} }
if (overriddenValidationResult != null)
return overriddenValidationResult;
return result; return result;
} }
/** /**
* Used to integrate external validation (e.g. for MinAmount/Amount) * Used to integrate external validation (e.g. for MinAmount/Amount)
* TODO Might be improved but does the job for now... * TODO To be improved but does the job for now...
* *
* @param overriddenValidationResult * @param externalValidationResult
*/ */
public void overrideResult(ValidationResult overriddenValidationResult) public void overrideResult(ValidationResult externalValidationResult)
{ {
this.overriddenValidationResult = overriddenValidationResult; this.externalValidationResult = externalValidationResult;
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Protected methods // Protected methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -25,7 +25,6 @@ public abstract class NumberValidator
// Protected methods // Protected methods
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
protected ValidationResult validateIfNotEmpty(String input) protected ValidationResult validateIfNotEmpty(String input)
{ {
if (input == null || input.length() == 0) if (input == null || input.length() == 0)

View file

@ -149,8 +149,8 @@ public class OrderBook implements OrderBookListener
", directionResult = " + directionResult + ", directionResult = " + directionResult +
", priceResult = " + priceResult + ", priceResult = " + priceResult +
", arbitratorResult = " + arbitratorResult ", arbitratorResult = " + arbitratorResult
); );*/
/*
log.debug("currentBankAccount.getCurrency() = " + currentBankAccount.getCurrency() + log.debug("currentBankAccount.getCurrency() = " + currentBankAccount.getCurrency() +
", offer.getCurrency() = " + offer.getCurrency()); ", offer.getCurrency() = " + offer.getCurrency());
log.debug("offer.getCountryLocale() = " + offer.getBankAccountCountryLocale() + log.debug("offer.getCountryLocale() = " + offer.getBankAccountCountryLocale() +

View file

@ -1,5 +1,7 @@
package io.bitsquare.trade.protocol.createoffer.tasks; package io.bitsquare.trade.protocol.createoffer.tasks;
import com.google.bitcoin.core.Coin;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.Restritions; import io.bitsquare.btc.Restritions;
import io.bitsquare.trade.Offer; import io.bitsquare.trade.Offer;
import io.bitsquare.trade.handlers.FaultHandler; import io.bitsquare.trade.handlers.FaultHandler;
@ -37,17 +39,22 @@ public class ValidateOffer
checkArgument(offer.getAcceptedCountries().size() > 0); checkArgument(offer.getAcceptedCountries().size() > 0);
checkArgument(offer.getAcceptedLanguageLocales().size() > 0); checkArgument(offer.getAcceptedLanguageLocales().size() > 0);
checkArgument(offer.getAmount().isGreaterThan(Restritions.MIN_TRADE_AMOUNT)); checkArgument(offer.getMinAmount().compareTo(Restritions.MIN_TRADE_AMOUNT) >= 0);
checkArgument(offer.getAmount().compareTo(Restritions.MIN_TRADE_AMOUNT) >= 0); checkArgument(offer.getAmount().compareTo(Restritions.MIN_TRADE_AMOUNT) >= 0);
checkArgument(offer.getAmount().compareTo(offer.getMinAmount()) >= 0); checkArgument(offer.getAmount().compareTo(offer.getMinAmount()) >= 0);
checkArgument(offer.getCollateral() > 0); checkArgument(offer.getCollateral() > 0);
checkArgument(offer.getPrice() > 0); checkArgument(offer.getPrice() > 0);
// TODO check balance
Coin collateralAsCoin = offer.getAmount().divide((long) (1d / offer.getCollateral()));
Coin totalsToFund = collateralAsCoin.add(FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE));
// getAddressInfoByTradeID(offerId)
// TODO when offer is flattened continue here... // TODO when offer is flattened continue here...
resultHandler.onResult(); resultHandler.onResult();
} catch (Throwable t) } catch (Throwable t)
{ {
faultHandler.onFault("Offer validation failed with exception: " + t.getMessage(), t); faultHandler.onFault("Offer validation failed.", t);
} }
} }
} }