diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersDataModel.java index 66c9cab0b5..79586ce9d9 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersDataModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersDataModel.java @@ -19,6 +19,7 @@ package io.bitsquare.gui.main.portfolio.offer; import io.bitsquare.offer.Direction; import io.bitsquare.offer.Offer; +import io.bitsquare.offer.OpenOffer; import io.bitsquare.trade.TradeManager; import io.bitsquare.user.User; import io.bitsquare.util.handlers.ErrorMessageHandler; @@ -44,8 +45,8 @@ class OffersDataModel implements Activatable, DataModel { private final TradeManager tradeManager; private final User user; - private final ObservableList list = FXCollections.observableArrayList(); - private final MapChangeListener offerMapChangeListener; + private final ObservableList list = FXCollections.observableArrayList(); + private final MapChangeListener offerMapChangeListener; @Inject @@ -55,19 +56,19 @@ class OffersDataModel implements Activatable, DataModel { this.offerMapChangeListener = change -> { if (change.wasAdded()) - list.add(new OfferListItem(change.getValueAdded())); + list.add(new OpenOfferListItem(change.getValueAdded())); else if (change.wasRemoved()) - list.removeIf(e -> e.getOffer().getId().equals(change.getValueRemoved().getId())); + list.removeIf(e -> e.getOpenOffer().getId().equals(change.getValueRemoved().getId())); }; } @Override public void activate() { list.clear(); - list.addAll(tradeManager.getOpenOffers().values().stream().map(OfferListItem::new).collect(Collectors.toList())); + list.addAll(tradeManager.getOpenOffers().values().stream().map(OpenOfferListItem::new).collect(Collectors.toList())); // we sort by date, earliest first - list.sort((o1, o2) -> o2.getOffer().getCreationDate().compareTo(o1.getOffer().getCreationDate())); + list.sort((o1, o2) -> o2.getOpenOffer().getOffer().getCreationDate().compareTo(o1.getOpenOffer().getOffer().getCreationDate())); tradeManager.getOpenOffers().addListener(offerMapChangeListener); } @@ -77,16 +78,17 @@ class OffersDataModel implements Activatable, DataModel { tradeManager.getOpenOffers().removeListener(offerMapChangeListener); } - void removeOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { - tradeManager.requestRemoveOffer(offer, resultHandler, errorMessageHandler); + void removeOpenOffer(String offerId, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + tradeManager.requestRemoveOpenOffer(offerId, resultHandler, errorMessageHandler); } - public ObservableList getList() { + public ObservableList getList() { return list; } - public Direction getDirection(Offer offer) { + public Direction getDirection(OpenOffer openOffer) { + Offer offer = openOffer.getOffer(); return offer.getMessagePublicKey().equals(user.getMessagePublicKey()) ? offer.getDirection() : offer.getMirroredDirection(); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersView.java index 947665cc0e..99ed4418cd 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersView.java @@ -35,8 +35,8 @@ import javafx.util.Callback; @FxmlView public class OffersView extends ActivatableViewAndModel { - @FXML TableView table; - @FXML TableColumn priceColumn, amountColumn, volumeColumn, + @FXML TableView table; + @FXML TableColumn priceColumn, amountColumn, volumeColumn, directionColumn, dateColumn, offerIdColumn, removeItemColumn; @Inject @@ -63,14 +63,14 @@ public class OffersView extends ActivatableViewAndModel new ReadOnlyObjectWrapper<>(offerListItem.getValue())); offerIdColumn.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call(TableColumn column) { - return new TableCell() { + public TableCell call(TableColumn column) { + return new TableCell() { private Hyperlink hyperlink; @Override - public void updateItem(final OfferListItem item, boolean empty) { + public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); if (item != null && !empty) { @@ -112,14 +112,14 @@ public class OffersView extends ActivatableViewAndModel new ReadOnlyObjectWrapper<>(offer.getValue())); dateColumn.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call( - TableColumn column) { - return new TableCell() { + public TableCell call( + TableColumn column) { + return new TableCell() { @Override - public void updateItem(final OfferListItem item, boolean empty) { + public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); if (item != null) setText(model.getDate(item)); @@ -134,14 +134,14 @@ public class OffersView extends ActivatableViewAndModel new ReadOnlyObjectWrapper<>(offer.getValue())); amountColumn.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call( - TableColumn column) { - return new TableCell() { + public TableCell call( + TableColumn column) { + return new TableCell() { @Override - public void updateItem(final OfferListItem item, boolean empty) { + public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); setText(model.getAmount(item)); } @@ -153,14 +153,14 @@ public class OffersView extends ActivatableViewAndModel new ReadOnlyObjectWrapper<>(offer.getValue())); priceColumn.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call( - TableColumn column) { - return new TableCell() { + public TableCell call( + TableColumn column) { + return new TableCell() { @Override - public void updateItem(final OfferListItem item, boolean empty) { + public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); setText(model.getPrice(item)); } @@ -172,14 +172,14 @@ public class OffersView extends ActivatableViewAndModel new ReadOnlyObjectWrapper<>(offer.getValue())); volumeColumn.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call( - TableColumn column) { - return new TableCell() { + public TableCell call( + TableColumn column) { + return new TableCell() { @Override - public void updateItem(final OfferListItem item, boolean empty) { + public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); if (item != null) setText(model.getVolume(item)); @@ -194,14 +194,14 @@ public class OffersView extends ActivatableViewAndModel new ReadOnlyObjectWrapper<>(offer.getValue())); directionColumn.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call( - TableColumn column) { - return new TableCell() { + public TableCell call( + TableColumn column) { + return new TableCell() { @Override - public void updateItem(final OfferListItem item, boolean empty) { + public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); setText(model.getDirectionLabel(item)); } @@ -213,11 +213,11 @@ public class OffersView extends ActivatableViewAndModel new ReadOnlyObjectWrapper<>(offerListItem.getValue())); removeItemColumn.setCellFactory( - new Callback, TableCell>() { + new Callback, TableCell>() { @Override - public TableCell call(TableColumn directionColumn) { - return new TableCell() { + public TableCell call(TableColumn directionColumn) { + return new TableCell() { final ImageView iconView = new ImageView(); final Button button = new Button(); @@ -229,11 +229,11 @@ public class OffersView extends ActivatableViewAndModel removeOffer(item)); + button.setOnAction(event -> removeOpenOffer(item.getOpenOffer().getId())); setGraphic(button); } else { diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersViewModel.java index c5308340ce..9a149977d5 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OffersViewModel.java @@ -44,8 +44,8 @@ class OffersViewModel extends ActivatableWithDataModel implemen } - void removeOffer(OfferListItem item) { - dataModel.removeOffer(item.getOffer(), + void removeOpenOffer(String offerId) { + dataModel.removeOpenOffer(offerId, () -> { // visual feedback? log.debug("Remove offer was successful"); @@ -56,32 +56,32 @@ class OffersViewModel extends ActivatableWithDataModel implemen }); } - public ObservableList getList() { + public ObservableList getList() { return dataModel.getList(); } - String getTradeId(OfferListItem item) { - return item.getOffer().getId(); + String getTradeId(OpenOfferListItem item) { + return item.getOpenOffer().getId(); } - String getAmount(OfferListItem item) { - return (item != null) ? formatter.formatAmountWithMinAmount(item.getOffer()) : ""; + String getAmount(OpenOfferListItem item) { + return (item != null) ? formatter.formatAmountWithMinAmount(item.getOpenOffer().getOffer()) : ""; } - String getPrice(OfferListItem item) { - return (item != null) ? formatter.formatFiat(item.getOffer().getPrice()) : ""; + String getPrice(OpenOfferListItem item) { + return (item != null) ? formatter.formatFiat(item.getOpenOffer().getOffer().getPrice()) : ""; } - String getVolume(OfferListItem item) { - return (item != null) ? formatter.formatVolumeWithMinVolume(item.getOffer()) : ""; + String getVolume(OpenOfferListItem item) { + return (item != null) ? formatter.formatVolumeWithMinVolume(item.getOpenOffer().getOffer()) : ""; } - String getDirectionLabel(OfferListItem item) { - return (item != null) ? formatter.formatDirection(dataModel.getDirection(item.getOffer())) : ""; + String getDirectionLabel(OpenOfferListItem item) { + return (item != null) ? formatter.formatDirection(dataModel.getDirection(item.getOpenOffer())) : ""; } - String getDate(OfferListItem item) { - return formatter.formatDateTime(item.getOffer().getCreationDate()); + String getDate(OpenOfferListItem item) { + return formatter.formatDateTime(item.getOpenOffer().getOffer().getCreationDate()); } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OfferListItem.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OpenOfferListItem.java similarity index 77% rename from gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OfferListItem.java rename to gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OpenOfferListItem.java index 51cec54090..24351687d6 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OfferListItem.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/offer/OpenOfferListItem.java @@ -17,20 +17,20 @@ package io.bitsquare.gui.main.portfolio.offer; -import io.bitsquare.offer.Offer; +import io.bitsquare.offer.OpenOffer; /** * We could remove that wrapper if it is not needed for additional UI only fields. */ -class OfferListItem { +class OpenOfferListItem { - private final Offer offer; + private final OpenOffer openOffer; - public OfferListItem(Offer offer) { - this.offer = offer; + public OpenOfferListItem(OpenOffer openOffer) { + this.openOffer = openOffer; } - public Offer getOffer() { - return offer; + public OpenOffer getOpenOffer() { + return openOffer; } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookDataModel.java index 1710ca811f..017ed56540 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookDataModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookDataModel.java @@ -114,8 +114,8 @@ class OfferBookDataModel implements Activatable, DataModel { btcCode.unbind(); } - void removeOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { - tradeManager.requestRemoveOffer(offer, resultHandler, errorMessageHandler); + void removeOpenOffer(String offerId, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + tradeManager.requestRemoveOpenOffer(offerId, resultHandler, errorMessageHandler); } void calculateVolume() { diff --git a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookView.java b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookView.java index 16f4d5efc7..6d0489a349 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookView.java @@ -468,8 +468,8 @@ public class OfferBookView extends ActivatableViewAndModel model.removeOffer(item - .getOffer())); + button.setOnAction(event -> model.removeOpenOffer(item + .getOffer().getId())); } else { if (offer.getDirection() == Direction.SELL) diff --git a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookViewModel.java index 88e6898844..1319daf2a5 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBookViewModel.java @@ -103,8 +103,8 @@ class OfferBookViewModel extends ActivatableWithDataModel im (newValue))); } - void removeOffer(Offer offer) { - dataModel.removeOffer(offer, + void removeOpenOffer(String offerId) { + dataModel.removeOpenOffer(offerId, () -> { // visual feedback? log.debug("Remove offer was successful"); diff --git a/gui/src/main/java/io/bitsquare/offer/Offer.java b/gui/src/main/java/io/bitsquare/offer/Offer.java index 9df82065e1..e567dbdb3d 100644 --- a/gui/src/main/java/io/bitsquare/offer/Offer.java +++ b/gui/src/main/java/io/bitsquare/offer/Offer.java @@ -76,9 +76,13 @@ public class Offer implements Serializable { private final String bankAccountUID; private final List arbitrators; + // Mutable property. Has to be set before offer is save in DHT as it changes the objects hash! private String offerFeePaymentTxID; - private State state = State.UNKNOWN; - private transient ObjectProperty stateProperty; // don't access directly, use getStateProperty() + + // Those state properties are transient and only used at runtime! + private transient State state = State.UNKNOWN; + // don't access directly as it might be null; use getStateProperty() which creates an object if not instantiated + private transient ObjectProperty stateProperty; /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gui/src/main/java/io/bitsquare/offer/OfferBook.java b/gui/src/main/java/io/bitsquare/offer/OfferBook.java index f039f4f6cc..3c26572a53 100644 --- a/gui/src/main/java/io/bitsquare/offer/OfferBook.java +++ b/gui/src/main/java/io/bitsquare/offer/OfferBook.java @@ -139,7 +139,7 @@ public class OfferBook { country = bankAccount.getCountry(); fiatCode = bankAccount.getCurrency().getCurrencyCode(); - // TODO check why that was used + // TODO check why that was used (probably just for update triggering, if so refactor that) //offerBookListItems.stream().forEach(e -> e.setBankAccountCountry(country)); } else { diff --git a/gui/src/main/java/io/bitsquare/offer/OpenOffer.java b/gui/src/main/java/io/bitsquare/offer/OpenOffer.java new file mode 100644 index 0000000000..215d03c80b --- /dev/null +++ b/gui/src/main/java/io/bitsquare/offer/OpenOffer.java @@ -0,0 +1,43 @@ +/* + * 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 . + */ + +package io.bitsquare.offer; + +import java.io.Serializable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OpenOffer implements Serializable { + private static final long serialVersionUID = -7523483764145982933L; + + private static final Logger log = LoggerFactory.getLogger(OpenOffer.class); + + private final Offer offer; + + public OpenOffer( Offer offer) { + this.offer = offer; + } + + public Offer getOffer() { + return offer; + } + + public String getId() { + return offer.getId(); + } +} diff --git a/gui/src/main/java/io/bitsquare/trade/TradeManager.java b/gui/src/main/java/io/bitsquare/trade/TradeManager.java index a6d831a833..2d211ee10c 100644 --- a/gui/src/main/java/io/bitsquare/trade/TradeManager.java +++ b/gui/src/main/java/io/bitsquare/trade/TradeManager.java @@ -27,6 +27,7 @@ import io.bitsquare.network.Peer; import io.bitsquare.offer.Direction; import io.bitsquare.offer.Offer; import io.bitsquare.offer.OfferBookService; +import io.bitsquare.offer.OpenOffer; import io.bitsquare.persistence.Persistence; import io.bitsquare.trade.handlers.TransactionResultHandler; import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol; @@ -94,7 +95,7 @@ public class TradeManager { private final Map offererAsBuyerProtocolMap = new HashMap<>(); private final Map requestIsOfferAvailableProtocolMap = new HashMap<>(); - private final ObservableMap openOffers = FXCollections.observableHashMap(); + private final ObservableMap openOffers = FXCollections.observableHashMap(); private final ObservableMap pendingTrades = FXCollections.observableHashMap(); private final ObservableMap closedTrades = FXCollections.observableHashMap(); @@ -121,9 +122,9 @@ public class TradeManager { this.signatureService = signatureService; this.offerBookService = offerBookService; - Object offersObject = persistence.read(this, "offers"); - if (offersObject instanceof Map) { - openOffers.putAll((Map) offersObject); + Object openOffersObject = persistence.read(this, "openOffers"); + if (openOffersObject instanceof Map) { + openOffers.putAll((Map) openOffersObject); } Object pendingTradesObject = persistence.read(this, "pendingTrades"); @@ -177,12 +178,13 @@ public class TradeManager { accountSettings.getAcceptedCountries(), accountSettings.getAcceptedLanguageLocales()); + PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol( offer, walletService, offerBookService, (transaction) -> { - saveOffer(offer); + saveOpenOffer(new OpenOffer(offer)); resultHandler.handleResult(transaction); }, (message, throwable) -> errorMessageHandler.handleErrorMessage(message) @@ -191,22 +193,22 @@ public class TradeManager { placeOfferProtocol.placeOffer(); } - private void saveOffer(Offer offer) { - openOffers.put(offer.getId(), offer); - persistOffers(); + private void saveOpenOffer(OpenOffer openOffer) { + openOffers.put(openOffer.getId(), openOffer); + persistOpenOffers(); } - public void requestRemoveOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { - offerBookService.removeOffer(offer, + public void requestRemoveOpenOffer(String offerId, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + offerBookService.removeOffer(openOffers.get(offerId).getOffer(), () -> { - if (openOffers.containsKey(offer.getId())) { - openOffers.remove(offer.getId()); - persistOffers(); + if (openOffers.containsKey(offerId)) { + openOffers.remove(offerId); + persistOpenOffers(); resultHandler.handleResult(); } else { - log.error("Locally stored offers does not contain the offer with the ID " + offer.getId()); - errorMessageHandler.handleErrorMessage("Locally stored offers does not contain the offer with the ID " + offer.getId()); + log.error("Locally stored offers does not contain the offer with the ID " + offerId); + errorMessageHandler.handleErrorMessage("Locally stored offers does not contain the offer with the ID " + offerId); } }, (message, throwable) -> errorMessageHandler.handleErrorMessage(message)); @@ -247,8 +249,7 @@ public class TradeManager { private void createOffererAsBuyerProtocol(String offerId, Peer sender) { log.trace("createOffererAsBuyerProtocol offerId = " + offerId); if (openOffers.containsKey(offerId)) { - Offer offer = openOffers.get(offerId); - + Offer offer = openOffers.get(offerId).getOffer(); Trade trade = createTrade(offer); currentPendingTrade = trade; @@ -264,7 +265,7 @@ public class TradeManager { public void onOfferAccepted(Offer offer) { trade.setState(Trade.State.OFFERER_ACCEPTED); persistPendingTrades(); - requestRemoveOffer(offer, + requestRemoveOpenOffer(offer.getId(), () -> log.debug("remove was successful"), (message) -> log.error(message)); } @@ -535,7 +536,7 @@ public class TradeManager { // Getters /////////////////////////////////////////////////////////////////////////////////////////// - public ObservableMap getOpenOffers() { + public ObservableMap getOpenOffers() { return openOffers; } @@ -563,8 +564,8 @@ public class TradeManager { // Private /////////////////////////////////////////////////////////////////////////////////////////// - private void persistOffers() { - persistence.write(this, "offers", (Map) new HashMap<>(openOffers)); + private void persistOpenOffers() { + persistence.write(this, "openOffers", (Map) new HashMap<>(openOffers)); } private void persistPendingTrades() { diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/placeoffer/PlaceOfferProtocol.java b/gui/src/main/java/io/bitsquare/trade/protocol/placeoffer/PlaceOfferProtocol.java index 270ace95a5..b67a465c29 100644 --- a/gui/src/main/java/io/bitsquare/trade/protocol/placeoffer/PlaceOfferProtocol.java +++ b/gui/src/main/java/io/bitsquare/trade/protocol/placeoffer/PlaceOfferProtocol.java @@ -128,7 +128,7 @@ public class PlaceOfferProtocol { void addOffer(Transaction transaction) { // need to write data before storage, otherwise hash is different when removing offer! offer.setOfferFeePaymentTxID(transaction.getHashAsString()); - + offerBookService.addOffer(offer, () -> { resultHandler.handleResult(transaction);