From 6459184ce946f21bb1b93ba3dd5ce8fe3e9e566e Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Sat, 10 May 2014 18:31:55 +0200 Subject: [PATCH] integration of TomP2P and basic use cases in dummy views tested --- README.md | 4 +- TODO.txt | 1 - pom.xml | 28 +- src/main/java/io/bitsquare/BitSquare.java | 11 +- .../java/io/bitsquare/btc/WalletFacade.java | 15 +- .../io/bitsquare/gui/ChildController.java | 2 + .../java/io/bitsquare/gui/MainController.java | 18 +- .../bitsquare/gui/funds/FundsController.java | 6 + .../gui/history/HistoryController.java | 6 + .../io/bitsquare/gui/home/HomeController.java | 6 + .../gui/market/MarketController.java | 6 +- .../market/offer/CreateOfferController.java | 6 + .../market/orderbook/OrderBookController.java | 15 +- .../gui/market/trade/TradeController.java | 6 + .../java/io/bitsquare/gui/msg/MockDelay.java | 40 -- .../io/bitsquare/gui/msg/MsgController.java | 326 ++++++++++++++- .../java/io/bitsquare/gui/msg/MsgView.fxml | 86 +++- .../io/bitsquare/gui/msg/OfferListItem.java | 40 ++ .../gui/orders/OrdersController.java | 6 + .../gui/settings/SettingsController.java | 6 + .../bitsquare/gui/setup/SetupController.java | 11 +- .../io/bitsquare/msg/BootstrapMasterPeer.java | 24 ++ .../java/io/bitsquare/msg/MessageFacade.java | 384 +++++++++++++++++- .../io/bitsquare/msg/MessageListener.java | 26 ++ .../java/io/bitsquare/msg/MsgKeyUtil.java | 131 ++++++ .../java/io/bitsquare/storage/Storage.java | 3 +- src/main/java/io/bitsquare/trade/Offer.java | 7 +- src/main/java/io/bitsquare/trade/Trading.java | 3 +- src/main/java/io/bitsquare/util/Utils.java | 6 + src/main/resources/logback.xml | 7 +- 30 files changed, 1134 insertions(+), 102 deletions(-) delete mode 100644 src/main/java/io/bitsquare/gui/msg/MockDelay.java create mode 100644 src/main/java/io/bitsquare/gui/msg/OfferListItem.java create mode 100755 src/main/java/io/bitsquare/msg/BootstrapMasterPeer.java create mode 100644 src/main/java/io/bitsquare/msg/MessageListener.java create mode 100755 src/main/java/io/bitsquare/msg/MsgKeyUtil.java diff --git a/README.md b/README.md index ff6dedeb54..36764bb759 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,13 @@ git clone --recursive git://github.com/bitsquare/bitsquare * Offer fee payment with a OP_RETURN tx and fees to miners * Pay in to MS fund * Payout from MS fund +* TomP2P as messaging lib integrated and basic use cases in msg screen implemented: orderbook, add order, remove order, find peer, chat with peer ### Next steps: +* Implement messaging with TomP2P for registration, orderbook and payment process * Arbitrator integration -* Messaging system * Other trade variants (Buy BTC taker, Sell BTC offerer, Sell BTC offerer) +* Verify registration and fee payments tx and get them from the blockchain * ... diff --git a/TODO.txt b/TODO.txt index d7537c35f8..5e55bbfa05 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,5 +1,4 @@ - arbitration integration -- Messaging! - settings low prio: diff --git a/pom.xml b/pom.xml index fbf83c9527..6ca28ffb93 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ bitcoinj-release - + http://distribution.bitcoinj.googlecode.com/git/releases @@ -59,6 +59,12 @@ http://mvn-adamgent.googlecode.com/svn/maven/release Adam Gent Maven Repository + + + tomp2p.net + http://tomp2p.net/dev/mvn/ + + @@ -106,13 +112,13 @@ 4.11 test - + org.slf4j slf4j-api @@ -170,6 +176,12 @@ 1.3 + + net.tomp2p + TomP2P + 4.4 + + diff --git a/src/main/java/io/bitsquare/BitSquare.java b/src/main/java/io/bitsquare/BitSquare.java index 113cd712e8..436eee24f3 100644 --- a/src/main/java/io/bitsquare/BitSquare.java +++ b/src/main/java/io/bitsquare/BitSquare.java @@ -9,6 +9,7 @@ import io.bitsquare.btc.WalletFacade; import io.bitsquare.di.BitSquareModule; import io.bitsquare.di.GuiceFXMLLoader; import io.bitsquare.gui.util.Localisation; +import io.bitsquare.msg.MessageFacade; import io.bitsquare.settings.Settings; import io.bitsquare.storage.Storage; import io.bitsquare.user.Arbitrator; @@ -28,9 +29,15 @@ public class BitSquare extends Application { private static final Logger log = LoggerFactory.getLogger(BitSquare.class); private WalletFacade walletFacade; + private MessageFacade messageFacade; public static void main(String[] args) { + if (args.length > 0) + WalletFacade.WALLET_PREFIX = args[0]; + else + WalletFacade.WALLET_PREFIX = "bitsquare"; + launch(args); } @@ -39,6 +46,7 @@ public class BitSquare extends Application { final Injector injector = Guice.createInjector(new BitSquareModule()); walletFacade = injector.getInstance(WalletFacade.class); + messageFacade = injector.getInstance(MessageFacade.class); // apply stored data final User user = injector.getInstance(User.class); @@ -51,7 +59,7 @@ public class BitSquare extends Application settings.updateFromStorage((Settings) storage.read(settings.getClass().getName())); - stage.setTitle("BitSquare"); + stage.setTitle("BitSquare (" + WalletFacade.WALLET_PREFIX + ")"); GuiceFXMLLoader.setInjector(injector); final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource("/io/bitsquare/gui/MainView.fxml"), Localisation.getResourceBundle()); @@ -75,6 +83,7 @@ public class BitSquare extends Application public void stop() throws Exception { walletFacade.shutDown(); + messageFacade.shutDown(); super.stop(); } diff --git a/src/main/java/io/bitsquare/btc/WalletFacade.java b/src/main/java/io/bitsquare/btc/WalletFacade.java index 4f56a96dfd..08f02079a1 100644 --- a/src/main/java/io/bitsquare/btc/WalletFacade.java +++ b/src/main/java/io/bitsquare/btc/WalletFacade.java @@ -36,11 +36,13 @@ public class WalletFacade implements WalletEventListener public static final String MAIN_NET = "MAIN_NET"; public static final String TEST_NET = "TEST_NET"; - // for testing trade process between offerer and taker - //public static final String WALLET_PREFIX = "offerer"; // offerer - public static final String WALLET_PREFIX = "taker"; // offerer + public static String WALLET_PREFIX; - //public static final String WALLET_PREFIX = "bitsquare"; + // for testing trade process between offerer and taker + //public static String WALLET_PREFIX = "offerer"; // offerer + //public static String WALLET_PREFIX = "taker"; // offerer + + //public static String WALLET_PREFIX = "bitsquare"; private static final Logger log = LoggerFactory.getLogger(WalletFacade.class); @@ -105,14 +107,11 @@ public class WalletFacade implements WalletEventListener wallet = walletAppKit.wallet(); - // Don't make the user wait for confirmations for now, as the intention is they're sending it their own money! - wallet.allowSpendingUnconfirmedTransactions(); + //wallet.allowSpendingUnconfirmedTransactions(); walletAppKit.peerGroup().setMaxConnections(20); wallet.addEventListener(this); - log.info(wallet.toString()); - // testTradeProcessDepositTx(); // testTradeProcessPayOutTx(); } diff --git a/src/main/java/io/bitsquare/gui/ChildController.java b/src/main/java/io/bitsquare/gui/ChildController.java index 2d44b2fd25..03a20c98db 100644 --- a/src/main/java/io/bitsquare/gui/ChildController.java +++ b/src/main/java/io/bitsquare/gui/ChildController.java @@ -3,4 +3,6 @@ package io.bitsquare.gui; public interface ChildController { void setNavigationController(NavigationController navigationController); + + void cleanup(); } diff --git a/src/main/java/io/bitsquare/gui/MainController.java b/src/main/java/io/bitsquare/gui/MainController.java index 675f6ea63b..423d9ef3a8 100644 --- a/src/main/java/io/bitsquare/gui/MainController.java +++ b/src/main/java/io/bitsquare/gui/MainController.java @@ -10,6 +10,7 @@ import io.bitsquare.gui.market.MarketController; import io.bitsquare.gui.setup.SetupController; import io.bitsquare.gui.util.Icons; import io.bitsquare.gui.util.Localisation; +import io.bitsquare.msg.MessageFacade; import io.bitsquare.trade.Direction; import io.bitsquare.user.User; import javafx.application.Platform; @@ -39,6 +40,7 @@ public class MainController implements Initializable, NavigationController, Wall private User user; private WalletFacade walletFacade; + private MessageFacade messageFacade; private ChildController childController; private ToggleGroup toggleGroup; private ToggleButton prevToggleButton; @@ -62,10 +64,11 @@ public class MainController implements Initializable, NavigationController, Wall /////////////////////////////////////////////////////////////////////////////////////////// @Inject - public MainController(User user, WalletFacade walletFacade) + public MainController(User user, WalletFacade walletFacade, MessageFacade messageFacade) { this.user = user; this.walletFacade = walletFacade; + this.messageFacade = messageFacade; } @@ -80,6 +83,8 @@ public class MainController implements Initializable, NavigationController, Wall networkSyncPane.setSpacing(10); networkSyncPane.setPrefHeight(20); + messageFacade.init(); + walletFacade.addDownloadListener(this); walletFacade.initWallet(); @@ -116,10 +121,8 @@ public class MainController implements Initializable, NavigationController, Wall return null; } - if (childController instanceof MarketController) - { - ((MarketController) childController).cleanup(); - } + if (childController != null) + childController.cleanup(); final GuiceFXMLLoader loader = new GuiceFXMLLoader(getClass().getResource(fxmlView), Localisation.getResourceBundle()); try @@ -184,14 +187,15 @@ public class MainController implements Initializable, NavigationController, Wall addNavButton(leftNavPane, "Orders", Icons.ORDERS, Icons.ORDERS, NavigationController.ORDERS); addNavButton(leftNavPane, "History", Icons.HISTORY, Icons.HISTORY, NavigationController.HISTORY); addNavButton(leftNavPane, "Funds", Icons.FUNDS, Icons.FUNDS, NavigationController.FUNDS); - addNavButton(leftNavPane, "Message", Icons.MSG, Icons.MSG, NavigationController.MSG); + ToggleButton msgButton = addNavButton(leftNavPane, "Message", Icons.MSG, Icons.MSG, NavigationController.MSG); addBalanceInfo(rightNavPane); addAccountComboBox(rightNavPane); addNavButton(rightNavPane, "Settings", Icons.SETTINGS, Icons.SETTINGS, NavigationController.SETTINGS); - sellButton.fire(); + //sellButton.fire(); //homeButton.fire(); + msgButton.fire(); } private ToggleButton addNavButton(Pane parent, String title, String iconId, String iconIdActivated, String navTarget) diff --git a/src/main/java/io/bitsquare/gui/funds/FundsController.java b/src/main/java/io/bitsquare/gui/funds/FundsController.java index 850591e6d0..b61d935962 100644 --- a/src/main/java/io/bitsquare/gui/funds/FundsController.java +++ b/src/main/java/io/bitsquare/gui/funds/FundsController.java @@ -66,6 +66,12 @@ public class FundsController implements Initializable, ChildController balanceLabel.setText(BtcFormatter.formatSatoshis(walletFacade.getBalance(), false)); } + @Override + public void cleanup() + { + + } + } diff --git a/src/main/java/io/bitsquare/gui/history/HistoryController.java b/src/main/java/io/bitsquare/gui/history/HistoryController.java index f30f2da28f..3f90c155f4 100644 --- a/src/main/java/io/bitsquare/gui/history/HistoryController.java +++ b/src/main/java/io/bitsquare/gui/history/HistoryController.java @@ -24,5 +24,11 @@ public class HistoryController implements Initializable, ChildController { this.navigationController = navigationController; } + + @Override + public void cleanup() + { + + } } diff --git a/src/main/java/io/bitsquare/gui/home/HomeController.java b/src/main/java/io/bitsquare/gui/home/HomeController.java index 2d91fd5754..9d557c51a9 100644 --- a/src/main/java/io/bitsquare/gui/home/HomeController.java +++ b/src/main/java/io/bitsquare/gui/home/HomeController.java @@ -28,5 +28,11 @@ public class HomeController implements Initializable, ChildController this.navigationController = navigationController; } + @Override + public void cleanup() + { + + } + } diff --git a/src/main/java/io/bitsquare/gui/market/MarketController.java b/src/main/java/io/bitsquare/gui/market/MarketController.java index 3c69dab6cb..0360c82c3c 100644 --- a/src/main/java/io/bitsquare/gui/market/MarketController.java +++ b/src/main/java/io/bitsquare/gui/market/MarketController.java @@ -93,11 +93,7 @@ public class MarketController implements Initializable, NavigationController, Ch this.navigationController = navigationController; } - - /////////////////////////////////////////////////////////////////////////////////////////// - // Public methods - /////////////////////////////////////////////////////////////////////////////////////////// - + @Override public void cleanup() { if (orderBookController != null) diff --git a/src/main/java/io/bitsquare/gui/market/offer/CreateOfferController.java b/src/main/java/io/bitsquare/gui/market/offer/CreateOfferController.java index 39ea036a67..354612817c 100644 --- a/src/main/java/io/bitsquare/gui/market/offer/CreateOfferController.java +++ b/src/main/java/io/bitsquare/gui/market/offer/CreateOfferController.java @@ -114,6 +114,12 @@ public class CreateOfferController implements Initializable, ChildController, Wa this.navigationController = navigationController; } + @Override + public void cleanup() + { + + } + /////////////////////////////////////////////////////////////////////////////////////////// // Interface implementation: WalletFacade.WalletListener diff --git a/src/main/java/io/bitsquare/gui/market/orderbook/OrderBookController.java b/src/main/java/io/bitsquare/gui/market/orderbook/OrderBookController.java index 4e687d5431..2a9cc05f62 100644 --- a/src/main/java/io/bitsquare/gui/market/orderbook/OrderBookController.java +++ b/src/main/java/io/bitsquare/gui/market/orderbook/OrderBookController.java @@ -138,6 +138,15 @@ public class OrderBookController implements Initializable, ChildController this.navigationController = navigationController; } + @Override + public void cleanup() + { + orderBookTable.setItems(null); + orderBookTable.getSortOrder().clear(); + offerList.comparatorProperty().unbind(); + } + + public void setDirection(Direction direction) { orderBookTable.getSelectionModel().clearSelection(); @@ -145,12 +154,6 @@ public class OrderBookController implements Initializable, ChildController orderBookFilter.setDirection(direction); } - public void cleanup() - { - orderBookTable.setItems(null); - orderBookTable.getSortOrder().clear(); - offerList.comparatorProperty().unbind(); - } private void openTradeTab(OrderBookListItem orderBookListItem) { diff --git a/src/main/java/io/bitsquare/gui/market/trade/TradeController.java b/src/main/java/io/bitsquare/gui/market/trade/TradeController.java index 630fcdbb91..cbf586e6fb 100644 --- a/src/main/java/io/bitsquare/gui/market/trade/TradeController.java +++ b/src/main/java/io/bitsquare/gui/market/trade/TradeController.java @@ -122,6 +122,12 @@ public class TradeController implements Initializable, ChildController, WalletFa this.navigationController = navigationController; } + @Override + public void cleanup() + { + + } + /////////////////////////////////////////////////////////////////////////////////////////// // Interface implementation: WalletFacade.WalletListener diff --git a/src/main/java/io/bitsquare/gui/msg/MockDelay.java b/src/main/java/io/bitsquare/gui/msg/MockDelay.java deleted file mode 100644 index 61af376bec..0000000000 --- a/src/main/java/io/bitsquare/gui/msg/MockDelay.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.bitsquare.gui.msg; - - -import java.util.concurrent.*; - -public class MockDelay -{ - public String waitForMsg(String expectedMsg) - { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Future future = executor.submit(new Task(expectedMsg)); - // max timeout 5 sec - try - { - return future.get(5, TimeUnit.SECONDS); - } catch (InterruptedException | TimeoutException | ExecutionException e) - { - e.printStackTrace(); - } - executor.shutdownNow(); - return null; - } -} - -class Task implements Callable -{ - private String expectedMsg; - - Task(String expectedMsg) - { - this.expectedMsg = expectedMsg; - } - - @Override - public String call() throws Exception - { - Thread.sleep(1000); // 1 seconds pause - return expectedMsg; - } -} \ No newline at end of file diff --git a/src/main/java/io/bitsquare/gui/msg/MsgController.java b/src/main/java/io/bitsquare/gui/msg/MsgController.java index 46fdf1f79c..9669fa1491 100644 --- a/src/main/java/io/bitsquare/gui/msg/MsgController.java +++ b/src/main/java/io/bitsquare/gui/msg/MsgController.java @@ -1,26 +1,346 @@ package io.bitsquare.gui.msg; +import com.google.inject.Inject; +import io.bitsquare.btc.WalletFacade; import io.bitsquare.gui.ChildController; import io.bitsquare.gui.NavigationController; +import io.bitsquare.msg.MessageFacade; +import io.bitsquare.msg.MessageListener; +import javafx.beans.property.ReadOnlyObjectWrapper; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; import javafx.fxml.Initializable; +import javafx.scene.control.*; +import javafx.util.Callback; +import net.tomp2p.peers.Number160; +import net.tomp2p.storage.Data; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.IOException; import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; import java.util.ResourceBundle; -public class MsgController implements Initializable, ChildController +public class MsgController implements Initializable, ChildController, MessageListener { - private NavigationController navigationController; + private static final Logger log = LoggerFactory.getLogger(MsgController.class); + + private MessageFacade messageFacade; + private String selectedCurrency; + private ObservableList offerList = FXCollections.observableArrayList(); + private int selectedIndex; + private String myID, otherID; + private boolean pingPending; + + @FXML + public ComboBox currencyComboBox; + @FXML + public Button sendButton; + @FXML + public TextArea chatTextArea; + @FXML + public TextField chatInputField, peerIDTextField, currencyTextField, offerDataTextField; + @FXML + public TableView offerTable; + @FXML + public TableColumn connectToPeerColumn, removeOfferColumn, offerColumn; + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + @Inject + public MsgController(MessageFacade messageFacade) + { + this.messageFacade = messageFacade; + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Interface implementation: Initializable + /////////////////////////////////////////////////////////////////////////////////////////// @Override public void initialize(URL url, ResourceBundle rb) { + myID = WalletFacade.WALLET_PREFIX; + otherID = WalletFacade.WALLET_PREFIX.equals("taker") ? "offerer" : "taker"; + messageFacade.addMessageListener(this); + + peerIDTextField.setText(myID); + currencyTextField.setText("EUR"); + offerDataTextField.setText(myID + " serialized offer object"); + + selectedCurrency = currencyTextField.getText(); + + currencyComboBox.setItems(FXCollections.observableArrayList(new ArrayList<>(Arrays.asList("EUR", "USD", "CHF")))); + currencyComboBox.getSelectionModel().select(0); + + setupConnectToPeerOfferColumn(); + setupRemoveOfferColumn(); + offerTable.setItems(offerList); + offerTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Interface implementation: MessageListener + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void onMessage(Object message) + { + sendButton.setDisable(!messageFacade.isOtherPeerDefined()); + + if (message instanceof String) + chatTextArea.appendText("\n" + otherID + ": " + message); + } + + @Override + public void onPing() + { + sendChatMsg(MessageFacade.PONG); + } + + @Override + public void onOfferPublished(boolean success) + { + if (success) + getOffers(); + else + log.warn("onOfferPublished returned false"); + } + + @Override + public void onOffersReceived(Map dataMap, boolean success) + { + if (success && dataMap != null) + { + offerList.clear(); + for (Data offerData : dataMap.values()) + { + try + { + Object offerDataObject = offerData.getObject(); + if (offerDataObject instanceof OfferListItem && offerDataObject != null) + offerList.add((OfferListItem) offerDataObject); + } catch (ClassNotFoundException | IOException e) + { + e.printStackTrace(); + } + } + } + else + { + offerList.clear(); + } + } + + + @Override + public void onOfferRemoved(boolean success) + { + if (success) + getOffers(); + else + log.warn("onOfferRemoved failed"); + } + + @Override + public void onResponseFromSend(Object response) + { + String msg = (response instanceof String) ? (String) response : null; + if (msg != null) + { + chatTextArea.appendText("\n" + otherID + ": " + msg); + offerTable.getSelectionModel().select(selectedIndex); + } + } + + @Override + public void onSendFailed() + { + offerTable.getSelectionModel().clearSelection(); + } + + @Override + public void onPeerFound() + { + sendButton.setDisable(!messageFacade.isOtherPeerDefined()); + if (pingPending) + sendChatMsg(MessageFacade.PING); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Interface implementation: ChildController + /////////////////////////////////////////////////////////////////////////////////////////// + @Override public void setNavigationController(NavigationController navigationController) { - this.navigationController = navigationController; + } + + @Override + public void cleanup() + { + messageFacade.removeMessageListener(this); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // GUI Event handlers + /////////////////////////////////////////////////////////////////////////////////////////// + + @FXML + public void publishOffer(ActionEvent actionEvent) + { + OfferListItem offerListItem = new OfferListItem(offerDataTextField.getText(), messageFacade.getPubKeyAsHex(), currencyTextField.getText()); + try + { + messageFacade.publishOffer(currencyTextField.getText(), offerListItem); + } catch (IOException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + + @FXML + public void selectCurrency(ActionEvent actionEvent) + { + selectedCurrency = currencyComboBox.getSelectionModel().getSelectedItem().toString(); + getOffers(); + } + + @FXML + public void sendChatMsg(ActionEvent actionEvent) + { + sendChatMsg(chatInputField.getText()); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private Methods + /////////////////////////////////////////////////////////////////////////////////////////// + + private void inviteForChat(OfferListItem item, int index) + { + selectedIndex = index; + messageFacade.findPeer(item.getPubKey()); + pingPending = true; + + } + + private void sendChatMsg(String msg) + { + messageFacade.sendMessage(msg); + + chatTextArea.appendText("\n" + myID + ": " + msg); + chatInputField.setText(""); + } + + private void getOffers() + { + messageFacade.getOffers(selectedCurrency); + } + + private void removeOffer(OfferListItem offer) + { + try + { + messageFacade.removeOffer(currencyTextField.getText(), offer); + } catch (IOException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Columns + /////////////////////////////////////////////////////////////////////////////////////////// + + private void setupRemoveOfferColumn() + { + removeOfferColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue())); + removeOfferColumn.setCellFactory(new Callback, TableCell>() + { + @Override + public TableCell call(TableColumn directionColumn) + { + return new TableCell() + { + final Button button = new Button(); + + { + button.setMinWidth(70); + } + + @Override + public void updateItem(final OfferListItem item, boolean empty) + { + super.updateItem(item, empty); + + if (item != null) + { + button.setText("Remove"); + setGraphic(button); + + button.setOnAction(event -> removeOffer(item)); + } + else + { + setGraphic(null); + } + } + }; + } + }); + } + + private void setupConnectToPeerOfferColumn() + { + connectToPeerColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper(offer.getValue())); + connectToPeerColumn.setCellFactory(new Callback, TableCell>() + { + @Override + public TableCell call(TableColumn directionColumn) + { + return new TableCell() + { + final Button button = new Button(); + + { + button.setMinWidth(70); + } + + @Override + public void updateItem(OfferListItem item, boolean empty) + { + super.updateItem(item, empty); + + if (item != null) + { + button.setText("Chat"); + setGraphic(button); + + + button.setOnAction(event -> inviteForChat(item, getIndex())); + } + else + { + setGraphic(null); + } + } + }; + } + }); } } diff --git a/src/main/java/io/bitsquare/gui/msg/MsgView.fxml b/src/main/java/io/bitsquare/gui/msg/MsgView.fxml index 8114fc9289..f8bf7197b2 100644 --- a/src/main/java/io/bitsquare/gui/msg/MsgView.fxml +++ b/src/main/java/io/bitsquare/gui/msg/MsgView.fxml @@ -1,6 +1,80 @@ - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +