Handle views for trade process

This commit is contained in:
Manfred Karrer 2015-04-03 16:51:36 +02:00
parent 3a95e51bc9
commit a2aa0b40b4
18 changed files with 273 additions and 296 deletions

View file

@ -61,14 +61,7 @@ public class TaskRunner<T extends Model> {
try { try {
currentTask = tasks.poll(); currentTask = tasks.poll();
log.trace("Run task: " + currentTask.getSimpleName()); log.trace("Run task: " + currentTask.getSimpleName());
log.debug("sharedModel.getClass() " + sharedModel.getClass()); // We use also super class as type ein tasks, so we need to support both variants
log.debug("sharedModel.getClass().getSuperclass() " + sharedModel.getClass().getSuperclass());
/* Object c = currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass());
log.debug("c " + c);
Object c2 = currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass().getSuperclass());
log.debug("c getSuperclass " + c2);
Object o = currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass()).newInstance(this, sharedModel);*/
//TODO solve in tasks problem with superclasses
try { try {
currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass()).newInstance(this, sharedModel).run(); currentTask.getDeclaredConstructor(TaskRunner.class, sharedModel.getClass()).newInstance(this, sharedModel).run();
} catch (Throwable throwable) { } catch (Throwable throwable) {

View file

@ -79,8 +79,11 @@ public class BuyerSubView extends TradeSubView {
waitFiatReceived.inactive(); waitFiatReceived.inactive();
completed.inactive(); completed.inactive();
if (tradeStepDetailsView != null)
tradeStepDetailsView.deactivate();
switch (viewState) { switch (viewState) {
case EMPTY: case UNDEFINED:
break; break;
case BUYER_WAIT_TX_CONF: case BUYER_WAIT_TX_CONF:
showItem(waitTxInBlockchain); showItem(waitTxInBlockchain);

View file

@ -0,0 +1,30 @@
/*
* 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.main.portfolio.pending;
// That is used if trade is null but must not be null in that state
public class MissingTradeException extends RuntimeException {
public MissingTradeException(String msg) {
super(msg);
}
public MissingTradeException() {
super("Trade is null.That must not happen.");
}
}

View file

@ -0,0 +1,30 @@
/*
* 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.main.portfolio.pending;
// That is used if trade is null and it is a valid state
public class NoTradeFoundException extends Throwable {
public NoTradeFoundException(String msg) {
super(msg);
}
public NoTradeFoundException() {
super("Trade is null");
}
}

View file

@ -21,7 +21,11 @@ import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.common.viewfx.model.Activatable; import io.bitsquare.common.viewfx.model.Activatable;
import io.bitsquare.common.viewfx.model.DataModel; import io.bitsquare.common.viewfx.model.DataModel;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.components.Popups; import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.portfolio.PortfolioView;
import io.bitsquare.gui.main.portfolio.closed.ClosedTradesView;
import io.bitsquare.offer.Offer; import io.bitsquare.offer.Offer;
import io.bitsquare.trade.BuyerTrade; import io.bitsquare.trade.BuyerTrade;
import io.bitsquare.trade.Contract; import io.bitsquare.trade.Contract;
@ -37,9 +41,8 @@ import com.google.inject.Inject;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javafx.beans.property.IntegerProperty; import javafx.application.Platform;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
@ -56,6 +59,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
private final TradeManager tradeManager; private final TradeManager tradeManager;
private final WalletService walletService; private final WalletService walletService;
private final User user; private final User user;
private Navigation navigation;
private final ObservableList<PendingTradesListItem> list = FXCollections.observableArrayList(); private final ObservableList<PendingTradesListItem> list = FXCollections.observableArrayList();
@ -65,7 +69,6 @@ class PendingTradesDataModel implements Activatable, DataModel {
private final ListChangeListener<Trade> tradesListChangeListener; private final ListChangeListener<Trade> tradesListChangeListener;
final StringProperty txId = new SimpleStringProperty(); final StringProperty txId = new SimpleStringProperty();
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1);
final ObjectProperty<TradeState.ProcessState> sellerProcessState = new SimpleObjectProperty<>(); final ObjectProperty<TradeState.ProcessState> sellerProcessState = new SimpleObjectProperty<>();
final ObjectProperty<TradeState.ProcessState> buyerProcessState = new SimpleObjectProperty<>(); final ObjectProperty<TradeState.ProcessState> buyerProcessState = new SimpleObjectProperty<>();
@ -73,23 +76,19 @@ class PendingTradesDataModel implements Activatable, DataModel {
final ObjectProperty<Trade> currentTrade = new SimpleObjectProperty<>(); final ObjectProperty<Trade> currentTrade = new SimpleObjectProperty<>();
@Inject @Inject
public PendingTradesDataModel(TradeManager tradeManager, WalletService walletService, User user) { public PendingTradesDataModel(TradeManager tradeManager, WalletService walletService, User user, Navigation navigation) {
this.tradeManager = tradeManager; this.tradeManager = tradeManager;
this.walletService = walletService; this.walletService = walletService;
this.user = user; this.user = user;
this.navigation = navigation;
tradesListChangeListener = change -> onListChanged(); tradesListChangeListener = change -> onListChanged();
} }
@Override @Override
public void activate() { public void activate() {
onListChanged();
tradeManager.getPendingTrades().addListener(tradesListChangeListener); tradeManager.getPendingTrades().addListener(tradesListChangeListener);
onListChanged();
if (list.size() > 0) {
selectTrade(list.get(0));
selectedIndex.set(0);
}
} }
@Override @Override
@ -105,20 +104,22 @@ class PendingTradesDataModel implements Activatable, DataModel {
// we sort by date, earliest first // we sort by date, earliest first
list.sort((o1, o2) -> o2.getTrade().getDate().compareTo(o1.getTrade().getDate())); list.sort((o1, o2) -> o2.getTrade().getDate().compareTo(o1.getTrade().getDate()));
if (list.size() > 0) { log.debug("onListChanged {}", list.size());
if (list.size() > 0)
selectTrade(list.get(0)); selectTrade(list.get(0));
selectedIndex.set(0); else if (list.size() == 0)
} selectTrade(null);
} }
boolean isBuyOffer() { boolean isBuyOffer() throws NoTradeFoundException {
if (getTrade() != null) if (getTrade() != null)
return getTrade().getOffer().getDirection() == Offer.Direction.BUY; return getTrade().getOffer().getDirection() == Offer.Direction.BUY;
else else
return false; throw new NoTradeFoundException();
} }
void selectTrade(PendingTradesListItem item) { void selectTrade(PendingTradesListItem item) {
log.debug("selectTrade {} {}", item != null, item != null ? item.getTrade().getId() : "null");
// clean up previous selectedItem // clean up previous selectedItem
unbindStates(); unbindStates();
@ -144,52 +145,67 @@ class PendingTradesDataModel implements Activatable, DataModel {
} }
void fiatPaymentStarted() { void fiatPaymentStarted() {
if (getTrade() instanceof BuyerTrade) try {
((BuyerTrade) getTrade()).onFiatPaymentStarted(); if (getTrade() instanceof BuyerTrade)
((BuyerTrade) getTrade()).onFiatPaymentStarted();
} catch (NoTradeFoundException e) {
throw new MissingTradeException();
}
} }
void fiatPaymentReceived() { void fiatPaymentReceived() {
if (getTrade() instanceof SellerTrade) try {
((SellerTrade) getTrade()).onFiatPaymentReceived(); if (getTrade() instanceof SellerTrade)
((SellerTrade) getTrade()).onFiatPaymentReceived();
} catch (NoTradeFoundException e) {
throw new MissingTradeException();
}
} }
void withdraw(String toAddress) { void withdraw(String toAddress) {
if (getTrade() != null) { try {
tradeManager.requestWithdraw(toAddress, if (getTrade() != null) {
getTrade(), tradeManager.requestWithdraw(toAddress,
() -> log.debug("requestWithdraw was successful"), getTrade(),
(errorMessage, throwable) -> { () -> {
log.error(errorMessage); log.debug("requestWithdraw was successful");
Popups.openExceptionPopup(throwable); Platform.runLater(() -> navigation.navigateTo(MainView.class, PortfolioView.class, ClosedTradesView.class));
}); },
(errorMessage, throwable) -> {
log.error(errorMessage);
/* Popups.openExceptionPopup(throwable);
Action response = Popups.openConfirmPopup( });
"Withdrawal request", "Confirm your request",
"Your withdrawal request:\n\n" + "Amount: " + amountTextField.getText() + " BTC\n" + "Sending" +
" address: " + withdrawFromTextField.getText() + "\n" + "Receiving address: " + /*
withdrawToTextField.getText() + "\n" + "Transaction fee: " + Action response = Popups.openConfirmPopup(
formatter.formatCoinWithCode(FeePolicy.TX_FEE) + "\n" + "Withdrawal request", "Confirm your request",
"You receive in total: " + "Your withdrawal request:\n\n" + "Amount: " + amountTextField.getText() + " BTC\n" + "Sending" +
formatter.formatCoinWithCode(amount.subtract(FeePolicy.TX_FEE)) + " BTC\n\n" + " address: " + withdrawFromTextField.getText() + "\n" + "Receiving address: " +
"Are you sure you withdraw that amount?"); withdrawToTextField.getText() + "\n" + "Transaction fee: " +
formatter.formatCoinWithCode(FeePolicy.TX_FEE) + "\n" +
if (Popups.isOK(response)) { "You receive in total: " +
try { formatter.formatCoinWithCode(amount.subtract(FeePolicy.TX_FEE)) + " BTC\n\n" +
walletService.sendFunds( "Are you sure you withdraw that amount?");
withdrawFromTextField.getText(), withdrawToTextField.getText(),
changeAddressTextField.getText(), amount, callback); if (Popups.isOK(response)) {
} catch (AddressFormatException e) { try {
Popups.openErrorPopup("Address invalid", walletService.sendFunds(
"The address is not correct. Please check the address format."); withdrawFromTextField.getText(), withdrawToTextField.getText(),
changeAddressTextField.getText(), amount, callback);
} catch (InsufficientMoneyException e) { } catch (AddressFormatException e) {
Popups.openInsufficientMoneyPopup(); Popups.openErrorPopup("Address invalid",
} catch (IllegalArgumentException e) { "The address is not correct. Please check the address format.");
Popups.openErrorPopup("Wrong inputs", "Please check the inputs.");
} catch (InsufficientMoneyException e) {
Popups.openInsufficientMoneyPopup();
} catch (IllegalArgumentException e) {
Popups.openErrorPopup("Wrong inputs", "Please check the inputs.");
}
}*/
} }
}*/ } catch (NoTradeFoundException e) {
throw new MissingTradeException();
} }
} }
@ -223,17 +239,19 @@ class PendingTradesDataModel implements Activatable, DataModel {
} }
Throwable getTradeException() { Throwable getTradeException() {
if (getTrade() != null) try {
return getTrade().getThrowable(); return getTrade().getThrowable();
else } catch (NoTradeFoundException e) {
return null; return null;
}
} }
String getErrorMessage() { String getErrorMessage() {
if (getTrade() != null) try {
return getTrade().getErrorMessage(); return getTrade().getErrorMessage();
else } catch (NoTradeFoundException e) {
return null; return null;
}
} }
public Offer.Direction getDirection(Offer offer) { public Offer.Direction getDirection(Offer offer) {
@ -247,21 +265,26 @@ class PendingTradesDataModel implements Activatable, DataModel {
} }
public Coin getPayoutAmount() { public Coin getPayoutAmount() {
return getTrade().getPayoutAmount(); try {
return getTrade().getPayoutAmount();
} catch (NoTradeFoundException e) {
return Coin.ZERO;
}
} }
public Contract getContract() { public Contract getContract() {
if (getTrade() != null) try {
return getTrade().getContract(); return getTrade().getContract();
else } catch (NoTradeFoundException e) {
return null; throw new MissingTradeException();
}
} }
public Trade getTrade() { public Trade getTrade() throws NoTradeFoundException {
if (currentTrade.get() != null) if (currentTrade.get() != null)
return currentTrade.get(); return currentTrade.get();
else else
return null; throw new NoTradeFoundException();
} }
} }

View file

@ -20,6 +20,7 @@ package io.bitsquare.gui.main.portfolio.pending;
import io.bitsquare.common.viewfx.view.ActivatableViewAndModel; import io.bitsquare.common.viewfx.view.ActivatableViewAndModel;
import io.bitsquare.common.viewfx.view.FxmlView; import io.bitsquare.common.viewfx.view.FxmlView;
import io.bitsquare.gui.components.Popups; import io.bitsquare.gui.components.Popups;
import io.bitsquare.trade.Trade;
import io.bitsquare.util.Utilities; import io.bitsquare.util.Utilities;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
@ -30,6 +31,7 @@ import java.util.Date;
import javax.inject.Inject; import javax.inject.Inject;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@ -55,7 +57,9 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
private ChangeListener<PendingTradesListItem> selectedItemChangeListener; private ChangeListener<PendingTradesListItem> selectedItemChangeListener;
private TradeSubView currentSubView; private TradeSubView currentSubView;
private ChangeListener<Boolean> appFocusChangeListener;
private ReadOnlyBooleanProperty appFocusProperty;
private ChangeListener<Trade> currentTradeChangeListener;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, Initialisation // Constructor, Initialisation
@ -79,17 +83,43 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
table.setPlaceholder(new Label("No pending trades available")); table.setPlaceholder(new Label("No pending trades available"));
selectedItemChangeListener = (ov, oldValue, newValue) -> { selectedItemChangeListener = (ov, oldValue, newValue) -> {
log.debug("selectedItemChangeListener {}", newValue);
model.selectTrade(newValue);
if (newValue != null) if (newValue != null)
addSubView(); addSubView();
else
removeSubView();
};
model.selectTrade(newValue); appFocusChangeListener = (observable, oldValue, newValue) -> {
log.debug("appFocusChangeListener {}", newValue);
if (newValue && model.getSelectedItem() != null) {
// Focus selectedItem from model
int index = table.getItems().indexOf(model.getSelectedItem());
Platform.runLater(() -> {
table.requestFocus();
Platform.runLater(() -> table.getFocusModel().focus(index));
});
}
};
currentTradeChangeListener = (observable, oldValue, newValue) -> {
log.debug("currentTradeChangeListener {} {}", newValue, model.getList().size());
if (newValue != null)
addSubView();
else
removeSubView();
}; };
} }
@Override @Override
public void doActivate() { public void doActivate() {
appFocusProperty = root.getScene().getWindow().focusedProperty();
appFocusProperty.addListener(appFocusChangeListener);
model.currentTrade().addListener(currentTradeChangeListener);
table.setItems(model.getList()); table.setItems(model.getList());
table.getSelectionModel().selectedItemProperty().addListener(selectedItemChangeListener); table.getSelectionModel().selectedItemProperty().addListener(selectedItemChangeListener);
PendingTradesListItem selectedItem = model.getSelectedItem(); PendingTradesListItem selectedItem = model.getSelectedItem();
if (selectedItem != null) { if (selectedItem != null) {
@ -117,6 +147,9 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
if (currentSubView != null) if (currentSubView != null)
currentSubView.deactivate(); currentSubView.deactivate();
appFocusProperty.removeListener(appFocusChangeListener);
model.currentTrade().removeListener(currentTradeChangeListener);
} }
@ -125,31 +158,48 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void addSubView() { private void addSubView() {
log.debug("addSubView");
removeSubView(); removeSubView();
if (model.isOfferer()) { if (model.isOfferer()) {
if (model.isBuyOffer()) try {
currentSubView = new BuyerSubView(model); if (model.isBuyOffer())
else currentSubView = new BuyerSubView(model);
currentSubView = new SellerSubView(model); else
currentSubView = new SellerSubView(model);
} catch (NoTradeFoundException e) {
log.warn("No trade selected");
}
} }
else { else {
if (model.isBuyOffer()) try {
currentSubView = new SellerSubView(model); if (model.isBuyOffer())
else currentSubView = new SellerSubView(model);
currentSubView = new BuyerSubView(model); else
currentSubView = new BuyerSubView(model);
} catch (NoTradeFoundException e) {
log.warn("No trade selected");
}
} }
currentSubView.activate(); if (currentSubView != null) {
currentSubView.activate();
AnchorPane.setTopAnchor(currentSubView, 0d); AnchorPane.setTopAnchor(currentSubView, 0d);
AnchorPane.setRightAnchor(currentSubView, 0d); AnchorPane.setRightAnchor(currentSubView, 0d);
AnchorPane.setBottomAnchor(currentSubView, 0d); AnchorPane.setBottomAnchor(currentSubView, 0d);
AnchorPane.setLeftAnchor(currentSubView, 0d); AnchorPane.setLeftAnchor(currentSubView, 0d);
tradeStepPane.getChildren().setAll(currentSubView); tradeStepPane.getChildren().setAll(currentSubView);
log.warn("currentSubView added");
}
else {
log.warn("currentSubView=null");
}
} }
private void removeSubView() { private void removeSubView() {
log.debug("removeSubView called");
if (currentSubView != null) { if (currentSubView != null) {
log.debug("remove currentSubView");
currentSubView.deactivate(); currentSubView.deactivate();
tradeStepPane.getChildren().remove(currentSubView); tradeStepPane.getChildren().remove(currentSubView);
currentSubView = null; currentSubView = null;

View file

@ -20,13 +20,10 @@ package io.bitsquare.gui.main.portfolio.pending;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.common.viewfx.model.ActivatableWithDataModel; import io.bitsquare.common.viewfx.model.ActivatableWithDataModel;
import io.bitsquare.common.viewfx.model.ViewModel; import io.bitsquare.common.viewfx.model.ViewModel;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.portfolio.PortfolioView;
import io.bitsquare.gui.main.portfolio.closed.ClosedTradesView;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.validation.BtcAddressValidator; import io.bitsquare.gui.util.validation.BtcAddressValidator;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
import io.bitsquare.trade.Trade;
import io.bitsquare.trade.states.OffererTradeState; import io.bitsquare.trade.states.OffererTradeState;
import io.bitsquare.trade.states.TakerTradeState; import io.bitsquare.trade.states.TakerTradeState;
@ -37,13 +34,10 @@ import com.google.inject.Inject;
import java.util.Date; import java.util.Date;
import javafx.application.Platform;
import javafx.beans.InvalidationListener; import javafx.beans.InvalidationListener;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
@ -56,7 +50,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
private static final Logger log = LoggerFactory.getLogger(PendingTradesViewModel.class); private static final Logger log = LoggerFactory.getLogger(PendingTradesViewModel.class);
enum ViewState { enum ViewState {
EMPTY, UNDEFINED,
SELLER_WAIT_TX_CONF, SELLER_WAIT_TX_CONF,
SELLER_WAIT_PAYMENT_STARTED, SELLER_WAIT_PAYMENT_STARTED,
SELLER_CONFIRM_RECEIVE_PAYMENT, SELLER_CONFIRM_RECEIVE_PAYMENT,
@ -71,25 +65,22 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
EXCEPTION EXCEPTION
} }
private Navigation navigation;
private final BSFormatter formatter; private final BSFormatter formatter;
private final InvalidationListener sellerStateListener; private final InvalidationListener sellerStateListener;
private final InvalidationListener buyerStateListener; private final InvalidationListener buyerStateListener;
private final BtcAddressValidator btcAddressValidator; private final BtcAddressValidator btcAddressValidator;
public final StringProperty txId = new SimpleStringProperty(); public final StringProperty txId = new SimpleStringProperty();
public final BooleanProperty withdrawalButtonDisable = new SimpleBooleanProperty(true); public final BooleanProperty withdrawalButtonDisable = new SimpleBooleanProperty(true);
final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1); final ObjectProperty<ViewState> viewState = new SimpleObjectProperty<>(ViewState.UNDEFINED);
final ObjectProperty<ViewState> viewState = new SimpleObjectProperty<>(ViewState.EMPTY);
@Inject @Inject
public PendingTradesViewModel(PendingTradesDataModel dataModel, Navigation navigation, BSFormatter formatter, public PendingTradesViewModel(PendingTradesDataModel dataModel, BSFormatter formatter,
BtcAddressValidator btcAddressValidator) { BtcAddressValidator btcAddressValidator) {
super(dataModel); super(dataModel);
this.navigation = navigation;
this.formatter = formatter; this.formatter = formatter;
this.btcAddressValidator = btcAddressValidator; this.btcAddressValidator = btcAddressValidator;
@ -100,7 +91,6 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
@Override @Override
public void doActivate() { public void doActivate() {
txId.bind(dataModel.txId); txId.bind(dataModel.txId);
selectedIndex.bind(dataModel.selectedIndex);
dataModel.sellerProcessState.addListener(sellerStateListener); dataModel.sellerProcessState.addListener(sellerStateListener);
dataModel.buyerProcessState.addListener(buyerStateListener); dataModel.buyerProcessState.addListener(buyerStateListener);
@ -112,7 +102,6 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
@Override @Override
public void doDeactivate() { public void doDeactivate() {
txId.unbind(); txId.unbind();
selectedIndex.unbind();
dataModel.sellerProcessState.removeListener(sellerStateListener); dataModel.sellerProcessState.removeListener(sellerStateListener);
dataModel.buyerProcessState.removeListener(buyerStateListener); dataModel.buyerProcessState.removeListener(buyerStateListener);
@ -123,10 +112,13 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
dataModel.selectTrade(item); dataModel.selectTrade(item);
} }
boolean isBuyOffer() { boolean isBuyOffer() throws NoTradeFoundException {
return dataModel.isBuyOffer(); return dataModel.isBuyOffer();
} }
ObjectProperty<Trade> currentTrade() {
return dataModel.currentTrade;
}
public void fiatPaymentStarted() { public void fiatPaymentStarted() {
dataModel.fiatPaymentStarted(); dataModel.fiatPaymentStarted();
@ -138,7 +130,6 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
public void withdraw(String withdrawToAddress) { public void withdraw(String withdrawToAddress) {
dataModel.withdraw(withdrawToAddress); dataModel.withdraw(withdrawToAddress);
Platform.runLater(() -> navigation.navigateTo(MainView.class, PortfolioView.class, ClosedTradesView.class));
} }
public void withdrawAddressFocusOut(String text) { public void withdrawAddressFocusOut(String text) {
@ -201,7 +192,11 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
} }
public String getFiatAmount() { public String getFiatAmount() {
return formatter.formatFiatWithCode(dataModel.getTrade().getTradeVolume()); try {
return formatter.formatFiatWithCode(dataModel.getTrade().getTradeVolume());
} catch (NoTradeFoundException e) {
return "";
}
} }
public String getHolderName() { public String getHolderName() {
@ -221,11 +216,19 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
// summary // summary
public String getTradeVolume() { public String getTradeVolume() {
return dataModel.getTrade() != null ? formatter.formatCoinWithCode(dataModel.getTrade().getTradeAmount()) : ""; try {
return formatter.formatCoinWithCode(dataModel.getTrade().getTradeAmount());
} catch (NoTradeFoundException e) {
return "";
}
} }
public String getFiatVolume() { public String getFiatVolume() {
return formatter.formatFiatWithCode(dataModel.getTrade().getTradeVolume()); try {
return formatter.formatFiatWithCode(dataModel.getTrade().getTradeVolume());
} catch (NoTradeFoundException e) {
return "";
}
} }
public String getTotalFees() { public String getTotalFees() {
@ -235,10 +238,15 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
public String getSecurityDeposit() { public String getSecurityDeposit() {
// securityDeposit is handled different for offerer and taker. // securityDeposit is handled different for offerer and taker.
// Offerer have paid in the max amount, but taker might have taken less so also paid in less securityDeposit // Offerer have paid in the max amount, but taker might have taken less so also paid in less securityDeposit
if (dataModel.isOfferer()) try {
return formatter.formatCoinWithCode(dataModel.getTrade().getOffer().getSecurityDeposit()); if (dataModel.isOfferer())
else return formatter.formatCoinWithCode(dataModel.getTrade().getOffer().getSecurityDeposit());
return formatter.formatCoinWithCode(dataModel.getTrade().getSecurityDeposit()); else
return formatter.formatCoinWithCode(dataModel.getTrade().getSecurityDeposit());
} catch (NoTradeFoundException e) {
return "";
}
} }
public BtcAddressValidator getBtcAddressValidator() { public BtcAddressValidator getBtcAddressValidator() {

View file

@ -78,8 +78,11 @@ public class SellerSubView extends TradeSubView {
confirmFiatReceived.inactive(); confirmFiatReceived.inactive();
completed.inactive(); completed.inactive();
if (tradeStepDetailsView != null)
tradeStepDetailsView.deactivate();
switch (viewState) { switch (viewState) {
case EMPTY: case UNDEFINED:
break; break;
case SELLER_WAIT_TX_CONF: case SELLER_WAIT_TX_CONF:
showItem(waitTxInBlockchain); showItem(waitTxInBlockchain);

View file

@ -33,8 +33,8 @@ public abstract class TradeSubView extends HBox {
protected VBox leftVBox; protected VBox leftVBox;
protected AnchorPane contentPane; protected AnchorPane contentPane;
protected PendingTradesViewModel model; protected PendingTradesViewModel model;
protected ChangeListener<PendingTradesViewModel.ViewState> offererStateChangeListener;
protected TradeStepDetailsView tradeStepDetailsView; protected TradeStepDetailsView tradeStepDetailsView;
protected ChangeListener<PendingTradesViewModel.ViewState> offererStateChangeListener;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -24,7 +24,6 @@ import io.bitsquare.gui.main.portfolio.pending.PendingTradesViewModel;
import io.bitsquare.gui.util.Layout; import io.bitsquare.gui.util.Layout;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.scene.control.*; import javafx.scene.control.*;
@ -84,7 +83,7 @@ public class StartFiatView extends TradeStepDetailsView {
super.activate(); super.activate();
model.txId.addListener(txIdChangeListener); model.txId.addListener(txIdChangeListener);
Platform.runLater(() -> txIdTextField.setup(model.getWalletService(), model.txId.get())); txIdTextField.setup(model.getWalletService(), model.txId.get());
} }
@Override @Override

View file

@ -54,6 +54,7 @@ public abstract class TradeStepDetailsView extends AnchorPane {
buildGridEntries(); buildGridEntries();
} }
// That is called at every state change!
public void activate() { public void activate() {
log.debug("activate"); log.debug("activate");
} }

View file

@ -35,7 +35,6 @@ import io.bitsquare.gui.main.help.Help;
import io.bitsquare.gui.main.help.HelpId; import io.bitsquare.gui.main.help.HelpId;
import io.bitsquare.gui.main.portfolio.PortfolioView; import io.bitsquare.gui.main.portfolio.PortfolioView;
import io.bitsquare.gui.main.portfolio.offer.OffersView; import io.bitsquare.gui.main.portfolio.offer.OffersView;
import io.bitsquare.gui.main.portfolio.pending.PendingTradesView;
import io.bitsquare.gui.main.trade.TradeView; import io.bitsquare.gui.main.trade.TradeView;
import io.bitsquare.gui.util.ImageUtil; import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
@ -295,7 +294,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
// TODO temp just for testing // TODO temp just for testing
newValue = false; newValue = false;
close(); close();
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class, OffersView.class); navigation.navigateTo(MainView.class, PortfolioView.class, OffersView.class);
if (newValue) { if (newValue) {
overlayManager.blurContent(); overlayManager.blurContent();

View file

@ -282,7 +282,7 @@ public class Offer implements Serializable {
", fiatPrice=" + fiatPrice + ", fiatPrice=" + fiatPrice +
", amount=" + amount + ", amount=" + amount +
", minAmount=" + minAmount + ", minAmount=" + minAmount +
", p2pSigPubKey=" + p2pSigPubKey + /* ", p2pSigPubKey=" + p2pSigPubKey +*/
", fiatAccountType=" + fiatAccountType + ", fiatAccountType=" + fiatAccountType +
", bankAccountCountry=" + bankAccountCountry + ", bankAccountCountry=" + bankAccountCountry +
", securityDeposit=" + securityDeposit + ", securityDeposit=" + securityDeposit +
@ -292,6 +292,7 @@ public class Offer implements Serializable {
", arbitratorIds=" + arbitratorIds + ", arbitratorIds=" + arbitratorIds +
", offerFeePaymentTxID='" + offerFeePaymentTxID + '\'' + ", offerFeePaymentTxID='" + offerFeePaymentTxID + '\'' +
", state=" + state + ", state=" + state +
", stateProperty=" + stateProperty +
'}'; '}';
} }
} }

View file

@ -75,7 +75,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/ */
public class FileManager<T> { public class FileManager<T> {
private static final Logger log = LoggerFactory.getLogger(FileManager.class); private static final Logger log = LoggerFactory.getLogger(FileManager.class);
private static final ReentrantLock lock = Threading.lock("FileUtil"); private static final ReentrantLock lock = Threading.lock("FileManager");
private final File dir; private final File dir;
private final File storageFile; private final File storageFile;
@ -164,6 +164,7 @@ public class FileManager<T> {
} }
public T read(File file) throws IOException, ClassNotFoundException { public T read(File file) throws IOException, ClassNotFoundException {
log.debug("read" + file);
lock.lock(); lock.lock();
try (final FileInputStream fileInputStream = new FileInputStream(file); try (final FileInputStream fileInputStream = new FileInputStream(file);
final ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) { final ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) {
@ -256,6 +257,9 @@ public class FileManager<T> {
fileOutputStream = new FileOutputStream(tempFile); fileOutputStream = new FileOutputStream(tempFile);
objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream = new ObjectOutputStream(fileOutputStream);
// TODO ConcurrentModificationException happens sometimes at that line
//log.debug("serializable " + serializable.toString());
log.debug("storageFile " + storageFile.toString());
objectOutputStream.writeObject(serializable); objectOutputStream.writeObject(serializable);
// Attempt to force the bits to hit the disk. In reality the OS or hard disk itself may still decide // Attempt to force the bits to hit the disk. In reality the OS or hard disk itself may still decide
@ -271,6 +275,7 @@ public class FileManager<T> {
renameTempFileToFile(tempFile, storageFile); renameTempFileToFile(tempFile, storageFile);
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
log.error("Error at saveToFile: " + t.getMessage());
} finally { } finally {
if (tempFile != null && tempFile.exists()) { if (tempFile != null && tempFile.exists()) {
log.warn("Temp file still exists after failed save. storageFile=" + storageFile); log.warn("Temp file still exists after failed save. storageFile=" + storageFile);
@ -286,7 +291,7 @@ public class FileManager<T> {
} catch (IOException e) { } catch (IOException e) {
// We swallow that // We swallow that
e.printStackTrace(); e.printStackTrace();
log.error("Cannot close resources."); log.error("Cannot close resources." + e.getMessage());
} }
lock.unlock(); lock.unlock();
} }

View file

@ -427,7 +427,6 @@ abstract public class Trade implements Model, Serializable {
abstract protected void initStates(); abstract protected void initStates();
@Override @Override
public String toString() { public String toString() {
return "Trade{" + return "Trade{" +
@ -446,10 +445,10 @@ abstract public class Trade implements Model, Serializable {
", lifeCycleState=" + lifeCycleState + ", lifeCycleState=" + lifeCycleState +
", mailboxMessage=" + mailboxMessage + ", mailboxMessage=" + mailboxMessage +
", depositTx=" + depositTx + ", depositTx=" + depositTx +
", contract=" + contract + /* ", contract=" + contract +
", contractAsJson='" + contractAsJson + '\'' + ", contractAsJson='" + contractAsJson + '\'' +*/
", sellerContractSignature='" + sellerContractSignature + '\'' + /* ", sellerContractSignature='" + sellerContractSignature + '\'' +
", buyerContractSignature='" + buyerContractSignature + '\'' + ", buyerContractSignature='" + buyerContractSignature + '\'' +*/
", payoutTx=" + payoutTx + ", payoutTx=" + payoutTx +
", errorMessage='" + errorMessage + '\'' + ", errorMessage='" + errorMessage + '\'' +
", throwable=" + throwable + ", throwable=" + throwable +

View file

@ -167,14 +167,6 @@ public class ProcessModel implements Model, Serializable {
return mailboxMessage; return mailboxMessage;
} }
@Override
public String toString() {
return "ProcessModel{" +
"offer=" + offer +
'}';
}
@Nullable @Nullable
public Transaction getPayoutTx() { public Transaction getPayoutTx() {
return payoutTx; return payoutTx;
@ -280,11 +272,9 @@ public class ProcessModel implements Model, Serializable {
@Override @Override
public void persist() { public void persist() {
} }
@Override @Override
public void onComplete() { public void onComplete() {
} }
} }

View file

@ -29,7 +29,6 @@ import java.io.Serializable;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -178,24 +177,4 @@ public class TradingPeer implements Serializable {
public void setContractSignature(String contractSignature) { public void setContractSignature(String contractSignature) {
this.contractSignature = contractSignature; this.contractSignature = contractSignature;
} }
@Override
public String toString() {
return "TradingPeer{" +
"accountId='" + accountId + '\'' +
", p2pSigPubKey=" + p2pSigPubKey +
", p2pEncryptPubKey=" + p2pEncryptPubKey +
", tradeWalletPubKey=" + Arrays.toString(tradeWalletPubKey) +
", fiatAccount=" + fiatAccount +
", preparedDepositTx=" + preparedDepositTx +
", connectedOutputsForAllInputs=" + connectedOutputsForAllInputs +
", outputs=" + outputs +
", payoutAmount=" + payoutAmount +
", payoutAddressString='" + payoutAddressString + '\'' +
", signature=" + Arrays.toString(signature) +
", contractAsJson='" + contractAsJson + '\'' +
", contractSignature='" + contractSignature + '\'' +
'}';
}
} }

View file

@ -1,136 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.trade.protocol.placeoffer;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TaskRunner {
private static final Logger log = LoggerFactory.getLogger(TaskRunner.class);
private Queue<Class> tasks;
private SharedModel sharedModel = new SharedModel();
private FaultHandler faultHandler;
private ResultHandler taskCompleted;
private final boolean[] failed = {false};
@Test
public void test() {
// Task1.run();
//Task2.run();
tasks = new LinkedBlockingQueue<>();
tasks.add(Task1.class);
tasks.add(Task2.class);
faultHandler = (throwable) -> {
log.debug(throwable.getMessage());
failed[0] = true;
};
taskCompleted = () -> {
next();
};
next();
/* ResultHandler handleResult = () -> {
Class task = tasks.poll();
try {
if (!failed[0])
((Task) task.newInstance()).run(sharedModel, taskCompleted, faultHandler);
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
};*/
/* tasks.stream().forEach((e) -> {
try {
((Task) e.newInstance()).run(sharedModel, faultHandler);
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
});*/
}
private void next() {
Class task = tasks.poll();
if (task != null) {
try {
if (!failed[0])
((Task) task.newInstance()).run(sharedModel, taskCompleted, faultHandler);
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
}
}
}
interface ResultHandler {
void handleResult();
}
interface FaultHandler {
void handleFault(Throwable throwable);
}
class SharedModel {
public int data = 42;
}
class Task {
protected void run(SharedModel sharedModel, ResultHandler resultHandler, FaultHandler faultHandler) {
}
}
class Task1 extends Task {
private static final Logger log = LoggerFactory.getLogger(Task1.class);
@Override
public void run(SharedModel sharedModel, ResultHandler resultHandler, FaultHandler faultHandler) {
log.debug("run " + Task1.class);
log.debug("data " + sharedModel.data);
// faultHandler.handleFault(new Exception("test"));
sharedModel.data++;
resultHandler.handleResult();
}
}
class Task2 extends Task {
private static final Logger log = LoggerFactory.getLogger(Task2.class);
@Override
public void run(SharedModel sharedModel, ResultHandler resultHandler, FaultHandler faultHandler) {
log.debug("run " + Task2.class);
log.debug("data " + sharedModel.data);
resultHandler.handleResult();
}
}