Add check for payment accounts in use when trying to delete

This commit is contained in:
Manfred Karrer 2016-03-10 22:51:05 +01:00
parent 56008caef3
commit bab70abf9e
12 changed files with 90 additions and 28 deletions

View file

@ -47,6 +47,8 @@ import javafx.scene.image.ImageView;
import javafx.scene.layout.*; import javafx.scene.layout.*;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.text.TextAlignment; import javafx.scene.text.TextAlignment;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.monadic.MonadicBinding;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -59,6 +61,7 @@ import static javafx.scene.layout.AnchorPane.*;
public class MainView extends InitializableView<StackPane, MainViewModel> { public class MainView extends InitializableView<StackPane, MainViewModel> {
public static final String TITLE_KEY = "view.title"; public static final String TITLE_KEY = "view.title";
private MonadicBinding<String> marketPriceBinding;
public static StackPane getRootContainer() { public static StackPane getRootContainer() {
return MainView.rootContainer; return MainView.rootContainer;
@ -138,14 +141,19 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
Tuple3<TextField, Label, VBox> marketPriceBox = getMarketPriceBox("Market price"); Tuple3<TextField, Label, VBox> marketPriceBox = getMarketPriceBox("Market price");
final BooleanProperty priceInverted = new SimpleBooleanProperty(false); final BooleanProperty priceInverted = new SimpleBooleanProperty(false);
marketPriceBox.first.setOnMouseClicked(e -> priceInverted.setValue(!priceInverted.get())); marketPriceBox.first.setOnMouseClicked(e -> priceInverted.setValue(!priceInverted.get()));
marketPriceBox.first.textProperty().bind(createStringBinding( marketPriceBinding = EasyBind.combine(
() -> (priceInverted.get() ? model.marketPriceCurrency, model.marketPrice, model.marketPriceInverted, priceInverted,
model.marketPriceInverted.get() : (marketPriceCurrency, marketPrice, marketPriceInverted, inverted) ->
model.marketPrice.get()) +
(priceInverted.get() ? (priceInverted.get() ?
" BTC/" + model.marketPriceCurrency.get() : marketPriceInverted :
" " + model.marketPriceCurrency.get() + "/BTC"), marketPrice) +
model.marketPriceCurrency, model.marketPrice, priceInverted)); (priceInverted.get() ?
" BTC/" + marketPriceCurrency :
" " + marketPriceCurrency + "/BTC"));
marketPriceBinding.subscribe((observable, oldValue, newValue) -> {
marketPriceBox.first.setText(newValue);
});
marketPriceBox.second.textProperty().bind(createStringBinding( marketPriceBox.second.textProperty().bind(createStringBinding(
() -> { () -> {

View file

@ -21,6 +21,8 @@ import com.google.inject.Inject;
import io.bitsquare.gui.common.model.ActivatableDataModel; import io.bitsquare.gui.common.model.ActivatableDataModel;
import io.bitsquare.payment.PaymentAccount; import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.PaymentMethod; import io.bitsquare.payment.PaymentMethod;
import io.bitsquare.trade.TradeManager;
import io.bitsquare.trade.offer.OpenOfferManager;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@ -31,12 +33,16 @@ import java.util.stream.Collectors;
class AltCoinAccountsDataModel extends ActivatableDataModel { class AltCoinAccountsDataModel extends ActivatableDataModel {
private final User user; private final User user;
private final OpenOfferManager openOfferManager;
private final TradeManager tradeManager;
final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList(); final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList();
private final SetChangeListener<PaymentAccount> setChangeListener; private final SetChangeListener<PaymentAccount> setChangeListener;
@Inject @Inject
public AltCoinAccountsDataModel(User user) { public AltCoinAccountsDataModel(User user, OpenOfferManager openOfferManager, TradeManager tradeManager) {
this.user = user; this.user = user;
this.openOfferManager = openOfferManager;
this.tradeManager = tradeManager;
setChangeListener = change -> fillAndSortPaymentAccounts(); setChangeListener = change -> fillAndSortPaymentAccounts();
} }
@ -67,8 +73,20 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
user.addPaymentAccount(paymentAccount); user.addPaymentAccount(paymentAccount);
} }
public void onDeleteAccount(PaymentAccount paymentAccount) {
public boolean onDeleteAccount(PaymentAccount paymentAccount) {
boolean isPaymentAccountUsed = openOfferManager.getOpenOffers().stream()
.filter(o -> o.getOffer().getOffererPaymentAccountId().equals(paymentAccount.getId()))
.findAny()
.isPresent();
isPaymentAccountUsed = isPaymentAccountUsed || tradeManager.getTrades().stream()
.filter(t -> t.getOffer().getOffererPaymentAccountId().equals(paymentAccount.getId()) ||
t.getTakerPaymentAccountId().equals(paymentAccount.getId()))
.findAny()
.isPresent();
if (!isPaymentAccountUsed)
user.removePaymentAccount(paymentAccount); user.removePaymentAccount(paymentAccount);
return isPaymentAccountUsed;
} }
public void onSelectAccount(PaymentAccount paymentAccount) { public void onSelectAccount(PaymentAccount paymentAccount) {

View file

@ -17,6 +17,7 @@
package io.bitsquare.gui.main.account.content.altcoinaccounts; package io.bitsquare.gui.main.account.content.altcoinaccounts;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple2;
import io.bitsquare.gui.common.view.ActivatableViewAndModel; import io.bitsquare.gui.common.view.ActivatableViewAndModel;
import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.common.view.FxmlView;
@ -44,6 +45,7 @@ import javafx.scene.layout.GridPane;
import javafx.util.Callback; import javafx.util.Callback;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.concurrent.TimeUnit;
import static io.bitsquare.gui.util.FormBuilder.*; import static io.bitsquare.gui.util.FormBuilder.*;
@ -143,8 +145,14 @@ public class AltCoinAccountsView extends ActivatableViewAndModel<GridPane, AltCo
new Popup().warning("Do you really want to delete the selected account?") new Popup().warning("Do you really want to delete the selected account?")
.actionButtonText("Yes") .actionButtonText("Yes")
.onAction(() -> { .onAction(() -> {
model.onDeleteAccount(paymentAccount); boolean isPaymentAccountUsed = model.onDeleteAccount(paymentAccount);
if (!isPaymentAccountUsed)
removeSelectAccountForm(); removeSelectAccountForm();
else
UserThread.runAfter(() -> {
new Popup().warning("You cannot delete that account because it is used in an " +
"open offer or in a trade.").show();
}, 100, TimeUnit.MILLISECONDS);
}) })
.closeButtonText("Cancel") .closeButtonText("Cancel")
.show(); .show();

View file

@ -72,8 +72,8 @@ class AltCoinAccountsViewModel extends ActivatableWithDataModel<AltCoinAccountsD
} }
} }
public void onDeleteAccount(PaymentAccount paymentAccount) { public boolean onDeleteAccount(PaymentAccount paymentAccount) {
dataModel.onDeleteAccount(paymentAccount); return dataModel.onDeleteAccount(paymentAccount);
} }
public void onSelectAccount(PaymentAccount paymentAccount) { public void onSelectAccount(PaymentAccount paymentAccount) {

View file

@ -24,6 +24,8 @@ import io.bitsquare.locale.FiatCurrency;
import io.bitsquare.locale.TradeCurrency; import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.payment.PaymentAccount; import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.payment.PaymentMethod; import io.bitsquare.payment.PaymentMethod;
import io.bitsquare.trade.TradeManager;
import io.bitsquare.trade.offer.OpenOfferManager;
import io.bitsquare.user.Preferences; import io.bitsquare.user.Preferences;
import io.bitsquare.user.User; import io.bitsquare.user.User;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
@ -37,13 +39,17 @@ class FiatAccountsDataModel extends ActivatableDataModel {
private final User user; private final User user;
private Preferences preferences; private Preferences preferences;
private final OpenOfferManager openOfferManager;
private final TradeManager tradeManager;
final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList(); final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList();
private final SetChangeListener<PaymentAccount> setChangeListener; private final SetChangeListener<PaymentAccount> setChangeListener;
@Inject @Inject
public FiatAccountsDataModel(User user, Preferences preferences) { public FiatAccountsDataModel(User user, Preferences preferences, OpenOfferManager openOfferManager, TradeManager tradeManager) {
this.user = user; this.user = user;
this.preferences = preferences; this.preferences = preferences;
this.openOfferManager = openOfferManager;
this.tradeManager = tradeManager;
setChangeListener = change -> fillAndSortPaymentAccounts(); setChangeListener = change -> fillAndSortPaymentAccounts();
} }
@ -90,8 +96,19 @@ class FiatAccountsDataModel extends ActivatableDataModel {
} }
} }
public void onDeleteAccount(PaymentAccount paymentAccount) { public boolean onDeleteAccount(PaymentAccount paymentAccount) {
boolean isPaymentAccountUsed = openOfferManager.getOpenOffers().stream()
.filter(o -> o.getOffer().getOffererPaymentAccountId().equals(paymentAccount.getId()))
.findAny()
.isPresent();
isPaymentAccountUsed = isPaymentAccountUsed || tradeManager.getTrades().stream()
.filter(t -> t.getOffer().getOffererPaymentAccountId().equals(paymentAccount.getId()) ||
t.getTakerPaymentAccountId().equals(paymentAccount.getId()))
.findAny()
.isPresent();
if (!isPaymentAccountUsed)
user.removePaymentAccount(paymentAccount); user.removePaymentAccount(paymentAccount);
return isPaymentAccountUsed;
} }
public void onSelectAccount(PaymentAccount paymentAccount) { public void onSelectAccount(PaymentAccount paymentAccount) {

View file

@ -17,6 +17,7 @@
package io.bitsquare.gui.main.account.content.fiataccounts; package io.bitsquare.gui.main.account.content.fiataccounts;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple2;
import io.bitsquare.gui.common.view.ActivatableViewAndModel; import io.bitsquare.gui.common.view.ActivatableViewAndModel;
import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.common.view.FxmlView;
@ -45,6 +46,7 @@ import javafx.util.StringConverter;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static io.bitsquare.gui.util.FormBuilder.*; import static io.bitsquare.gui.util.FormBuilder.*;
@ -146,8 +148,14 @@ public class FiatAccountsView extends ActivatableViewAndModel<GridPane, FiatAcco
new Popup().warning("Do you really want to delete the selected account?") new Popup().warning("Do you really want to delete the selected account?")
.actionButtonText("Yes") .actionButtonText("Yes")
.onAction(() -> { .onAction(() -> {
model.onDeleteAccount(paymentAccount); boolean isPaymentAccountUsed = model.onDeleteAccount(paymentAccount);
if (!isPaymentAccountUsed)
removeSelectAccountForm(); removeSelectAccountForm();
else
UserThread.runAfter(() -> {
new Popup().warning("You cannot delete that account because it is used in an " +
"open offer or in a trade.").show();
}, 100, TimeUnit.MILLISECONDS);
}) })
.closeButtonText("Cancel") .closeButtonText("Cancel")
.show(); .show();

View file

@ -48,8 +48,8 @@ class FiatAccountsViewModel extends ActivatableWithDataModel<FiatAccountsDataMod
dataModel.onSaveNewAccount(paymentAccount); dataModel.onSaveNewAccount(paymentAccount);
} }
public void onDeleteAccount(PaymentAccount paymentAccount) { public boolean onDeleteAccount(PaymentAccount paymentAccount) {
dataModel.onDeleteAccount(paymentAccount); return dataModel.onDeleteAccount(paymentAccount);
} }
public void onSelectAccount(PaymentAccount paymentAccount) { public void onSelectAccount(PaymentAccount paymentAccount) {

View file

@ -550,7 +550,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
button.setOnAction(e -> onTakeOffer(offer)); button.setOnAction(e -> onTakeOffer(offer));
} }
if (!isTradable) if (!myOffer && !isTradable)
button.setOnAction(e -> onShowInfo(isPaymentAccountValidForOffer, hasMatchingArbitrator, hasSameProtocolVersion)); button.setOnAction(e -> onShowInfo(isPaymentAccountValidForOffer, hasMatchingArbitrator, hasSameProtocolVersion));
button.setText(title); button.setText(title);

View file

@ -149,9 +149,11 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
addTitledGroupBg(gridPane, ++rowIndex, rows, "Offer"); addTitledGroupBg(gridPane, ++rowIndex, rows, "Offer");
if (takeOfferHandlerOptional.isPresent()) if (takeOfferHandlerOptional.isPresent())
addLabelTextField(gridPane, rowIndex, "Offer type:", formatter.getDirectionForTaker(offer.getDirection()), Layout.FIRST_ROW_DISTANCE); addLabelTextField(gridPane, rowIndex, "Offer type:", formatter.getDirectionForTakeOffer(offer.getDirection()), Layout.FIRST_ROW_DISTANCE);
else if (placeOfferHandlerOptional.isPresent())
addLabelTextField(gridPane, rowIndex, "Offer type:", formatter.getOfferDirectionForCreateOffer(offer.getDirection()), Layout.FIRST_ROW_DISTANCE);
else else
addLabelTextField(gridPane, rowIndex, "Offer type:", formatter.getOfferDirectionForOfferer(offer.getDirection()), Layout.FIRST_ROW_DISTANCE); addLabelTextField(gridPane, rowIndex, "Offer type:", formatter.getDirectionBothSides(offer.getDirection()), Layout.FIRST_ROW_DISTANCE);
if (takeOfferHandlerOptional.isPresent()) { if (takeOfferHandlerOptional.isPresent()) {
addLabelTextField(gridPane, ++rowIndex, "Trade amount:", formatter.formatCoinWithCode(tradeAmount)); addLabelTextField(gridPane, ++rowIndex, "Trade amount:", formatter.formatCoinWithCode(tradeAmount));

View file

@ -230,7 +230,8 @@ public class SellerStep3View extends TradeStepView {
if (preferences.showAgain(key)) { if (preferences.showAgain(key)) {
new Popup() new Popup()
.headLine("Confirm that you have received the payment") .headLine("Confirm that you have received the payment")
.confirmation("Have you received the " + model.dataModel.getCurrencyCode() + " payment from your trading partner?\n\n" + .confirmation("Have you received the " + CurrencyUtil.getNameByCode(model.dataModel.getCurrencyCode()) +
" payment from your trading partner?\n\n" +
"Please note that as soon you have confirmed the receipt, the locked trade amount will be released " + "Please note that as soon you have confirmed the receipt, the locked trade amount will be released " +
"to the bitcoin buyer and the security deposit will be refunded.") "to the bitcoin buyer and the security deposit will be refunded.")
.width(700) .width(700)

View file

@ -409,12 +409,12 @@ public class BSFormatter {
"You are selling bitcoin as taker / Offerer is buying bitcoin"; "You are selling bitcoin as taker / Offerer is buying bitcoin";
} }
public String getDirectionForTaker(Offer.Direction direction) { public String getDirectionForTakeOffer(Offer.Direction direction) {
return direction == Offer.Direction.BUY ? "You are selling bitcoin (by taking an offer from someone who wants to buy bitcoin)" : return direction == Offer.Direction.BUY ? "You are selling bitcoin (by taking an offer from someone who wants to buy bitcoin)" :
"You are buying bitcoin (by taking an offer from someone who wants to sell bitcoin)"; "You are buying bitcoin (by taking an offer from someone who wants to sell bitcoin)";
} }
public String getOfferDirectionForOfferer(Offer.Direction direction) { public String getOfferDirectionForCreateOffer(Offer.Direction direction) {
return direction == Offer.Direction.BUY ? "You are creating an offer for buying bitcoin" : return direction == Offer.Direction.BUY ? "You are creating an offer for buying bitcoin" :
"You are creating an offer for selling bitcoin"; "You are creating an offer for selling bitcoin";
} }