/* * This file is part of Bitsquare. * * Bitsquare is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * * Bitsquare is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. */ package io.bitsquare.gui.components.paymentmethods; import io.bitsquare.gui.components.InputTextField; import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.Layout; import io.bitsquare.gui.util.validation.BICValidator; import io.bitsquare.gui.util.validation.IBANValidator; import io.bitsquare.gui.util.validation.InputValidator; import io.bitsquare.locale.*; import io.bitsquare.payment.*; import javafx.collections.FXCollections; import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.geometry.VPos; import javafx.scene.control.*; import javafx.scene.layout.FlowPane; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.text.TextAlignment; import javafx.util.StringConverter; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; import static io.bitsquare.gui.util.FormBuilder.*; public class SepaForm extends PaymentMethodForm { private static final Logger log = LoggerFactory.getLogger(SepaForm.class); private final SepaAccount sepaAccount; private final IBANValidator ibanValidator; private final BICValidator bicValidator; private InputTextField ibanInputTextField; private InputTextField bicInputTextField; private TextField currencyTextField; private final List<CheckBox> euroCountryCheckBoxes = new ArrayList<>(); private final List<CheckBox> nonEuroCountryCheckBoxes = new ArrayList<>(); private ComboBox<TradeCurrency> currencyComboBox; public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountContractData paymentAccountContractData) { SepaAccountContractData sepaAccountContractData = (SepaAccountContractData) paymentAccountContractData; addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Account holder name:", sepaAccountContractData.getHolderName()); addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "Country of bank:", CountryUtil.getNameAndCode(sepaAccountContractData.getCountryCode())); addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "IBAN:", sepaAccountContractData.getIban()); addLabelTextFieldWithCopyIcon(gridPane, ++gridRow, "BIC:", sepaAccountContractData.getBic()); return gridRow; } public SepaForm(PaymentAccount paymentAccount, IBANValidator ibanValidator, BICValidator bicValidator, InputValidator inputValidator, GridPane gridPane, int gridRow, BSFormatter formatter) { super(paymentAccount, inputValidator, gridPane, gridRow, formatter); this.sepaAccount = (SepaAccount) paymentAccount; this.ibanValidator = ibanValidator; this.bicValidator = bicValidator; } @Override public void addFormForAddAccount() { gridRowFrom = gridRow + 1; InputTextField holderNameInputTextField = addLabelInputTextField(gridPane, ++gridRow, "Account holder name:").second; holderNameInputTextField.setValidator(inputValidator); holderNameInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { sepaAccount.setHolderName(newValue); updateFromInputs(); }); ibanInputTextField = addLabelInputTextField(gridPane, ++gridRow, "IBAN:").second; ibanInputTextField.setValidator(ibanValidator); ibanInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { sepaAccount.setIban(newValue); updateFromInputs(); }); bicInputTextField = addLabelInputTextField(gridPane, ++gridRow, "BIC:").second; bicInputTextField.setValidator(bicValidator); bicInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { sepaAccount.setBic(newValue); updateFromInputs(); }); addLabel(gridPane, ++gridRow, "Country of bank:"); HBox hBox = new HBox(); hBox.setSpacing(10); ComboBox<Country> countryComboBox = new ComboBox<>(); currencyComboBox = new ComboBox<>(); currencyTextField = new TextField(""); currencyTextField.setEditable(false); currencyTextField.setMouseTransparent(true); currencyTextField.setFocusTraversable(false); currencyTextField.setMinWidth(300); currencyTextField.setVisible(false); currencyTextField.setManaged(false); currencyComboBox.setVisible(false); currencyComboBox.setManaged(false); hBox.getChildren().addAll(countryComboBox, currencyTextField, currencyComboBox); GridPane.setRowIndex(hBox, gridRow); GridPane.setColumnIndex(hBox, 1); gridPane.getChildren().add(hBox); countryComboBox.setPromptText("Select country of bank"); countryComboBox.setConverter(new StringConverter<Country>() { @Override public String toString(Country country) { return country.name + " (" + country.code + ")"; } @Override public Country fromString(String s) { return null; } }); countryComboBox.setOnAction(e -> { Country selectedItem = countryComboBox.getSelectionModel().getSelectedItem(); sepaAccount.setCountry(selectedItem); TradeCurrency currency = CurrencyUtil.getCurrencyByCountryCode(selectedItem.code); setupCurrency(selectedItem, currency); updateCountriesSelection(true, euroCountryCheckBoxes); updateCountriesSelection(true, nonEuroCountryCheckBoxes); updateFromInputs(); }); addEuroCountriesGrid(true); addNonEuroCountriesGrid(true); addAllowedPeriod(); addAccountNameTextFieldWithAutoFillCheckBox(); countryComboBox.setItems(FXCollections.observableArrayList(CountryUtil.getAllSepaCountries())); Country country = CountryUtil.getDefaultCountry(); if (CountryUtil.getAllSepaCountries().contains(country)) { countryComboBox.getSelectionModel().select(country); sepaAccount.setCountry(country); TradeCurrency currency = CurrencyUtil.getCurrencyByCountryCode(country.code); setupCurrency(country, currency); } updateFromInputs(); } private void setupCurrency(Country country, TradeCurrency currency) { if (CountryUtil.getAllSepaEuroCountries().contains(country)) { currencyTextField.setVisible(true); currencyTextField.setManaged(true); currencyComboBox.setVisible(false); currencyComboBox.setManaged(false); sepaAccount.setSingleTradeCurrency(currency); currencyTextField.setText("Currency: " + currency.getNameAndCode()); } else { currencyComboBox.setVisible(true); currencyComboBox.setManaged(true); currencyTextField.setVisible(false); currencyTextField.setManaged(false); currencyComboBox.setItems(FXCollections.observableArrayList(currency, CurrencyUtil.getFiatCurrency("EUR").get())); currencyComboBox.setOnAction(e2 -> { sepaAccount.setSingleTradeCurrency(currencyComboBox.getSelectionModel().getSelectedItem()); updateCountriesSelection(true, euroCountryCheckBoxes); autoFillNameTextField(); }); currencyComboBox.setConverter(new StringConverter<TradeCurrency>() { @Override public String toString(TradeCurrency currency) { return currency.getNameAndCode(); } @Override public TradeCurrency fromString(String string) { return null; } }); currencyComboBox.getSelectionModel().select(0); } } private void addEuroCountriesGrid(boolean isEditable) { addCountriesGrid(isEditable, "Accept trades from these Euro countries:", euroCountryCheckBoxes, CountryUtil.getAllSepaEuroCountries()); } private void addNonEuroCountriesGrid(boolean isEditable) { addCountriesGrid(isEditable, "Accept trades from these non-Euro countries:", nonEuroCountryCheckBoxes, CountryUtil.getAllSepaNonEuroCountries()); } private void addCountriesGrid(boolean isEditable, String title, List<CheckBox> checkBoxList, List<Country> dataProvider) { Label label = addLabel(gridPane, ++gridRow, title, 0); label.setWrapText(true); label.setMaxWidth(180); label.setTextAlignment(TextAlignment.RIGHT); GridPane.setHalignment(label, HPos.RIGHT); GridPane.setValignment(label, VPos.TOP); FlowPane flowPane = new FlowPane(); flowPane.setPadding(new Insets(10, 10, 10, 10)); flowPane.setVgap(10); flowPane.setHgap(10); flowPane.setMinHeight(55); if (isEditable) flowPane.setId("flow-pane-checkboxes-bg"); else flowPane.setId("flow-pane-checkboxes-non-editable-bg"); dataProvider.stream().forEach(country -> { final String countryCode = country.code; CheckBox checkBox = new CheckBox(countryCode); checkBox.setUserData(countryCode); checkBoxList.add(checkBox); checkBox.setMouseTransparent(!isEditable); checkBox.setMinWidth(45); checkBox.setMaxWidth(45); checkBox.setTooltip(new Tooltip(country.name)); checkBox.setOnAction(event -> { if (checkBox.isSelected()) sepaAccount.addAcceptedCountry(countryCode); else sepaAccount.removeAcceptedCountry(countryCode); updateAllInputsValid(); }); flowPane.getChildren().add(checkBox); }); updateCountriesSelection(isEditable, checkBoxList); GridPane.setRowIndex(flowPane, gridRow); GridPane.setColumnIndex(flowPane, 1); gridPane.getChildren().add(flowPane); } private void updateCountriesSelection(boolean isEditable, List<CheckBox> checkBoxList) { checkBoxList.stream().forEach(checkBox -> { String countryCode = (String) checkBox.getUserData(); TradeCurrency selectedCurrency = sepaAccount.getSelectedTradeCurrency(); if (selectedCurrency == null) { Country country = CountryUtil.getDefaultCountry(); if (CountryUtil.getAllSepaCountries().contains(country)) selectedCurrency = CurrencyUtil.getCurrencyByCountryCode(country.code); } boolean selected; if (isEditable && selectedCurrency != null) { selected = CurrencyUtil.getCurrencyByCountryCode(countryCode).getCode().equals(selectedCurrency.getCode()); if (selected) sepaAccount.addAcceptedCountry(countryCode); else sepaAccount.removeAcceptedCountry(countryCode); } else { selected = sepaAccount.getAcceptedCountryCodes().contains(countryCode); } checkBox.setSelected(selected); }); } @Override protected void autoFillNameTextField() { if (useCustomAccountNameCheckBox != null && !useCustomAccountNameCheckBox.isSelected()) { String iban = ibanInputTextField.getText(); if (iban.length() > 9) iban = StringUtils.abbreviate(iban, 9); String method = BSResources.get(paymentAccount.getPaymentMethod().getId()); CountryBasedPaymentAccount countryBasedPaymentAccount = (CountryBasedPaymentAccount) this.paymentAccount; String country = countryBasedPaymentAccount.getCountry() != null ? countryBasedPaymentAccount.getCountry().code : "?"; String currency = this.paymentAccount.getSingleTradeCurrency() != null ? this.paymentAccount.getSingleTradeCurrency().getCode() : "?"; accountNameTextField.setText(method.concat(" (").concat(currency).concat("/").concat(country).concat("): ").concat(iban)); } } @Override public void updateAllInputsValid() { allInputsValid.set(isAccountNameValid() && bicValidator.validate(sepaAccount.getBic()).isValid && ibanValidator.validate(sepaAccount.getIban()).isValid && inputValidator.validate(sepaAccount.getHolderName()).isValid && sepaAccount.getAcceptedCountryCodes().size() > 0 && sepaAccount.getSingleTradeCurrency() != null && sepaAccount.getCountry() != null); } @Override public void addFormForDisplayAccount() { gridRowFrom = gridRow; addLabelTextField(gridPane, gridRow, "Account name:", sepaAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE); addLabelTextField(gridPane, ++gridRow, "Payment method:", BSResources.get(sepaAccount.getPaymentMethod().getId())); addLabelTextField(gridPane, ++gridRow, "Account holder name:", sepaAccount.getHolderName()); addLabelTextField(gridPane, ++gridRow, "IBAN:", sepaAccount.getIban()).second.setMouseTransparent(false); addLabelTextField(gridPane, ++gridRow, "BIC:", sepaAccount.getBic()).second.setMouseTransparent(false); addLabelTextField(gridPane, ++gridRow, "Country of Bank:", sepaAccount.getCountry() != null ? sepaAccount.getCountry().name : ""); addLabelTextField(gridPane, ++gridRow, "Currency:", sepaAccount.getSingleTradeCurrency().getNameAndCode()); String countries; Tooltip tooltip = null; if (CountryUtil.containsAllSepaEuroCountries(sepaAccount.getAcceptedCountryCodes())) { countries = "All Euro countries"; } else { countries = CountryUtil.getCodesString(sepaAccount.getAcceptedCountryCodes()); tooltip = new Tooltip(CountryUtil.getNamesByCodesString(sepaAccount.getAcceptedCountryCodes())); } TextField acceptedCountries = addLabelTextField(gridPane, ++gridRow, "Accepted countries:", countries).second; if (tooltip != null) { acceptedCountries.setMouseTransparent(false); acceptedCountries.setTooltip(tooltip); } addAllowedPeriod(); } }