diff --git a/src/main/java/io/bitsquare/BitSquare.java b/src/main/java/io/bitsquare/BitSquare.java index 9e573cdf04..140a3ec9bd 100644 --- a/src/main/java/io/bitsquare/BitSquare.java +++ b/src/main/java/io/bitsquare/BitSquare.java @@ -128,6 +128,9 @@ public class BitSquare extends Application { primaryStage.setMinWidth(750); primaryStage.setMinHeight(500); + Profiler.initScene(primaryStage.getScene()); + + primaryStage.show(); } catch (IOException e) { log.error(e.getMessage()); diff --git a/src/main/java/io/bitsquare/btc/FeePolicy.java b/src/main/java/io/bitsquare/btc/FeePolicy.java index b57f791a5e..32ac55fd9a 100644 --- a/src/main/java/io/bitsquare/btc/FeePolicy.java +++ b/src/main/java/io/bitsquare/btc/FeePolicy.java @@ -63,7 +63,7 @@ public class FeePolicy { try { return new Address(params, registrationFeeAddress); } catch (AddressFormatException e) { - e.printStackTrace(); + e.printStackTrace(); return null; } }*/ diff --git a/src/main/java/io/bitsquare/btc/WalletFacade.java b/src/main/java/io/bitsquare/btc/WalletFacade.java index 5f0d6baae8..93b0b7594f 100644 --- a/src/main/java/io/bitsquare/btc/WalletFacade.java +++ b/src/main/java/io/bitsquare/btc/WalletFacade.java @@ -18,8 +18,9 @@ package io.bitsquare.btc; import io.bitsquare.BitSquare; +import io.bitsquare.btc.listeners.AddressConfidenceListener; import io.bitsquare.btc.listeners.BalanceListener; -import io.bitsquare.btc.listeners.ConfidenceListener; +import io.bitsquare.btc.listeners.TxConfidenceListener; import io.bitsquare.crypto.CryptoFacade; import io.bitsquare.persistence.Persistence; @@ -104,7 +105,8 @@ public class WalletFacade { private final CryptoFacade cryptoFacade; private final Persistence persistence; private final List downloadListeners = new ArrayList<>(); - private final List confidenceListeners = new ArrayList<>(); + private final List addressConfidenceListeners = new ArrayList<>(); + private final List txConfidenceListeners = new ArrayList<>(); private final List balanceListeners = new ArrayList<>(); private Wallet wallet; private WalletEventListener walletEventListener; @@ -268,13 +270,22 @@ public class WalletFacade { downloadListeners.remove(listener); } - public ConfidenceListener addConfidenceListener(ConfidenceListener listener) { - confidenceListeners.add(listener); + public AddressConfidenceListener addAddressConfidenceListener(AddressConfidenceListener listener) { + addressConfidenceListeners.add(listener); return listener; } - public void removeConfidenceListener(ConfidenceListener listener) { - confidenceListeners.remove(listener); + public void removeAddressConfidenceListener(AddressConfidenceListener listener) { + addressConfidenceListeners.remove(listener); + } + + public TxConfidenceListener addTxConfidenceListener(TxConfidenceListener listener) { + txConfidenceListeners.add(listener); + return listener; + } + + public void removeTxConfidenceListener(TxConfidenceListener listener) { + txConfidenceListeners.remove(listener); } public BalanceListener addBalanceListener(BalanceListener listener) { @@ -354,16 +365,31 @@ public class WalletFacade { return getMostRecentConfidence(transactionConfidenceList); } - private void notifyConfidenceListeners(Transaction tx) { - for (ConfidenceListener confidenceListener : confidenceListeners) { - List transactionConfidenceList = new ArrayList<>(); - transactionConfidenceList.add(getTransactionConfidence(tx, confidenceListener.getAddress())); - - TransactionConfidence transactionConfidence = getMostRecentConfidence(transactionConfidenceList); - confidenceListener.onTransactionConfidenceChanged(transactionConfidence); + public TransactionConfidence getConfidenceForTxId(String txId) { + if (wallet != null) { + Set transactions = wallet.getTransactions(true); + for (Transaction tx : transactions) { + if (tx.getHashAsString().equals(txId)) + return tx.getConfidence(); + } } + return null; } + private void notifyConfidenceListeners(Transaction tx) { + for (AddressConfidenceListener addressConfidenceListener : addressConfidenceListeners) { + List transactionConfidenceList = new ArrayList<>(); + transactionConfidenceList.add(getTransactionConfidence(tx, addressConfidenceListener.getAddress())); + + TransactionConfidence transactionConfidence = getMostRecentConfidence(transactionConfidenceList); + addressConfidenceListener.onTransactionConfidenceChanged(transactionConfidence); + } + + for (TxConfidenceListener txConfidenceListener : txConfidenceListeners) { + if (tx.getHashAsString().equals(txConfidenceListener.getTxID())) + txConfidenceListener.onTransactionConfidenceChanged(tx.getConfidence()); + } + } private TransactionConfidence getTransactionConfidence(Transaction tx, Address address) { List mergedOutputs = getOutputsWithConnectedOutputs(tx); @@ -924,7 +950,7 @@ public class WalletFacade { } // 4 step deposit tx: Offerer send deposit tx to taker - public String takerCommitDepositTx(String depositTxAsHex) { + public Transaction takerCommitDepositTx(String depositTxAsHex) { log.trace("takerCommitDepositTx"); log.trace("inputs: "); log.trace("depositTxID=" + depositTxAsHex); @@ -941,7 +967,7 @@ public class WalletFacade { throw new RuntimeException(e); // Cannot happen, we already called multisigContract.verify() } - return depositTx.getHashAsString(); + return depositTx; } diff --git a/src/main/java/io/bitsquare/btc/listeners/ConfidenceListener.java b/src/main/java/io/bitsquare/btc/listeners/AddressConfidenceListener.java similarity index 91% rename from src/main/java/io/bitsquare/btc/listeners/ConfidenceListener.java rename to src/main/java/io/bitsquare/btc/listeners/AddressConfidenceListener.java index 16674b8484..8cf4f68088 100644 --- a/src/main/java/io/bitsquare/btc/listeners/ConfidenceListener.java +++ b/src/main/java/io/bitsquare/btc/listeners/AddressConfidenceListener.java @@ -20,10 +20,10 @@ package io.bitsquare.btc.listeners; import com.google.bitcoin.core.Address; import com.google.bitcoin.core.TransactionConfidence; -public class ConfidenceListener { +public class AddressConfidenceListener { private final Address address; - public ConfidenceListener(Address address) { + public AddressConfidenceListener(Address address) { this.address = address; } diff --git a/src/main/java/io/bitsquare/btc/listeners/TxConfidenceListener.java b/src/main/java/io/bitsquare/btc/listeners/TxConfidenceListener.java new file mode 100644 index 0000000000..2c1f60131c --- /dev/null +++ b/src/main/java/io/bitsquare/btc/listeners/TxConfidenceListener.java @@ -0,0 +1,35 @@ +/* + * 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.btc.listeners; + +import com.google.bitcoin.core.TransactionConfidence; + +public class TxConfidenceListener { + private final String txID; + + public TxConfidenceListener(String txID) { + this.txID = txID; + } + + public String getTxID() { + return txID; + } + + public void onTransactionConfidenceChanged(TransactionConfidence confidence) { + } +} \ No newline at end of file diff --git a/src/main/java/io/bitsquare/gui/Navigation.java b/src/main/java/io/bitsquare/gui/Navigation.java index dc9f2f2059..541b27b067 100644 --- a/src/main/java/io/bitsquare/gui/Navigation.java +++ b/src/main/java/io/bitsquare/gui/Navigation.java @@ -178,9 +178,9 @@ public class Navigation { TAKE_OFFER("/io/bitsquare/gui/main/trade/takeoffer/TakeOfferView.fxml"), // orders - OFFER("/io/bitsquare/gui/main/orders/offer/OfferView.fxml"), - PENDING_TRADE("/io/bitsquare/gui/main/orders/pending/PendingTradeView.fxml"), - CLOSED_TRADE("/io/bitsquare/gui/main/orders/closed/ClosedTradeView.fxml"), + OFFERS("/io/bitsquare/gui/main/orders/offer/OffersView.fxml"), + PENDING_TRADES("/io/bitsquare/gui/main/orders/pending/PendingTradesView.fxml"), + CLOSED_TRADES("/io/bitsquare/gui/main/orders/closed/ClosedTradesView.fxml"), // funds DEPOSIT("/io/bitsquare/gui/main/funds/deposit/DepositView.fxml"), diff --git a/src/main/java/io/bitsquare/gui/bitsquare.css b/src/main/java/io/bitsquare/gui/bitsquare.css index ed0f832934..56e259fce0 100644 --- a/src/main/java/io/bitsquare/gui/bitsquare.css +++ b/src/main/java/io/bitsquare/gui/bitsquare.css @@ -29,13 +29,6 @@ lower gradient color on tab: dddddd -fx-focus-color: -fx-accent; -fx-faint-focus-color: #0f87c322; -fx-selection-bar: derive(-fx-accent,50%); - - /*-fx-hover-base: ladder( - -fx-base, - derive(-fx-base,20%) 20%, - derive(-fx-base,30%) 35%, - derive(-fx-base,40%) 50% - );*/ } /* Splash */ @@ -144,9 +137,9 @@ lower gradient color on tab: dddddd ******************************************************************************/ .tooltip { - -fx-background: rgba(30,30,30); + -fx-background: white; -fx-text-fill: black; - -fx-background-color: rgba(100,100,100,0.8); + -fx-background-color: white; -fx-background-radius: 6px; -fx-background-insets: 0; -fx-padding: 0.667em 0.75em 0.667em 0.75em; /* 10px */ diff --git a/src/main/java/io/bitsquare/gui/components/btc/AddressTextField.java b/src/main/java/io/bitsquare/gui/components/AddressTextField.java similarity index 96% rename from src/main/java/io/bitsquare/gui/components/btc/AddressTextField.java rename to src/main/java/io/bitsquare/gui/components/AddressTextField.java index 32aa111d75..87dfb9b0d9 100644 --- a/src/main/java/io/bitsquare/gui/components/btc/AddressTextField.java +++ b/src/main/java/io/bitsquare/gui/components/AddressTextField.java @@ -15,10 +15,9 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.components.btc; +package io.bitsquare.gui.components; import io.bitsquare.gui.OverlayManager; -import io.bitsquare.gui.components.Popups; import com.google.bitcoin.core.Coin; import com.google.bitcoin.uri.BitcoinURI; @@ -77,14 +76,13 @@ public class AddressTextField extends AnchorPane { Desktop.getDesktop().browse(URI.create(getBitcoinURI())); } catch (IOException e) { log.warn(e.getMessage()); - Popups.openWarningPopup("Information", "Opening a system Bitcoin wallet application has failed. " + + Popups.openWarningPopup("Warning", "Opening a system Bitcoin wallet application has failed. " + "Perhaps you don't have one installed?"); } }); addressLabel.focusTraversableProperty().set(focusTraversableProperty().get()); focusedProperty().addListener((ov, oldValue, newValue) -> { addressLabel.requestFocus(); - log.debug("foc"); }); Label copyIcon = new Label(); diff --git a/src/main/java/io/bitsquare/gui/components/btc/BalanceTextField.java b/src/main/java/io/bitsquare/gui/components/BalanceTextField.java similarity index 96% rename from src/main/java/io/bitsquare/gui/components/btc/BalanceTextField.java rename to src/main/java/io/bitsquare/gui/components/BalanceTextField.java index 1c5bdeebaa..f5042f850d 100644 --- a/src/main/java/io/bitsquare/gui/components/btc/BalanceTextField.java +++ b/src/main/java/io/bitsquare/gui/components/BalanceTextField.java @@ -15,11 +15,11 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.gui.components.btc; +package io.bitsquare.gui.components; import io.bitsquare.btc.WalletFacade; +import io.bitsquare.btc.listeners.AddressConfidenceListener; import io.bitsquare.btc.listeners.BalanceListener; -import io.bitsquare.btc.listeners.ConfidenceListener; import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator; import io.bitsquare.gui.util.BSFormatter; @@ -74,7 +74,7 @@ public class BalanceTextField extends AnchorPane { } public void setup(WalletFacade walletFacade, Address address) { - walletFacade.addConfidenceListener(new ConfidenceListener(address) { + walletFacade.addAddressConfidenceListener(new AddressConfidenceListener(address) { @Override public void onTransactionConfidenceChanged(TransactionConfidence confidence) { updateConfidence(confidence); diff --git a/src/main/java/io/bitsquare/gui/components/InfoDisplay.java b/src/main/java/io/bitsquare/gui/components/InfoDisplay.java index 2a23ac89c4..ebaad8c549 100644 --- a/src/main/java/io/bitsquare/gui/components/InfoDisplay.java +++ b/src/main/java/io/bitsquare/gui/components/InfoDisplay.java @@ -134,12 +134,13 @@ public class InfoDisplay extends Parent { }); sceneProperty().addListener((ov, oldValue, newValue) -> { - if (oldValue == null && newValue != null) { + if (oldValue == null && newValue != null && newValue.getWindow() != null) { newValue.getWindow().widthProperty().addListener(listener); // localToScene does deliver 0 instead of the correct x position when scene propery gets set, // so we delay for 1 render cycle Platform.runLater(() -> { label.setVisible(true); + label.prefWidthProperty().unbind(); label.setPrefWidth(newValue.getWindow().getWidth() - localToScene(0, 0).getX() - 35); }); } diff --git a/src/main/java/io/bitsquare/gui/components/Popups.java b/src/main/java/io/bitsquare/gui/components/Popups.java index 9d4846a1a7..443c128a2b 100644 --- a/src/main/java/io/bitsquare/gui/components/Popups.java +++ b/src/main/java/io/bitsquare/gui/components/Popups.java @@ -169,6 +169,8 @@ public class Popups { // Support handling of uncaught exception from any thread (also non gui thread) public static void handleUncaughtExceptions(Throwable throwable) { // while dev + log.error(throwable.getMessage()); + log.error(throwable.toString()); throwable.printStackTrace(); Runnable runnable = () -> { diff --git a/src/main/java/io/bitsquare/gui/components/TextFieldWithCopyIcon.java b/src/main/java/io/bitsquare/gui/components/TextFieldWithCopyIcon.java new file mode 100644 index 0000000000..a51ee7b5b7 --- /dev/null +++ b/src/main/java/io/bitsquare/gui/components/TextFieldWithCopyIcon.java @@ -0,0 +1,87 @@ +/* + * 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.gui.components; + +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.scene.control.*; +import javafx.scene.input.*; +import javafx.scene.layout.*; + +import de.jensd.fx.fontawesome.AwesomeDude; +import de.jensd.fx.fontawesome.AwesomeIcon; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TextFieldWithCopyIcon extends AnchorPane { + private static final Logger log = LoggerFactory.getLogger(TextFieldWithCopyIcon.class); + + private final StringProperty text = new SimpleStringProperty(); + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + public TextFieldWithCopyIcon() { + Label copyIcon = new Label(); + copyIcon.setLayoutY(3); + copyIcon.getStyleClass().add("copy-icon"); + Tooltip.install(copyIcon, new Tooltip("Copy to clipboard")); + AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY); + AnchorPane.setRightAnchor(copyIcon, 0.0); + copyIcon.setOnMouseClicked(e -> { + if (getText() != null && getText().length() > 0) { + Clipboard clipboard = Clipboard.getSystemClipboard(); + ClipboardContent content = new ClipboardContent(); + content.putString(getText()); + clipboard.setContent(content); + } + }); + TextField txIdLabel = new TextField(); + txIdLabel.setEditable(false); + txIdLabel.textProperty().bindBidirectional(text); + AnchorPane.setRightAnchor(txIdLabel, 30.0); + AnchorPane.setLeftAnchor(txIdLabel, 0.0); + txIdLabel.focusTraversableProperty().set(focusTraversableProperty().get()); + focusedProperty().addListener((ov, oldValue, newValue) -> { + txIdLabel.requestFocus(); + }); + + getChildren().addAll(txIdLabel, copyIcon); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Getter/Setter + /////////////////////////////////////////////////////////////////////////////////////////// + + public String getText() { + return text.get(); + } + + public StringProperty textProperty() { + return text; + } + + public void setText(String text) { + this.text.set(text); + } + +} diff --git a/src/main/java/io/bitsquare/gui/components/TxIdTextField.java b/src/main/java/io/bitsquare/gui/components/TxIdTextField.java new file mode 100644 index 0000000000..54ca225a7c --- /dev/null +++ b/src/main/java/io/bitsquare/gui/components/TxIdTextField.java @@ -0,0 +1,157 @@ +/* + * 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.gui.components; + +import io.bitsquare.btc.WalletFacade; +import io.bitsquare.btc.listeners.TxConfidenceListener; +import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator; + +import com.google.bitcoin.core.TransactionConfidence; + +import java.awt.*; + +import java.io.IOException; + +import java.net.URI; + +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.control.*; +import javafx.scene.input.*; +import javafx.scene.layout.*; + +import de.jensd.fx.fontawesome.AwesomeDude; +import de.jensd.fx.fontawesome.AwesomeIcon; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TxIdTextField extends AnchorPane { + private static final Logger log = LoggerFactory.getLogger(TxIdTextField.class); + + private final TextField txIdLabel; + private final Tooltip progressIndicatorTooltip; + private final ConfidenceProgressIndicator progressIndicator; + private final Label copyIcon; + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + public TxIdTextField() { + progressIndicator = new ConfidenceProgressIndicator(); + progressIndicator.setFocusTraversable(false); + progressIndicator.setPrefSize(24, 24); + progressIndicator.setId("funds-confidence"); + progressIndicator.setLayoutY(1); + progressIndicator.setProgress(0); + progressIndicator.setVisible(false); + AnchorPane.setRightAnchor(progressIndicator, 0.0); + progressIndicatorTooltip = new Tooltip("-"); + Tooltip.install(progressIndicator, progressIndicatorTooltip); + + copyIcon = new Label(); + copyIcon.setLayoutY(3); + copyIcon.getStyleClass().add("copy-icon"); + Tooltip.install(copyIcon, new Tooltip("Copy transaction ID to clipboard")); + AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY); + AnchorPane.setRightAnchor(copyIcon, 30.0); + + txIdLabel = new TextField(); + txIdLabel.setId("address-text-field"); + txIdLabel.setEditable(false); + AnchorPane.setRightAnchor(txIdLabel, 55.0); + AnchorPane.setLeftAnchor(txIdLabel, 0.0); + txIdLabel.focusTraversableProperty().set(focusTraversableProperty().get()); + focusedProperty().addListener((ov, oldValue, newValue) -> { + txIdLabel.requestFocus(); + }); + + getChildren().addAll(txIdLabel, copyIcon, progressIndicator); + } + + public void setup(WalletFacade walletFacade, String txID) { + txIdLabel.setText(txID); + txIdLabel.setOnMouseClicked(mouseEvent -> { + try { + Desktop.getDesktop().browse(URI.create("https://blockchain.info/address/" + txID)); + } catch (IOException e) { + log.warn(e.getMessage()); + Popups.openWarningPopup("Warning", "Opening blockchain.info failed. Please check your internet " + + "connection."); + } + }); + + copyIcon.setOnMouseClicked(e -> { + if (txID != null && txID.length() > 0) { + Clipboard clipboard = Clipboard.getSystemClipboard(); + ClipboardContent content = new ClipboardContent(); + content.putString(txID); + clipboard.setContent(content); + } + }); + + walletFacade.addTxConfidenceListener(new TxConfidenceListener(txID) { + @Override + public void onTransactionConfidenceChanged(TransactionConfidence confidence) { + updateConfidence(confidence); + } + }); + updateConfidence(walletFacade.getConfidenceForTxId(txID)); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Getters/Setters + /////////////////////////////////////////////////////////////////////////////////////////// + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private + /////////////////////////////////////////////////////////////////////////////////////////// + + + private void updateConfidence(TransactionConfidence confidence) { + if (confidence != null) { + switch (confidence.getConfidenceType()) { + case UNKNOWN: + progressIndicatorTooltip.setText("Unknown transaction status"); + progressIndicator.setProgress(0); + break; + case PENDING: + progressIndicatorTooltip.setText( + "Seen by " + confidence.numBroadcastPeers() + " peer(s) / 0 " + "confirmations"); + progressIndicator.setProgress(-1.0); + break; + case BUILDING: + progressIndicatorTooltip.setText("Confirmed in " + confidence.getDepthInBlocks() + " block(s)"); + progressIndicator.setProgress(Math.min(1, (double) confidence.getDepthInBlocks() / 6.0)); + break; + case DEAD: + progressIndicatorTooltip.setText("Transaction is invalid."); + progressIndicator.setProgress(0); + break; + } + + if (progressIndicator.getProgress() != 0) { + progressIndicator.setVisible(true); + AnchorPane.setRightAnchor(progressIndicator, 0.0); + } + } + } +} diff --git a/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepBar.java b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepBar.java new file mode 100644 index 0000000000..c9fb087fa7 --- /dev/null +++ b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepBar.java @@ -0,0 +1,89 @@ +/* + * 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.gui.components.processbar; + +import java.util.List; + +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.scene.control.*; + +public class ProcessStepBar extends Control { + + private List processStepItems; + private IntegerProperty selectedIndex = new SimpleIntegerProperty(0); + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + public ProcessStepBar() { + } + + public ProcessStepBar(List processStepItems) { + this.processStepItems = processStepItems; + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Methods + /////////////////////////////////////////////////////////////////////////////////////////// + + public void next() { + setSelectedIndex(getSelectedIndex() + 1); + } + + @Override + protected Skin createDefaultSkin() { + return new ProcessStepBarSkin<>(this); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Setters + /////////////////////////////////////////////////////////////////////////////////////////// + + public void setProcessStepItems(List processStepItems) { + this.processStepItems = processStepItems; + if (getSkin() != null) + ((ProcessStepBarSkin) getSkin()).setProcessStepItems(processStepItems); + } + + public void setSelectedIndex(int selectedIndex) { + this.selectedIndex.set(selectedIndex); + if (getSkin() != null) + ((ProcessStepBarSkin) getSkin()).setSelectedIndex(selectedIndex); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Getters + /////////////////////////////////////////////////////////////////////////////////////////// + public List getProcessStepItems() { + return processStepItems; + } + + public int getSelectedIndex() { + return selectedIndex.get(); + } + + public IntegerProperty selectedIndexProperty() { + return selectedIndex; + } +} diff --git a/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepBarSkin.java b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepBarSkin.java new file mode 100644 index 0000000000..7cc89db43e --- /dev/null +++ b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepBarSkin.java @@ -0,0 +1,235 @@ +/* + * 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.gui.components.processbar; + +import io.bitsquare.gui.util.Colors; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; +import javafx.scene.paint.*; +import javafx.scene.shape.*; + +import com.sun.javafx.scene.control.behavior.BehaviorBase; +import com.sun.javafx.scene.control.behavior.KeyBinding; +import com.sun.javafx.scene.control.skin.BehaviorSkinBase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class ProcessStepBarSkin extends BehaviorSkinBase, BehaviorBase>> { + private static final Logger log = LoggerFactory.getLogger(ProcessStepBarSkin.class); + + private final ProcessStepBar controller; + private LabelWithBorder currentLabelWithBorder; + private LabelWithBorder prevLabelWithBorder; + private int index; + private final List labelWithBorders = new ArrayList<>(); + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + public ProcessStepBarSkin(final ProcessStepBar control) { + super(control, new BehaviorBase<>(control, Collections.emptyList())); + + controller = getSkinnable(); + + setProcessStepItems(controller.getProcessStepItems()); + setSelectedIndex(controller.getSelectedIndex()); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Setters + /////////////////////////////////////////////////////////////////////////////////////////// + + public void setProcessStepItems(List processStepItems) { + if (processStepItems != null) { + int i = 0; + int size = controller.getProcessStepItems().size(); + for (ProcessStepItem processStepItem : controller.getProcessStepItems()) { + + LabelWithBorder labelWithBorder = new LabelWithBorder(processStepItem, i == 0, i == size - 1); + getChildren().add(labelWithBorder); + labelWithBorders.add(labelWithBorder); + if (i == 0) + currentLabelWithBorder = prevLabelWithBorder = labelWithBorder; + + i++; + } + + currentLabelWithBorder.select(); + } + } + + public void setSelectedIndex(int index) { + + this.index = index; + + if (index < labelWithBorders.size()) { + for (int i = 0; i <= index; i++) { + + if (prevLabelWithBorder != null) + prevLabelWithBorder.deSelect(); + + currentLabelWithBorder = labelWithBorders.get(i); + currentLabelWithBorder.select(); + + prevLabelWithBorder = currentLabelWithBorder; + } + } + } + + @Override + protected void layoutChildren(double x, double y, double width, double height) { + double distance = 10; + double padding = 50; + for (int i = 0; i < getChildren().size(); i++) { + Node node = getChildren().get(i); + + double newWidth = snapSize(node.prefWidth(height)) + padding; + double newHeight = snapSize(node.prefHeight(-1) + 10); + + if (i > 0) + x = x - ((LabelWithBorder) node).getArrowWidth(); + + node.resize(newWidth, newHeight); + // need to add 0.5 to make it sharp + node.relocate(x + 0.5, 0.5); + x += newWidth + distance; + } + } + + + public static class LabelWithBorder extends Label { + final double borderWidth = 1; + private final double arrowWidth = 10; + private final double arrowHeight = 30; + + private final ProcessStepItem processStepItem; + private final boolean isFirst; + private final boolean isLast; + + public LabelWithBorder(ProcessStepItem processStepItem, boolean isFirst, boolean isLast) { + super(processStepItem.getLabel()); + + this.processStepItem = processStepItem; + + this.isFirst = isFirst; + this.isLast = isLast; + + setAlignment(Pos.CENTER); + setStyle("-fx-font-size: 14"); + + this.setShape(createButtonShape()); + + BorderStroke borderStroke = new BorderStroke(Colors.LIGHT_GREY, BorderStrokeStyle.SOLID, null, + new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY); + this.setBorder(new Border(borderStroke)); + setTextFill(Colors.LIGHT_GREY); + } + + public void select() { + log.debug("select " + processStepItem.getLabel()); + BorderStroke borderStroke = new BorderStroke(Colors.BLUE, BorderStrokeStyle.SOLID, null, + new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY); + this.setBorder(new Border(borderStroke)); + setTextFill(Colors.BLUE); + } + + public void deSelect() { + log.debug("deSelect " + processStepItem.getLabel()); + BorderStroke borderStroke = new BorderStroke(Colors.GREEN, BorderStrokeStyle.SOLID, null, + new BorderWidths(borderWidth, borderWidth, borderWidth, borderWidth), Insets.EMPTY); + this.setBorder(new Border(borderStroke)); + setTextFill(Colors.GREEN); + } + + public double getArrowWidth() { + return arrowWidth; + } + + + private Path createButtonShape() { + // build the following shape (or home without left arrow) + + // -------- + // \ \ + // / / + // -------- + Path path = new Path(); + + // begin in the upper left corner + MoveTo e1 = new MoveTo(0, 0); + path.getElements().add(e1); + + // draw a horizontal line that defines the width of the shape + HLineTo e2 = new HLineTo(); + // bind the width of the shape to the width of the button + e2.xProperty().bind(this.widthProperty().subtract(arrowWidth)); + path.getElements().add(e2); + + if (!isLast) { + // draw upper part of right arrow + LineTo e3 = new LineTo(); + // the x endpoint of this line depends on the x property of line e2 + e3.xProperty().bind(e2.xProperty().add(arrowWidth)); + e3.setY(arrowHeight / 2.0); + path.getElements().add(e3); + } + + + // draw lower part of right arrow + LineTo e4 = new LineTo(); + // the x endpoint of this line depends on the x property of line e2 + e4.xProperty().bind(e2.xProperty()); + e4.setY(arrowHeight); + path.getElements().add(e4); + + // draw lower horizontal line + HLineTo e5 = new HLineTo(0); + path.getElements().add(e5); + + if (!isFirst) { + LineTo e6 = new LineTo(arrowWidth, arrowHeight / 2.0); + path.getElements().add(e6); + } + + // close path + ClosePath e7 = new ClosePath(); + path.getElements().add(e7); + // this is a dummy color to fill the shape, it won't be visible + path.setFill(Color.BLACK); + + return path; + } + + @Override + public String toString() { + return "LabelWithBorder{" + + ", processStepItem=" + processStepItem + + '}'; + } + } +} diff --git a/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepItem.java b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepItem.java new file mode 100644 index 0000000000..c4cdd54d76 --- /dev/null +++ b/src/main/java/io/bitsquare/gui/components/processbar/ProcessStepItem.java @@ -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 . + */ +package io.bitsquare.gui.components.processbar; + +public class ProcessStepItem { + private final String label; + + public ProcessStepItem(String label) { + this.label = label; + } + + String getLabel() { + return label; + } + +} diff --git a/src/main/java/io/bitsquare/gui/main/MainViewCB.java b/src/main/java/io/bitsquare/gui/main/MainViewCB.java index e0850cb70e..0a4a3844b2 100644 --- a/src/main/java/io/bitsquare/gui/main/MainViewCB.java +++ b/src/main/java/io/bitsquare/gui/main/MainViewCB.java @@ -141,7 +141,7 @@ public class MainViewCB extends ViewCB { return childController; } catch (IOException e) { - e.getStackTrace(); + e.printStackTrace(); log.error("Loading view failed. FxmlUrl = " + navigationItem.getFxmlUrl()); } return null; @@ -191,7 +191,7 @@ public class MainViewCB extends ViewCB { alertButton.setOnAction((e) -> navigation.navigationTo(Navigation.Item.MAIN, Navigation.Item.ORDERS, - Navigation.Item.PENDING_TRADE)); + Navigation.Item.PENDING_TRADES)); Tooltip.install(alertButton, new Tooltip("Your offer has been accepted")); ordersButtonButtonPane.getChildren().add(alertButton); diff --git a/src/main/java/io/bitsquare/gui/main/account/AccountViewCB.java b/src/main/java/io/bitsquare/gui/main/account/AccountViewCB.java index 6c4e351b07..44225cd481 100644 --- a/src/main/java/io/bitsquare/gui/main/account/AccountViewCB.java +++ b/src/main/java/io/bitsquare/gui/main/account/AccountViewCB.java @@ -38,7 +38,7 @@ import javafx.scene.layout.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -class AccountViewCB extends CachedViewCB { +public class AccountViewCB extends CachedViewCB { private static final Logger log = LoggerFactory.getLogger(AccountViewCB.class); @@ -125,7 +125,7 @@ class AccountViewCB extends CachedViewCB { } catch (IOException e) { log.error("Loading view failed. FxmlUrl = " + Navigation.Item.ACCOUNT_SETUP.getFxmlUrl()); - e.getStackTrace(); + e.printStackTrace(); } return childController; } diff --git a/src/main/java/io/bitsquare/gui/main/account/content/fiat/FiatAccountView.fxml b/src/main/java/io/bitsquare/gui/main/account/content/fiat/FiatAccountView.fxml index 79f0905521..8cb5e35af7 100644 --- a/src/main/java/io/bitsquare/gui/main/account/content/fiat/FiatAccountView.fxml +++ b/src/main/java/io/bitsquare/gui/main/account/content/fiat/FiatAccountView.fxml @@ -47,7 +47,7 @@ -