new validation impl., use bindings in create offer controller, profiler added, use caching for FXML loader

This commit is contained in:
Manfred Karrer 2014-08-10 23:59:18 +02:00
parent 83203554e9
commit 1bc0dbfa31
45 changed files with 1084 additions and 414 deletions

View File

@ -8,13 +8,12 @@ import io.bitsquare.di.BitSquareModule;
import io.bitsquare.di.GuiceFXMLLoader;
import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.popups.Popups;
import io.bitsquare.locale.Localisation;
import io.bitsquare.gui.util.Profiler;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.settings.Settings;
import io.bitsquare.storage.Persistence;
import io.bitsquare.user.User;
import io.bitsquare.util.AWTSystemTray;
import io.bitsquare.util.FileUtil;
import io.bitsquare.util.StorageDirectory;
import java.io.File;
import java.io.IOException;
@ -47,6 +46,8 @@ public class BitSquare extends Application
public static void main(String[] args)
{
Profiler.init();
Profiler.printMsgWithTime("main called");
log.debug("Startup: main " + Arrays.asList(args).toString());
if (args != null && args.length > 0) APP_NAME = args[0];
@ -63,15 +64,10 @@ public class BitSquare extends Application
return APP_NAME;
}
public static String getUID()
{
return FileUtil.getApplicationFileName();
}
@Override
public void start(Stage primaryStage) throws IOException
{
log.trace("Startup: start");
Profiler.printMsgWithTime("start called");
BitSquare.primaryStage = primaryStage;
Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> Popups.handleUncaughtExceptions(Throwables.getRootCause(throwable)));
@ -85,7 +81,7 @@ public class BitSquare extends Application
walletFacade = injector.getInstance(WalletFacade.class);
messageFacade = injector.getInstance(MessageFacade.class);
log.trace("Startup: messageFacade, walletFacade inited");
Profiler.printMsgWithTime("Startup: messageFacade, walletFacade inited");
// apply stored data
final User user = injector.getInstance(User.class);
@ -99,30 +95,29 @@ public class BitSquare extends Application
settings.applyPersistedSettings((Settings) persistence.read(settings.getClass().getName()));
primaryStage.setTitle("BitSquare (" + getUID() + ")");
primaryStage.setTitle("BitSquare (" + APP_NAME + ")");
GuiceFXMLLoader.setInjector(injector);
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(NavigationItem.MAIN.getFxmlUrl()), Localisation.getResourceBundle());
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(NavigationItem.MAIN.getFxmlUrl()));
final Parent mainView = loader.load();
BorderPane rootPane = new BorderPane();
rootPane.setTop(getMenuBar());
rootPane.setCenter(mainView);
final Scene scene = new Scene(rootPane, 800, 600);
scene.getStylesheets().setAll(getClass().getResource("/io/bitsquare/gui/bitsquare.css").toExternalForm());
final Scene scene = new Scene(rootPane, 1000, 750);
scene.getStylesheets().setAll(getClass().getResource("/io/bitsquare/gui/bitsquare.css").toExternalForm(),
getClass().getResource("/io/bitsquare/gui/validation.css").toExternalForm());
setupCloseHandlers(primaryStage, scene);
primaryStage.setScene(scene);
primaryStage.setMinWidth(750);
primaryStage.setMinHeight(500);
primaryStage.setWidth(1000);
primaryStage.setHeight(750);
primaryStage.show();
log.debug("Startup: stage displayed");
Profiler.printMsgWithTime("Startup: primaryStage.show");
}
private void setupCloseHandlers(Stage primaryStage, Scene scene)

View File

@ -1,36 +1,90 @@
package io.bitsquare.di;
import com.google.inject.Injector;
import io.bitsquare.locale.Localisation;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.HashMap;
import java.util.Map;
import javafx.fxml.FXMLLoader;
import javafx.util.Callback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Guice support for fxml controllers
* Support caching. Speed up switches between UI screens.
*/
public class GuiceFXMLLoader extends FXMLLoader
public class GuiceFXMLLoader
{
private static final Logger log = LoggerFactory.getLogger(GuiceFXMLLoader.class);
private static Injector injector = null;
private FXMLLoader loader;
private final boolean isCached;
private final URL url;
private Item item;
public static void setInjector(Injector injector)
{
GuiceFXMLLoader.injector = injector;
}
// private static ClassLoader cachingClassLoader = new CachingClassLoader(FXMLLoader.getDefaultClassLoader());
public GuiceFXMLLoader(URL url, ResourceBundle resourceBundle)
// TODO maybe add more sophisticated caching strategy with removal of rarely accessed items
private static final Map<URL, Item> cachedGUIItems = new HashMap<>();
public GuiceFXMLLoader(URL url)
{
super(url, resourceBundle);
// might be helpful for performance, but need further profiling. has memory drawbacks
//setClassLoader(cachingClassLoader);
setupControllerFactory();
this(url, true);
}
private void setupControllerFactory()
public GuiceFXMLLoader(URL url, boolean useCaching)
{
if (GuiceFXMLLoader.injector != null)
this.url = url;
isCached = useCaching && cachedGUIItems.containsKey(url);
if (!isCached)
{
setControllerFactory(new GuiceControllerFactory(GuiceFXMLLoader.injector));
loader = new FXMLLoader(url, Localisation.getResourceBundle());
if (GuiceFXMLLoader.injector != null)
loader.setControllerFactory(new GuiceControllerFactory(GuiceFXMLLoader.injector));
}
}
@SuppressWarnings("unchecked")
public <T> T load() throws java.io.IOException
{
if (isCached)
{
item = cachedGUIItems.get(url);
log.debug("loaded from cache " + url);
return (T) cachedGUIItems.get(url).view;
}
else
{
log.debug("load from disc " + url);
T result = loader.load();
item = new Item(result, loader.getController());
cachedGUIItems.put(url, item);
return result;
}
}
@SuppressWarnings("unchecked")
public <T> T getController()
{
return (T) item.controller;
}
class Item<T>
{
final T view;
final T controller;
Item(T view, T controller)
{
this.view = view;
this.controller = controller;
}
}
}

View File

@ -10,7 +10,6 @@ import io.bitsquare.gui.market.MarketController;
import io.bitsquare.gui.orders.OrdersController;
import io.bitsquare.gui.util.Icons;
import io.bitsquare.gui.util.Transitions;
import io.bitsquare.locale.Localisation;
import io.bitsquare.msg.BootstrapListener;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.storage.Persistence;
@ -21,7 +20,6 @@ import io.bitsquare.util.AWTSystemTray;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
@ -53,7 +51,7 @@ public class MainController implements Initializable, NavigationController
private final ToggleGroup toggleGroup = new ToggleGroup();
private ChildController childController;
private ChildController controller;
private ToggleButton prevToggleButton;
private Image prevToggleButtonIcon;
private ToggleButton buyButton, sellButton, homeButton, msgButton, ordersButton, fundsButton, settingsButton;
@ -108,75 +106,6 @@ public class MainController implements Initializable, NavigationController
@Override
public void initialize(URL url, ResourceBundle rb)
{
Platform.runLater(this::init);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: NavigationController
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public ChildController navigateToView(NavigationItem navigationItem)
{
switch (navigationItem)
{
case HOME:
homeButton.fire();
break;
case FUNDS:
fundsButton.fire();
break;
case MSG:
msgButton.fire();
break;
case ORDERS:
ordersButton.fire();
break;
case SETTINGS:
settingsButton.fire();
break;
case SELL:
sellButton.fire();
break;
case BUY:
buyButton.fire();
break;
}
return childController;
}
private ChildController loadView(NavigationItem navigationItem)
{
if (childController != null)
{
childController.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
try
{
final Node view = loader.load();
contentPane.getChildren().setAll(view);
childController = loader.getController();
childController.setNavigationController(this);
} catch (IOException e)
{
e.printStackTrace();
log.error("Loading view failed. " + navigationItem.getFxmlUrl());
}
return childController;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////////////////
private void init()
{
messageFacade.init(new BootstrapListener()
{
@ -215,6 +144,70 @@ public class MainController implements Initializable, NavigationController
tradeManager.addTakeOfferRequestListener(this::onTakeOfferRequested);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: NavigationController
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public ChildController navigateToView(NavigationItem navigationItem)
{
switch (navigationItem)
{
case HOME:
homeButton.fire();
break;
case FUNDS:
fundsButton.fire();
break;
case MSG:
msgButton.fire();
break;
case ORDERS:
ordersButton.fire();
break;
case SETTINGS:
settingsButton.fire();
break;
case SELL:
sellButton.fire();
break;
case BUY:
buyButton.fire();
break;
}
return controller;
}
private ChildController loadView(NavigationItem navigationItem)
{
if (controller != null)
{
controller.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()));
try
{
final Node view = loader.load();
contentPane.getChildren().setAll(view);
controller = loader.getController();
controller.setNavigationController(this);
} catch (IOException e)
{
e.printStackTrace();
log.error("Loading view failed. " + navigationItem.getFxmlUrl());
}
return controller;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////////////////
private void initialisationDone()
{
addNavigation();
@ -292,11 +285,11 @@ public class MainController implements Initializable, NavigationController
prevToggleButtonIcon = ((ImageView) (toggleButton.getGraphic())).getImage();
((ImageView) (toggleButton.getGraphic())).setImage(Icons.getIconImage(navigationItem.getActiveIcon()));
childController = loadView(navigationItem);
controller = loadView(navigationItem);
if (childController instanceof MarketController)
if (controller instanceof MarketController)
{
((MarketController) childController).setDirection(navigationItem == NavigationItem.BUY ? Direction.BUY : Direction.SELL);
((MarketController) controller).setDirection(navigationItem == NavigationItem.BUY ? Direction.BUY : Direction.SELL);
}
persistence.write(this, "selectedNavigationItem", navigationItem);

View File

@ -6,7 +6,6 @@ import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.arbitrators.profile.ArbitratorProfileController;
import io.bitsquare.locale.LanguageUtil;
import io.bitsquare.locale.Localisation;
import io.bitsquare.msg.MessageFacade;
import io.bitsquare.msg.listeners.ArbitratorListener;
import io.bitsquare.settings.Settings;
@ -113,7 +112,7 @@ public class ArbitratorOverviewController implements Initializable, ChildControl
arbitratorProfileController.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()));
try
{
final Node view = loader.load();

View File

@ -9,7 +9,6 @@ import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.arbitrators.profile.ArbitratorProfileController;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
import io.bitsquare.gui.util.BitSquareConverter;
import io.bitsquare.gui.util.BitSquareFormatter;
import io.bitsquare.gui.util.BitSquareValidator;
import io.bitsquare.gui.util.ConfidenceDisplay;
@ -475,11 +474,11 @@ public class ArbitratorRegistrationController implements Initializable, ChildCon
String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(user.getMessagePublicKey());
String name = nameTextField.getText();
double maxTradeVolume = BitSquareConverter.stringToDouble(maxTradeVolumeTextField.getText());
double passiveServiceFee = BitSquareConverter.stringToDouble(passiveServiceFeeTextField.getText());
double minPassiveServiceFee = BitSquareConverter.stringToDouble(minPassiveServiceFeeTextField.getText());
double arbitrationFee = BitSquareConverter.stringToDouble(arbitrationFeeTextField.getText());
double minArbitrationFee = BitSquareConverter.stringToDouble(minArbitrationFeeTextField.getText());
double maxTradeVolume = BitSquareFormatter.parseToDouble(maxTradeVolumeTextField.getText());
double passiveServiceFee = BitSquareFormatter.parseToDouble(passiveServiceFeeTextField.getText());
double minPassiveServiceFee = BitSquareFormatter.parseToDouble(minPassiveServiceFeeTextField.getText());
double arbitrationFee = BitSquareFormatter.parseToDouble(arbitrationFeeTextField.getText());
double minArbitrationFee = BitSquareFormatter.parseToDouble(minArbitrationFeeTextField.getText());
String webUrl = webPageTextField.getText();
String description = descriptionTextArea.getText();

View File

@ -111,7 +111,7 @@
-fx-fill: black;
}
.table-view .table-row-cell:selected .table-row-cell:row-selection .table-row-cell:cell-selection .text {
.table-view .table-row-cell:selected .table-row-cell:row-selection .table-row-cell:cell-selection .text {
-fx-fill: white;
}
@ -204,3 +204,9 @@
.scroll-pane .corner {
-fx-background-insets: 0;
}
/* validation */
#validation-error {
-fx-text-fill: red;
}

View File

@ -4,7 +4,6 @@ import io.bitsquare.di.GuiceFXMLLoader;
import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.Hibernate;
import io.bitsquare.gui.NavigationController;
import io.bitsquare.locale.Localisation;
import io.bitsquare.storage.Persistence;
import java.io.IOException;
import java.util.ArrayList;
@ -92,7 +91,7 @@ public class CachingTabPane extends TabPane
{
// load for the first time
String fxmlView = tabInfoList.get(selectedTabIndex).url;
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(fxmlView), Localisation.getResourceBundle());
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(fxmlView));
try
{
tabInfoList.get(selectedTabIndex).view = loader.load();

View File

@ -132,7 +132,7 @@ public class ValidatedTextField extends TextField
@Override
public void changed(ObservableValue<? extends String> ov, String t, String t1)
{
if (textProperty().get().length() > maxLength.get())
if (textProperty().get() != null && textProperty().get().length() > maxLength.get())
{
setText(t);
}
@ -173,7 +173,7 @@ public class ValidatedTextField extends TextField
@Override
protected boolean computeValue()
{
return !textProperty().get().matches(mask.get());
return (textProperty().get() != null) ? !textProperty().get().matches(mask.get()) : false;
}
};
}
@ -189,7 +189,7 @@ public class ValidatedTextField extends TextField
@Override
protected boolean computeValue()
{
return textProperty().get().length() < minLength.get();
return (textProperty().get() != null) ? textProperty().get().length() < minLength.get() : false;
}
};
}

View File

@ -0,0 +1,182 @@
package io.bitsquare.gui.components;
import io.bitsquare.gui.util.NumberValidator;
import java.util.LinkedList;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.effect.BlurType;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Effect;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.stage.Window;
import org.controlsfx.control.PopOver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* TextField with validation support. Validation is executed on the Validator object.
* In case of a invalid result we display a error message with a PopOver.
* The position is derived from the textField or if set from the errorPopupLayoutReference object.
* <p>
* That class implements just what we need for the moment. It is not intended as a general purpose library class.
*/
public class ValidatingTextField extends TextField
{
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);
// we hold all error popups any only display the latest one
private static final LinkedList<PopOver> allErrorPopups = new LinkedList<>();
private Effect invalidEffect = DEFAULT_EFFECT;
private final BooleanProperty valid = new SimpleBooleanProperty(true);
private NumberValidator numberValidator;
private boolean validateOnFocusOut = true;
private boolean needsValidationOnFocusOut;
private PopOver popOver;
private Region errorPopupLayoutReference;
private double errorPopOverX;
private double errorPopOverY;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public ValidatingTextField()
{
super();
setupListeners();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public methods
///////////////////////////////////////////////////////////////////////////////////////////
public void reValidate()
{
validate(getText());
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
public void setNumberValidator(NumberValidator numberValidator)
{
this.numberValidator = numberValidator;
}
public void setErrorPopupLayoutReference(Region errorPopupLayoutReference)
{
this.errorPopupLayoutReference = errorPopupLayoutReference;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////////////////
private void setupListeners()
{
this.textProperty().addListener((ov, oldValue, newValue) -> {
if (numberValidator != null)
{
if (!validateOnFocusOut)
validate(newValue);
else
needsValidationOnFocusOut = true;
}
});
this.focusedProperty().addListener((ov, oldValue, newValue) -> {
if (validateOnFocusOut && needsValidationOnFocusOut && !newValue && getScene().getWindow().isFocused())
validate(getText());
});
this.valid.addListener((ov, oldValue, newValue) -> applyEffect(newValue));
}
private void validate(String input)
{
NumberValidator.ValidationResult validationResult = numberValidator.validate(input);
valid.set(validationResult.isValid);
applyErrorMessage(validationResult);
}
private void applyErrorMessage(NumberValidator.ValidationResult validationResult)
{
if (validationResult.isValid)
{
if (allErrorPopups.contains(popOver))
{
allErrorPopups.remove(popOver);
popOver.hide();
}
if (allErrorPopups.size() > 0)
{
PopOver lastPopOver = allErrorPopups.getLast();
lastPopOver.show(getScene().getWindow());
}
popOver = null;
}
else
{
if (allErrorPopups.size() > 0)
{
PopOver lastPopOver = allErrorPopups.getLast();
lastPopOver.hide();
}
if (allErrorPopups.contains(popOver))
{
allErrorPopups.remove(popOver);
popOver.hide();
}
popOver = createErrorPopOver(validationResult.errorMessage);
popOver.show(getScene().getWindow(), errorPopOverX, errorPopOverY);
allErrorPopups.add(popOver);
}
}
private void applyEffect(boolean isValid)
{
setEffect(isValid ? null : invalidEffect);
}
private PopOver createErrorPopOver(String errorMessage)
{
Label errorLabel = new Label(errorMessage);
errorLabel.setId("validation-error");
errorLabel.setPadding(new Insets(0, 10, 0, 10));
PopOver popOver = new PopOver(errorLabel);
popOver.setAutoFix(true);
popOver.setDetachedTitle("");
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

@ -19,7 +19,7 @@ public class FundsController implements Initializable, ChildController, Navigati
private final Persistence persistence;
@FXML
private CachingTabPane tabPane;
private CachingTabPane root;
///////////////////////////////////////////////////////////////////////////////////////////
@ -40,7 +40,7 @@ public class FundsController implements Initializable, ChildController, Navigati
@Override
public void initialize(URL url, ResourceBundle rb)
{
tabPane.initialize(this, persistence, NavigationItem.DEPOSIT.getFxmlUrl(), NavigationItem.WITHDRAWAL.getFxmlUrl(), NavigationItem.TRANSACTIONS.getFxmlUrl());
root.initialize(this, persistence, NavigationItem.DEPOSIT.getFxmlUrl(), NavigationItem.WITHDRAWAL.getFxmlUrl(), NavigationItem.TRANSACTIONS.getFxmlUrl());
}
@ -56,7 +56,7 @@ public class FundsController implements Initializable, ChildController, Navigati
@Override
public void cleanup()
{
tabPane.cleanup();
root.cleanup();
}
///////////////////////////////////////////////////////////////////////////////////////////
@ -66,7 +66,7 @@ public class FundsController implements Initializable, ChildController, Navigati
@Override
public ChildController navigateToView(NavigationItem navigationItem)
{
return tabPane.navigateToView(navigationItem.getFxmlUrl());
return root.navigateToView(navigationItem.getFxmlUrl());
}
}

View File

@ -3,8 +3,8 @@
<?import io.bitsquare.gui.components.CachingTabPane?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.layout.AnchorPane?>
<CachingTabPane 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"
xmlns="http://javafx.com/javafx/8" fx:controller="io.bitsquare.gui.funds.FundsController">
<CachingTabPane xmlns:fx="http://javafx.com/fxml/1" fx:id="root" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"
xmlns="http://javafx.com/javafx/8" fx:controller="io.bitsquare.gui.funds.FundsController">
<Tab text="Deposit" closable="false"/>
<Tab text="Withdrawal" closable="false"/>

View File

@ -19,6 +19,7 @@ import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
import javax.inject.Inject;
import org.slf4j.Logger;
@ -31,12 +32,10 @@ public class DepositController implements Initializable, ChildController, Hibern
private final WalletFacade walletFacade;
private ObservableList<DepositListItem> addressList;
@FXML
private TableView<DepositListItem> tableView;
@FXML
private TableColumn<String, DepositListItem> labelColumn, addressColumn, balanceColumn, copyColumn, confidenceColumn;
@FXML
private Button addNewAddressButton;
@FXML private VBox root;
@FXML private TableView<DepositListItem> tableView;
@FXML private TableColumn<String, DepositListItem> labelColumn, addressColumn, balanceColumn, copyColumn, confidenceColumn;
@FXML private Button addNewAddressButton;
///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -4,7 +4,7 @@
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml/1" spacing="10" fx:controller="io.bitsquare.gui.funds.deposit.DepositController"
<VBox fx:id="root" xmlns:fx="http://javafx.com/fxml/1" spacing="10" fx:controller="io.bitsquare.gui.funds.deposit.DepositController"
xmlns="http://javafx.com/javafx/8">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>

View File

@ -15,6 +15,7 @@ import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
import javax.inject.Inject;
import org.slf4j.Logger;
@ -27,12 +28,10 @@ public class TransactionsController implements Initializable, ChildController, H
private final WalletFacade walletFacade;
private ObservableList<TransactionsListItem> transactionsListItems;
@FXML
private TableView<TransactionsListItem> tableView;
@FXML
private TableColumn<String, TransactionsListItem> dateColumn, addressColumn, amountColumn, typeColumn, confidenceColumn;
@FXML
private Button addNewAddressButton;
@FXML private VBox root;
@FXML private TableView<TransactionsListItem> tableView;
@FXML private TableColumn<String, TransactionsListItem> dateColumn, addressColumn, amountColumn, typeColumn, confidenceColumn;
@FXML private Button addNewAddressButton;
///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -4,7 +4,7 @@
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml/1" spacing="10" fx:controller="io.bitsquare.gui.funds.transactions.TransactionsController"
<VBox fx:id="root" xmlns:fx="http://javafx.com/fxml/1" spacing="10" fx:controller="io.bitsquare.gui.funds.transactions.TransactionsController"
xmlns="http://javafx.com/javafx/8">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>

View File

@ -29,6 +29,7 @@ import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
import javax.inject.Inject;
import org.controlsfx.control.action.Action;
@ -44,14 +45,11 @@ public class WithdrawalController implements Initializable, ChildController, Hib
private final WalletFacade walletFacade;
private ObservableList<WithdrawalListItem> addressList;
@FXML
private TableView<WithdrawalListItem> tableView;
@FXML
private TableColumn<String, WithdrawalListItem> labelColumn, addressColumn, balanceColumn, copyColumn, confidenceColumn;
@FXML
private Button addNewAddressButton;
@FXML
private TextField withdrawFromTextField, withdrawToTextField, amountTextField, changeAddressTextField;
@FXML private VBox root;
@FXML private TableView<WithdrawalListItem> tableView;
@FXML private TableColumn<String, WithdrawalListItem> labelColumn, addressColumn, balanceColumn, copyColumn, confidenceColumn;
@FXML private Button addNewAddressButton;
@FXML private TextField withdrawFromTextField, withdrawToTextField, amountTextField, changeAddressTextField;
///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -4,7 +4,7 @@
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.*?>
<VBox xmlns:fx="http://javafx.com/fxml/1" spacing="10" fx:controller="io.bitsquare.gui.funds.withdrawal.WithdrawalController" xmlns="http://javafx.com/javafx/8">
<VBox fx:id="root" xmlns:fx="http://javafx.com/fxml/1" spacing="10" fx:controller="io.bitsquare.gui.funds.withdrawal.WithdrawalController" xmlns="http://javafx.com/javafx/8">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>

View File

@ -6,23 +6,18 @@ import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.arbitrators.registration.ArbitratorRegistrationController;
import io.bitsquare.locale.Localisation;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class HomeController implements Initializable, ChildController, NavigationController
{
@FXML
public Pane rootContainer;
private ArbitratorRegistrationController arbitratorRegistrationController;
@Override
@ -54,10 +49,11 @@ public class HomeController implements Initializable, ChildController, Navigatio
arbitratorRegistrationController.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
// dont use caching here, cause exc. -> need to investigate and is rarely called so no caching is better
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), false);
try
{
final Node view = loader.load();
final Parent view = loader.load();
arbitratorRegistrationController = loader.getController();
arbitratorRegistrationController.setNavigationController(this);
@ -72,7 +68,7 @@ public class HomeController implements Initializable, ChildController, Navigatio
stage.setY(rootStage.getY() + 50);
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(rootStage);
Scene scene = new Scene((Parent) view, 800, 600);
Scene scene = new Scene(view, 800, 600);
stage.setScene(scene);
stage.show();

View File

@ -5,16 +5,15 @@ 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.locale.Localisation;
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;
import javafx.scene.layout.Pane;
public class MarketController implements Initializable, NavigationController, ChildController
{
@ -52,10 +51,10 @@ public class MarketController implements Initializable, NavigationController, Ch
return null;
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()));
try
{
final Pane view = loader.load();
final Parent view = loader.load();
ChildController childController = loader.getController();
childController.setNavigationController(this);

View File

@ -9,12 +9,15 @@ import io.bitsquare.gui.ChildController;
import io.bitsquare.gui.Hibernate;
import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.components.ValidatingTextField;
import io.bitsquare.gui.components.btc.AddressTextField;
import io.bitsquare.gui.components.btc.BalanceTextField;
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
import io.bitsquare.gui.popups.Popups;
import io.bitsquare.gui.util.BitSquareConverter;
import io.bitsquare.gui.util.BitSquareFormatter;
import io.bitsquare.gui.util.BtcValidator;
import io.bitsquare.gui.util.FiatValidator;
import io.bitsquare.gui.util.ValidationHelper;
import io.bitsquare.locale.Localisation;
import io.bitsquare.settings.Settings;
import io.bitsquare.trade.Direction;
@ -36,6 +39,7 @@ import javafx.scene.control.Label;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Region;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -64,7 +68,7 @@ class ViewModel
final StringProperty acceptedLanguages = new SimpleStringProperty();
final StringProperty transactionId = new SimpleStringProperty();
final BooleanProperty isOfferPlacedScreen = new SimpleBooleanProperty();
final BooleanProperty isPlaceOfferButtonDisabled = new SimpleBooleanProperty();
final BooleanProperty isPlaceOfferButtonDisabled = new SimpleBooleanProperty(false);
}
public class CreateOfferController implements Initializable, ChildController, Hibernate
@ -74,33 +78,34 @@ public class CreateOfferController implements Initializable, ChildController, Hi
private NavigationController navigationController;
private final TradeManager tradeManager;
private final WalletFacade walletFacade;
private final ViewModel viewModel = new ViewModel();
final ViewModel viewModel = new ViewModel();
private final double collateral;
private Direction direction;
@FXML private AnchorPane rootContainer;
@FXML private Label buyLabel, confirmationLabel, txTitleLabel, collateralLabel;
@FXML private TextField volumeTextField, amountTextField, priceTextField, totalsTextField;
@FXML private ValidatingTextField amountTextField, minAmountTextField, priceTextField, volumeTextField;
@FXML private Button placeOfferButton, closeButton;
@FXML private TextField collateralTextField, minAmountTextField, bankAccountTypeTextField, bankAccountCurrencyTextField, bankAccountCountyTextField, acceptedCountriesTextField, acceptedLanguagesTextField,
@FXML private TextField totalsTextField, collateralTextField, bankAccountTypeTextField, bankAccountCurrencyTextField, bankAccountCountyTextField, acceptedCountriesTextField, acceptedLanguagesTextField,
feeLabel, transactionIdTextField;
@FXML private ConfidenceProgressIndicator progressIndicator;
@FXML private AddressTextField addressTextField;
@FXML private BalanceTextField balanceTextField;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private CreateOfferController(TradeManager tradeManager, WalletFacade walletFacade, Settings settings, User user)
CreateOfferController(TradeManager tradeManager, WalletFacade walletFacade, Settings settings, User user)
{
this.tradeManager = tradeManager;
this.walletFacade = walletFacade;
this.collateral = settings.getCollateral();
viewModel.collateralLabel.set("Collateral (" + BitSquareFormatter.formatCollateralPercent(collateral) + "):");
BankAccount bankAccount = user.getCurrentBankAccount();
if (bankAccount != null)
{
@ -126,20 +131,6 @@ public class CreateOfferController implements Initializable, ChildController, Hi
viewModel.amount.set(BitSquareFormatter.formatCoin(orderBookFilter.getAmount()));
viewModel.minAmount.set(BitSquareFormatter.formatCoin(orderBookFilter.getAmount()));
viewModel.price.set(BitSquareFormatter.formatPrice(orderBookFilter.getPrice()));
viewModel.collateralLabel.set("Collateral (" + BitSquareFormatter.formatCollateralPercent(collateral) + "):");
//TODO just for dev testing
if (BitSquare.fillFormsWithDummyData)
{
if (orderBookFilter.getAmount() == null)
{
amountTextField.setText("1");
minAmountTextField.setText("0.1");
}
if (orderBookFilter.getPrice() == 0)
priceTextField.setText("" + (int) (499 - new Random().nextDouble() * 1000 / 100));
}
}
@ -150,15 +141,34 @@ public class CreateOfferController implements Initializable, ChildController, Hi
@Override
public void initialize(URL url, ResourceBundle rb)
{
AddressEntry addressEntry = walletFacade.getUnusedTradeAddressInfo();
addressTextField.setAddress(addressEntry.getAddress().toString());
setupBindings();
setupValidation();
balanceTextField.setAddress(addressEntry.getAddress());
balanceTextField.setWalletFacade(walletFacade);
//TODO
if (walletFacade.getWallet() != null)
{
AddressEntry addressEntry = walletFacade.getUnusedTradeAddressInfo();
addressTextField.setAddress(addressEntry.getAddress().toString());
balanceTextField.setAddress(addressEntry.getAddress());
balanceTextField.setWalletFacade(walletFacade);
}
//TODO just for dev testing
if (BitSquare.fillFormsWithDummyData)
{
amountTextField.setText("1");
minAmountTextField.setText("0.1");
priceTextField.setText("" + (int) (499 - new Random().nextDouble() * 1000 / 100));
}
}
private void setupBindings()
{
// setup bindings
DoubleBinding amountBinding = createDoubleBinding(() -> BitSquareConverter.stringToDouble(viewModel.amount.get()), viewModel.amount);
DoubleBinding priceBinding = createDoubleBinding(() -> BitSquareConverter.stringToDouble(viewModel.price.get()), viewModel.price);
DoubleBinding amountBinding = createDoubleBinding(() -> BitSquareFormatter.parseToDouble(viewModel.amount.get()), viewModel.amount);
DoubleBinding priceBinding = createDoubleBinding(() -> BitSquareFormatter.parseToDouble(viewModel.price.get()), viewModel.price);
viewModel.volume.bind(createStringBinding(() -> BitSquareFormatter.formatVolume(amountBinding.get() * priceBinding.get()), amountBinding, priceBinding));
viewModel.collateral.bind(createStringBinding(() -> BitSquareFormatter.formatCollateralAsBtc(viewModel.amount.get(), collateral), amountBinding));
@ -185,7 +195,6 @@ public class CreateOfferController implements Initializable, ChildController, Hi
transactionIdTextField.textProperty().bind(viewModel.transactionId);
placeOfferButton.visibleProperty().bind(viewModel.isOfferPlacedScreen.not());
placeOfferButton.disableProperty().bind(viewModel.isPlaceOfferButtonDisabled);
progressIndicator.visibleProperty().bind(viewModel.isOfferPlacedScreen);
confirmationLabel.visibleProperty().bind(viewModel.isOfferPlacedScreen);
txTitleLabel.visibleProperty().bind(viewModel.isOfferPlacedScreen);
@ -193,6 +202,25 @@ public class CreateOfferController implements Initializable, ChildController, Hi
closeButton.visibleProperty().bind(viewModel.isOfferPlacedScreen);
}
private void setupValidation()
{
BtcValidator amountValidator = new BtcValidator();
amountTextField.setNumberValidator(amountValidator);
amountTextField.setErrorPopupLayoutReference((Region) amountTextField.getParent());
priceTextField.setNumberValidator(new FiatValidator());
priceTextField.setErrorPopupLayoutReference((Region) amountTextField.getParent());
BtcValidator minAmountValidator = new BtcValidator();
minAmountTextField.setNumberValidator(minAmountValidator);
ValidationHelper.setupMinAmountInRangeOfAmountValidation(amountTextField,
minAmountTextField,
viewModel.amount,
viewModel.minAmount,
amountValidator,
minAmountValidator);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Interface implementation: ChildController
@ -229,27 +257,24 @@ public class CreateOfferController implements Initializable, ChildController, Hi
///////////////////////////////////////////////////////////////////////////////////////////
// UI Handlers
///////////////////////////////////////////////////////////////////////////////////////////
@FXML
public void onPlaceOffer()
{
if (inputsValid())
{
viewModel.isPlaceOfferButtonDisabled.set(true);
viewModel.isPlaceOfferButtonDisabled.set(true);
tradeManager.requestPlaceOffer(direction,
BitSquareConverter.stringToDouble(viewModel.price.get()),
BitSquareFormatter.parseToCoin(viewModel.amount.get()),
BitSquareFormatter.parseToCoin(viewModel.minAmount.get()),
(transaction) -> {
viewModel.isOfferPlacedScreen.set(true);
viewModel.transactionId.set(transaction.getHashAsString());
},
errorMessage -> {
Popups.openErrorPopup("An error occurred", errorMessage);
viewModel.isPlaceOfferButtonDisabled.set(false);
});
}
tradeManager.requestPlaceOffer(direction,
BitSquareFormatter.parseToDouble(viewModel.price.get()),
BitSquareFormatter.parseToCoin(viewModel.amount.get()),
BitSquareFormatter.parseToCoin(viewModel.minAmount.get()),
(transaction) -> {
viewModel.isOfferPlacedScreen.set(true);
viewModel.transactionId.set(transaction.getHashAsString());
},
errorMessage -> {
Popups.openErrorPopup("An error occurred", errorMessage);
viewModel.isPlaceOfferButtonDisabled.set(false);
});
}
@FXML
@ -260,48 +285,5 @@ public class CreateOfferController implements Initializable, ChildController, Hi
navigationController.navigateToView(NavigationItem.ORDER_BOOK);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////////////////
private boolean inputsValid()
{
//TODO
/* boolean inputFieldsValid;
double amount = BitSquareConverter.stringToDouble(viewModel.amount.get());
double minAmount = BitSquareConverter.stringToDouble(viewModel.minAmount.get());
double price = BitSquareConverter.stringToDouble(viewModel.price.get());
inputFieldsValid = price > 0 &&
amount > 0 &&
minAmount > 0 &&
minAmount <= amount/* &&
viewModel.collateral >= settings.getMinCollateral() &&
viewModel.collateral <= settings.getMaxCollateral()*/ /*;
if (!inputFieldsValid)
{
Popups.openWarningPopup("Invalid input", "Your input is invalid");
return false;
}
*/
/* Arbitrator arbitrator = settings.getRandomArbitrator(getAmountAsCoin());
if (arbitrator == null)
{
Popups.openWarningPopup("No arbitrator available", "No arbitrator from your arbitrator list does match the collateral and amount value.");
return false;
}*/
/*
if (user.getCurrentBankAccount() == null)
{
log.error("Must never happen!");
Popups.openWarningPopup("No bank account selected", "No bank account selected.");
return false;
}*/
return true;
}
}

View File

@ -3,6 +3,7 @@
<?import io.bitsquare.gui.components.btc.AddressTextField?>
<?import io.bitsquare.gui.components.btc.BalanceTextField?>
<?import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator?>
<?import io.bitsquare.gui.components.ValidatingTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
@ -16,16 +17,16 @@
<Label fx:id="buyLabel" GridPane.rowIndex="1"/>
<HBox spacing="5" GridPane.rowIndex="1" GridPane.columnIndex="1" GridPane.hgrow="NEVER" alignment="CENTER_LEFT">
<TextField fx:id="amountTextField" prefWidth="70.0" alignment="CENTER_RIGHT"/>
<ValidatingTextField fx:id="amountTextField" prefWidth="70.0" alignment="CENTER_RIGHT"/>
<Label text="BTC for:"/>
<TextField fx:id="priceTextField" prefWidth="70.0" alignment="CENTER_RIGHT"/>
<ValidatingTextField fx:id="priceTextField" prefWidth="70.0" alignment="CENTER_RIGHT"/>
<Label text="EUR ="/>
<TextField fx:id="volumeTextField" prefWidth="70.0" alignment="CENTER_RIGHT" editable="false"/>
<ValidatingTextField fx:id="volumeTextField" prefWidth="70.0" alignment="CENTER_RIGHT" editable="false"/>
<Label text="EUR in total"/>
</HBox>
<Label text="Min. Amount (BTC):" GridPane.rowIndex="2"/>
<TextField fx:id="minAmountTextField" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
<ValidatingTextField fx:id="minAmountTextField" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
<Label fx:id="collateralLabel" text="Collateral:" GridPane.rowIndex="3"/>
<TextField fx:id="collateralTextField" editable="false" GridPane.columnIndex="1" GridPane.rowIndex="3"/>

View File

@ -14,7 +14,6 @@ import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.market.createOffer.CreateOfferController;
import io.bitsquare.gui.market.trade.TakerOfferController;
import io.bitsquare.gui.popups.Popups;
import io.bitsquare.gui.util.BitSquareConverter;
import io.bitsquare.gui.util.BitSquareFormatter;
import io.bitsquare.gui.util.Icons;
import io.bitsquare.locale.Country;
@ -564,7 +563,7 @@ public class OrderBookController implements Initializable, ChildController
} catch (ParseException e)
{
amount.setText(oldValue);
d = BitSquareConverter.stringToDouble(oldValue);
d = BitSquareFormatter.parseToDouble(oldValue);
}
}
return d;

View File

@ -9,7 +9,6 @@ import io.bitsquare.gui.NavigationController;
import io.bitsquare.gui.NavigationItem;
import io.bitsquare.gui.components.ValidatedTextField;
import io.bitsquare.gui.popups.Popups;
import io.bitsquare.gui.util.BitSquareConverter;
import io.bitsquare.gui.util.BitSquareFormatter;
import io.bitsquare.gui.util.BitSquareValidator;
import io.bitsquare.msg.MessageFacade;
@ -290,7 +289,7 @@ public class TakerOfferController implements Initializable, ChildController
// values
private double getAmountAsDouble()
{
return BitSquareConverter.stringToDouble(getAmountString());
return BitSquareFormatter.parseToDouble(getAmountString());
}
private Coin getAmountInSatoshis()

View File

@ -4,7 +4,7 @@
<?import javafx.scene.control.Tab?>
<?import javafx.scene.layout.AnchorPane?>
<CachingTabPane 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"
xmlns="http://javafx.com/javafx/8" fx:controller="io.bitsquare.gui.orders.OrdersController">
xmlns="http://javafx.com/javafx/8" fx:controller="io.bitsquare.gui.orders.OrdersController">
<Tab text="Open offers" closable="false"/>
<Tab text="Pending trades" closable="false"/>

View File

@ -54,6 +54,7 @@ public class SettingsController implements Initializable, ChildController, Navig
private List<String> regionList;
private ObservableList<Arbitrator> arbitratorList;
@FXML private TabPane root;
@FXML
private ListView<Locale> languagesListView;
@FXML
@ -133,7 +134,6 @@ public class SettingsController implements Initializable, ChildController, Navig
addMockArbitrator();
}
@SuppressWarnings("ConstantConditions")
private void addMockArbitrator()
{
if (settings.getAcceptedArbitrators().isEmpty())
@ -204,7 +204,7 @@ public class SettingsController implements Initializable, ChildController, Navig
childController.cleanup();
}
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()), Localisation.getResourceBundle());
final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(navigationItem.getFxmlUrl()));
try
{
final Node view = loader.load();

View File

@ -3,7 +3,7 @@
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<TabPane xmlns:fx="http://javafx.com/fxml/1" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"
<TabPane fx:id="root" xmlns:fx="http://javafx.com/fxml/1" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"
xmlns="http://javafx.com/javafx/8" fx:controller="io.bitsquare.gui.settings.SettingsController">
<Tab text="General" closable="false">

View File

@ -1,25 +0,0 @@
package io.bitsquare.gui.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BitSquareConverter
{
private static final Logger log = LoggerFactory.getLogger(BitSquareConverter.class);
/**
* @param input String to be converted to a double. Both decimal points "." and "," are supported. Thousands separator is not supported.
* @return Returns a double value. Any invalid value returns Double.NEGATIVE_INFINITY.
*/
public static double stringToDouble(String input)
{
try
{
input = input.replace(",", ".");
return Double.parseDouble(input);
} catch (NumberFormatException | NullPointerException e)
{
return 0;
}
}
}

View File

@ -13,6 +13,9 @@ import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
//TODO cleanup...
public class BitSquareFormatter
{
@ -45,26 +48,25 @@ public class BitSquareFormatter
*/
public static Coin parseToCoin(String input)
{
Coin result;
try
{
input = input.replace(",", ".");
Double.parseDouble(input);
} catch (NumberFormatException | NullPointerException e)
result = Coin.parseCoin(input);
} catch (Exception e)
{
log.warn("Exception at parseBtcToCoin: " + e.toString());
input = "0";
//log.warn("Exception at parseBtcToCoin: " + e.toString());
result = Coin.ZERO;
}
return Coin.parseCoin(input);
return result;
}
///////////////////////////////////////////////////////////////////////////////////////////
// FIAT
///////////////////////////////////////////////////////////////////////////////////////////
public static String formatPrice(double price)
{
return formatDouble(price);
@ -85,13 +87,31 @@ public class BitSquareFormatter
// Other
///////////////////////////////////////////////////////////////////////////////////////////
/**
* @param input String to be converted to a double. Both decimal points "." and "," are supported. Thousands separator is not supported.
* @return Returns a double value. Any invalid value returns Double.NEGATIVE_INFINITY.
*/
public static double parseToDouble(String input)
{
try
{
checkNotNull(input);
checkArgument(input.length() > 0);
input = input.replace(",", ".").trim();
return Double.parseDouble(input);
} catch (Exception e)
{
return 0;
}
}
public static String formatCollateralAsBtc(String amount, double collateral)
{
Coin amountAsCoin = BitSquareFormatter.parseToCoin(amount);
Coin collateralAsCoin = amountAsCoin.divide((long) (1d / collateral));
return formatCoinWithCode(collateralAsCoin);
}
public static String formatTotalsAsBtc(String amount, double collateral, Coin fees)
{
Coin amountAsCoin = BitSquareFormatter.parseToCoin(amount);
@ -99,7 +119,7 @@ public class BitSquareFormatter
Coin totals = collateralAsCoin.add(fees);
return formatCoinWithCode(totals);
}
public static String formatDirection(Direction direction, boolean allUpperCase)
{
String result = (direction == Direction.BUY) ? "Buy" : "Sell";

View File

@ -9,7 +9,8 @@ import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Effect;
import javafx.scene.paint.Color;
@SuppressWarnings("WeakerAccess")
//TODO to be removed
@Deprecated
public class BitSquareValidator
{
private static final Effect invalidEffect = new DropShadow(BlurType.GAUSSIAN, Color.RED, 4, 0.0, 0, 0);

View File

@ -0,0 +1,81 @@
package io.bitsquare.gui.util;
import com.google.bitcoin.core.NetworkParameters;
import java.math.BigDecimal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* BtcValidator for validating BTC values.
* <p>
* That class implements just what we need for the moment. It is not intended as a general purpose library class.
*/
public class BtcValidator extends NumberValidator
{
private static final Logger log = LoggerFactory.getLogger(BtcValidator.class);
private ValidationResult overriddenValidationResult;
///////////////////////////////////////////////////////////////////////////////////////////
// Public methods
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public ValidationResult validate(String input)
{
ValidationResult result = validateIfNotEmpty(input);
if (result.isValid)
{
input = cleanInput(input);
result = validateIfNumber(input);
}
if (result.isValid)
{
result = validateIfNotZero(input)
.and(validateIfNotNegative(input))
.and(validateIfNotFractionalBtcValue(input))
.and(validateIfNotExceedsMaxBtcValue(input));
}
if (overriddenValidationResult != null)
return overriddenValidationResult;
return result;
}
/**
* Used to integrate external validation (e.g. for MinAmount/Amount)
* TODO Might be improved but does the job for now...
*
* @param overriddenValidationResult
*/
public void overrideResult(ValidationResult overriddenValidationResult)
{
this.overriddenValidationResult = overriddenValidationResult;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected methods
///////////////////////////////////////////////////////////////////////////////////////////
protected ValidationResult validateIfNotFractionalBtcValue(String input)
{
BigDecimal bd = new BigDecimal(input);
final BigDecimal satoshis = bd.movePointRight(8);
if (satoshis.scale() > 0)
return new ValidationResult(false, "Input results in a Bitcoin value with a fraction of the smallest unit (Satoshi).", ErrorType.FRACTIONAL_SATOSHI);
else
return new ValidationResult(true);
}
protected ValidationResult validateIfNotExceedsMaxBtcValue(String input)
{
BigDecimal bd = new BigDecimal(input);
final BigDecimal satoshis = bd.movePointRight(8);
if (satoshis.longValue() > NetworkParameters.MAX_MONEY.longValue())
return new ValidationResult(false, "Input larger as maximum possible Bitcoin value is not allowed.", ErrorType.EXCEEDS_MAX_BTC_VALUE);
else
return new ValidationResult(true);
}
}

View File

@ -0,0 +1,67 @@
package io.bitsquare.gui.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* FiatNumberValidator for validating fiat values.
* <p>
* That class implements just what we need for the moment. It is not intended as a general purpose library class.
*/
public class FiatValidator extends NumberValidator
{
private static final Logger log = LoggerFactory.getLogger(FiatValidator.class);
//TODO Find appropriate values - depends on currencies
public static final double MIN_FIAT_VALUE = 0.01; // usually a cent is the smallest currency unit
public static final double MAX_FIAT_VALUE = 1000000;
///////////////////////////////////////////////////////////////////////////////////////////
// Public methods
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public ValidationResult validate(String input)
{
ValidationResult result = validateIfNotEmpty(input);
if (result.isValid)
{
input = cleanInput(input);
result = validateIfNumber(input);
}
if (result.isValid)
{
result = validateIfNotZero(input)
.and(validateIfNotNegative(input))
.and(validateIfNotExceedsMinFiatValue(input))
.and(validateIfNotExceedsMaxFiatValue(input));
}
return result;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected methods
///////////////////////////////////////////////////////////////////////////////////////////
protected ValidationResult validateIfNotExceedsMinFiatValue(String input)
{
double d = Double.parseDouble(input);
if (d < MIN_FIAT_VALUE)
return new ValidationResult(false, "Input smaller as minimum possible Fiat value is not allowed..", ErrorType.UNDERCUT_MIN_FIAT_VALUE);
else
return new ValidationResult(true);
}
protected ValidationResult validateIfNotExceedsMaxFiatValue(String input)
{
double d = Double.parseDouble(input);
if (d > MAX_FIAT_VALUE)
return new ValidationResult(false, "Input larger as maximum possible Fiat value is not allowed.", ErrorType.EXCEEDS_MAX_FIAT_VALUE);
else
return new ValidationResult(true);
}
}

View File

@ -0,0 +1,127 @@
package io.bitsquare.gui.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* NumberValidator for validating basic number values.
* Localisation not supported at the moment
* The decimal mark can be either "." or ",". Thousand separators are not supported yet, but might be added alter with Local support.
* <p>
* That class implements just what we need for the moment. It is not intended as a general purpose library class.
*/
public abstract class NumberValidator
{
private static final Logger log = LoggerFactory.getLogger(NumberValidator.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Abstract methods
///////////////////////////////////////////////////////////////////////////////////////////
abstract public ValidationResult validate(String input);
///////////////////////////////////////////////////////////////////////////////////////////
// Protected methods
///////////////////////////////////////////////////////////////////////////////////////////
protected ValidationResult validateIfNotEmpty(String input)
{
if (input == null || input.length() == 0)
return new ValidationResult(false, "Empty input is not allowed.", ErrorType.EMPTY_INPUT);
else
return new ValidationResult(true);
}
protected String cleanInput(String input)
{
return input.replace(",", ".").trim();
}
protected ValidationResult validateIfNumber(String input)
{
try
{
//noinspection ResultOfMethodCallIgnored
Double.parseDouble(input);
return new ValidationResult(true);
} catch (Exception e)
{
return new ValidationResult(false, "Input is not a valid number.", ErrorType.NOT_A_NUMBER);
}
}
protected ValidationResult validateIfNotZero(String input)
{
if (Double.parseDouble(input) == 0)
return new ValidationResult(false, "Input of 0 is not allowed.", ErrorType.ZERO_NUMBER);
else
return new ValidationResult(true);
}
protected ValidationResult validateIfNotNegative(String input)
{
if (Double.parseDouble(input) < 0)
return new ValidationResult(false, "A negative value is not allowed.", ErrorType.NEGATIVE_NUMBER);
else
return new ValidationResult(true);
}
///////////////////////////////////////////////////////////////////////////////////////////
// ErrorType
///////////////////////////////////////////////////////////////////////////////////////////
public enum ErrorType
{
EMPTY_INPUT,
NOT_A_NUMBER,
ZERO_NUMBER,
NEGATIVE_NUMBER,
FRACTIONAL_SATOSHI,
EXCEEDS_MAX_FIAT_VALUE, UNDERCUT_MIN_FIAT_VALUE, AMOUNT_LESS_THAN_MIN_AMOUNT, MIN_AMOUNT_LARGER_THAN_MIN_AMOUNT, EXCEEDS_MAX_BTC_VALUE
}
///////////////////////////////////////////////////////////////////////////////////////////
// ValidationResult
///////////////////////////////////////////////////////////////////////////////////////////
public static class ValidationResult
{
public final boolean isValid;
public final String errorMessage;
public final ErrorType errorType;
public ValidationResult(boolean isValid, String errorMessage, ErrorType errorType)
{
this.isValid = isValid;
this.errorMessage = errorMessage;
this.errorType = errorType;
}
ValidationResult(boolean isValid)
{
this(isValid, null, null);
}
public ValidationResult and(ValidationResult next)
{
if (this.isValid)
return next;
else
return this;
}
@Override
public String toString()
{
return "ValidationResult{" +
"isValid=" + isValid +
", errorMessage='" + errorMessage + '\'' +
", errorType=" + errorType +
'}';
}
}
}

View File

@ -0,0 +1,50 @@
package io.bitsquare.gui.util;
import com.google.common.base.Stopwatch;
import java.util.concurrent.TimeUnit;
import javafx.animation.AnimationTimer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Profiler
{
private static final Logger log = LoggerFactory.getLogger(Profiler.class);
private static final Stopwatch globalStopwatch = Stopwatch.createStarted();
private static final ThreadLocal<Stopwatch> threadStopwatch = ThreadLocal.withInitial(Stopwatch::createStarted);
private static final ThreadLocal<Long> last = ThreadLocal.withInitial(() -> 0L);
private static long lastCurrentTimeMillis = System.currentTimeMillis();
private static long lastFPSTime = System.currentTimeMillis();
private static long counter = 0;
public static void printMsgWithTime(String msg)
{
final long elapsed = threadStopwatch.get().elapsed(TimeUnit.MILLISECONDS);
log.trace("Msg: {} elapsed: {}ms / total time:[globalStopwatch: {}ms / threadStopwatch: {}ms / currentTimeMillis: {}ms]",
msg,
elapsed - last.get(),
globalStopwatch.elapsed(TimeUnit.MILLISECONDS),
elapsed,
System.currentTimeMillis() - lastCurrentTimeMillis);
lastCurrentTimeMillis = System.currentTimeMillis();
last.set(elapsed);
}
public static void init()
{
AnimationTimer fpsTimer = new AnimationTimer()
{
@Override
public void handle(long l)
{
counter++;
long elapsed = (System.currentTimeMillis() - lastFPSTime);
if (elapsed > 19)
log.trace("FPS: elapsed: {}ms / FPS total counter: {}", elapsed, counter);
lastFPSTime = System.currentTimeMillis();
}
};
fpsTimer.start();
}
}

View File

@ -0,0 +1,97 @@
package io.bitsquare.gui.util;
import io.bitsquare.gui.components.ValidatingTextField;
import javafx.beans.property.StringProperty;
import javafx.scene.control.TextField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Helper class for setting up the validation and dependencies for minAmount and Amount.
* TODO Might be improved but does the job for now...
*/
public class ValidationHelper
{
private static final Logger log = LoggerFactory.getLogger(ValidationHelper.class);
/**
* Handles validation between minAmount and amount fields
*/
public static void setupMinAmountInRangeOfAmountValidation(ValidatingTextField amountTextField,
ValidatingTextField minAmountTextField,
StringProperty amount,
StringProperty minAmount,
BtcValidator amountValidator,
BtcValidator minAmountValidator)
{
amountTextField.focusedProperty().addListener((ov, oldValue, newValue) -> {
// only on focus out and ignore focus loss from window
if (!newValue && amountTextField.getScene().getWindow().isFocused())
validateMinAmount(amountTextField,
minAmountTextField,
amount,
minAmount,
amountValidator,
minAmountValidator,
amountTextField);
});
minAmountTextField.focusedProperty().addListener((ov, oldValue, newValue) -> {
// only on focus out and ignore focus loss from window
if (!newValue && minAmountTextField.getScene().getWindow().isFocused())
validateMinAmount(amountTextField,
minAmountTextField,
amount,
minAmount,
amountValidator,
minAmountValidator,
minAmountTextField);
});
}
private static void validateMinAmount(ValidatingTextField amountTextField,
ValidatingTextField minAmountTextField,
StringProperty amount,
StringProperty minAmount,
BtcValidator amountValidator,
BtcValidator minAmountValidator,
TextField currentTextField)
{
amountValidator.overrideResult(null);
if (!amountValidator.validate(amount.get()).isValid)
return;
minAmountValidator.overrideResult(null);
if (!minAmountValidator.validate(minAmount.get()).isValid)
return;
if (currentTextField == amountTextField)
{
if (Double.parseDouble(amount.get()) < Double.parseDouble(minAmount.get()))
{
amountValidator.overrideResult(new NumberValidator.ValidationResult(false, "Amount cannot be smaller than minimum amount.", NumberValidator.ErrorType.AMOUNT_LESS_THAN_MIN_AMOUNT));
amountTextField.reValidate();
}
else
{
amountValidator.overrideResult(null);
minAmountTextField.reValidate();
}
}
else if (currentTextField == minAmountTextField)
{
if (Double.parseDouble(minAmount.get()) > Double.parseDouble(amount.get()))
{
minAmountValidator.overrideResult(new NumberValidator.ValidationResult(false, "Minimum amount cannot be larger than amount.", NumberValidator.ErrorType.MIN_AMOUNT_LARGER_THAN_MIN_AMOUNT));
minAmountTextField.reValidate();
}
else
{
minAmountValidator.overrideResult(null);
amountTextField.reValidate();
}
}
}
}

View File

@ -0,0 +1,22 @@
.text-field.validation_error, .text-area.validation_error .content, .date-picker.validation_error > .text-field {
-fx-effect: innershadow(three-pass-box, red, 12 , 0.5, 1, 1);
}
#error-msg-item .label {
-fx-text-fill: white;
}
#error-msg-item:focused {
-fx-background-color: #B80000;
}
#error-msg-item:focused .label {
-fx-text-fill: white;
}
#error-msg {
-fx-background-color: #B80000;
-fx-padding: 0;
-fx-background-radius: 4 4 4 4;
}

View File

@ -1,4 +1,5 @@
package io.bitsquare.trade.handlers;
/**
* For reporting throwables only
*/

View File

@ -42,10 +42,10 @@ public class VerifyAndSignContract
//TODO PublicKey cause problems, need to be changed to hex
/*if (contractAsJson.equals(peersContractAsJson))
{*/
log.trace("The 2 contracts as json does match");
String signature = cryptoFacade.signContract(registrationKey, contractAsJson);
//log.trace("signature: " + signature);
resultHandler.onResult(contract, contractAsJson, signature);
log.trace("The 2 contracts as json does match");
String signature = cryptoFacade.signContract(registrationKey, contractAsJson);
//log.trace("signature: " + signature);
resultHandler.onResult(contract, contractAsJson, signature);
/* }
else
{

View File

@ -31,7 +31,7 @@ public class AWTSystemTray
trayIcon.setToolTip("BitSquare P2P Fiat-Bitcoin exchange");
PopupMenu popupMenu = new PopupMenu();
MenuItem aboutItem = new MenuItem("Info about " + BitSquare.getUID());
MenuItem aboutItem = new MenuItem("Info about " + BitSquare.getAppName());
popupMenu.add(aboutItem);
popupMenu.addSeparator();
showGuiItem = new MenuItem("Close exchange window");

View File

@ -1,98 +0,0 @@
package io.bitsquare.util;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
public class CachingClassLoader extends ClassLoader
{
private final Map<String, Class> classes = new HashMap<String, Class>();
private final ClassLoader parent;
public CachingClassLoader(ClassLoader parent)
{
this.parent = parent;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException
{
Class<?> c = findClass(name);
if (c == null)
{
throw new ClassNotFoundException(name);
}
return c;
}
@Override
protected Class<?> findClass(String className) throws ClassNotFoundException
{
if (classes.containsKey(className))
{
// System.out.print("############## cached " + className);
Class<?> result = classes.get(className);
return result;
}
else
{
try
{
Class<?> result = parent.loadClass(className);
System.out.print("############## not cached " + className);
classes.put(className, result);
return result;
} catch (ClassNotFoundException ignore)
{
// System.out.println();
classes.put(className, null);
return null;
}
}
}
// ========= delegating methods =============
@Override
public URL getResource(String name)
{
return parent.getResource(name);
}
@Override
public Enumeration<URL> getResources(String name) throws IOException
{
return parent.getResources(name);
}
@Override
public String toString()
{
return parent.toString();
}
@Override
public void setDefaultAssertionStatus(boolean enabled)
{
parent.setDefaultAssertionStatus(enabled);
}
@Override
public void setPackageAssertionStatus(String packageName, boolean enabled)
{
parent.setPackageAssertionStatus(packageName, enabled);
}
@Override
public void setClassAssertionStatus(String className, boolean enabled)
{
parent.setClassAssertionStatus(className, enabled);
}
@Override
public void clearAssertionStatus()
{
parent.clearAssertionStatus();
}
}

View File

@ -1,7 +1,6 @@
package io.bitsquare.util;
import com.google.bitcoin.core.Utils;
import io.bitsquare.BitSquare;
import java.io.File;
import java.io.IOException;
import org.slf4j.Logger;
@ -21,6 +20,7 @@ public class FileUtil
return File.createTempFile("temp_" + prefix, null, StorageDirectory.getStorageDirectory());
}
/*
public static String getApplicationFileName()
{
File executionRoot = new File(StorageDirectory.class.getProtectionDomain().getCodeSource().getLocation().getFile());
@ -50,9 +50,11 @@ public class FileUtil
{
e.printStackTrace();
}
// fallback use AppName
return BitSquare.getAppName();
}
*/
public static void writeTempFileToFile(File tempFile, File file) throws IOException
{

View File

@ -2,7 +2,8 @@ package io.bitsquare;
import io.bitsquare.btc.BtcValidatorTest;
import io.bitsquare.gui.util.BitSquareConverterTest;
import io.bitsquare.gui.util.BitSquareValidatorTest;
import io.bitsquare.gui.util.BitSquareNumberValidatorTest;
import io.bitsquare.gui.util.FiatValidatorTest;
import io.bitsquare.msg.P2PNodeTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@ -11,8 +12,10 @@ import org.junit.runners.Suite;
@Suite.SuiteClasses({
BtcValidatorTest.class,
BitSquareConverterTest.class,
BitSquareValidatorTest.class,
P2PNodeTest.class
BitSquareNumberValidatorTest.class,
P2PNodeTest.class,
FiatValidatorTest.class,
BtcValidatorTest.class
})
public class BitSquareTestSuite

View File

@ -11,19 +11,19 @@ public class BitSquareConverterTest
public void testStringToDouble()
{
assertEquals(1, BitSquareConverter.stringToDouble("1"), 0);
assertEquals(0.1, BitSquareConverter.stringToDouble("0.1"), 0);
assertEquals(0.1, BitSquareConverter.stringToDouble("0,1"), 0);
assertEquals(1, BitSquareConverter.stringToDouble("1.0"), 0);
assertEquals(1, BitSquareConverter.stringToDouble("1,0"), 0);
assertEquals(1, BitSquareFormatter.parseToDouble("1"), 0);
assertEquals(0.1, BitSquareFormatter.parseToDouble("0.1"), 0);
assertEquals(0.1, BitSquareFormatter.parseToDouble("0,1"), 0);
assertEquals(1, BitSquareFormatter.parseToDouble("1.0"), 0);
assertEquals(1, BitSquareFormatter.parseToDouble("1,0"), 0);
assertEquals(0, BitSquareConverter.stringToDouble("1,000.2"), 0);
assertEquals(0, BitSquareConverter.stringToDouble("1,000.2"), 0);
assertEquals(0, BitSquareConverter.stringToDouble(null), 0);
assertEquals(0, BitSquareConverter.stringToDouble(""), 0);
assertEquals(0, BitSquareConverter.stringToDouble(""), 0);
assertEquals(0, BitSquareConverter.stringToDouble("."), 0);
assertEquals(0, BitSquareConverter.stringToDouble(","), 0);
assertEquals(0, BitSquareConverter.stringToDouble("a"), 0);
assertEquals(0, BitSquareFormatter.parseToDouble("1,000.2"), 0);
assertEquals(0, BitSquareFormatter.parseToDouble("1,000.2"), 0);
assertEquals(0, BitSquareFormatter.parseToDouble(null), 0);
assertEquals(0, BitSquareFormatter.parseToDouble(""), 0);
assertEquals(0, BitSquareFormatter.parseToDouble(""), 0);
assertEquals(0, BitSquareFormatter.parseToDouble("."), 0);
assertEquals(0, BitSquareFormatter.parseToDouble(","), 0);
assertEquals(0, BitSquareFormatter.parseToDouble("a"), 0);
}
}

View File

@ -5,7 +5,7 @@ import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class BitSquareValidatorTest
public class BitSquareNumberValidatorTest
{
@Test
public void testValidateStringAsDouble()

View File

@ -0,0 +1,35 @@
package io.bitsquare.gui.util;
import com.google.bitcoin.core.Coin;
import com.google.bitcoin.core.NetworkParameters;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class BtcValidatorTest
{
@Test
public void testValidate()
{
BtcValidator validator = new BtcValidator();
NumberValidator.ValidationResult validationResult;
// invalid cases
validationResult = validator.validate("0.000000011");// minBtc is "0.00000001"
assertFalse(validationResult.isValid);
validationResult = validator.validate("21000001"); //maxBtc is "21000000"
assertFalse(validationResult.isValid);
// valid cases
String minBtc = Coin.SATOSHI.toPlainString(); // "0.00000001"
validationResult = validator.validate(minBtc);
assertTrue(validationResult.isValid);
String maxBtc = Coin.valueOf(NetworkParameters.MAX_MONEY.longValue()).toPlainString(); //"21000000"
validationResult = validator.validate(maxBtc);
assertTrue(validationResult.isValid);
}
}

View File

@ -0,0 +1,88 @@
package io.bitsquare.gui.util;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class FiatValidatorTest
{
@Test
public void testValidate()
{
FiatValidator validator = new FiatValidator();
NumberValidator.ValidationResult validationResult;
// invalid cases
validationResult = validator.validate(null);
assertFalse(validationResult.isValid);
validationResult = validator.validate("");
assertFalse(validationResult.isValid);
validationResult = validator.validate("0");
assertFalse(validationResult.isValid);
validationResult = validator.validate("-1");
assertFalse(validationResult.isValid);
validationResult = validator.validate("a");
assertFalse(validationResult.isValid);
validationResult = validator.validate("2a");
assertFalse(validationResult.isValid);
validationResult = validator.validate("a2");
assertFalse(validationResult.isValid);
// at the moment we dont support thousand separators, can be added later
validationResult = validator.validate("1,100.1");
assertFalse(validationResult.isValid);
// at the moment we dont support thousand separators, can be added later
validationResult = validator.validate("1.100,1");
assertFalse(validationResult.isValid);
validationResult = validator.validate("1.100.1");
assertFalse(validationResult.isValid);
validationResult = validator.validate("1,100,1");
assertFalse(validationResult.isValid);
validationResult = validator.validate(String.valueOf(FiatValidator.MIN_FIAT_VALUE - 0.0000001));
assertFalse(validationResult.isValid);
validationResult = validator.validate(String.valueOf(FiatValidator.MAX_FIAT_VALUE + 0.0000001));
assertFalse(validationResult.isValid);
validationResult = validator.validate(String.valueOf(Double.MIN_VALUE));
assertFalse(validationResult.isValid);
validationResult = validator.validate(String.valueOf(Double.MAX_VALUE));
assertFalse(validationResult.isValid);
// valid cases
validationResult = validator.validate("1");
assertTrue(validationResult.isValid);
validationResult = validator.validate("0,1");
assertTrue(validationResult.isValid);
validationResult = validator.validate("0.1");
assertTrue(validationResult.isValid);
validationResult = validator.validate(",1");
assertTrue(validationResult.isValid);
validationResult = validator.validate(".1");
assertTrue(validationResult.isValid);
validationResult = validator.validate(String.valueOf(FiatValidator.MIN_FIAT_VALUE));
assertTrue(validationResult.isValid);
validationResult = validator.validate(String.valueOf(FiatValidator.MAX_FIAT_VALUE));
assertTrue(validationResult.isValid);
}
}