diff --git a/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesDataModel.java b/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesDataModel.java index ad1d4701a4..b8beffd8e8 100644 --- a/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesDataModel.java +++ b/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesDataModel.java @@ -21,13 +21,13 @@ import io.bitsquare.btc.AddressEntry; import io.bitsquare.btc.FeePolicy; import io.bitsquare.btc.WalletService; import io.bitsquare.btc.listeners.TxConfidenceListener; +import io.bitsquare.common.viewfx.model.Activatable; +import io.bitsquare.common.viewfx.model.DataModel; import io.bitsquare.offer.Direction; import io.bitsquare.offer.Offer; import io.bitsquare.trade.Trade; import io.bitsquare.trade.TradeManager; import io.bitsquare.user.User; -import io.bitsquare.common.viewfx.model.Activatable; -import io.bitsquare.common.viewfx.model.DataModel; import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.Coin; @@ -39,9 +39,9 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.inject.Inject; -import java.util.Optional; - +import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -67,14 +67,14 @@ class PendingTradesDataModel implements Activatable, DataModel { private PendingTradesListItem selectedItem; private boolean isOfferer; private Trade closedTrade; - private TxConfidenceListener txConfidenceListener; - private final ChangeListener stateChangeListener; + private TxConfidenceListener txConfidenceListener; + private final ChangeListener tradeStateChangeListener; private final MapChangeListener mapChangeListener; final StringProperty txId = new SimpleStringProperty(); final ObjectProperty tradeState = new SimpleObjectProperty<>(); - + final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1); @Inject public PendingTradesDataModel(TradeManager tradeManager, WalletService walletService, User user) { @@ -82,13 +82,23 @@ class PendingTradesDataModel implements Activatable, DataModel { this.walletService = walletService; this.user = user; - this.stateChangeListener = (ov, oldValue, newValue) -> tradeState.set(newValue); + tradeStateChangeListener = (ov, oldValue, newValue) -> tradeState.set(newValue); - this.mapChangeListener = change -> { - if (change.wasAdded()) + mapChangeListener = change -> { + if (change.wasAdded()) { list.add(new PendingTradesListItem(change.getValueAdded())); - else if (change.wasRemoved()) + if (list.size() == 1) { + selectTrade(list.get(0)); + selectedIndex.set(0); + } + } + else if (change.wasRemoved()) { closedTrade = change.getValueRemoved(); + if (list.size() == 0) { + selectTrade(null); + selectedIndex.set(-1); + } + } sortList(); }; @@ -98,27 +108,33 @@ class PendingTradesDataModel implements Activatable, DataModel { public void activate() { list.clear(); // transform trades to list of PendingTradesListItems and keep it updated - tradeManager.getPendingTrades().values().stream() - .forEach(e -> list.add(new PendingTradesListItem(e))); + tradeManager.getPendingTrades().values().stream().forEach(e -> list.add(new PendingTradesListItem(e))); tradeManager.getPendingTrades().addListener(mapChangeListener); // we sort by date, earliest first sortList(); // select either currentPendingTrade or first in the list - Optional currentTradeItemOptional = list.stream() - .filter((e) -> tradeManager.getCurrentPendingTrade() != null && - tradeManager.getCurrentPendingTrade().getId().equals(e.getTrade().getId())) - .findFirst(); - if (currentTradeItemOptional.isPresent()) - selectTrade(currentTradeItemOptional.get()); - else if (list.size() > 0) + if (tradeManager.getCurrentPendingTrade() != null) { + for (int i = 0; i < list.size(); i++) { + PendingTradesListItem item = list.get(i); + if (tradeManager.getCurrentPendingTrade().getId().equals(item.getTrade().getId())) { + selectedIndex.set(i); + selectTrade(item); + break; + } + } + } + else if (list.size() > 0) { selectTrade(list.get(0)); + selectedIndex.set(0); + } } @Override public void deactivate() { tradeManager.getPendingTrades().removeListener(mapChangeListener); + cleanUpSelectedTrade(); } @@ -133,7 +149,7 @@ class PendingTradesDataModel implements Activatable, DataModel { isOfferer = getTrade().getOffer().getMessagePublicKey().equals(user.getMessagePubKey()); Trade trade = getTrade(); - trade.stateProperty().addListener(stateChangeListener); + trade.stateProperty().addListener(tradeStateChangeListener); tradeState.set(trade.stateProperty().get()); log.trace("selectTrade trade.stateProperty().get() " + trade.stateProperty().get()); @@ -287,8 +303,7 @@ class PendingTradesDataModel implements Activatable, DataModel { private void cleanUpSelectedTrade() { if (selectedItem != null) { - Trade trade = getTrade(); - trade.stateProperty().removeListener(stateChangeListener); + selectedItem.getTrade().stateProperty().removeListener(tradeStateChangeListener); } if (txConfidenceListener != null) diff --git a/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesView.java b/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesView.java index 0354103311..eebc23f434 100644 --- a/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesView.java +++ b/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesView.java @@ -82,13 +82,15 @@ public class PendingTradesView extends ActivatableViewAndModel dateColumn; @FXML TableColumn tradeAmountColumn; - private ChangeListener selectedItemChangeListener; + private ChangeListener selectedIndexChangeListener; private ListChangeListener listChangeListener; private ChangeListener txIdChangeListener; private ChangeListener offererStateChangeListener; private ChangeListener takerStateChangeListener; private final Navigation navigation; + private ChangeListener focusedPropertyListener; + private ChangeListener selectedItemChangeListener; @Inject public PendingTradesView(PendingTradesViewModel model, Navigation navigation) { @@ -112,60 +114,68 @@ public class PendingTradesView extends ActivatableViewAndModel - txIdTextField.setup(model.getWalletService(), newValue); + txIdChangeListener = (ov, oldValue, newValue) -> txIdTextField.setup(model.getWalletService(), newValue); - selectedItemChangeListener = (obsValue, oldValue, newValue) -> { - if (oldValue != null && newValue != null) { - model.selectTrade(newValue); - updateScreen(); - } + selectedIndexChangeListener = (ov, oldValue, newValue) -> { + if ((Integer) newValue > -1) + table.getSelectionModel().select((Integer) newValue); + + updateScreen(); }; listChangeListener = change -> { change.next(); if ((change.wasAdded() && change.getList().size() == 1) || (change.wasRemoved() && change.getList().size() == 0)) + updateScreen(); }; offererStateChangeListener = (ov, oldValue, newValue) -> applyOffererState(newValue); takerStateChangeListener = (ov, oldValue, newValue) -> applyTakerState(newValue); + focusedPropertyListener = (ov, oldValue, newValue) -> { + if (oldValue && !newValue) + model.withdrawAddressFocusOut(withdrawAddressTextField.getText()); + }; + selectedItemChangeListener = (ov, oldValue, newValue) -> { + model.selectTrade(newValue); + updateScreen(); + }; + withdrawAddressTextField.setValidator(model.getBtcAddressValidator()); - withdrawButton.disableProperty().bind(model.withdrawalButtonDisable); } @Override public void doActivate() { table.setItems(model.getList()); - + table.getSelectionModel().selectedItemProperty().addListener(selectedItemChangeListener); model.getList().addListener(listChangeListener); model.txId.addListener(txIdChangeListener); + model.selectedIndex.addListener(selectedIndexChangeListener); + withdrawAddressTextField.focusedProperty().addListener(focusedPropertyListener); - txIdTextField.setup(model.getWalletService(), model.txId.get()); - table.getSelectionModel().select(model.getSelectedItem()); - table.getSelectionModel().selectedItemProperty().addListener(selectedItemChangeListener); // TODO Set focus to row does not work yet... - /* table.requestFocus(); - table.getFocusModel().focus( table.getSelectionModel().getSelectedIndex());*/ + Platform.runLater(() -> table.requestFocus()); + table.getFocusModel().focus(model.selectedIndex.get()); + txIdTextField.setup(model.getWalletService(), model.txId.get()); + selectedIndexChangeListener.changed(null, null, model.selectedIndex.get()); - withdrawAddressTextField.focusedProperty().addListener((ov, oldValue, newValue) -> { - if (oldValue && !newValue) - model.withdrawAddressFocusOut(withdrawAddressTextField.getText()); - }); + withdrawButton.disableProperty().bind(model.withdrawalButtonDisable); updateScreen(); } @Override public void doDeactivate() { - table.getSelectionModel().selectedItemProperty().removeListener(selectedItemChangeListener); model.getList().removeListener(listChangeListener); model.txId.removeListener(txIdChangeListener); - model.state.removeListener(offererStateChangeListener); model.state.removeListener(takerStateChangeListener); + model.selectedIndex.removeListener(selectedIndexChangeListener); + table.getSelectionModel().selectedItemProperty().removeListener(selectedItemChangeListener); + + withdrawButton.disableProperty().unbind(); } @FXML @@ -450,7 +460,8 @@ public class PendingTradesView extends ActivatableViewAndModel scrollPane.setVvalue(visible ? scrollPane.getVmax() : 0)); + if (visible) + Platform.runLater(() -> scrollPane.setVvalue(scrollPane.getVmax())); } private void setSummaryControlsVisible(boolean visible) { @@ -491,11 +502,14 @@ public class PendingTradesView extends ActivatableViewAndModel scrollPane.setVvalue(visible ? scrollPane.getVmax() : 0)); + Platform.runLater(() -> { + withdrawAddressTextField.requestFocus(); + scrollPane.setVvalue(scrollPane.getVmax()); + }); } + // CellFactories + private void setTradeIdColumnCellFactory() { idColumn.setCellFactory( new Callback, TableCell>() { diff --git a/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesViewModel.java b/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesViewModel.java index 6a6c4bb0ec..668d2e9535 100644 --- a/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesViewModel.java +++ b/core/src/main/java/io/bitsquare/gui/main/portfolio/pending/PendingTradesViewModel.java @@ -34,8 +34,10 @@ import java.util.Date; import javafx.beans.InvalidationListener; import javafx.beans.property.BooleanProperty; +import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -66,6 +68,7 @@ class PendingTradesViewModel extends ActivatableWithDataModel state = new SimpleObjectProperty<>(); final BooleanProperty withdrawalButtonDisable = new SimpleBooleanProperty(true); + final IntegerProperty selectedIndex = new SimpleIntegerProperty(-1); @Inject @@ -81,6 +84,7 @@ class PendingTradesViewModel extends ActivatableWithDataModel) { openOffers.putAll((Map) openOffersObject); } - Object pendingTradesObject = persistence.read(this, "pendingTrades"); + Serializable pendingTradesObject = persistence.read(this, "pendingTrades"); if (pendingTradesObject instanceof Map) { pendingTrades.putAll((Map) pendingTradesObject); } - Object closedTradesObject = persistence.read(this, "closedTrades"); + Serializable closedTradesObject = persistence.read(this, "closedTrades"); if (closedTradesObject instanceof Map) { closedTrades.putAll((Map) closedTradesObject); } @@ -120,7 +122,8 @@ public class TradeManager { tradeMessageService.addMessageHandler(this::handleMessage); } - // When all services are initialized we create the protocols for our open offers (which will listen for take offer requests) + // When all services are initialized we create the protocols for our open offers and persisted not completed pendingTrades + // BuyerAcceptsOfferProtocol listens for take offer requests, so we need to instantiate it early. public void onAllServicesInitialized() { for (Map.Entry entry : openOffers.entrySet()) { createBuyerAcceptsOfferProtocol(entry.getValue());