Merge branch 'Development'

This commit is contained in:
Manfred Karrer 2016-07-30 01:58:28 +02:00
commit ef46e50798
136 changed files with 1089 additions and 758 deletions

View file

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.9.1</version> <version>0.4.9.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View file

@ -24,7 +24,7 @@ public class Version {
private static final Logger log = LoggerFactory.getLogger(Version.class); private static final Logger log = LoggerFactory.getLogger(Version.class);
// The application versions // The application versions
public static final String VERSION = "0.4.9.1"; public static final String VERSION = "0.4.9.2";
// The version nr. for the objects sent over the network. A change will break the serialization of old objects. // The version nr. for the objects sent over the network. A change will break the serialization of old objects.
// If objects are used for both network and database the network version is applied. // If objects are used for both network and database the network version is applied.

View file

@ -34,6 +34,7 @@ import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPrivateCrtKey;
import java.security.spec.*; import java.security.spec.*;
import java.util.Date;
// TODO: use a password protection for key storage // TODO: use a password protection for key storage
public class KeyStorage { public class KeyStorage {
@ -124,7 +125,7 @@ public class KeyStorage {
throw new RuntimeException("Unsupported key algo" + keyEntry.getAlgorithm()); throw new RuntimeException("Unsupported key algo" + keyEntry.getAlgorithm());
} }
//log.info("load completed in {} msec", System.currentTimeMillis() - now); log.debug("load completed in {} msec", System.currentTimeMillis() - new Date().getTime());
return new KeyPair(publicKey, privateKey); return new KeyPair(publicKey, privateKey);
} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) { } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) {
e.printStackTrace(); e.printStackTrace();

View file

@ -24,12 +24,11 @@ public class Profiler {
private static final Logger log = LoggerFactory.getLogger(Profiler.class); private static final Logger log = LoggerFactory.getLogger(Profiler.class);
public static void printSystemLoad(Logger log) { public static void printSystemLoad(Logger log) {
log.warn(printSystemLoadString()); log.info(printSystemLoadString());
} }
public static String printSystemLoadString() { public static String printSystemLoadString() {
long used = getUsedMemoryInMB(); return "System load: Memory (MB)): " + getUsedMemoryInMB() + " / Nr. of threads: " + Thread.activeCount();
return "System load: Memory (MB)): " + used + " / Nr. of threads: " + Thread.activeCount();
} }
public static long getUsedMemoryInMB() { public static long getUsedMemoryInMB() {

View file

@ -33,9 +33,7 @@ import java.awt.*;
import java.io.*; import java.io.*;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLConnection; import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.Permission; import java.security.Permission;
import java.security.PermissionCollection; import java.security.PermissionCollection;
import java.util.Locale; import java.util.Locale;
@ -207,26 +205,6 @@ public class Utilities {
} }
} }
public static void openWebPage(String target) {
try {
openURI(new URI(target));
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage());
}
}
public static void openMail(String to, String subject, String body) {
try {
subject = URLEncoder.encode(subject, "UTF-8").replace("+", "%20");
body = URLEncoder.encode(body, "UTF-8").replace("+", "%20");
openURI(new URI("mailto:" + to + "?subject=" + subject + "&body=" + body));
} catch (IOException | URISyntaxException e) {
log.error("openMail failed " + e.getMessage());
e.printStackTrace();
}
}
public static void printSystemLoad() { public static void printSystemLoad() {
Runtime runtime = Runtime.getRuntime(); Runtime runtime = Runtime.getRuntime();
long free = runtime.freeMemory() / 1024 / 1024; long free = runtime.freeMemory() / 1024 / 1024;

View file

@ -197,12 +197,12 @@ public class FileManager<T> {
renameTempFileToFile(tempFile, storageFile); renameTempFileToFile(tempFile, storageFile);
} catch (Throwable t) { } catch (Throwable t) {
log.debug("storageFile " + storageFile.toString()); log.error("storageFile " + storageFile.toString());
t.printStackTrace(); t.printStackTrace();
log.error("Error at saveToFile: " + t.getMessage()); log.error("Error at saveToFile: " + t.getMessage());
} finally { } finally {
if (tempFile != null && tempFile.exists()) { if (tempFile != null && tempFile.exists()) {
log.warn("Temp file still exists after failed save. storageFile=" + storageFile); log.warn("Temp file still exists after failed save. We will delete it now. storageFile=" + storageFile);
if (!tempFile.delete()) if (!tempFile.delete())
log.error("Cannot delete temp file."); log.error("Cannot delete temp file.");
} }

View file

@ -6,7 +6,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.9.1</version> <version>0.4.9.2</version>
</parent> </parent>
<artifactId>core</artifactId> <artifactId>core</artifactId>

View file

@ -62,7 +62,7 @@ public class BitsquareEnvironment extends StandardEnvironment {
public static final String DEFAULT_USER_DATA_DIR = defaultUserDataDir(); public static final String DEFAULT_USER_DATA_DIR = defaultUserDataDir();
public static final String DEFAULT_APP_DATA_DIR = appDataDir(DEFAULT_USER_DATA_DIR, DEFAULT_APP_NAME); public static final String DEFAULT_APP_DATA_DIR = appDataDir(DEFAULT_USER_DATA_DIR, DEFAULT_APP_NAME);
public static final String LOG_LEVEL_DEFAULT = (DevFlags.STRESS_TEST_MODE || DevFlags.DEV_MODE) ? Level.TRACE.levelStr : Level.WARN.levelStr; public static final String LOG_LEVEL_DEFAULT = (DevFlags.STRESS_TEST_MODE || DevFlags.DEV_MODE) ? Level.TRACE.levelStr : Level.INFO.levelStr;
static final String BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME = "bitsquareCommandLineProperties"; static final String BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME = "bitsquareCommandLineProperties";
static final String BITSQUARE_APP_DIR_PROPERTY_SOURCE_NAME = "bitsquareAppDirProperties"; static final String BITSQUARE_APP_DIR_PROPERTY_SOURCE_NAME = "bitsquareAppDirProperties";

View file

@ -159,19 +159,26 @@ public final class Dispute implements Payload {
} }
public void setIsClosed(boolean isClosed) { public void setIsClosed(boolean isClosed) {
boolean changed = this.isClosed != isClosed;
this.isClosed = isClosed; this.isClosed = isClosed;
isClosedProperty.set(isClosed); isClosedProperty.set(isClosed);
storage.queueUpForSave(); if (changed)
storage.queueUpForSave();
} }
public void setDisputeResult(DisputeResult disputeResult) { public void setDisputeResult(DisputeResult disputeResult) {
boolean changed = this.disputeResult == null || !this.disputeResult.equals(disputeResult);
this.disputeResult = disputeResult; this.disputeResult = disputeResult;
disputeResultProperty.set(disputeResult); disputeResultProperty.set(disputeResult);
storage.queueUpForSave(); if (changed)
storage.queueUpForSave();
} }
public void setDisputePayoutTxId(String disputePayoutTxId) { public void setDisputePayoutTxId(String disputePayoutTxId) {
boolean changed = this.disputePayoutTxId == null || !this.disputePayoutTxId.equals(disputePayoutTxId);
this.disputePayoutTxId = disputePayoutTxId; this.disputePayoutTxId = disputePayoutTxId;
if (changed)
storage.queueUpForSave();
} }

View file

@ -60,10 +60,11 @@ public final class DisputeList<DisputeCase> extends ArrayList<DisputeCase> imple
@Override @Override
public boolean add(DisputeCase disputeCase) { public boolean add(DisputeCase disputeCase) {
if (!super.contains(disputeCase)) { if (!super.contains(disputeCase)) {
boolean result = super.add(disputeCase); boolean changed = super.add(disputeCase);
getObservableList().add(disputeCase); getObservableList().add(disputeCase);
storage.queueUpForSave(); if (changed)
return result; storage.queueUpForSave();
return changed;
} else { } else {
return false; return false;
} }
@ -71,10 +72,11 @@ public final class DisputeList<DisputeCase> extends ArrayList<DisputeCase> imple
@Override @Override
public boolean remove(Object disputeCase) { public boolean remove(Object disputeCase) {
boolean result = super.remove(disputeCase); boolean changed = super.remove(disputeCase);
getObservableList().remove(disputeCase); getObservableList().remove(disputeCase);
storage.queueUpForSave(); if (changed)
return result; storage.queueUpForSave();
return changed;
} }
private ObservableList<DisputeCase> getObservableList() { private ObservableList<DisputeCase> getObservableList() {

View file

@ -68,8 +68,9 @@ public final class AddressEntryList extends ArrayList<AddressEntry> implements P
} }
public AddressEntry addAddressEntry(AddressEntry addressEntry) { public AddressEntry addAddressEntry(AddressEntry addressEntry) {
add(addressEntry); boolean changed = add(addressEntry);
storage.queueUpForSave(); if (changed)
storage.queueUpForSave();
return addressEntry; return addressEntry;
} }
@ -78,17 +79,19 @@ public final class AddressEntryList extends ArrayList<AddressEntry> implements P
Optional<AddressEntry> addressEntryOptional = this.stream().filter(addressEntry -> offerId.equals(addressEntry.getOfferId())).findAny(); Optional<AddressEntry> addressEntryOptional = this.stream().filter(addressEntry -> offerId.equals(addressEntry.getOfferId())).findAny();
if (addressEntryOptional.isPresent()) { if (addressEntryOptional.isPresent()) {
AddressEntry addressEntry = addressEntryOptional.get(); AddressEntry addressEntry = addressEntryOptional.get();
add(new AddressEntry(addressEntry.getKeyPair(), wallet.getParams(), AddressEntry.Context.AVAILABLE)); boolean changed1 = add(new AddressEntry(addressEntry.getKeyPair(), wallet.getParams(), AddressEntry.Context.AVAILABLE));
remove(addressEntry); boolean changed2 = remove(addressEntry);
storage.queueUpForSave(); if (changed1 || changed2)
storage.queueUpForSave();
} }
} }
public void swapToAvailable(AddressEntry addressEntry) { public void swapToAvailable(AddressEntry addressEntry) {
remove(addressEntry); remove(addressEntry);
add(new AddressEntry(addressEntry.getKeyPair(), wallet.getParams(), AddressEntry.Context.AVAILABLE)); boolean changed1 = add(new AddressEntry(addressEntry.getKeyPair(), wallet.getParams(), AddressEntry.Context.AVAILABLE));
remove(addressEntry); boolean changed2 = remove(addressEntry);
storage.queueUpForSave(); if (changed1 || changed2)
storage.queueUpForSave();
} }
public void queueUpForSave() { public void queueUpForSave() {

View file

@ -145,7 +145,7 @@ public class SeedPeersSocks5Dns implements PeerDiscovery {
InetAddress addrResolved = proxySocket.getInetAddress(); InetAddress addrResolved = proxySocket.getInetAddress();
proxySocket.close(); proxySocket.close();
if( addrResolved != null ) { if( addrResolved != null ) {
log.info("Resolved " + addr.getHostString() + " to " + addrResolved.getHostAddress() ); log.debug("Resolved " + addr.getHostString() + " to " + addrResolved.getHostAddress());
return new InetSocketAddress(addrResolved, addr.getPort() ); return new InetSocketAddress(addrResolved, addr.getPort() );
} }
else { else {

View file

@ -981,7 +981,7 @@ public class TradeWalletService {
transaction.addOutput(buyerPayoutAmount, new Address(params, buyerAddressString)); transaction.addOutput(buyerPayoutAmount, new Address(params, buyerAddressString));
transaction.addOutput(sellerPayoutAmount, new Address(params, sellerAddressString)); transaction.addOutput(sellerPayoutAmount, new Address(params, sellerAddressString));
if (lockTime != 0) { if (lockTime != 0) {
log.info("We use a lockTime of " + lockTime); log.debug("We use a lockTime of " + lockTime);
// When using lockTime we need to set sequenceNumber to 0 // When using lockTime we need to set sequenceNumber to 0
transaction.getInputs().stream().forEach(i -> i.setSequenceNumber(0)); transaction.getInputs().stream().forEach(i -> i.setSequenceNumber(0));
transaction.setLockTime(lockTime); transaction.setLockTime(lockTime);

View file

@ -170,7 +170,7 @@ public class WalletService {
backupWallet(); backupWallet();
final Socks5Proxy socks5Proxy = preferences.getUseTorForBitcoinJ() ? socks5ProxyProvider.getSocks5Proxy() : null; final Socks5Proxy socks5Proxy = preferences.getUseTorForBitcoinJ() ? socks5ProxyProvider.getSocks5Proxy() : null;
log.info("Use socks5Proxy for bitcoinj: " + socks5Proxy); log.debug("Use socks5Proxy for bitcoinj: " + socks5Proxy);
// If seed is non-null it means we are restoring from backup. // If seed is non-null it means we are restoring from backup.
walletAppKit = new WalletAppKitBitSquare(params, socks5Proxy, walletDir, "Bitsquare") { walletAppKit = new WalletAppKitBitSquare(params, socks5Proxy, walletDir, "Bitsquare") {
@ -714,7 +714,7 @@ public class WalletService {
public void doubleSpendTransaction(Transaction txToDoubleSpend, Address toAddress, Runnable resultHandler, ErrorMessageHandler errorMessageHandler) throws InsufficientMoneyException, AddressFormatException, AddressEntryException { public void doubleSpendTransaction(Transaction txToDoubleSpend, Address toAddress, Runnable resultHandler, ErrorMessageHandler errorMessageHandler) throws InsufficientMoneyException, AddressFormatException, AddressEntryException {
final TransactionConfidence.ConfidenceType confidenceType = txToDoubleSpend.getConfidence().getConfidenceType(); final TransactionConfidence.ConfidenceType confidenceType = txToDoubleSpend.getConfidence().getConfidenceType();
if (confidenceType == TransactionConfidence.ConfidenceType.PENDING) { if (confidenceType == TransactionConfidence.ConfidenceType.PENDING) {
log.info("txToDoubleSpend nr. of inputs " + txToDoubleSpend.getInputs().size()); log.debug("txToDoubleSpend nr. of inputs " + txToDoubleSpend.getInputs().size());
Transaction newTransaction = new Transaction(params); Transaction newTransaction = new Transaction(params);
txToDoubleSpend.getInputs().stream().forEach(input -> { txToDoubleSpend.getInputs().stream().forEach(input -> {
@ -739,8 +739,8 @@ public class WalletService {
} }
); );
log.info("newTransaction nr. of inputs " + newTransaction.getInputs().size()); log.debug("newTransaction nr. of inputs " + newTransaction.getInputs().size());
log.info("newTransaction size in kB " + newTransaction.bitcoinSerialize().length / 1024); log.debug("newTransaction size in kB " + newTransaction.bitcoinSerialize().length / 1024);
if (!newTransaction.getInputs().isEmpty()) { if (!newTransaction.getInputs().isEmpty()) {
Coin amount = Coin.valueOf(newTransaction.getInputs().stream() Coin amount = Coin.valueOf(newTransaction.getInputs().stream()
@ -795,7 +795,7 @@ public class WalletService {
} }
} }
if (sendResult != null) { if (sendResult != null) {
log.info("Broadcasting double spending transaction. " + newTransaction); log.debug("Broadcasting double spending transaction. " + newTransaction);
Futures.addCallback(sendResult.broadcastComplete, new FutureCallback<Transaction>() { Futures.addCallback(sendResult.broadcastComplete, new FutureCallback<Transaction>() {
@Override @Override
public void onSuccess(Transaction result) { public void onSuccess(Transaction result) {
@ -835,9 +835,9 @@ public class WalletService {
newSendRequest.feePerKb = FeePolicy.getNonTradeFeePerKb(); newSendRequest.feePerKb = FeePolicy.getNonTradeFeePerKb();
wallet.completeTx(newSendRequest); wallet.completeTx(newSendRequest);
log.info("After fee check: amount " + amount.toFriendlyString()); log.debug("After fee check: amount " + amount.toFriendlyString());
log.info("Output fee " + sendRequest.tx.getFee().toFriendlyString()); log.debug("Output fee " + sendRequest.tx.getFee().toFriendlyString());
sendRequest.tx.getOutputs().stream().forEach(o -> log.info("Output value " + o.getValue().toFriendlyString())); sendRequest.tx.getOutputs().stream().forEach(o -> log.debug("Output value " + o.getValue().toFriendlyString()));
} catch (InsufficientMoneyException e) { } catch (InsufficientMoneyException e) {
if (e.missing != null) { if (e.missing != null) {
log.trace("missing fee " + e.missing.toFriendlyString()); log.trace("missing fee " + e.missing.toFriendlyString());

View file

@ -38,7 +38,7 @@ public class BlockchainService {
Futures.addCallback(future, new FutureCallback<Coin>() { Futures.addCallback(future, new FutureCallback<Coin>() {
public void onSuccess(Coin fee) { public void onSuccess(Coin fee) {
if (!resultFuture.isDone()) { if (!resultFuture.isDone()) {
log.info("Request fee from providers done after {} ms.", (System.currentTimeMillis() - startTime)); log.debug("Request fee from providers done after {} ms.", (System.currentTimeMillis() - startTime));
resultFuture.set(fee); resultFuture.set(fee);
} }
} }

View file

@ -33,7 +33,7 @@ class GetFeeRequest {
try { try {
return provider.getFee(transactionId); return provider.getFee(transactionId);
} catch (IOException | HttpException e) { } catch (IOException | HttpException e) {
log.info("Fee request failed for tx {} from provider {}\n" + log.debug("Fee request failed for tx {} from provider {}\n" +
"That is expected if the tx was not propagated yet to the provider.\n" + "That is expected if the tx was not propagated yet to the provider.\n" +
"error={}", "error={}",
transactionId, provider, e.getMessage()); transactionId, provider, e.getMessage());
@ -43,7 +43,7 @@ class GetFeeRequest {
Futures.addCallback(future, new FutureCallback<Coin>() { Futures.addCallback(future, new FutureCallback<Coin>() {
public void onSuccess(Coin fee) { public void onSuccess(Coin fee) {
log.info("Received fee of {}\nfor tx {}\nfrom provider {}", fee.toFriendlyString(), transactionId, provider); log.debug("Received fee of {}\nfor tx {}\nfrom provider {}", fee.toFriendlyString(), transactionId, provider);
resultFuture.set(fee); resultFuture.set(fee);
} }

View file

@ -58,6 +58,7 @@ class GetPriceRequest {
} }
public void onFailure(@NotNull Throwable throwable) { public void onFailure(@NotNull Throwable throwable) {
log.error("requestPrice.onFailure: throwable=" + throwable.toString());
resultFuture.setException(throwable); resultFuture.setException(throwable);
} }
}); });

View file

@ -46,7 +46,7 @@ public class PriceFeedService {
} }
} }
private static final long PERIOD_FIAT_SEC = new Random().nextInt(5) + 90; private static final long PERIOD_FIAT_SEC = new Random().nextInt(5) + 70;
private static final long PERIOD_ALL_FIAT_SEC = new Random().nextInt(5) + 180; private static final long PERIOD_ALL_FIAT_SEC = new Random().nextInt(5) + 180;
private static final long PERIOD_ALL_CRYPTO_SEC = new Random().nextInt(5) + 180; private static final long PERIOD_ALL_CRYPTO_SEC = new Random().nextInt(5) + 180;
@ -63,8 +63,7 @@ public class PriceFeedService {
private long bitcoinAveragePriceProviderLastCallAllTs; private long bitcoinAveragePriceProviderLastCallAllTs;
private long poloniexPriceProviderLastCallAllTs; private long poloniexPriceProviderLastCallAllTs;
private long bitcoinAveragePriceProviderLastCallTs; private long bitcoinAveragePriceProviderLastCallTs;
private Timer cryptoCurrenciesTime; private Timer requestFiatPriceTimer;
private Timer fiatCurrenciesTime;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -86,20 +85,11 @@ public class PriceFeedService {
this.priceConsumer = resultHandler; this.priceConsumer = resultHandler;
this.faultHandler = faultHandler; this.faultHandler = faultHandler;
requestAllPrices(fiatPriceProvider, () -> { requestAllPrices(fiatPriceProvider, () -> applyPriceToConsumer());
applyPrice(); UserThread.runPeriodically(() -> requestAllPrices(fiatPriceProvider, this::applyPriceToConsumer), PERIOD_ALL_FIAT_SEC);
if (fiatCurrenciesTime == null)
fiatCurrenciesTime = UserThread.runPeriodically(() -> requestPrice(fiatPriceProvider), PERIOD_FIAT_SEC);
});
requestAllPrices(cryptoCurrenciesPriceProvider, () -> { requestAllPrices(cryptoCurrenciesPriceProvider, () -> applyPriceToConsumer());
applyPrice(); UserThread.runPeriodically(() -> requestAllPrices(cryptoCurrenciesPriceProvider, this::applyPriceToConsumer), PERIOD_ALL_CRYPTO_SEC);
if (cryptoCurrenciesTime == null)
cryptoCurrenciesTime = UserThread.runPeriodically(() -> requestAllPrices(cryptoCurrenciesPriceProvider, this::applyPrice),
PERIOD_ALL_CRYPTO_SEC);
});
UserThread.runPeriodically(() -> requestAllPrices(fiatPriceProvider, this::applyPrice), PERIOD_ALL_FIAT_SEC);
} }
@Nullable @Nullable
@ -110,7 +100,6 @@ public class PriceFeedService {
return null; return null;
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Setter // Setter
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -118,19 +107,21 @@ public class PriceFeedService {
public void setType(Type type) { public void setType(Type type) {
this.type = type; this.type = type;
typeProperty.set(type); typeProperty.set(type);
applyPrice(); applyPriceToConsumer();
} }
public void setCurrencyCode(String currencyCode) { public void setCurrencyCode(String currencyCode) {
if (this.currencyCode == null || !this.currencyCode.equals(currencyCode)) { if (this.currencyCode == null || !this.currencyCode.equals(currencyCode)) {
this.currencyCode = currencyCode; this.currencyCode = currencyCode;
currencyCodeProperty.set(currencyCode); currencyCodeProperty.set(currencyCode);
applyPrice(); applyPriceToConsumer();
if (CurrencyUtil.isCryptoCurrency(currencyCode)) { if (CurrencyUtil.isCryptoCurrency(currencyCode)) {
stopRequestFiatPriceTimer();
// Poloniex does not support calls for one currency just for all which is quite a bit of data // Poloniex does not support calls for one currency just for all which is quite a bit of data
requestAllPrices(cryptoCurrenciesPriceProvider, this::applyPrice); requestAllPrices(cryptoCurrenciesPriceProvider, this::applyPriceToConsumer);
} else { } else {
startRequestFiatPriceTimer();
requestPrice(fiatPriceProvider); requestPrice(fiatPriceProvider);
} }
} }
@ -166,12 +157,27 @@ public class PriceFeedService {
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void applyPrice() {
private void startRequestFiatPriceTimer() {
stopRequestFiatPriceTimer();
requestFiatPriceTimer = UserThread.runPeriodically(() -> requestPrice(fiatPriceProvider), PERIOD_FIAT_SEC);
}
private void stopRequestFiatPriceTimer() {
if (requestFiatPriceTimer != null)
requestFiatPriceTimer.stop();
}
private void applyPriceToConsumer() {
if (priceConsumer != null && currencyCode != null && type != null) { if (priceConsumer != null && currencyCode != null && type != null) {
if (cache.containsKey(currencyCode)) { if (cache.containsKey(currencyCode)) {
MarketPrice marketPrice = cache.get(currencyCode); try {
if (marketPrice != null) MarketPrice marketPrice = cache.get(currencyCode);
priceConsumer.accept(marketPrice.getPrice(type)); priceConsumer.accept(marketPrice.getPrice(type));
} catch (Throwable t) {
log.warn("Error at applyPriceToConsumer " + t.getMessage());
}
} else { } else {
String errorMessage = "We don't have a price for currencyCode " + currencyCode; String errorMessage = "We don't have a price for currencyCode " + currencyCode;
log.debug(errorMessage); log.debug(errorMessage);
@ -192,21 +198,25 @@ public class PriceFeedService {
if (allowed) { if (allowed) {
GetPriceRequest getPriceRequest = new GetPriceRequest(); GetPriceRequest getPriceRequest = new GetPriceRequest();
SettableFuture<MarketPrice> future = getPriceRequest.requestPrice(currencyCode, provider); if (CurrencyUtil.isFiatCurrency(currencyCode)) {
Futures.addCallback(future, new FutureCallback<MarketPrice>() { SettableFuture<MarketPrice> future = getPriceRequest.requestPrice(currencyCode, provider);
public void onSuccess(MarketPrice marketPrice) { Futures.addCallback(future, new FutureCallback<MarketPrice>() {
UserThread.execute(() -> { public void onSuccess(MarketPrice marketPrice) {
if (marketPrice != null && priceConsumer != null) { UserThread.execute(() -> {
cache.put(marketPrice.currencyCode, marketPrice); if (marketPrice != null && priceConsumer != null) {
priceConsumer.accept(marketPrice.getPrice(type)); cache.put(marketPrice.currencyCode, marketPrice);
} priceConsumer.accept(marketPrice.getPrice(type));
}); }
} });
}
public void onFailure(@NotNull Throwable throwable) { public void onFailure(@NotNull Throwable throwable) {
log.debug("Could not load marketPrice\n" + throwable.getMessage()); log.debug("Could not load marketPrice\n" + throwable.getMessage());
} }
}); });
} else {
log.warn("We tried to call requestPrice with a non fiat currency selected: selectedCurrencyCode=" + currencyCode);
}
} else { } else {
log.debug("Ignore request. Too many attempt to call the API provider " + provider); log.debug("Ignore request. Too many attempt to call the API provider " + provider);
} }

View file

@ -30,11 +30,11 @@ public class ScryptUtil {
public static void deriveKeyWithScrypt(KeyCrypterScrypt keyCrypterScrypt, String password, DeriveKeyResultHandler resultHandler) { public static void deriveKeyWithScrypt(KeyCrypterScrypt keyCrypterScrypt, String password, DeriveKeyResultHandler resultHandler) {
Utilities.getThreadPoolExecutor("ScryptUtil:deriveKeyWithScrypt-%d", 1, 2, 5L).submit(() -> { Utilities.getThreadPoolExecutor("ScryptUtil:deriveKeyWithScrypt-%d", 1, 2, 5L).submit(() -> {
try { try {
log.info("Doing key derivation"); log.debug("Doing key derivation");
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
KeyParameter aesKey = keyCrypterScrypt.deriveKey(password); KeyParameter aesKey = keyCrypterScrypt.deriveKey(password);
long duration = System.currentTimeMillis() - start; long duration = System.currentTimeMillis() - start;
log.info("Key derivation took {} msec", duration); log.debug("Key derivation took {} msec", duration);
UserThread.execute(() -> { UserThread.execute(() -> {
try { try {
resultHandler.handleResult(aesKey); resultHandler.handleResult(aesKey);

View file

@ -0,0 +1,32 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.locale;
import java.io.Serializable;
public class CurrencyTuple implements Serializable {
// That object is used for serializing to a Json file.
public final String code;
public final String name;
public CurrencyTuple(String code, String name) {
this.code = code;
this.name = name;
}
}

View file

@ -65,18 +65,20 @@ public final class TradableList<T extends Tradable> extends ArrayList<T> impleme
@Override @Override
public boolean add(T tradable) { public boolean add(T tradable) {
boolean result = super.add(tradable); boolean changed = super.add(tradable);
getObservableList().add(tradable); getObservableList().add(tradable);
storage.queueUpForSave(); if (changed)
return result; storage.queueUpForSave();
return changed;
} }
@Override @Override
public boolean remove(Object tradable) { public boolean remove(Object tradable) {
boolean result = super.remove(tradable); boolean changed = super.remove(tradable);
getObservableList().remove(tradable); getObservableList().remove(tradable);
storage.queueUpForSave(); if (changed)
return result; storage.queueUpForSave();
return changed;
} }
public ObservableList<T> getObservableList() { public ObservableList<T> getObservableList() {

View file

@ -316,16 +316,20 @@ public abstract class Trade implements Tradable, Model {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void setState(State state) { public void setState(State state) {
boolean changed = this.state != state;
this.state = state; this.state = state;
stateProperty.set(state); stateProperty.set(state);
persist(); if (changed)
persist();
} }
public void setDisputeState(DisputeState disputeState) { public void setDisputeState(DisputeState disputeState) {
Log.traceCall("disputeState=" + disputeState + "\n\ttrade=" + this); Log.traceCall("disputeState=" + disputeState + "\n\ttrade=" + this);
boolean changed = this.disputeState != disputeState;
this.disputeState = disputeState; this.disputeState = disputeState;
disputeStateProperty.set(disputeState); disputeStateProperty.set(disputeState);
persist(); if (changed)
persist();
} }
public DisputeState getDisputeState() { public DisputeState getDisputeState() {
@ -333,9 +337,11 @@ public abstract class Trade implements Tradable, Model {
} }
public void setTradePeriodState(TradePeriodState tradePeriodState) { public void setTradePeriodState(TradePeriodState tradePeriodState) {
boolean changed = this.tradePeriodState != tradePeriodState;
this.tradePeriodState = tradePeriodState; this.tradePeriodState = tradePeriodState;
tradePeriodStateProperty.set(tradePeriodState); tradePeriodStateProperty.set(tradePeriodState);
persist(); if (changed)
persist();
} }
public TradePeriodState getTradePeriodState() { public TradePeriodState getTradePeriodState() {

View file

@ -75,8 +75,6 @@ import static io.bitsquare.util.Validator.nonEmptyStringOf;
public class TradeManager { public class TradeManager {
private static final Logger log = LoggerFactory.getLogger(TradeManager.class); private static final Logger log = LoggerFactory.getLogger(TradeManager.class);
private static final long REPUBLISH_STATISTICS_INTERVAL_MIN = TimeUnit.HOURS.toMillis(1);
private final User user; private final User user;
private final KeyRing keyRing; private final KeyRing keyRing;
private final WalletService walletService; private final WalletService walletService;
@ -223,17 +221,9 @@ public class TradeManager {
} }
// We start later to have better connectivity to the network // We start later to have better connectivity to the network
UserThread.runPeriodically(() -> publishTradeStatistics(tradesForStatistics), UserThread.runAfter(() -> publishTradeStatistics(tradesForStatistics),
30, TimeUnit.SECONDS); 30, TimeUnit.SECONDS);
//TODO can be removed at next release
// For the first 2 weeks of the release we re publish the trades to get faster good distribution
// otherwise the trades would only be published again at restart and if a client dont do that the stats might be missing
// for a longer time as initially there are not many peer upgraded and supporting flooding of the stats data.
if (new Date().before(new Date(2016 - 1900, Calendar.AUGUST, 8)))
UserThread.runPeriodically(() -> publishTradeStatistics(tradesForStatistics),
REPUBLISH_STATISTICS_INTERVAL_MIN, TimeUnit.MILLISECONDS);
pendingTradesInitialized.set(true); pendingTradesInitialized.set(true);
} }
@ -249,7 +239,8 @@ public class TradeManager {
tradeStatisticsManager.add(tradeStatistics); tradeStatisticsManager.add(tradeStatistics);
// Only trades from last 30 days // Only trades from last 30 days
if ((new Date().getTime() - trade.getDate().getTime()) < TimeUnit.DAYS.toMillis(30)) { //TODO we want to get old trades published so we dont do the 30 days check for the first few weeks of the new version
if (new Date().before(new Date(2016 - 1900, Calendar.AUGUST, 30)) || (new Date().getTime() - trade.getDate().getTime()) < TimeUnit.DAYS.toMillis(30)) {
long delay = 3000; long delay = 3000;
final long minDelay = (i + 1) * delay; final long minDelay = (i + 1) * delay;
final long maxDelay = (i + 2) * delay; final long maxDelay = (i + 2) * delay;
@ -289,7 +280,7 @@ public class TradeManager {
// TODO respond // TODO respond
//(RequestDepositTxInputsMessage)message. //(RequestDepositTxInputsMessage)message.
// messageService.sendEncryptedMessage(peerAddress,messageWithPubKey.getMessage().); // messageService.sendEncryptedMessage(peerAddress,messageWithPubKey.getMessage().);
log.info("We received a take offer request but don't have that offer anymore."); log.debug("We received a take offer request but don't have that offer anymore.");
} }
} }
@ -391,7 +382,7 @@ public class TradeManager {
@Override @Override
public void onSuccess(@javax.annotation.Nullable Transaction transaction) { public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
if (transaction != null) { if (transaction != null) {
log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString()); log.debug("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
addTradeToClosedTrades(trade); addTradeToClosedTrades(trade);
trade.setState(Trade.State.WITHDRAW_COMPLETED); trade.setState(Trade.State.WITHDRAW_COMPLETED);
resultHandler.handleResult(); resultHandler.handleResult();

View file

@ -68,6 +68,7 @@ public final class OpenOffer implements Tradable {
log.warn("Cannot be deserialized." + t.getMessage()); log.warn("Cannot be deserialized." + t.getMessage());
} }
} }
public Date getDate() { public Date getDate() {
return offer.getDate(); return offer.getDate();
} }
@ -92,8 +93,10 @@ public final class OpenOffer implements Tradable {
public void setState(State state) { public void setState(State state) {
log.trace("setState" + state); log.trace("setState" + state);
boolean changed = this.state != state;
this.state = state; this.state = state;
storage.queueUpForSave(); if (changed)
storage.queueUpForSave();
// We keep it reserved for a limited time, if trade preparation fails we revert to available state // We keep it reserved for a limited time, if trade preparation fails we revert to available state
if (this.state == State.RESERVED) if (this.state == State.RESERVED)
@ -111,7 +114,7 @@ public final class OpenOffer implements Tradable {
stopTimeout(); stopTimeout();
timeoutTimer = UserThread.runAfter(() -> { timeoutTimer = UserThread.runAfter(() -> {
log.info("Timeout for resettin State.RESERVED reached"); log.debug("Timeout for resettin State.RESERVED reached");
if (state == State.RESERVED) if (state == State.RESERVED)
setState(State.AVAILABLE); setState(State.AVAILABLE);
}, TIMEOUT_SEC); }, TIMEOUT_SEC);

View file

@ -152,7 +152,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
stopPeriodicRepublishOffersTimer(); stopPeriodicRepublishOffersTimer();
stopRetryRepublishOffersTimer(); stopRetryRepublishOffersTimer();
log.info("remove all open offers at shutDown"); log.debug("remove all open offers at shutDown");
// we remove own offers from offerbook when we go offline // we remove own offers from offerbook when we go offline
// Normally we use a delay for broadcasting to the peers, but at shut down we want to get it fast out // Normally we use a delay for broadcasting to the peers, but at shut down we want to get it fast out
@ -407,12 +407,12 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
@Override @Override
public void onFault() { public void onFault() {
log.info("Sending OfferAvailabilityResponse failed."); log.debug("Sending OfferAvailabilityResponse failed.");
} }
}); });
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
log.info("Exception at handleRequestIsOfferAvailableMessage " + t.getMessage()); log.debug("Exception at handleRequestIsOfferAvailableMessage " + t.getMessage());
} }
} else { } else {
log.debug("We have stopped already. We ignore that handleOfferAvailabilityRequest call."); log.debug("We have stopped already. We ignore that handleOfferAvailabilityRequest call.");
@ -505,7 +505,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
// we delay to avoid reaching throttle limits // we delay to avoid reaching throttle limits
// roughly 4 offers per second // roughly 4 offers per second
long delay = 150; long delay = 300;
final long minDelay = (i + 1) * delay; final long minDelay = (i + 1) * delay;
final long maxDelay = (i + 2) * delay; final long maxDelay = (i + 2) * delay;
final OpenOffer openOffer = openOffersList.get(i); final OpenOffer openOffer = openOffersList.get(i);
@ -532,7 +532,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
} }
private void restart() { private void restart() {
log.info("Restart after connection loss"); log.debug("Restart after connection loss");
if (retryRepublishOffersTimer == null) if (retryRepublishOffersTimer == null)
retryRepublishOffersTimer = UserThread.runAfter(() -> { retryRepublishOffersTimer = UserThread.runAfter(() -> {
stopped = false; stopped = false;

View file

@ -135,7 +135,7 @@ public class OfferAvailabilityProtocol {
private void startTimeout() { private void startTimeout() {
if (timeoutTimer == null) { if (timeoutTimer == null) {
timeoutTimer = UserThread.runAfter(() -> { timeoutTimer = UserThread.runAfter(() -> {
log.warn("Timeout reached at " + this); log.debug("Timeout reached at " + this);
model.offer.setState(Offer.State.OFFERER_OFFLINE); model.offer.setState(Offer.State.OFFERER_OFFLINE);
errorMessageHandler.handleErrorMessage("Timeout reached: Peer has not responded."); errorMessageHandler.handleErrorMessage("Timeout reached: Peer has not responded.");
}, TIMEOUT_SEC); }, TIMEOUT_SEC);

View file

@ -44,7 +44,7 @@ public class BroadcastCreateOfferFeeTx extends Task<PlaceOfferModel> {
model.tradeWalletService.broadcastTx(model.getTransaction(), new FutureCallback<Transaction>() { model.tradeWalletService.broadcastTx(model.getTransaction(), new FutureCallback<Transaction>() {
@Override @Override
public void onSuccess(Transaction transaction) { public void onSuccess(Transaction transaction) {
log.info("Broadcast of offer fee payment succeeded: transaction = " + transaction.toString()); log.debug("Broadcast of offer fee payment succeeded: transaction = " + transaction.toString());
if (model.getTransaction().getHashAsString().equals(transaction.getHashAsString())) { if (model.getTransaction().getHashAsString().equals(transaction.getHashAsString())) {
model.offer.setState(Offer.State.OFFER_FEE_PAID); model.offer.setState(Offer.State.OFFER_FEE_PAID);
@ -57,7 +57,7 @@ public class BroadcastCreateOfferFeeTx extends Task<PlaceOfferModel> {
// Normally we use a delay for broadcasting to the peers, but at shut down we want to get it fast out // Normally we use a delay for broadcasting to the peers, but at shut down we want to get it fast out
model.offerBookService.removeOffer(model.offer, model.offerBookService.removeOffer(model.offer,
() -> { () -> {
log.info("We store now the changed txID to the offer and add that again."); log.debug("We store now the changed txID to the offer and add that again.");
// We store now the changed txID to the offer and add that again. // We store now the changed txID to the offer and add that again.
model.offer.setOfferFeePaymentTxID(transaction.getHashAsString()); model.offer.setOfferFeePaymentTxID(transaction.getHashAsString());
model.setTransaction(transaction); model.setTransaction(transaction);
@ -106,7 +106,7 @@ public class BroadcastCreateOfferFeeTx extends Task<PlaceOfferModel> {
if (!removeOfferFailed && !addOfferFailed) { if (!removeOfferFailed && !addOfferFailed) {
// If broadcast fails we need to remove offer from offerbook // If broadcast fails we need to remove offer from offerbook
model.offerBookService.removeOffer(model.offer, model.offerBookService.removeOffer(model.offer,
() -> log.info("Offer removed from offerbook because broadcast failed."), () -> log.debug("Offer removed from offerbook because broadcast failed."),
errorMessage -> log.error("removeOffer failed. " + errorMessage)); errorMessage -> log.error("removeOffer failed. " + errorMessage));
} }
} }

View file

@ -64,7 +64,7 @@ public abstract class TradeTask extends Task<Trade> {
if (processModel.getTradeMessage() instanceof MailboxMessage) { if (processModel.getTradeMessage() instanceof MailboxMessage) {
DecryptedMsgWithPubKey mailboxMessage = trade.getMailboxMessage(); DecryptedMsgWithPubKey mailboxMessage = trade.getMailboxMessage();
if (mailboxMessage != null && mailboxMessage.message.equals(processModel.getTradeMessage())) { if (mailboxMessage != null && mailboxMessage.message.equals(processModel.getTradeMessage())) {
log.info("Remove mailboxMessage from P2P network. mailboxMessage = " + mailboxMessage); log.debug("Remove mailboxMessage from P2P network. mailboxMessage = " + mailboxMessage);
processModel.getP2PService().removeEntryFromMailbox(mailboxMessage); processModel.getP2PService().removeEntryFromMailbox(mailboxMessage);
trade.setMailboxMessage(null); trade.setMailboxMessage(null);
} }

View file

@ -46,7 +46,7 @@ public class OffererCreatesAndSignsDepositTxAsBuyer extends TradeTask {
Coin buyerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades()); Coin buyerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades());
Coin msOutputAmount = buyerInputAmount.add(FeePolicy.getSecurityDeposit()).add(trade.getTradeAmount()); Coin msOutputAmount = buyerInputAmount.add(FeePolicy.getSecurityDeposit()).add(trade.getTradeAmount());
log.info("\n\n------------------------------------------------------------\n" log.debug("\n\n------------------------------------------------------------\n"
+ "Contract as json\n" + "Contract as json\n"
+ trade.getContractAsJson() + trade.getContractAsJson()
+ "\n------------------------------------------------------------\n"); + "\n------------------------------------------------------------\n");

View file

@ -48,14 +48,14 @@ public class SendFiatTransferStartedMessage extends TradeTask {
new SendMailboxMessageListener() { new SendMailboxMessageListener() {
@Override @Override
public void onArrived() { public void onArrived() {
log.info("Message arrived at peer."); log.debug("Message arrived at peer.");
trade.setState(Trade.State.BUYER_SENT_FIAT_PAYMENT_INITIATED_MSG); trade.setState(Trade.State.BUYER_SENT_FIAT_PAYMENT_INITIATED_MSG);
complete(); complete();
} }
@Override @Override
public void onStoredInMailbox() { public void onStoredInMailbox() {
log.info("Message stored in mailbox."); log.debug("Message stored in mailbox.");
trade.setState(Trade.State.BUYER_SENT_FIAT_PAYMENT_INITIATED_MSG); trade.setState(Trade.State.BUYER_SENT_FIAT_PAYMENT_INITIATED_MSG);
complete(); complete();
} }

View file

@ -47,7 +47,7 @@ public class SignAndPublishDepositTxAsBuyer extends TradeTask {
try { try {
runInterceptHook(); runInterceptHook();
log.info("\n\n------------------------------------------------------------\n" log.debug("\n\n------------------------------------------------------------\n"
+ "Contract as json\n" + "Contract as json\n"
+ trade.getContractAsJson() + trade.getContractAsJson()
+ "\n------------------------------------------------------------\n"); + "\n------------------------------------------------------------\n");

View file

@ -46,7 +46,7 @@ public class OffererCreatesAndSignsDepositTxAsSeller extends TradeTask {
Coin sellerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades()).add(trade.getTradeAmount()); Coin sellerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades()).add(trade.getTradeAmount());
Coin msOutputAmount = sellerInputAmount.add(FeePolicy.getSecurityDeposit()); Coin msOutputAmount = sellerInputAmount.add(FeePolicy.getSecurityDeposit());
log.info("\n\n------------------------------------------------------------\n" log.debug("\n\n------------------------------------------------------------\n"
+ "Contract as json\n" + "Contract as json\n"
+ trade.getContractAsJson() + trade.getContractAsJson()
+ "\n------------------------------------------------------------\n"); + "\n------------------------------------------------------------\n");

View file

@ -46,7 +46,7 @@ public class SignAndPublishDepositTxAsSeller extends TradeTask {
protected void run() { protected void run() {
try { try {
runInterceptHook(); runInterceptHook();
log.info("\n\n------------------------------------------------------------\n" log.debug("\n\n------------------------------------------------------------\n"
+ "Contract as json\n" + "Contract as json\n"
+ trade.getContractAsJson() + trade.getContractAsJson()
+ "\n------------------------------------------------------------\n"); + "\n------------------------------------------------------------\n");

View file

@ -64,7 +64,7 @@ public class PublishTradeStatistics extends TradeTask {
} }
} }
if (!matches) { if (!matches) {
log.warn("We publish tradeStatistics because the offerer uses an old version."); log.debug("We publish tradeStatistics because the offerer uses an old version so we publish to have at least 1 data item published.");
processModel.getP2PService().addData(tradeStatistics, true); processModel.getP2PService().addData(tradeStatistics, true);
} else { } else {
log.trace("We do not publish tradeStatistics because the offerer support the capabilities."); log.trace("We do not publish tradeStatistics because the offerer support the capabilities.");

View file

@ -4,6 +4,8 @@ import com.google.inject.Inject;
import com.google.inject.name.Named; import com.google.inject.name.Named;
import io.bitsquare.app.CoreOptionKeys; import io.bitsquare.app.CoreOptionKeys;
import io.bitsquare.common.util.Utilities; import io.bitsquare.common.util.Utilities;
import io.bitsquare.locale.CurrencyTuple;
import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.p2p.P2PService; import io.bitsquare.p2p.P2PService;
import io.bitsquare.p2p.storage.HashMapChangedListener; import io.bitsquare.p2p.storage.HashMapChangedListener;
import io.bitsquare.p2p.storage.payload.StoragePayload; import io.bitsquare.p2p.storage.payload.StoragePayload;
@ -14,6 +16,7 @@ import javafx.collections.ObservableSet;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -21,22 +24,44 @@ import java.util.stream.Collectors;
public class TradeStatisticsManager { public class TradeStatisticsManager {
private static final Logger log = LoggerFactory.getLogger(TradeStatisticsManager.class); private static final Logger log = LoggerFactory.getLogger(TradeStatisticsManager.class);
private final Storage<HashSet<TradeStatistics>> storage; private final Storage<HashSet<TradeStatistics>> statisticsStorage;
private Storage<String> jsonStorage; private Storage<String> fiatCurrencyListJsonStorage;
private Storage<String> cryptoCurrencyListJsonStorage;
private Storage<String> statisticsJsonStorage;
private boolean dumpStatistics; private boolean dumpStatistics;
private ObservableSet<TradeStatistics> observableTradeStatisticsSet = FXCollections.observableSet(); private ObservableSet<TradeStatistics> observableTradeStatisticsSet = FXCollections.observableSet();
private HashSet<TradeStatistics> tradeStatisticsSet = new HashSet<>(); private HashSet<TradeStatistics> tradeStatisticsSet = new HashSet<>();
@Inject @Inject
public TradeStatisticsManager(Storage<HashSet<TradeStatistics>> storage, Storage<String> jsonStorage, P2PService p2PService, @Named(CoreOptionKeys.DUMP_STATISTICS) boolean dumpStatistics) { public TradeStatisticsManager(Storage<HashSet<TradeStatistics>> statisticsStorage,
this.storage = storage; Storage<String> fiatCurrencyListJsonStorage,
this.jsonStorage = jsonStorage; Storage<String> cryptoCurrencyListJsonStorage,
Storage<String> statisticsJsonStorage,
P2PService p2PService,
@Named(CoreOptionKeys.DUMP_STATISTICS) boolean dumpStatistics) {
this.statisticsStorage = statisticsStorage;
this.fiatCurrencyListJsonStorage = fiatCurrencyListJsonStorage;
this.cryptoCurrencyListJsonStorage = cryptoCurrencyListJsonStorage;
this.statisticsJsonStorage = statisticsJsonStorage;
this.dumpStatistics = dumpStatistics; this.dumpStatistics = dumpStatistics;
if (dumpStatistics) if (dumpStatistics) {
this.jsonStorage.initAndGetPersistedWithFileName("trade_statistics.json"); this.statisticsJsonStorage.initAndGetPersistedWithFileName("trade_statistics.json");
HashSet<TradeStatistics> persisted = storage.initAndGetPersistedWithFileName("TradeStatistics"); this.fiatCurrencyListJsonStorage.initAndGetPersistedWithFileName("fiat_currency_list.json");
ArrayList<CurrencyTuple> fiatCurrencyList = new ArrayList<>(CurrencyUtil.getAllSortedFiatCurrencies().stream()
.map(e -> new CurrencyTuple(e.getCode(), e.getName()))
.collect(Collectors.toList()));
fiatCurrencyListJsonStorage.queueUpForSave(Utilities.objectToJson(fiatCurrencyList), 2000);
this.cryptoCurrencyListJsonStorage.initAndGetPersistedWithFileName("crypto_currency_list.json");
ArrayList<CurrencyTuple> cryptoCurrencyList = new ArrayList<>(CurrencyUtil.getAllSortedCryptoCurrencies().stream()
.map(e -> new CurrencyTuple(e.getCode(), e.getName()))
.collect(Collectors.toList()));
cryptoCurrencyListJsonStorage.queueUpForSave(Utilities.objectToJson(cryptoCurrencyList), 2000);
}
HashSet<TradeStatistics> persisted = statisticsStorage.initAndGetPersistedWithFileName("TradeStatistics");
if (persisted != null) if (persisted != null)
persisted.stream().forEach(this::add); persisted.stream().forEach(this::add);
@ -61,7 +86,7 @@ public class TradeStatisticsManager {
if (!itemAlreadyAdded) { if (!itemAlreadyAdded) {
tradeStatisticsSet.add(tradeStatistics); tradeStatisticsSet.add(tradeStatistics);
observableTradeStatisticsSet.add(tradeStatistics); observableTradeStatisticsSet.add(tradeStatistics);
storage.queueUpForSave(tradeStatisticsSet, 2000); statisticsStorage.queueUpForSave(new HashSet<>(tradeStatisticsSet), 2000);
dump(); dump();
} else { } else {
@ -86,7 +111,7 @@ public class TradeStatisticsManager {
list.sort((o1, o2) -> (o1.tradeDate < o2.tradeDate ? 1 : (o1.tradeDate == o2.tradeDate ? 0 : -1))); list.sort((o1, o2) -> (o1.tradeDate < o2.tradeDate ? 1 : (o1.tradeDate == o2.tradeDate ? 0 : -1)));
TradeStatistics[] array = new TradeStatistics[tradeStatisticsSet.size()]; TradeStatistics[] array = new TradeStatistics[tradeStatisticsSet.size()];
list.toArray(array); list.toArray(array);
jsonStorage.queueUpForSave(Utilities.objectToJson(array), 5_000); statisticsJsonStorage.queueUpForSave(Utilities.objectToJson(array), 5000);
} }
} }

View file

@ -121,8 +121,10 @@ public final class Preferences implements Persistable {
private long nonTradeTxFeePerKB = FeePolicy.getNonTradeFeePerKb().value; private long nonTradeTxFeePerKB = FeePolicy.getNonTradeFeePerKb().value;
private double maxPriceDistanceInPercent; private double maxPriceDistanceInPercent;
private boolean useInvertedMarketPrice; private boolean useInvertedMarketPrice;
private String marketScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode();
private String tradeStatisticsScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode(); private String offerBookChartScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode();
private String tradeChartsScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode();
private String buyScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode(); private String buyScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode();
private String sellScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode(); private String sellScreenCurrencyCode = CurrencyUtil.getDefaultTradeCurrency().getCode();
private int tradeStatisticsTickUnitIndex = 0; private int tradeStatisticsTickUnitIndex = 0;
@ -215,10 +217,10 @@ public final class Preferences implements Persistable {
if (persisted.getPeerTagMap() != null) if (persisted.getPeerTagMap() != null)
peerTagMap = persisted.getPeerTagMap(); peerTagMap = persisted.getPeerTagMap();
marketScreenCurrencyCode = persisted.getMarketScreenCurrencyCode(); offerBookChartScreenCurrencyCode = persisted.getOfferBookChartScreenCurrencyCode();
buyScreenCurrencyCode = persisted.getBuyScreenCurrencyCode(); buyScreenCurrencyCode = persisted.getBuyScreenCurrencyCode();
sellScreenCurrencyCode = persisted.getSellScreenCurrencyCode(); sellScreenCurrencyCode = persisted.getSellScreenCurrencyCode();
tradeStatisticsScreenCurrencyCode = persisted.getTradeStatisticsScreenCurrencyCode(); tradeChartsScreenCurrencyCode = persisted.getTradeChartsScreenCurrencyCode();
tradeStatisticsTickUnitIndex = persisted.getTradeStatisticsTickUnitIndex(); tradeStatisticsTickUnitIndex = persisted.getTradeStatisticsTickUnitIndex();
if (persisted.getIgnoreTradersList() != null) if (persisted.getIgnoreTradersList() != null)
@ -449,8 +451,8 @@ public final class Preferences implements Persistable {
} }
} }
public void setMarketScreenCurrencyCode(String marketScreenCurrencyCode) { public void setOfferBookChartScreenCurrencyCode(String offerBookChartScreenCurrencyCode) {
this.marketScreenCurrencyCode = marketScreenCurrencyCode; this.offerBookChartScreenCurrencyCode = offerBookChartScreenCurrencyCode;
storage.queueUpForSave(); storage.queueUpForSave();
} }
@ -474,8 +476,8 @@ public final class Preferences implements Persistable {
storage.queueUpForSave(); storage.queueUpForSave();
} }
public void setTradeStatisticsScreenCurrencyCode(String tradeStatisticsScreenCurrencyCode) { public void setTradeChartsScreenCurrencyCode(String tradeChartsScreenCurrencyCode) {
this.tradeStatisticsScreenCurrencyCode = tradeStatisticsScreenCurrencyCode; this.tradeChartsScreenCurrencyCode = tradeChartsScreenCurrencyCode;
storage.queueUpForSave(); storage.queueUpForSave();
} }
@ -486,6 +488,7 @@ public final class Preferences implements Persistable {
public void setUseTorForHttpRequests(boolean useTorForHttpRequests) { public void setUseTorForHttpRequests(boolean useTorForHttpRequests) {
useTorForHttpRequestsProperty.set(useTorForHttpRequests); useTorForHttpRequestsProperty.set(useTorForHttpRequests);
storage.queueUpForSave();
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -620,8 +623,8 @@ public final class Preferences implements Persistable {
return bridgeAddresses; return bridgeAddresses;
} }
public String getMarketScreenCurrencyCode() { public String getOfferBookChartScreenCurrencyCode() {
return marketScreenCurrencyCode; return offerBookChartScreenCurrencyCode;
} }
public String getBuyScreenCurrencyCode() { public String getBuyScreenCurrencyCode() {
@ -640,8 +643,8 @@ public final class Preferences implements Persistable {
return defaultPath; return defaultPath;
} }
public String getTradeStatisticsScreenCurrencyCode() { public String getTradeChartsScreenCurrencyCode() {
return tradeStatisticsScreenCurrencyCode; return tradeChartsScreenCurrencyCode;
} }
public int getTradeStatisticsTickUnitIndex() { public int getTradeStatisticsTickUnitIndex() {
@ -679,11 +682,11 @@ public final class Preferences implements Persistable {
private void setBlockChainExplorerTestNet(BlockChainExplorer blockChainExplorerTestNet) { private void setBlockChainExplorerTestNet(BlockChainExplorer blockChainExplorerTestNet) {
this.blockChainExplorerTestNet = blockChainExplorerTestNet; this.blockChainExplorerTestNet = blockChainExplorerTestNet;
storage.queueUpForSave(2000); storage.queueUpForSave();
} }
private void setBlockChainExplorerMainNet(BlockChainExplorer blockChainExplorerMainNet) { private void setBlockChainExplorerMainNet(BlockChainExplorer blockChainExplorerMainNet) {
this.blockChainExplorerMainNet = blockChainExplorerMainNet; this.blockChainExplorerMainNet = blockChainExplorerMainNet;
storage.queueUpForSave(2000); storage.queueUpForSave();
} }
} }

View file

@ -181,8 +181,9 @@ public final class User implements Persistable {
public void addAcceptedArbitrator(Arbitrator arbitrator) { public void addAcceptedArbitrator(Arbitrator arbitrator) {
if (!acceptedArbitrators.contains(arbitrator) && !isMyOwnRegisteredArbitrator(arbitrator)) { if (!acceptedArbitrators.contains(arbitrator) && !isMyOwnRegisteredArbitrator(arbitrator)) {
acceptedArbitrators.add(arbitrator); boolean changed = acceptedArbitrators.add(arbitrator);
storage.queueUpForSave(); if (changed)
storage.queueUpForSave();
} }
} }
@ -191,8 +192,9 @@ public final class User implements Persistable {
} }
public void removeAcceptedArbitrator(Arbitrator arbitrator) { public void removeAcceptedArbitrator(Arbitrator arbitrator) {
acceptedArbitrators.remove(arbitrator); boolean changed = acceptedArbitrators.remove(arbitrator);
storage.queueUpForSave(); if (changed)
storage.queueUpForSave();
} }
public void clearAcceptedArbitrators() { public void clearAcceptedArbitrators() {
@ -200,7 +202,7 @@ public final class User implements Persistable {
storage.queueUpForSave(); storage.queueUpForSave();
} }
public void setRegisteredArbitrator(@org.jetbrains.annotations.Nullable Arbitrator arbitrator) { public void setRegisteredArbitrator(@Nullable Arbitrator arbitrator) {
this.registeredArbitrator = arbitrator; this.registeredArbitrator = arbitrator;
storage.queueUpForSave(); storage.queueUpForSave();
} }
@ -330,7 +332,7 @@ public final class User implements Persistable {
public void setDevelopersAlert(Alert developersAlert) { public void setDevelopersAlert(Alert developersAlert) {
this.developersAlert = developersAlert; this.developersAlert = developersAlert;
storage.queueUpForSave(2000); storage.queueUpForSave();
} }
public Alert getDevelopersAlert() { public Alert getDevelopersAlert() {
@ -339,7 +341,7 @@ public final class User implements Persistable {
public void setDisplayedAlert(Alert displayedAlert) { public void setDisplayedAlert(Alert displayedAlert) {
this.displayedAlert = displayedAlert; this.displayedAlert = displayedAlert;
storage.queueUpForSave(2000); storage.queueUpForSave();
} }
public Alert getDisplayedAlert() { public Alert getDisplayedAlert() {

View file

@ -71,11 +71,11 @@ You need to get the Bitsquare dependencies first as we need to copy the BountyCa
### 4. Copy the jdkfix jar file ### 4. Copy the jdkfix jar file
Copy the jdkfix-0.4.9.1.jar from the Bitsquare jdkfix/target directory to $JAVA_HOME/jre/lib/ext/. Copy the jdkfix-0.4.9.2.jar from the Bitsquare jdkfix/target directory to $JAVA_HOME/jre/lib/ext/.
jdkfix-0.4.9.1.jar includes a bugfix of the SortedList class which will be released with the next JDK version. jdkfix-0.4.9.2.jar includes a bugfix of the SortedList class which will be released with the next JDK version.
We need to load that class before the default java class. This step will be removed once the bugfix is in the official JDK. We need to load that class before the default java class. This step will be removed once the bugfix is in the official JDK.
$ sudo cp bitsquare/jdkfix/target/jdkfix-0.4.9.1.jar $JAVA_HOME/jre/lib/ext/jdkfix-0.4.9.1.jar $ sudo cp bitsquare/jdkfix/target/jdkfix-0.4.9.2.jar $JAVA_HOME/jre/lib/ext/jdkfix-0.4.9.2.jar
### 5. Copy the BountyCastle provider jar file ### 5. Copy the BountyCastle provider jar file

View file

@ -22,7 +22,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.9.1</version> <version>0.4.9.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View file

@ -265,7 +265,7 @@ public class BitsquareApp extends Application {
private void showErrorPopup(Throwable throwable, boolean doShutDown) { private void showErrorPopup(Throwable throwable, boolean doShutDown) {
if (!shutDownRequested) { if (!shutDownRequested) {
if (scene == null) { if (scene == null) {
log.warn("Scene not available yet, we create a new scene. The bug might be caused by a guice circular dependency."); log.warn("Scene not available yet, we create a new scene. The bug might be caused by an exception in a constructor or by a circular dependency in guice.");
scene = new Scene(new StackPane(), 1000, 650); scene = new Scene(new StackPane(), 1000, 650);
scene.getStylesheets().setAll( scene.getStylesheets().setAll(
"/io/bitsquare/gui/bitsquare.css", "/io/bitsquare/gui/bitsquare.css",
@ -357,7 +357,7 @@ public class BitsquareApp extends Application {
.show(); .show();
UserThread.runAfter(() -> { UserThread.runAfter(() -> {
gracefulShutDown(() -> { gracefulShutDown(() -> {
log.info("App shutdown complete"); log.debug("App shutdown complete");
System.exit(0); System.exit(0);
}); });
}, 200, TimeUnit.MILLISECONDS); }, 200, TimeUnit.MILLISECONDS);
@ -376,7 +376,7 @@ public class BitsquareApp extends Application {
injector.getInstance(P2PService.class).shutDown(() -> { injector.getInstance(P2PService.class).shutDown(() -> {
injector.getInstance(WalletService.class).shutDownDone.addListener((ov, o, n) -> { injector.getInstance(WalletService.class).shutDownDone.addListener((ov, o, n) -> {
bitsquareAppModule.close(injector); bitsquareAppModule.close(injector);
log.info("Graceful shutdown completed"); log.debug("Graceful shutdown completed");
resultHandler.handleResult(); resultHandler.handleResult();
}); });
injector.getInstance(WalletService.class).shutDown(); injector.getInstance(WalletService.class).shutDown();
@ -388,7 +388,7 @@ public class BitsquareApp extends Application {
UserThread.runAfter(resultHandler::handleResult, 1); UserThread.runAfter(resultHandler::handleResult, 1);
} }
} catch (Throwable t) { } catch (Throwable t) {
log.info("App shutdown failed with exception"); log.debug("App shutdown failed with exception");
t.printStackTrace(); t.printStackTrace();
System.exit(1); System.exit(1);
} }

View file

@ -80,10 +80,6 @@
-fx-background-insets: 0, 1, 2; -fx-background-insets: 0, 1, 2;
} }
.volume-bar.bg {
-demo-bar-fill: #70bfc6;
}
.volume-bar { .volume-bar {
-fx-effect: dropshadow(two-pass-box, rgba(0, 0, 0, 0.4), 10, 0.0, 2, 4); -fx-effect: dropshadow(two-pass-box, rgba(0, 0, 0, 0.4), 10, 0.0, 2, 4);
} }

View file

@ -23,7 +23,7 @@ import io.bitsquare.common.persistance.Persistable;
import io.bitsquare.gui.common.view.View; import io.bitsquare.gui.common.view.View;
import io.bitsquare.gui.common.view.ViewPath; import io.bitsquare.gui.common.view.ViewPath;
import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.markets.MarketView; import io.bitsquare.gui.main.market.MarketView;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -101,7 +101,7 @@ public final class Navigation implements Persistable {
currentPath = newPath; currentPath = newPath;
previousPath = currentPath; previousPath = currentPath;
storage.queueUpForSave(2000); storage.queueUpForSave(1000);
listeners.stream().forEach((e) -> e.onNavigationRequested(currentPath)); listeners.stream().forEach((e) -> e.onNavigationRequested(currentPath));
} }

View file

@ -20,6 +20,7 @@ package io.bitsquare.gui;
import io.bitsquare.BitsquareException; import io.bitsquare.BitsquareException;
import io.bitsquare.common.UserThread; import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Utilities; import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.gui.util.ImageUtil; import io.bitsquare.gui.util.ImageUtil;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.stage.Stage; import javafx.stage.Stage;
@ -123,7 +124,7 @@ public class SystemTray {
aboutItem.addActionListener(e -> { aboutItem.addActionListener(e -> {
try { try {
Utilities.openWebPage("https://bitsquare.io"); GUIUtil.openWebPage("https://bitsquare.io");
} catch (Exception e1) { } catch (Exception e1) {
e1.printStackTrace(); e1.printStackTrace();
} }

View file

@ -3,8 +3,8 @@ Theme colors:
logo colors: logo colors:
new blue: 0f87c3 Bitsquare blue: 0f86c3
new grey: 666666 Bitsquare grey: 666666
00abff 00abff
orange web page quotes : ff7f00 orange web page quotes : ff7f00

View file

@ -24,6 +24,7 @@ import io.bitsquare.btc.listeners.TxConfidenceListener;
import io.bitsquare.common.util.Utilities; import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.components.indicator.TxConfidenceIndicator; import io.bitsquare.gui.components.indicator.TxConfidenceIndicator;
import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.user.Preferences; import io.bitsquare.user.Preferences;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
@ -135,7 +136,7 @@ public class TxIdTextField extends AnchorPane {
private void openBlockExplorer(String txID) { private void openBlockExplorer(String txID) {
try { try {
if (preferences != null) if (preferences != null)
Utilities.openWebPage(preferences.getBlockChainExplorer().txUrl + txID); GUIUtil.openWebPage(preferences.getBlockChainExplorer().txUrl + txID);
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage()); log.error(e.getMessage());
new Popup().warning("Opening browser failed. Please check your internet " + new Popup().warning("Opening browser failed. Please check your internet " +

View file

@ -24,20 +24,20 @@ import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.common.UserThread; import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple2;
import io.bitsquare.common.util.Tuple3; import io.bitsquare.common.util.Tuple3;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.Navigation; import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.view.*; import io.bitsquare.gui.common.view.*;
import io.bitsquare.gui.components.BusyAnimation; import io.bitsquare.gui.components.BusyAnimation;
import io.bitsquare.gui.main.account.AccountView; import io.bitsquare.gui.main.account.AccountView;
import io.bitsquare.gui.main.disputes.DisputesView; import io.bitsquare.gui.main.disputes.DisputesView;
import io.bitsquare.gui.main.funds.FundsView; import io.bitsquare.gui.main.funds.FundsView;
import io.bitsquare.gui.main.markets.MarketView; import io.bitsquare.gui.main.market.MarketView;
import io.bitsquare.gui.main.offer.BuyOfferView; import io.bitsquare.gui.main.offer.BuyOfferView;
import io.bitsquare.gui.main.offer.SellOfferView; import io.bitsquare.gui.main.offer.SellOfferView;
import io.bitsquare.gui.main.overlays.Overlay; import io.bitsquare.gui.main.overlays.Overlay;
import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.gui.main.portfolio.PortfolioView; import io.bitsquare.gui.main.portfolio.PortfolioView;
import io.bitsquare.gui.main.settings.SettingsView; import io.bitsquare.gui.main.settings.SettingsView;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.gui.util.Transitions; import io.bitsquare.gui.util.Transitions;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.geometry.Insets; import javafx.geometry.Insets;
@ -227,19 +227,24 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
navigation.navigateToPreviousVisitedView(); navigation.navigateToPreviousVisitedView();
if (!persistedFilesCorrupted.isEmpty()) { if (!persistedFilesCorrupted.isEmpty()) {
// show warning that some files has been corrupted if (persistedFilesCorrupted.size() > 1 || !persistedFilesCorrupted.get(0).equals("Navigation")) {
new Popup().warning("We detected incompatible data base files!\n\n" + // show warning that some files has been corrupted
"Those database file(s) are not compatible with our current code base:" + new Popup().warning("We detected incompatible data base files!\n\n" +
"\n" + persistedFilesCorrupted.toString() + "Those database file(s) are not compatible with our current code base:" +
"\n\nWe made a backup of the corrupted file(s) and applied the default values to a new " + "\n" + persistedFilesCorrupted.toString() +
"database version." + "\n\nWe made a backup of the corrupted file(s) and applied the default values to a new " +
"\n\nThe backup is located at:\n[you local app data directory]/db/backup_of_corrupted_data.\n\n" + "database version." +
"Please check if you have the latest version of Bitsquare installed.\n" + "\n\nThe backup is located at:\n[you local app data directory]/db/backup_of_corrupted_data.\n\n" +
"You can download it at:\nhttps://github.com/bitsquare/bitsquare/releases\n\n" + "Please check if you have the latest version of Bitsquare installed.\n" +
"Please restart the application.") "You can download it at:\nhttps://github.com/bitsquare/bitsquare/releases\n\n" +
.closeButtonText("Shut down") "Please restart the application.")
.onClose(BitsquareApp.shutDownHandler::run) .closeButtonText("Shut down")
.show(); .onClose(BitsquareApp.shutDownHandler::run)
.show();
} else {
log.debug("We detected incompatible data base file for Navigation. That is a minor issue happening with refactoring of UI classes " +
"and we don't display a warning popup to the user.");
}
} }
transitions.fadeOutAndRemove(splashScreen, 1500, actionEvent -> disposeSplashScreen()); transitions.fadeOutAndRemove(splashScreen, 1500, actionEvent -> disposeSplashScreen());
@ -320,7 +325,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
btcAverageIconButton.setFocusTraversable(false); btcAverageIconButton.setFocusTraversable(false);
btcAverageIconButton.setStyle("-fx-background-color: transparent;"); btcAverageIconButton.setStyle("-fx-background-color: transparent;");
HBox.setMargin(btcAverageIconButton, new Insets(0, 27, 0, 0)); HBox.setMargin(btcAverageIconButton, new Insets(0, 27, 0, 0));
btcAverageIconButton.setOnAction(e -> Utilities.openWebPage("https://bitcoinaverage.com")); btcAverageIconButton.setOnAction(e -> GUIUtil.openWebPage("https://bitcoinaverage.com"));
btcAverageIconButton.visibleProperty().bind(model.isFiatCurrencyPriceFeedSelected); btcAverageIconButton.visibleProperty().bind(model.isFiatCurrencyPriceFeedSelected);
btcAverageIconButton.managedProperty().bind(model.isFiatCurrencyPriceFeedSelected); btcAverageIconButton.managedProperty().bind(model.isFiatCurrencyPriceFeedSelected);
btcAverageIconButton.setTooltip(new Tooltip("Market price is provided by https://bitcoinaverage.com")); btcAverageIconButton.setTooltip(new Tooltip("Market price is provided by https://bitcoinaverage.com"));
@ -332,7 +337,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
poloniexIconButton.setFocusTraversable(false); poloniexIconButton.setFocusTraversable(false);
poloniexIconButton.setStyle("-fx-background-color: transparent;"); poloniexIconButton.setStyle("-fx-background-color: transparent;");
HBox.setMargin(poloniexIconButton, new Insets(1, 27, 0, 0)); HBox.setMargin(poloniexIconButton, new Insets(1, 27, 0, 0));
poloniexIconButton.setOnAction(e -> Utilities.openWebPage("https://poloniex.com")); poloniexIconButton.setOnAction(e -> GUIUtil.openWebPage("https://poloniex.com"));
poloniexIconButton.visibleProperty().bind(model.isCryptoCurrencyPriceFeedSelected); poloniexIconButton.visibleProperty().bind(model.isCryptoCurrencyPriceFeedSelected);
poloniexIconButton.managedProperty().bind(model.isCryptoCurrencyPriceFeedSelected); poloniexIconButton.managedProperty().bind(model.isCryptoCurrencyPriceFeedSelected);
poloniexIconButton.setTooltip(new Tooltip("Market price is provided by https://poloniex.com")); poloniexIconButton.setTooltip(new Tooltip("Market price is provided by https://poloniex.com"));

View file

@ -39,7 +39,6 @@ import io.bitsquare.common.Clock;
import io.bitsquare.common.Timer; import io.bitsquare.common.Timer;
import io.bitsquare.common.UserThread; import io.bitsquare.common.UserThread;
import io.bitsquare.common.crypto.*; import io.bitsquare.common.crypto.*;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.filter.FilterManager; import io.bitsquare.filter.FilterManager;
import io.bitsquare.gui.Navigation; import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ViewModel; import io.bitsquare.gui.common.model.ViewModel;
@ -53,6 +52,7 @@ import io.bitsquare.gui.main.overlays.windows.DisplayAlertMessageWindow;
import io.bitsquare.gui.main.overlays.windows.TacWindow; import io.bitsquare.gui.main.overlays.windows.TacWindow;
import io.bitsquare.gui.main.overlays.windows.WalletPasswordWindow; import io.bitsquare.gui.main.overlays.windows.WalletPasswordWindow;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.locale.TradeCurrency; import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.p2p.P2PService; import io.bitsquare.p2p.P2PService;
@ -322,8 +322,8 @@ public class MainViewModel implements ViewModel {
// Other disconnects might be caused by peers running an older version // Other disconnects might be caused by peers running an older version
if (connection.getPeerType() == Connection.PeerType.SEED_NODE && if (connection.getPeerType() == Connection.PeerType.SEED_NODE &&
closeConnectionReason == CloseConnectionReason.RULE_VIOLATION) { closeConnectionReason == CloseConnectionReason.RULE_VIOLATION) {
log.warn("onDisconnect closeConnectionReason=" + closeConnectionReason); log.warn("RULE_VIOLATION onDisconnect closeConnectionReason=" + closeConnectionReason);
log.warn("onDisconnect connection=" + connection); log.warn("RULE_VIOLATION onDisconnect connection=" + connection);
//TODO //TODO
/* new Popup() /* new Popup()
.warning("You got disconnected from a seed node.\n\n" + .warning("You got disconnected from a seed node.\n\n" +
@ -590,7 +590,7 @@ public class MainViewModel implements ViewModel {
.actionButtonText("Shut down") .actionButtonText("Shut down")
.onAction(BitsquareApp.shutDownHandler::run) .onAction(BitsquareApp.shutDownHandler::run)
.closeButtonText("Report bug at Github issues") .closeButtonText("Report bug at Github issues")
.onClose(() -> Utilities.openWebPage("https://github.com/bitsquare/bitsquare/issues")) .onClose(() -> GUIUtil.openWebPage("https://github.com/bitsquare/bitsquare/issues"))
.show()); .show());
} }
} }
@ -602,7 +602,7 @@ public class MainViewModel implements ViewModel {
.actionButtonText("Shut down") .actionButtonText("Shut down")
.onAction(BitsquareApp.shutDownHandler::run) .onAction(BitsquareApp.shutDownHandler::run)
.closeButtonText("Report bug at Github issues") .closeButtonText("Report bug at Github issues")
.onClose(() -> Utilities.openWebPage("https://github.com/bitsquare/bitsquare/issues")) .onClose(() -> GUIUtil.openWebPage("https://github.com/bitsquare/bitsquare/issues"))
.show(); .show();
} }
} }
@ -846,6 +846,8 @@ public class MainViewModel implements ViewModel {
else else
findPriceFeedComboBoxItem(preferences.getPreferredTradeCurrency().getCode()) findPriceFeedComboBoxItem(preferences.getPreferredTradeCurrency().getCode())
.ifPresent(item2 -> selectedPriceFeedComboBoxItemProperty.set(item2)); .ifPresent(item2 -> selectedPriceFeedComboBoxItemProperty.set(item2));
priceFeedService.setCurrencyCode(item.currencyCode);
} else if (item != null) { } else if (item != null) {
selectedPriceFeedComboBoxItemProperty.set(item); selectedPriceFeedComboBoxItemProperty.set(item);
priceFeedService.setCurrencyCode(item.currencyCode); priceFeedService.setCurrencyCode(item.currencyCode);

View file

@ -20,17 +20,13 @@ package io.bitsquare.gui.main.account.content.altcoinaccounts;
import io.bitsquare.common.UserThread; import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple2;
import io.bitsquare.common.util.Tuple3; import io.bitsquare.common.util.Tuple3;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.common.view.ActivatableViewAndModel; import io.bitsquare.gui.common.view.ActivatableViewAndModel;
import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.components.TitledGroupBg; import io.bitsquare.gui.components.TitledGroupBg;
import io.bitsquare.gui.components.paymentmethods.CryptoCurrencyForm; import io.bitsquare.gui.components.paymentmethods.CryptoCurrencyForm;
import io.bitsquare.gui.components.paymentmethods.PaymentMethodForm; import io.bitsquare.gui.components.paymentmethods.PaymentMethodForm;
import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.*;
import io.bitsquare.gui.util.FormBuilder;
import io.bitsquare.gui.util.ImageUtil;
import io.bitsquare.gui.util.Layout;
import io.bitsquare.gui.util.validation.*; import io.bitsquare.gui.util.validation.*;
import io.bitsquare.locale.CryptoCurrency; import io.bitsquare.locale.CryptoCurrency;
import io.bitsquare.locale.TradeCurrency; import io.bitsquare.locale.TradeCurrency;
@ -173,7 +169,7 @@ public class AltCoinAccountsView extends ActivatableViewAndModel<GridPane, AltCo
new Popup().information("The EHT/ETC fork situation carries considerable risks.\n" + new Popup().information("The EHT/ETC fork situation carries considerable risks.\n" +
"Be sure you fully understand the situation and check out the information on the \"Ethereum Classic\" and \"Ethereum\" project web pages.") "Be sure you fully understand the situation and check out the information on the \"Ethereum Classic\" and \"Ethereum\" project web pages.")
.closeButtonText("I understand") .closeButtonText("I understand")
.onAction(() -> Utilities.openWebPage("https://ethereumclassic.github.io/")) .onAction(() -> GUIUtil.openWebPage("https://ethereumclassic.github.io/"))
.actionButtonText("Open Ethereum Classic web page") .actionButtonText("Open Ethereum Classic web page")
.show(); .show();
} }

View file

@ -263,7 +263,6 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
} }
private void doRestore() { private void doRestore() {
log.info("Attempting wallet restore using seed '{}' from date {}", restoreSeedWordsTextArea.getText(), restoreDatePicker.getValue());
long date = restoreDatePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC); long date = restoreDatePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC);
DeterministicSeed seed = new DeterministicSeed(Splitter.on(" ").splitToList(restoreSeedWordsTextArea.getText()), null, "", date); DeterministicSeed seed = new DeterministicSeed(Splitter.on(" ").splitToList(restoreSeedWordsTextArea.getText()), null, "", date);
walletService.restoreSeedWords(seed, walletService.restoreSeedWords(seed,

View file

@ -25,7 +25,6 @@ import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.common.UserThread; import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple2;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.common.view.ActivatableView; import io.bitsquare.gui.common.view.ActivatableView;
import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.components.AddressTextField; import io.bitsquare.gui.components.AddressTextField;
@ -278,7 +277,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
private void openBlockExplorer(DepositListItem item) { private void openBlockExplorer(DepositListItem item) {
if (item.getAddressString() != null) { if (item.getAddressString() != null) {
try { try {
Utilities.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); GUIUtil.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString());
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage()); log.error(e.getMessage());
new Popup().warning("Opening browser failed. Please check your internet " + new Popup().warning("Opening browser failed. Please check your internet " +

View file

@ -21,7 +21,6 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.btc.AddressEntry; import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.common.view.ActivatableView; import io.bitsquare.gui.common.view.ActivatableView;
import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.components.HyperlinkWithIcon; import io.bitsquare.gui.components.HyperlinkWithIcon;
@ -29,6 +28,7 @@ import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow; import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow;
import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow; import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.trade.Tradable; import io.bitsquare.trade.Tradable;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager; import io.bitsquare.trade.TradeManager;
@ -157,7 +157,7 @@ public class LockedView extends ActivatableView<VBox, Void> {
private void openBlockExplorer(LockedListItem item) { private void openBlockExplorer(LockedListItem item) {
try { try {
Utilities.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); GUIUtil.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString());
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage()); log.error(e.getMessage());
new Popup().warning("Opening browser failed. Please check your internet " + new Popup().warning("Opening browser failed. Please check your internet " +

View file

@ -21,7 +21,6 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.btc.AddressEntry; import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.common.view.ActivatableView; import io.bitsquare.gui.common.view.ActivatableView;
import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.components.HyperlinkWithIcon; import io.bitsquare.gui.components.HyperlinkWithIcon;
@ -29,6 +28,7 @@ import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow; import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow;
import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow; import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.trade.Tradable; import io.bitsquare.trade.Tradable;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
import io.bitsquare.trade.TradeManager; import io.bitsquare.trade.TradeManager;
@ -157,7 +157,7 @@ public class ReservedView extends ActivatableView<VBox, Void> {
private void openBlockExplorer(ReservedListItem item) { private void openBlockExplorer(ReservedListItem item) {
try { try {
Utilities.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); GUIUtil.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString());
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage()); log.error(e.getMessage());
new Popup().warning("Opening browser failed. Please check your internet " + new Popup().warning("Opening browser failed. Please check your internet " +

View file

@ -294,7 +294,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
private void openTxInBlockExplorer(TransactionsListItem item) { private void openTxInBlockExplorer(TransactionsListItem item) {
if (item.getTxId() != null) { if (item.getTxId() != null) {
try { try {
Utilities.openWebPage(preferences.getBlockChainExplorer().txUrl + item.getTxId()); GUIUtil.openWebPage(preferences.getBlockChainExplorer().txUrl + item.getTxId());
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage()); log.error(e.getMessage());
new Popup().warning("Opening browser failed. Please check your internet " + new Popup().warning("Opening browser failed. Please check your internet " +
@ -306,7 +306,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
private void openAddressInBlockExplorer(TransactionsListItem item) { private void openAddressInBlockExplorer(TransactionsListItem item) {
if (item.getAddressString() != null) { if (item.getAddressString() != null) {
try { try {
Utilities.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); GUIUtil.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString());
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage()); log.error(e.getMessage());
new Popup().warning("Opening browser failed. Please check your internet " + new Popup().warning("Opening browser failed. Please check your internet " +

View file

@ -25,13 +25,13 @@ import io.bitsquare.btc.AddressEntryException;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.common.UserThread; import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.common.view.ActivatableView; import io.bitsquare.gui.common.view.ActivatableView;
import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.components.HyperlinkWithIcon; import io.bitsquare.gui.components.HyperlinkWithIcon;
import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.gui.main.overlays.windows.WalletPasswordWindow; import io.bitsquare.gui.main.overlays.windows.WalletPasswordWindow;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.gui.util.validation.BtcAddressValidator; import io.bitsquare.gui.util.validation.BtcAddressValidator;
import io.bitsquare.trade.Tradable; import io.bitsquare.trade.Tradable;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
@ -185,7 +185,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
@Override @Override
public void onSuccess(@javax.annotation.Nullable Transaction transaction) { public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
if (transaction != null) { if (transaction != null) {
log.info("onWithdraw onSuccess tx ID:" + transaction.getHashAsString()); log.debug("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
} else { } else {
log.error("onWithdraw transaction is null"); log.error("onWithdraw transaction is null");
} }
@ -287,7 +287,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
private void openBlockExplorer(WithdrawalListItem item) { private void openBlockExplorer(WithdrawalListItem item) {
if (item.getAddressString() != null) { if (item.getAddressString() != null) {
try { try {
Utilities.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString()); GUIUtil.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString());
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage()); log.error(e.getMessage());
new Popup().warning("Opening browser failed. Please check your internet " + new Popup().warning("Opening browser failed. Please check your internet " +

View file

@ -17,8 +17,8 @@
package io.bitsquare.gui.main.help; package io.bitsquare.gui.main.help;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.gui.util.GUIUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -34,7 +34,7 @@ public class Help {
public static void openWindow(HelpId id) { public static void openWindow(HelpId id) {
try { try {
// TODO create user guide // TODO create user guide
Utilities.openWebPage("http://bitsquare.io/faq"); GUIUtil.openWebPage("http://bitsquare.io/faq");
// Utilities.openWebPage("https://github.com/bitsquare/bitsquare/wiki/User-Guide"); // Utilities.openWebPage("https://github.com/bitsquare/bitsquare/wiki/User-Guide");
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage()); log.error(e.getMessage());

View file

@ -20,7 +20,7 @@
<?import javafx.scene.control.Tab?> <?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?> <?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.AnchorPane?>
<TabPane fx:id="root" fx:controller="io.bitsquare.gui.main.markets.MarketView" <TabPane fx:id="root" fx:controller="io.bitsquare.gui.main.market.MarketView"
AnchorPane.bottomAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.bottomAnchor="0" AnchorPane.leftAnchor="0"
AnchorPane.rightAnchor="0" AnchorPane.topAnchor="0" AnchorPane.rightAnchor="0" AnchorPane.topAnchor="0"
xmlns:fx="http://javafx.com/fxml"> xmlns:fx="http://javafx.com/fxml">

View file

@ -15,15 +15,15 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.markets; package io.bitsquare.gui.main.market;
import io.bitsquare.gui.Navigation; import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.Activatable; import io.bitsquare.gui.common.model.Activatable;
import io.bitsquare.gui.common.view.*; import io.bitsquare.gui.common.view.*;
import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.markets.charts.MarketsChartsView; import io.bitsquare.gui.main.market.offerbook.OfferBookChartView;
import io.bitsquare.gui.main.markets.statistics.MarketsStatisticsView; import io.bitsquare.gui.main.market.spread.SpreadView;
import io.bitsquare.gui.main.markets.trades.TradesChartsView; import io.bitsquare.gui.main.market.trades.TradesChartsView;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Tab; import javafx.scene.control.Tab;
@ -55,11 +55,11 @@ public class MarketView extends ActivatableViewAndModel<TabPane, Activatable> {
tabChangeListener = (ov, oldValue, newValue) -> { tabChangeListener = (ov, oldValue, newValue) -> {
if (newValue == chartsTab) if (newValue == chartsTab)
navigation.navigateTo(MainView.class, MarketView.class, MarketsChartsView.class); navigation.navigateTo(MainView.class, MarketView.class, OfferBookChartView.class);
else if (newValue == tradesTab) else if (newValue == tradesTab)
navigation.navigateTo(MainView.class, MarketView.class, TradesChartsView.class); navigation.navigateTo(MainView.class, MarketView.class, TradesChartsView.class);
else if (newValue == statisticsTab) else if (newValue == statisticsTab)
navigation.navigateTo(MainView.class, MarketView.class, MarketsStatisticsView.class); navigation.navigateTo(MainView.class, MarketView.class, SpreadView.class);
}; };
} }
@ -69,11 +69,11 @@ public class MarketView extends ActivatableViewAndModel<TabPane, Activatable> {
navigation.addListener(navigationListener); navigation.addListener(navigationListener);
if (root.getSelectionModel().getSelectedItem() == chartsTab) if (root.getSelectionModel().getSelectedItem() == chartsTab)
navigation.navigateTo(MainView.class, MarketView.class, MarketsChartsView.class); navigation.navigateTo(MainView.class, MarketView.class, OfferBookChartView.class);
else if (root.getSelectionModel().getSelectedItem() == tradesTab) else if (root.getSelectionModel().getSelectedItem() == tradesTab)
navigation.navigateTo(MainView.class, MarketView.class, TradesChartsView.class); navigation.navigateTo(MainView.class, MarketView.class, TradesChartsView.class);
else else
navigation.navigateTo(MainView.class, MarketView.class, MarketsStatisticsView.class); navigation.navigateTo(MainView.class, MarketView.class, SpreadView.class);
} }
@Override @Override
@ -86,9 +86,9 @@ public class MarketView extends ActivatableViewAndModel<TabPane, Activatable> {
final Tab tab; final Tab tab;
View view = viewLoader.load(viewClass); View view = viewLoader.load(viewClass);
if (view instanceof MarketsChartsView) tab = chartsTab; if (view instanceof OfferBookChartView) tab = chartsTab;
else if (view instanceof TradesChartsView) tab = tradesTab; else if (view instanceof TradesChartsView) tab = tradesTab;
else if (view instanceof MarketsStatisticsView) tab = statisticsTab; else if (view instanceof SpreadView) tab = statisticsTab;
else throw new IllegalArgumentException("Navigation to " + viewClass + " is not supported"); else throw new IllegalArgumentException("Navigation to " + viewClass + " is not supported");
tab.setContent(view.getRoot()); tab.setContent(view.getRoot());

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ This file is part of Bitsquare.
~
~ Bitsquare is free software: you can redistribute it and/or modify it
~ under the terms of the GNU Affero General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or (at
~ your option) any later version.
~
~ Bitsquare is distributed in the hope that it will be useful, but WITHOUT
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
~ License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
-->
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.*?>
<VBox fx:id="root" fx:controller="io.bitsquare.gui.main.market.offerbook.OfferBookChartView"
spacing="20.0" fillWidth="true"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"
xmlns:fx="http://javafx.com/fxml">
<padding>
<Insets bottom="10.0" left="20.0" top="10.0" right="20"/>
</padding>
</VBox>

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.markets.charts; package io.bitsquare.gui.main.market.offerbook;
import io.bitsquare.common.UserThread; import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple3; import io.bitsquare.common.util.Tuple3;
@ -27,7 +27,10 @@ import io.bitsquare.gui.main.offer.BuyOfferView;
import io.bitsquare.gui.main.offer.SellOfferView; import io.bitsquare.gui.main.offer.SellOfferView;
import io.bitsquare.gui.main.offer.offerbook.OfferBookListItem; import io.bitsquare.gui.main.offer.offerbook.OfferBookListItem;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.locale.*; import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.locale.BSResources;
import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.trade.offer.Offer; import io.bitsquare.trade.offer.Offer;
import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
@ -45,7 +48,6 @@ import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.util.Callback; import javafx.util.Callback;
import javafx.util.StringConverter;
import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription; import org.fxmisc.easybind.Subscription;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -54,8 +56,8 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject; import javax.inject.Inject;
@FxmlView @FxmlView
public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChartsViewModel> { public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookChartViewModel> {
private static final Logger log = LoggerFactory.getLogger(MarketsChartsView.class); private static final Logger log = LoggerFactory.getLogger(OfferBookChartView.class);
private NumberAxis xAxis, yAxis; private NumberAxis xAxis, yAxis;
XYChart.Series seriesBuy, seriesSell; XYChart.Series seriesBuy, seriesSell;
@ -71,6 +73,8 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
private final StringProperty volumeColumnLabel = new SimpleStringProperty(); private final StringProperty volumeColumnLabel = new SimpleStringProperty();
private Button buyOfferButton; private Button buyOfferButton;
private Button sellOfferButton; private Button sellOfferButton;
private ChangeListener<Number> selectedTabIndexListener;
private SingleSelectionModel<Tab> tabPaneSelectionModel;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -78,7 +82,7 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public MarketsChartsView(MarketsChartsViewModel model, Navigation navigation, BSFormatter formatter) { public OfferBookChartView(OfferBookChartViewModel model, Navigation navigation, BSFormatter formatter) {
super(model); super(model);
this.navigation = navigation; this.navigation = navigation;
this.formatter = formatter; this.formatter = formatter;
@ -90,24 +94,7 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
public void initialize() { public void initialize() {
currencyComboBox = new ComboBox<>(); currencyComboBox = new ComboBox<>();
currencyComboBox.setPromptText("Select currency"); currencyComboBox.setPromptText("Select currency");
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() { currencyComboBox.setConverter(GUIUtil.getCurrencyListConverter());
@Override
public String toString(TradeCurrency tradeCurrency) {
// http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618
if (tradeCurrency instanceof FiatCurrency)
return "" + tradeCurrency.getNameAndCode();
else if (tradeCurrency instanceof CryptoCurrency)
return "" + tradeCurrency.getNameAndCode();
else
return "-";
}
@Override
public TradeCurrency fromString(String s) {
return null;
}
});
Label currencyLabel = new Label("Currency:"); Label currencyLabel = new Label("Currency:");
HBox currencyHBox = new HBox(); HBox currencyHBox = new HBox();
@ -135,8 +122,15 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
@Override @Override
protected void activate() { protected void activate() {
// root.getParent() is null at initialize
tabPaneSelectionModel = ((TabPane) root.getParent().getParent()).getSelectionModel();
selectedTabIndexListener = (observable, oldValue, newValue) -> model.setSelectedTabIndex((int) newValue);
model.setSelectedTabIndex(tabPaneSelectionModel.getSelectedIndex());
tabPaneSelectionModel.selectedIndexProperty().addListener(selectedTabIndexListener);
currencyComboBox.setItems(model.getTradeCurrencies()); currencyComboBox.setItems(model.getTradeCurrencies());
currencyComboBox.getSelectionModel().select(model.getTradeCurrency()); currencyComboBox.getSelectionModel().select(model.getSelectedTradeCurrencyProperty());
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25)); currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25));
currencyComboBox.setOnAction(e -> { currencyComboBox.setOnAction(e -> {
TradeCurrency tradeCurrency = currencyComboBox.getSelectionModel().getSelectedItem(); TradeCurrency tradeCurrency = currencyComboBox.getSelectionModel().getSelectedItem();
@ -145,7 +139,7 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
}); });
model.getOfferBookListItems().addListener(changeListener); model.getOfferBookListItems().addListener(changeListener);
tradeCurrencySubscriber = EasyBind.subscribe(model.tradeCurrency, tradeCurrencySubscriber = EasyBind.subscribe(model.selectedTradeCurrencyProperty,
tradeCurrency -> { tradeCurrency -> {
String code = tradeCurrency.getCode(); String code = tradeCurrency.getCode();
String tradeCurrencyName = tradeCurrency.getName(); String tradeCurrencyName = tradeCurrency.getName();
@ -173,6 +167,7 @@ public class MarketsChartsView extends ActivatableViewAndModel<VBox, MarketsChar
@Override @Override
protected void deactivate() { protected void deactivate() {
model.getOfferBookListItems().removeListener(changeListener); model.getOfferBookListItems().removeListener(changeListener);
tabPaneSelectionModel.selectedIndexProperty().removeListener(selectedTabIndexListener);
tradeCurrencySubscriber.unsubscribe(); tradeCurrencySubscriber.unsubscribe();
currencyComboBox.setOnAction(null); currencyComboBox.setOnAction(null);
} }

View file

@ -15,14 +15,20 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.markets.charts; package io.bitsquare.gui.main.market.offerbook;
import com.google.common.math.LongMath; import com.google.common.math.LongMath;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bitsquare.btc.pricefeed.PriceFeedService; import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ActivatableViewModel; import io.bitsquare.gui.common.model.ActivatableViewModel;
import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.offer.offerbook.OfferBook; import io.bitsquare.gui.main.offer.offerbook.OfferBook;
import io.bitsquare.gui.main.offer.offerbook.OfferBookListItem; import io.bitsquare.gui.main.offer.offerbook.OfferBookListItem;
import io.bitsquare.gui.main.settings.SettingsView;
import io.bitsquare.gui.main.settings.preferences.PreferencesView;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.locale.CryptoCurrency;
import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.locale.TradeCurrency; import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.trade.offer.Offer; import io.bitsquare.trade.offer.Offer;
@ -44,16 +50,17 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
class MarketsChartsViewModel extends ActivatableViewModel { class OfferBookChartViewModel extends ActivatableViewModel {
private static final Logger log = LoggerFactory.getLogger(MarketsChartsViewModel.class); private static final Logger log = LoggerFactory.getLogger(OfferBookChartViewModel.class);
final static String EDIT_FLAG = "EDIT_FLAG"; private static final int TAB_INDEX = 0;
private final OfferBook offerBook; private final OfferBook offerBook;
private final Preferences preferences; private final Preferences preferences;
final PriceFeedService priceFeedService; final PriceFeedService priceFeedService;
private Navigation navigation;
final ObjectProperty<TradeCurrency> tradeCurrency = new SimpleObjectProperty<>(); final ObjectProperty<TradeCurrency> selectedTradeCurrencyProperty = new SimpleObjectProperty<>();
private final List<XYChart.Data> buyData = new ArrayList<>(); private final List<XYChart.Data> buyData = new ArrayList<>();
private final List<XYChart.Data> sellData = new ArrayList<>(); private final List<XYChart.Data> sellData = new ArrayList<>();
private final ObservableList<OfferBookListItem> offerBookListItems; private final ObservableList<OfferBookListItem> offerBookListItems;
@ -61,22 +68,25 @@ class MarketsChartsViewModel extends ActivatableViewModel {
private final ObservableList<Offer> top3BuyOfferList = FXCollections.observableArrayList(); private final ObservableList<Offer> top3BuyOfferList = FXCollections.observableArrayList();
private final ObservableList<Offer> top3SellOfferList = FXCollections.observableArrayList(); private final ObservableList<Offer> top3SellOfferList = FXCollections.observableArrayList();
private final ChangeListener<Number> currenciesUpdatedListener; private final ChangeListener<Number> currenciesUpdatedListener;
private int selectedTabIndex;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, lifecycle // Constructor, lifecycle
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public MarketsChartsViewModel(OfferBook offerBook, Preferences preferences, PriceFeedService priceFeedService) { public OfferBookChartViewModel(OfferBook offerBook, Preferences preferences, PriceFeedService priceFeedService, Navigation navigation) {
this.offerBook = offerBook; this.offerBook = offerBook;
this.preferences = preferences; this.preferences = preferences;
this.priceFeedService = priceFeedService; this.priceFeedService = priceFeedService;
this.navigation = navigation;
Optional<TradeCurrency> tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(preferences.getMarketScreenCurrencyCode()); Optional<TradeCurrency> tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(preferences.getOfferBookChartScreenCurrencyCode());
if (tradeCurrencyOptional.isPresent()) if (tradeCurrencyOptional.isPresent())
tradeCurrency.set(tradeCurrencyOptional.get()); selectedTradeCurrencyProperty.set(tradeCurrencyOptional.get());
else { else {
tradeCurrency.set(CurrencyUtil.getDefaultTradeCurrency()); selectedTradeCurrencyProperty.set(CurrencyUtil.getDefaultTradeCurrency());
} }
offerBookListItems = offerBook.getOfferBookListItems(); offerBookListItems = offerBook.getOfferBookListItems();
@ -87,7 +97,7 @@ class MarketsChartsViewModel extends ActivatableViewModel {
list.addAll(c.getAddedSubList()); list.addAll(c.getAddedSubList());
if (list.stream() if (list.stream()
.map(OfferBookListItem::getOffer) .map(OfferBookListItem::getOffer)
.filter(e -> e.getCurrencyCode().equals(tradeCurrency.get().getCode())) .filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode()))
.findAny() .findAny()
.isPresent()) .isPresent())
updateChartData(); updateChartData();
@ -117,8 +127,7 @@ class MarketsChartsViewModel extends ActivatableViewModel {
if (isAnyPricePresent()) if (isAnyPricePresent())
priceFeedService.currenciesUpdateFlagProperty().addListener(currenciesUpdatedListener); priceFeedService.currenciesUpdateFlagProperty().addListener(currenciesUpdatedListener);
if (!preferences.getUseStickyMarketPrice()) syncPriceFeedCurrency();
priceFeedService.setCurrencyCode(tradeCurrency.get().getCode());
} }
@Override @Override
@ -126,6 +135,83 @@ class MarketsChartsViewModel extends ActivatableViewModel {
offerBookListItems.removeListener(listChangeListener); offerBookListItems.removeListener(listChangeListener);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// UI actions
///////////////////////////////////////////////////////////////////////////////////////////
public void onSetTradeCurrency(TradeCurrency tradeCurrency) {
if (tradeCurrency != null) {
final String code = tradeCurrency.getCode();
if (isEditEntry(code)) {
navigation.navigateTo(MainView.class, SettingsView.class, PreferencesView.class);
} else {
selectedTradeCurrencyProperty.set(tradeCurrency);
preferences.setOfferBookChartScreenCurrencyCode(code);
updateChartData();
if (!preferences.getUseStickyMarketPrice())
priceFeedService.setCurrencyCode(code);
}
}
}
void setSelectedTabIndex(int selectedTabIndex) {
this.selectedTabIndex = selectedTabIndex;
syncPriceFeedCurrency();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public List<XYChart.Data> getBuyData() {
return buyData;
}
public List<XYChart.Data> getSellData() {
return sellData;
}
public String getCurrencyCode() {
return selectedTradeCurrencyProperty.get().getCode();
}
public ObservableList<OfferBookListItem> getOfferBookListItems() {
return offerBookListItems;
}
public ObservableList<Offer> getTop3BuyOfferList() {
return top3BuyOfferList;
}
public ObservableList<Offer> getTop3SellOfferList() {
return top3SellOfferList;
}
public ObservableList<TradeCurrency> getTradeCurrencies() {
final ObservableList<TradeCurrency> list = FXCollections.observableArrayList(preferences.getTradeCurrenciesAsObservable());
list.add(new CryptoCurrency(GUIUtil.EDIT_FLAG, GUIUtil.EDIT_FLAG));
return list;
}
public TradeCurrency getSelectedTradeCurrencyProperty() {
return selectedTradeCurrencyProperty.get();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void syncPriceFeedCurrency() {
if (!preferences.getUseStickyMarketPrice() && selectedTabIndex == TAB_INDEX)
priceFeedService.setCurrencyCode(selectedTradeCurrencyProperty.get().getCode());
}
private boolean isAnyPricePresent() { private boolean isAnyPricePresent() {
return offerBookListItems.stream().filter(item -> item.getOffer().getPrice() == null).findAny().isPresent(); return offerBookListItems.stream().filter(item -> item.getOffer().getPrice() == null).findAny().isPresent();
} }
@ -133,7 +219,7 @@ class MarketsChartsViewModel extends ActivatableViewModel {
private void updateChartData() { private void updateChartData() {
List<Offer> allBuyOffers = offerBookListItems.stream() List<Offer> allBuyOffers = offerBookListItems.stream()
.map(OfferBookListItem::getOffer) .map(OfferBookListItem::getOffer)
.filter(e -> e.getCurrencyCode().equals(tradeCurrency.get().getCode()) .filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode())
&& e.getDirection().equals(Offer.Direction.BUY)) && e.getDirection().equals(Offer.Direction.BUY))
.sorted((o1, o2) -> { .sorted((o1, o2) -> {
long a = o1.getPrice() != null ? o1.getPrice().value : 0; long a = o1.getPrice() != null ? o1.getPrice().value : 0;
@ -148,7 +234,7 @@ class MarketsChartsViewModel extends ActivatableViewModel {
List<Offer> allSellOffers = offerBookListItems.stream() List<Offer> allSellOffers = offerBookListItems.stream()
.map(OfferBookListItem::getOffer) .map(OfferBookListItem::getOffer)
.filter(e -> e.getCurrencyCode().equals(tradeCurrency.get().getCode()) .filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode())
&& e.getDirection().equals(Offer.Direction.SELL)) && e.getDirection().equals(Offer.Direction.SELL))
.sorted((o1, o2) -> { .sorted((o1, o2) -> {
long a = o1.getPrice() != null ? o1.getPrice().value : 0; long a = o1.getPrice() != null ? o1.getPrice().value : 0;
@ -179,54 +265,7 @@ class MarketsChartsViewModel extends ActivatableViewModel {
} }
} }
private boolean isEditEntry(String id) {
/////////////////////////////////////////////////////////////////////////////////////////// return id.equals(GUIUtil.EDIT_FLAG);
// UI actions
///////////////////////////////////////////////////////////////////////////////////////////
public void onSetTradeCurrency(TradeCurrency tradeCurrency) {
this.tradeCurrency.set(tradeCurrency);
updateChartData();
if (!preferences.getUseStickyMarketPrice())
priceFeedService.setCurrencyCode(tradeCurrency.getCode());
preferences.setMarketScreenCurrencyCode(tradeCurrency.getCode());
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
public List<XYChart.Data> getBuyData() {
return buyData;
}
public List<XYChart.Data> getSellData() {
return sellData;
}
public String getCurrencyCode() {
return tradeCurrency.get().getCode();
}
public ObservableList<OfferBookListItem> getOfferBookListItems() {
return offerBookListItems;
}
public ObservableList<Offer> getTop3BuyOfferList() {
return top3BuyOfferList;
}
public ObservableList<Offer> getTop3SellOfferList() {
return top3SellOfferList;
}
public ObservableList<TradeCurrency> getTradeCurrencies() {
return preferences.getTradeCurrenciesAsObservable();
}
public TradeCurrency getTradeCurrency() {
return tradeCurrency.get();
} }
} }

View file

@ -1,4 +1,4 @@
package io.bitsquare.gui.main.markets.statistics; package io.bitsquare.gui.main.market.spread;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat; import org.bitcoinj.utils.Fiat;
@ -7,8 +7,8 @@ import org.slf4j.LoggerFactory;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class MarketStatisticItem { public class SpreadItem {
private static final Logger log = LoggerFactory.getLogger(MarketStatisticItem.class); private static final Logger log = LoggerFactory.getLogger(SpreadItem.class);
public final String currencyCode; public final String currencyCode;
public final int numberOfBuyOffers; public final int numberOfBuyOffers;
public final int numberOfSellOffers; public final int numberOfSellOffers;
@ -17,7 +17,7 @@ public class MarketStatisticItem {
public final Fiat spread; public final Fiat spread;
public final Coin totalAmount; public final Coin totalAmount;
public MarketStatisticItem(String currencyCode, int numberOfBuyOffers, int numberOfSellOffers, int numberOfOffers, @Nullable Fiat spread, Coin totalAmount) { public SpreadItem(String currencyCode, int numberOfBuyOffers, int numberOfSellOffers, int numberOfOffers, @Nullable Fiat spread, Coin totalAmount) {
this.currencyCode = currencyCode; this.currencyCode = currencyCode;
this.numberOfBuyOffers = numberOfBuyOffers; this.numberOfBuyOffers = numberOfBuyOffers;
this.numberOfSellOffers = numberOfSellOffers; this.numberOfSellOffers = numberOfSellOffers;

View file

@ -20,7 +20,7 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<GridPane fx:id="root" fx:controller="io.bitsquare.gui.main.markets.statistics.MarketsStatisticsView" <GridPane fx:id="root" fx:controller="io.bitsquare.gui.main.market.spread.SpreadView"
hgap="5.0" vgap="5.0" hgap="5.0" vgap="5.0"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.markets.statistics; package io.bitsquare.gui.main.market.spread;
import io.bitsquare.gui.common.view.ActivatableViewAndModel; import io.bitsquare.gui.common.view.ActivatableViewAndModel;
import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.common.view.FxmlView;
@ -38,13 +38,13 @@ import org.bitcoinj.core.Coin;
import javax.inject.Inject; import javax.inject.Inject;
@FxmlView @FxmlView
public class MarketsStatisticsView extends ActivatableViewAndModel<GridPane, MarketsStatisticViewModel> { public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewModel> {
private final BSFormatter formatter; private final BSFormatter formatter;
private final int gridRow = 0; private final int gridRow = 0;
private TableView<MarketStatisticItem> tableView; private TableView<SpreadItem> tableView;
private SortedList<MarketStatisticItem> sortedList; private SortedList<SpreadItem> sortedList;
private ListChangeListener<MarketStatisticItem> itemListChangeListener; private ListChangeListener<SpreadItem> itemListChangeListener;
private TableColumn<MarketStatisticItem, MarketStatisticItem> totalAmountColumn, numberOfOffersColumn, numberOfBuyOffersColumn, numberOfSellOffersColumn; private TableColumn<SpreadItem, SpreadItem> totalAmountColumn, numberOfOffersColumn, numberOfBuyOffersColumn, numberOfSellOffersColumn;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -52,7 +52,7 @@ public class MarketsStatisticsView extends ActivatableViewAndModel<GridPane, Mar
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public MarketsStatisticsView(MarketsStatisticViewModel model, BSFormatter formatter) { public SpreadView(SpreadViewModel model, BSFormatter formatter) {
super(model); super(model);
this.formatter = formatter; this.formatter = formatter;
} }
@ -74,7 +74,7 @@ public class MarketsStatisticsView extends ActivatableViewAndModel<GridPane, Mar
placeholder.setWrapText(true); placeholder.setWrapText(true);
tableView.setPlaceholder(placeholder); tableView.setPlaceholder(placeholder);
TableColumn<MarketStatisticItem, MarketStatisticItem> currencyColumn = getCurrencyColumn(); TableColumn<SpreadItem, SpreadItem> currencyColumn = getCurrencyColumn();
tableView.getColumns().add(currencyColumn); tableView.getColumns().add(currencyColumn);
numberOfOffersColumn = getNumberOfOffersColumn(); numberOfOffersColumn = getNumberOfOffersColumn();
tableView.getColumns().add(numberOfOffersColumn); tableView.getColumns().add(numberOfOffersColumn);
@ -84,7 +84,7 @@ public class MarketsStatisticsView extends ActivatableViewAndModel<GridPane, Mar
tableView.getColumns().add(numberOfSellOffersColumn); tableView.getColumns().add(numberOfSellOffersColumn);
totalAmountColumn = getTotalAmountColumn(); totalAmountColumn = getTotalAmountColumn();
tableView.getColumns().add(totalAmountColumn); tableView.getColumns().add(totalAmountColumn);
TableColumn<MarketStatisticItem, MarketStatisticItem> spreadColumn = getSpreadColumn(); TableColumn<SpreadItem, SpreadItem> spreadColumn = getSpreadColumn();
tableView.getColumns().add(spreadColumn); tableView.getColumns().add(spreadColumn);
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
@ -102,7 +102,7 @@ public class MarketsStatisticsView extends ActivatableViewAndModel<GridPane, Mar
@Override @Override
protected void activate() { protected void activate() {
sortedList = new SortedList<>(model.marketStatisticItems); sortedList = new SortedList<>(model.spreadItems);
sortedList.comparatorProperty().bind(tableView.comparatorProperty()); sortedList.comparatorProperty().bind(tableView.comparatorProperty());
tableView.setItems(sortedList); tableView.setItems(sortedList);
sortedList.addListener(itemListChangeListener); sortedList.addListener(itemListChangeListener);
@ -127,22 +127,22 @@ public class MarketsStatisticsView extends ActivatableViewAndModel<GridPane, Mar
// Columns // Columns
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private TableColumn<MarketStatisticItem, MarketStatisticItem> getCurrencyColumn() { private TableColumn<SpreadItem, SpreadItem> getCurrencyColumn() {
TableColumn<MarketStatisticItem, MarketStatisticItem> column = new TableColumn<MarketStatisticItem, MarketStatisticItem>("Currency") { TableColumn<SpreadItem, SpreadItem> column = new TableColumn<SpreadItem, SpreadItem>("Currency") {
{ {
setMinWidth(100); setMinWidth(100);
} }
}; };
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory( column.setCellFactory(
new Callback<TableColumn<MarketStatisticItem, MarketStatisticItem>, TableCell<MarketStatisticItem, new Callback<TableColumn<SpreadItem, SpreadItem>, TableCell<SpreadItem,
MarketStatisticItem>>() { SpreadItem>>() {
@Override @Override
public TableCell<MarketStatisticItem, MarketStatisticItem> call( public TableCell<SpreadItem, SpreadItem> call(
TableColumn<MarketStatisticItem, MarketStatisticItem> column) { TableColumn<SpreadItem, SpreadItem> column) {
return new TableCell<MarketStatisticItem, MarketStatisticItem>() { return new TableCell<SpreadItem, SpreadItem>() {
@Override @Override
public void updateItem(final MarketStatisticItem item, boolean empty) { public void updateItem(final SpreadItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null && !empty) if (item != null && !empty)
setText(CurrencyUtil.getNameByCode(item.currencyCode)); setText(CurrencyUtil.getNameByCode(item.currencyCode));
@ -155,22 +155,22 @@ public class MarketsStatisticsView extends ActivatableViewAndModel<GridPane, Mar
return column; return column;
} }
private TableColumn<MarketStatisticItem, MarketStatisticItem> getNumberOfOffersColumn() { private TableColumn<SpreadItem, SpreadItem> getNumberOfOffersColumn() {
TableColumn<MarketStatisticItem, MarketStatisticItem> column = new TableColumn<MarketStatisticItem, MarketStatisticItem>("Total offers") { TableColumn<SpreadItem, SpreadItem> column = new TableColumn<SpreadItem, SpreadItem>("Total offers") {
{ {
setMinWidth(100); setMinWidth(100);
} }
}; };
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory( column.setCellFactory(
new Callback<TableColumn<MarketStatisticItem, MarketStatisticItem>, TableCell<MarketStatisticItem, new Callback<TableColumn<SpreadItem, SpreadItem>, TableCell<SpreadItem,
MarketStatisticItem>>() { SpreadItem>>() {
@Override @Override
public TableCell<MarketStatisticItem, MarketStatisticItem> call( public TableCell<SpreadItem, SpreadItem> call(
TableColumn<MarketStatisticItem, MarketStatisticItem> column) { TableColumn<SpreadItem, SpreadItem> column) {
return new TableCell<MarketStatisticItem, MarketStatisticItem>() { return new TableCell<SpreadItem, SpreadItem>() {
@Override @Override
public void updateItem(final MarketStatisticItem item, boolean empty) { public void updateItem(final SpreadItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null && !empty) if (item != null && !empty)
setText(String.valueOf(item.numberOfOffers)); setText(String.valueOf(item.numberOfOffers));
@ -183,22 +183,22 @@ public class MarketsStatisticsView extends ActivatableViewAndModel<GridPane, Mar
return column; return column;
} }
private TableColumn<MarketStatisticItem, MarketStatisticItem> getNumberOfBuyOffersColumn() { private TableColumn<SpreadItem, SpreadItem> getNumberOfBuyOffersColumn() {
TableColumn<MarketStatisticItem, MarketStatisticItem> column = new TableColumn<MarketStatisticItem, MarketStatisticItem>("Buy offers") { TableColumn<SpreadItem, SpreadItem> column = new TableColumn<SpreadItem, SpreadItem>("Buy offers") {
{ {
setMinWidth(100); setMinWidth(100);
} }
}; };
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory( column.setCellFactory(
new Callback<TableColumn<MarketStatisticItem, MarketStatisticItem>, TableCell<MarketStatisticItem, new Callback<TableColumn<SpreadItem, SpreadItem>, TableCell<SpreadItem,
MarketStatisticItem>>() { SpreadItem>>() {
@Override @Override
public TableCell<MarketStatisticItem, MarketStatisticItem> call( public TableCell<SpreadItem, SpreadItem> call(
TableColumn<MarketStatisticItem, MarketStatisticItem> column) { TableColumn<SpreadItem, SpreadItem> column) {
return new TableCell<MarketStatisticItem, MarketStatisticItem>() { return new TableCell<SpreadItem, SpreadItem>() {
@Override @Override
public void updateItem(final MarketStatisticItem item, boolean empty) { public void updateItem(final SpreadItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null && !empty) if (item != null && !empty)
setText(String.valueOf(item.numberOfBuyOffers)); setText(String.valueOf(item.numberOfBuyOffers));
@ -211,22 +211,22 @@ public class MarketsStatisticsView extends ActivatableViewAndModel<GridPane, Mar
return column; return column;
} }
private TableColumn<MarketStatisticItem, MarketStatisticItem> getNumberOfSellOffersColumn() { private TableColumn<SpreadItem, SpreadItem> getNumberOfSellOffersColumn() {
TableColumn<MarketStatisticItem, MarketStatisticItem> column = new TableColumn<MarketStatisticItem, MarketStatisticItem>("Sell offers") { TableColumn<SpreadItem, SpreadItem> column = new TableColumn<SpreadItem, SpreadItem>("Sell offers") {
{ {
setMinWidth(100); setMinWidth(100);
} }
}; };
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory( column.setCellFactory(
new Callback<TableColumn<MarketStatisticItem, MarketStatisticItem>, TableCell<MarketStatisticItem, new Callback<TableColumn<SpreadItem, SpreadItem>, TableCell<SpreadItem,
MarketStatisticItem>>() { SpreadItem>>() {
@Override @Override
public TableCell<MarketStatisticItem, MarketStatisticItem> call( public TableCell<SpreadItem, SpreadItem> call(
TableColumn<MarketStatisticItem, MarketStatisticItem> column) { TableColumn<SpreadItem, SpreadItem> column) {
return new TableCell<MarketStatisticItem, MarketStatisticItem>() { return new TableCell<SpreadItem, SpreadItem>() {
@Override @Override
public void updateItem(final MarketStatisticItem item, boolean empty) { public void updateItem(final SpreadItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null && !empty) if (item != null && !empty)
setText(String.valueOf(item.numberOfSellOffers)); setText(String.valueOf(item.numberOfSellOffers));
@ -239,22 +239,22 @@ public class MarketsStatisticsView extends ActivatableViewAndModel<GridPane, Mar
return column; return column;
} }
private TableColumn<MarketStatisticItem, MarketStatisticItem> getTotalAmountColumn() { private TableColumn<SpreadItem, SpreadItem> getTotalAmountColumn() {
TableColumn<MarketStatisticItem, MarketStatisticItem> column = new TableColumn<MarketStatisticItem, MarketStatisticItem>("Total amount") { TableColumn<SpreadItem, SpreadItem> column = new TableColumn<SpreadItem, SpreadItem>("Total amount") {
{ {
setMinWidth(150); setMinWidth(150);
} }
}; };
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory( column.setCellFactory(
new Callback<TableColumn<MarketStatisticItem, MarketStatisticItem>, TableCell<MarketStatisticItem, new Callback<TableColumn<SpreadItem, SpreadItem>, TableCell<SpreadItem,
MarketStatisticItem>>() { SpreadItem>>() {
@Override @Override
public TableCell<MarketStatisticItem, MarketStatisticItem> call( public TableCell<SpreadItem, SpreadItem> call(
TableColumn<MarketStatisticItem, MarketStatisticItem> column) { TableColumn<SpreadItem, SpreadItem> column) {
return new TableCell<MarketStatisticItem, MarketStatisticItem>() { return new TableCell<SpreadItem, SpreadItem>() {
@Override @Override
public void updateItem(final MarketStatisticItem item, boolean empty) { public void updateItem(final SpreadItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null && !empty) if (item != null && !empty)
setText(formatter.formatCoin(item.totalAmount)); setText(formatter.formatCoin(item.totalAmount));
@ -267,22 +267,22 @@ public class MarketsStatisticsView extends ActivatableViewAndModel<GridPane, Mar
return column; return column;
} }
private TableColumn<MarketStatisticItem, MarketStatisticItem> getSpreadColumn() { private TableColumn<SpreadItem, SpreadItem> getSpreadColumn() {
TableColumn<MarketStatisticItem, MarketStatisticItem> column = new TableColumn<MarketStatisticItem, MarketStatisticItem>("Spread") { TableColumn<SpreadItem, SpreadItem> column = new TableColumn<SpreadItem, SpreadItem>("Spread") {
{ {
setMinWidth(130); setMinWidth(130);
} }
}; };
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue())); column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory( column.setCellFactory(
new Callback<TableColumn<MarketStatisticItem, MarketStatisticItem>, TableCell<MarketStatisticItem, new Callback<TableColumn<SpreadItem, SpreadItem>, TableCell<SpreadItem,
MarketStatisticItem>>() { SpreadItem>>() {
@Override @Override
public TableCell<MarketStatisticItem, MarketStatisticItem> call( public TableCell<SpreadItem, SpreadItem> call(
TableColumn<MarketStatisticItem, MarketStatisticItem> column) { TableColumn<SpreadItem, SpreadItem> column) {
return new TableCell<MarketStatisticItem, MarketStatisticItem>() { return new TableCell<SpreadItem, SpreadItem>() {
@Override @Override
public void updateItem(final MarketStatisticItem item, boolean empty) { public void updateItem(final SpreadItem item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null && !empty) { if (item != null && !empty) {
if (item.spread != null) if (item.spread != null)

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.markets.statistics; package io.bitsquare.gui.main.market.spread;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bitsquare.gui.common.model.ActivatableViewModel; import io.bitsquare.gui.common.model.ActivatableViewModel;
@ -34,12 +34,12 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
class MarketsStatisticViewModel extends ActivatableViewModel { class SpreadViewModel extends ActivatableViewModel {
private final OfferBook offerBook; private final OfferBook offerBook;
private final ObservableList<OfferBookListItem> offerBookListItems; private final ObservableList<OfferBookListItem> offerBookListItems;
private final ListChangeListener<OfferBookListItem> listChangeListener; private final ListChangeListener<OfferBookListItem> listChangeListener;
final ObservableList<MarketStatisticItem> marketStatisticItems = FXCollections.observableArrayList(); final ObservableList<SpreadItem> spreadItems = FXCollections.observableArrayList();
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -47,7 +47,7 @@ class MarketsStatisticViewModel extends ActivatableViewModel {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public MarketsStatisticViewModel(OfferBook offerBook) { public SpreadViewModel(OfferBook offerBook) {
this.offerBook = offerBook; this.offerBook = offerBook;
offerBookListItems = offerBook.getOfferBookListItems(); offerBookListItems = offerBook.getOfferBookListItems();
@ -75,7 +75,7 @@ class MarketsStatisticViewModel extends ActivatableViewModel {
offersByCurrencyMap.put(currencyCode, new ArrayList<>()); offersByCurrencyMap.put(currencyCode, new ArrayList<>());
offersByCurrencyMap.get(currencyCode).add(offer); offersByCurrencyMap.get(currencyCode).add(offer);
} }
marketStatisticItems.clear(); spreadItems.clear();
for (String currencyCode : offersByCurrencyMap.keySet()) { for (String currencyCode : offersByCurrencyMap.keySet()) {
List<Offer> offers = offersByCurrencyMap.get(currencyCode); List<Offer> offers = offersByCurrencyMap.get(currencyCode);
List<Offer> buyOffers = offers List<Offer> buyOffers = offers
@ -109,7 +109,7 @@ class MarketsStatisticViewModel extends ActivatableViewModel {
spread = bestSellOfferPrice.subtract(bestBuyOfferPrice); spread = bestSellOfferPrice.subtract(bestBuyOfferPrice);
Coin totalAmount = Coin.valueOf(offers.stream().mapToLong(offer -> offer.getAmount().getValue()).sum()); Coin totalAmount = Coin.valueOf(offers.stream().mapToLong(offer -> offer.getAmount().getValue()).sum());
marketStatisticItems.add(new MarketStatisticItem(currencyCode, buyOffers.size(), sellOffers.size(), offers.size(), spread, totalAmount)); spreadItems.add(new SpreadItem(currencyCode, buyOffers.size(), sellOffers.size(), offers.size(), spread, totalAmount));
} }
} }
} }

View file

@ -20,7 +20,7 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<VBox fx:id="root" fx:controller="io.bitsquare.gui.main.markets.trades.TradesChartsView" <VBox fx:id="root" fx:controller="io.bitsquare.gui.main.market.trades.TradesChartsView"
spacing="10.0" fillWidth="true" spacing="10.0" fillWidth="true"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"

View file

@ -15,16 +15,15 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.markets.trades; package io.bitsquare.gui.main.market.trades;
import io.bitsquare.common.UserThread; import io.bitsquare.common.UserThread;
import io.bitsquare.gui.common.view.ActivatableViewAndModel; import io.bitsquare.gui.common.view.ActivatableViewAndModel;
import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.main.markets.trades.charts.price.CandleStickChart; import io.bitsquare.gui.main.market.trades.charts.price.CandleStickChart;
import io.bitsquare.gui.main.markets.trades.charts.volume.VolumeChart; import io.bitsquare.gui.main.market.trades.charts.volume.VolumeChart;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.locale.CryptoCurrency; import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.locale.FiatCurrency;
import io.bitsquare.locale.TradeCurrency; import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.trade.statistics.TradeStatistics; import io.bitsquare.trade.statistics.TradeStatistics;
import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyObjectWrapper;
@ -81,6 +80,11 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
private SortedList<TradeStatistics> sortedList; private SortedList<TradeStatistics> sortedList;
private Label nrOfTradeStatisticsLabel; private Label nrOfTradeStatisticsLabel;
private ListChangeListener<TradeStatistics> tradeStatisticsByCurrencyListener; private ListChangeListener<TradeStatistics> tradeStatisticsByCurrencyListener;
private TableColumn<TradeStatistics, TradeStatistics> priceColumn;
private ChangeListener<Number> selectedTabIndexListener;
private SingleSelectionModel<Tab> tabPaneSelectionModel;
private ChangeListener<Boolean> showAllTradeCurrenciesListener;
private TableColumn<TradeStatistics, TradeStatistics> volumeColumn;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -122,12 +126,30 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
layoutChart(); layoutChart();
}; };
tradeStatisticsByCurrencyListener = c -> nrOfTradeStatisticsLabel.setText("Nr. of trades: " + model.tradeStatisticsByCurrency.size()); tradeStatisticsByCurrencyListener = c -> nrOfTradeStatisticsLabel.setText("Nr. of trades: " + model.tradeStatisticsByCurrency.size());
showAllTradeCurrenciesListener = (observable, oldValue, newValue) -> {
priceChart.setVisible(!newValue);
priceChart.setManaged(!newValue);
priceColumn.setSortable(!newValue);
priceColumnLabel.set("Price" + (newValue ? "" : (" (" + model.getCurrencyCode() + ")")));
volumeColumn.setText("Volume" + (newValue ? "" : (" (" + model.getCurrencyCode() + ")")));
};
} }
@Override @Override
protected void activate() { protected void activate() {
// root.getParent() is null at initialize
tabPaneSelectionModel = ((TabPane) root.getParent().getParent()).getSelectionModel();
selectedTabIndexListener = (observable, oldValue, newValue) -> model.setSelectedTabIndex((int) newValue);
model.setSelectedTabIndex(tabPaneSelectionModel.getSelectedIndex());
tabPaneSelectionModel.selectedIndexProperty().addListener(selectedTabIndexListener);
currencyComboBox.setItems(model.getTradeCurrencies()); currencyComboBox.setItems(model.getTradeCurrencies());
currencyComboBox.getSelectionModel().select(model.getTradeCurrency());
if (model.showAllTradeCurrenciesProperty.get())
currencyComboBox.getSelectionModel().select(0);
else
currencyComboBox.getSelectionModel().select(model.getSelectedTradeCurrency());
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25)); currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25));
currencyComboBox.setOnAction(e -> model.onSetTradeCurrency(currencyComboBox.getSelectionModel().getSelectedItem())); currencyComboBox.setOnAction(e -> model.onSetTradeCurrency(currencyComboBox.getSelectionModel().getSelectedItem()));
@ -137,15 +159,22 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
toggleGroup.selectedToggleProperty().addListener(toggleChangeListener); toggleGroup.selectedToggleProperty().addListener(toggleChangeListener);
priceAxisY.widthProperty().addListener(priceAxisYWidthListener); priceAxisY.widthProperty().addListener(priceAxisYWidthListener);
volumeAxisY.widthProperty().addListener(volumeAxisYWidthListener); volumeAxisY.widthProperty().addListener(volumeAxisYWidthListener);
model.tradeStatisticsByCurrency.addListener(tradeStatisticsByCurrencyListener);
model.showAllTradeCurrenciesProperty.addListener(showAllTradeCurrenciesListener);
tradeCurrencySubscriber = EasyBind.subscribe(model.tradeCurrencyProperty, priceAxisY.labelProperty().bind(priceColumnLabel);
priceColumn.textProperty().bind(priceColumnLabel);
tradeCurrencySubscriber = EasyBind.subscribe(model.selectedTradeCurrencyProperty,
tradeCurrency -> { tradeCurrency -> {
String code = tradeCurrency.getCode(); String code = tradeCurrency.getCode();
String tradeCurrencyName = tradeCurrency.getName(); String tradeCurrencyName = tradeCurrency.getName();
priceSeries.setName(tradeCurrencyName); priceSeries.setName(tradeCurrencyName);
final String currencyPair = formatter.getCurrencyPair(code); final String currencyPair = formatter.getCurrencyPair(code);
priceColumnLabel.set("Price (" + currencyPair + ")"); final boolean showAllTradeCurrencies = model.showAllTradeCurrenciesProperty.get();
priceColumnLabel.set("Price" + (showAllTradeCurrencies ? "" : (" (" + currencyPair + ")")));
volumeColumn.setText("Volume" + (showAllTradeCurrencies ? "" : (" (" + code + ")")));
}); });
sortedList = new SortedList<>(model.tradeStatisticsByCurrency); sortedList = new SortedList<>(model.tradeStatisticsByCurrency);
@ -158,23 +187,30 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
priceAxisX.setTickLabelFormatter(getTimeAxisStringConverter()); priceAxisX.setTickLabelFormatter(getTimeAxisStringConverter());
volumeAxisX.setTickLabelFormatter(getTimeAxisStringConverter()); volumeAxisX.setTickLabelFormatter(getTimeAxisStringConverter());
model.tradeStatisticsByCurrency.addListener(tradeStatisticsByCurrencyListener);
nrOfTradeStatisticsLabel.setText("Nr. of trades: " + model.tradeStatisticsByCurrency.size()); nrOfTradeStatisticsLabel.setText("Nr. of trades: " + model.tradeStatisticsByCurrency.size());
} }
@Override @Override
protected void deactivate() { protected void deactivate() {
currencyComboBox.setOnAction(null);
tabPaneSelectionModel.selectedIndexProperty().removeListener(selectedTabIndexListener);
model.priceItems.removeListener(itemsChangeListener); model.priceItems.removeListener(itemsChangeListener);
toggleGroup.selectedToggleProperty().removeListener(toggleChangeListener); toggleGroup.selectedToggleProperty().removeListener(toggleChangeListener);
priceAxisY.widthProperty().removeListener(priceAxisYWidthListener); priceAxisY.widthProperty().removeListener(priceAxisYWidthListener);
volumeAxisY.widthProperty().removeListener(volumeAxisYWidthListener); volumeAxisY.widthProperty().removeListener(volumeAxisYWidthListener);
model.tradeStatisticsByCurrency.removeListener(tradeStatisticsByCurrencyListener); model.tradeStatisticsByCurrency.removeListener(tradeStatisticsByCurrencyListener);
tradeCurrencySubscriber.unsubscribe(); model.showAllTradeCurrenciesProperty.removeListener(showAllTradeCurrenciesListener);
currencyComboBox.setOnAction(null);
priceAxisY.labelProperty().unbind(); priceAxisY.labelProperty().unbind();
priceColumn.textProperty().unbind();
tradeCurrencySubscriber.unsubscribe();
sortedList.comparatorProperty().unbind();
priceSeries.getData().clear(); priceSeries.getData().clear();
priceChart.getData().clear(); priceChart.getData().clear();
sortedList.comparatorProperty().unbind();
} }
@ -194,7 +230,6 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
priceAxisY = new NumberAxis(); priceAxisY = new NumberAxis();
priceAxisY.setForceZeroInRange(false); priceAxisY.setForceZeroInRange(false);
priceAxisY.setAutoRanging(true); priceAxisY.setAutoRanging(true);
priceAxisY.labelProperty().bind(priceColumnLabel);
priceAxisY.setTickLabelFormatter(new StringConverter<Number>() { priceAxisY.setTickLabelFormatter(new StringConverter<Number>() {
@Override @Override
public String toString(Number object) { public String toString(Number object) {
@ -207,11 +242,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
} }
}); });
priceChart = new CandleStickChart(priceAxisX, priceAxisY); priceChart = new CandleStickChart(priceAxisX, priceAxisY, new StringConverter<Number>() {
priceChart.setMinHeight(250);
priceChart.setLegendVisible(false);
priceChart.setData(FXCollections.observableArrayList(priceSeries));
priceChart.setToolTipStringConverter(new StringConverter<Number>() {
@Override @Override
public String toString(Number object) { public String toString(Number object) {
return formatter.formatFiatWithCode(Fiat.valueOf(model.getCurrencyCode(), (long) object)); return formatter.formatFiatWithCode(Fiat.valueOf(model.getCurrencyCode(), (long) object));
@ -222,6 +253,10 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
return null; return null;
} }
}); });
priceChart.setMinHeight(250);
priceChart.setMaxHeight(300);
priceChart.setLegendVisible(false);
priceChart.setData(FXCollections.observableArrayList(priceSeries));
volumeSeries = new XYChart.Series<>(); volumeSeries = new XYChart.Series<>();
@ -248,14 +283,10 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
} }
}); });
volumeChart = new VolumeChart(volumeAxisX, volumeAxisY); volumeChart = new VolumeChart(volumeAxisX, volumeAxisY, new StringConverter<Number>() {
volumeChart.setData(FXCollections.observableArrayList(volumeSeries));
volumeChart.setMinHeight(140);
volumeChart.setLegendVisible(false);
volumeChart.setToolTipStringConverter(new StringConverter<Number>() {
@Override @Override
public String toString(Number object) { public String toString(Number object) {
return formatter.formatCoinWithCode(Coin.valueOf(new Double((double) object).longValue())); return formatter.formatCoinWithCode(Coin.valueOf((long) object));
} }
@Override @Override
@ -263,6 +294,10 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
return null; return null;
} }
}); });
volumeChart.setData(FXCollections.observableArrayList(volumeSeries));
volumeChart.setMinHeight(140);
volumeChart.setMaxHeight(200);
volumeChart.setLegendVisible(false);
} }
private void updateChartData() { private void updateChartData() {
@ -320,23 +355,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
currencyComboBox = new ComboBox<>(); currencyComboBox = new ComboBox<>();
currencyComboBox.setPromptText("Select currency"); currencyComboBox.setPromptText("Select currency");
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() { currencyComboBox.setConverter(GUIUtil.getCurrencyListConverter());
@Override
public String toString(TradeCurrency tradeCurrency) {
// http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618
if (tradeCurrency instanceof FiatCurrency)
return "" + tradeCurrency.getNameAndCode();
else if (tradeCurrency instanceof CryptoCurrency)
return "" + tradeCurrency.getNameAndCode();
else
return "-";
}
@Override
public TradeCurrency fromString(String s) {
return null;
}
});
Pane spacer = new Pane(); Pane spacer = new Pane();
HBox.setHgrow(spacer, Priority.ALWAYS); HBox.setHgrow(spacer, Priority.ALWAYS);
@ -377,6 +396,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
private void createTable() { private void createTable() {
tableView = new TableView<>(); tableView = new TableView<>();
tableView.setMinHeight(120); tableView.setMinHeight(120);
VBox.setVgrow(tableView, Priority.ALWAYS);
// date // date
TableColumn<TradeStatistics, TradeStatistics> dateColumn = new TableColumn<>("Date/Time"); TableColumn<TradeStatistics, TradeStatistics> dateColumn = new TableColumn<>("Date/Time");
@ -427,9 +447,8 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
tableView.getColumns().add(amountColumn); tableView.getColumns().add(amountColumn);
// price // price
TableColumn<TradeStatistics, TradeStatistics> priceColumn = new TableColumn<>(); priceColumn = new TableColumn<>();
priceColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue())); priceColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue()));
priceColumn.textProperty().bind(priceColumnLabel);
priceColumn.setCellFactory( priceColumn.setCellFactory(
new Callback<TableColumn<TradeStatistics, TradeStatistics>, TableCell<TradeStatistics, new Callback<TableColumn<TradeStatistics, TradeStatistics>, TableCell<TradeStatistics,
TradeStatistics>>() { TradeStatistics>>() {
@ -441,7 +460,9 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
public void updateItem(final TradeStatistics item, boolean empty) { public void updateItem(final TradeStatistics item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null) if (item != null)
setText(formatter.formatFiat(item.getTradePrice())); setText(model.showAllTradeCurrenciesProperty.get() ?
formatter.formatFiatWithCode(item.getTradePrice()) :
formatter.formatFiat(item.getTradePrice()));
else else
setText(""); setText("");
} }
@ -452,9 +473,8 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
tableView.getColumns().add(priceColumn); tableView.getColumns().add(priceColumn);
// volume // volume
TableColumn<TradeStatistics, TradeStatistics> volumeColumn = new TableColumn<>(); volumeColumn = new TableColumn<>();
volumeColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue())); volumeColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue()));
volumeColumn.setText("Volume (BTC)");
volumeColumn.setCellFactory( volumeColumn.setCellFactory(
new Callback<TableColumn<TradeStatistics, TradeStatistics>, TableCell<TradeStatistics, new Callback<TableColumn<TradeStatistics, TradeStatistics>, TableCell<TradeStatistics,
TradeStatistics>>() { TradeStatistics>>() {
@ -466,7 +486,9 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
public void updateItem(final TradeStatistics item, boolean empty) { public void updateItem(final TradeStatistics item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (item != null) if (item != null)
setText(formatter.formatFiatWithCode(item.getTradeVolume())); setText(model.showAllTradeCurrenciesProperty.get() ?
formatter.formatFiatWithCode(item.getTradeVolume()) :
formatter.formatFiat(item.getTradeVolume()));
else else
setText(""); setText("");
} }

View file

@ -15,19 +15,28 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.markets.trades; package io.bitsquare.gui.main.market.trades;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bitsquare.btc.pricefeed.PriceFeedService; import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ActivatableViewModel; import io.bitsquare.gui.common.model.ActivatableViewModel;
import io.bitsquare.gui.main.markets.trades.charts.CandleData; import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.market.trades.charts.CandleData;
import io.bitsquare.gui.main.settings.SettingsView;
import io.bitsquare.gui.main.settings.preferences.PreferencesView;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.locale.CryptoCurrency;
import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.locale.TradeCurrency; import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.trade.statistics.TradeStatistics; import io.bitsquare.trade.statistics.TradeStatistics;
import io.bitsquare.trade.statistics.TradeStatisticsManager; import io.bitsquare.trade.statistics.TradeStatisticsManager;
import io.bitsquare.user.Preferences; import io.bitsquare.user.Preferences;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@ -42,6 +51,8 @@ import java.util.stream.Collectors;
class TradesChartsViewModel extends ActivatableViewModel { class TradesChartsViewModel extends ActivatableViewModel {
private static final Logger log = LoggerFactory.getLogger(TradesChartsViewModel.class); private static final Logger log = LoggerFactory.getLogger(TradesChartsViewModel.class);
private static final int TAB_INDEX = 2;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Enum // Enum
@ -59,9 +70,12 @@ class TradesChartsViewModel extends ActivatableViewModel {
private final TradeStatisticsManager tradeStatisticsManager; private final TradeStatisticsManager tradeStatisticsManager;
final Preferences preferences; final Preferences preferences;
private PriceFeedService priceFeedService; private PriceFeedService priceFeedService;
private Navigation navigation;
private BSFormatter formatter;
private final SetChangeListener<TradeStatistics> setChangeListener; private final SetChangeListener<TradeStatistics> setChangeListener;
final ObjectProperty<TradeCurrency> tradeCurrencyProperty = new SimpleObjectProperty<>(); final ObjectProperty<TradeCurrency> selectedTradeCurrencyProperty = new SimpleObjectProperty<>();
final BooleanProperty showAllTradeCurrenciesProperty = new SimpleBooleanProperty(false);
final ObservableList<TradeStatistics> tradeStatisticsByCurrency = FXCollections.observableArrayList(); final ObservableList<TradeStatistics> tradeStatisticsByCurrency = FXCollections.observableArrayList();
ObservableList<XYChart.Data<Number, Number>> priceItems = FXCollections.observableArrayList(); ObservableList<XYChart.Data<Number, Number>> priceItems = FXCollections.observableArrayList();
@ -69,6 +83,7 @@ class TradesChartsViewModel extends ActivatableViewModel {
TickUnit tickUnit = TickUnit.MONTH; TickUnit tickUnit = TickUnit.MONTH;
int maxTicks = 30; int maxTicks = 30;
private int selectedTabIndex;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -76,19 +91,20 @@ class TradesChartsViewModel extends ActivatableViewModel {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public TradesChartsViewModel(TradeStatisticsManager tradeStatisticsManager, Preferences preferences, PriceFeedService priceFeedService) { public TradesChartsViewModel(TradeStatisticsManager tradeStatisticsManager, Preferences preferences, PriceFeedService priceFeedService, Navigation navigation, BSFormatter formatter) {
this.tradeStatisticsManager = tradeStatisticsManager; this.tradeStatisticsManager = tradeStatisticsManager;
this.preferences = preferences; this.preferences = preferences;
this.priceFeedService = priceFeedService; this.priceFeedService = priceFeedService;
this.navigation = navigation;
this.formatter = formatter;
setChangeListener = change -> updateChartData(); setChangeListener = change -> updateChartData();
Optional<TradeCurrency> tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(preferences.getTradeStatisticsScreenCurrencyCode()); Optional<TradeCurrency> tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(preferences.getTradeChartsScreenCurrencyCode());
if (tradeCurrencyOptional.isPresent()) if (tradeCurrencyOptional.isPresent())
tradeCurrencyProperty.set(tradeCurrencyOptional.get()); selectedTradeCurrencyProperty.set(tradeCurrencyOptional.get());
else { else
tradeCurrencyProperty.set(CurrencyUtil.getDefaultTradeCurrency()); selectedTradeCurrencyProperty.set(CurrencyUtil.getDefaultTradeCurrency());
}
tickUnit = TickUnit.values()[preferences.getTradeStatisticsTickUnitIndex()]; tickUnit = TickUnit.values()[preferences.getTradeStatisticsTickUnitIndex()];
} }
@ -105,9 +121,8 @@ class TradesChartsViewModel extends ActivatableViewModel {
protected void activate() { protected void activate() {
tradeStatisticsManager.getObservableTradeStatisticsSet().addListener(setChangeListener); tradeStatisticsManager.getObservableTradeStatisticsSet().addListener(setChangeListener);
updateChartData(); updateChartData();
syncPriceFeedCurrency();
if (!preferences.getUseStickyMarketPrice()) setMarketPriceFeedCurrency();
priceFeedService.setCurrencyCode(tradeCurrencyProperty.get().getCode());
} }
@Override @Override
@ -120,37 +135,62 @@ class TradesChartsViewModel extends ActivatableViewModel {
// UI actions // UI actions
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void onSetTradeCurrency(TradeCurrency tradeCurrency) { void onSetTradeCurrency(TradeCurrency tradeCurrency) {
this.tradeCurrencyProperty.set(tradeCurrency); if (tradeCurrency != null) {
preferences.setTradeStatisticsScreenCurrencyCode(tradeCurrency.getCode()); final String code = tradeCurrency.getCode();
updateChartData();
if (!preferences.getUseStickyMarketPrice()) if (isEditEntry(code)) {
priceFeedService.setCurrencyCode(tradeCurrency.getCode()); navigation.navigateTo(MainView.class, SettingsView.class, PreferencesView.class);
} else {
boolean showAllEntry = isShowAllEntry(code);
showAllTradeCurrenciesProperty.set(showAllEntry);
if (!showAllEntry) {
selectedTradeCurrencyProperty.set(tradeCurrency);
preferences.setTradeChartsScreenCurrencyCode(code);
}
updateChartData();
if (!preferences.getUseStickyMarketPrice()) {
if (showAllEntry)
priceFeedService.setCurrencyCode(CurrencyUtil.getDefaultTradeCurrency().getCode());
else
priceFeedService.setCurrencyCode(code);
}
}
}
} }
public void setTickUnit(TickUnit tickUnit) { void setTickUnit(TickUnit tickUnit) {
this.tickUnit = tickUnit; this.tickUnit = tickUnit;
preferences.setTradeStatisticsTickUnitIndex(tickUnit.ordinal()); preferences.setTradeStatisticsTickUnitIndex(tickUnit.ordinal());
updateChartData(); updateChartData();
} }
void setSelectedTabIndex(int selectedTabIndex) {
this.selectedTabIndex = selectedTabIndex;
syncPriceFeedCurrency();
setMarketPriceFeedCurrency();
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getters // Getters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public String getCurrencyCode() { public String getCurrencyCode() {
return tradeCurrencyProperty.get().getCode(); return selectedTradeCurrencyProperty.get().getCode();
} }
public ObservableList<TradeCurrency> getTradeCurrencies() { public ObservableList<TradeCurrency> getTradeCurrencies() {
return preferences.getTradeCurrenciesAsObservable(); final ObservableList<TradeCurrency> list = FXCollections.observableArrayList(preferences.getTradeCurrenciesAsObservable());
list.add(0, new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, GUIUtil.SHOW_ALL_FLAG));
list.add(new CryptoCurrency(GUIUtil.EDIT_FLAG, GUIUtil.EDIT_FLAG));
return list;
} }
public TradeCurrency getTradeCurrency() { public TradeCurrency getSelectedTradeCurrency() {
return tradeCurrencyProperty.get(); return selectedTradeCurrencyProperty.get();
} }
@ -158,10 +198,23 @@ class TradesChartsViewModel extends ActivatableViewModel {
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void setMarketPriceFeedCurrency() {
if (!preferences.getUseStickyMarketPrice() && selectedTabIndex == TAB_INDEX) {
if (showAllTradeCurrenciesProperty.get())
priceFeedService.setCurrencyCode(CurrencyUtil.getDefaultTradeCurrency().getCode());
else
priceFeedService.setCurrencyCode(getCurrencyCode());
}
}
private void syncPriceFeedCurrency() {
if (!preferences.getUseStickyMarketPrice() && selectedTabIndex == TAB_INDEX)
priceFeedService.setCurrencyCode(selectedTradeCurrencyProperty.get().getCode());
}
private void updateChartData() { private void updateChartData() {
tradeStatisticsByCurrency.setAll(tradeStatisticsManager.getObservableTradeStatisticsSet().stream() tradeStatisticsByCurrency.setAll(tradeStatisticsManager.getObservableTradeStatisticsSet().stream()
.filter(e -> e.currency.equals(getCurrencyCode())) .filter(e -> showAllTradeCurrenciesProperty.get() || e.currency.equals(getCurrencyCode()))
.collect(Collectors.toList())); .collect(Collectors.toList()));
// Get all entries for the defined time interval // Get all entries for the defined time interval
@ -183,6 +236,7 @@ class TradesChartsViewModel extends ActivatableViewModel {
// create CandleData for defined time interval // create CandleData for defined time interval
List<CandleData> candleDataList = itemsPerInterval.entrySet().stream() List<CandleData> candleDataList = itemsPerInterval.entrySet().stream()
.map(entry -> getCandleData(entry.getKey(), entry.getValue())) .map(entry -> getCandleData(entry.getKey(), entry.getValue()))
.filter(e -> e.tick >= 0)
.collect(Collectors.toList()); .collect(Collectors.toList());
candleDataList.sort((o1, o2) -> (o1.tick < o2.tick ? -1 : (o1.tick == o2.tick ? 0 : 1))); candleDataList.sort((o1, o2) -> (o1.tick < o2.tick ? -1 : (o1.tick == o2.tick ? 0 : 1)));
@ -221,7 +275,12 @@ class TradesChartsViewModel extends ActivatableViewModel {
close = list.get(list.size() - 1).tradePrice; close = list.get(list.size() - 1).tradePrice;
} }
boolean isBullish = close > open; boolean isBullish = close > open;
return new CandleData(tick, open, close, high, low, averagePrice, accumulatedAmount, accumulatedVolume, isBullish); final Date date = new Date(getTimeFromTickIndex(tick));
String dateString = tickUnit.ordinal() > TickUnit.DAY.ordinal() ?
formatter.formatDateTime(date) :
formatter.formatDate(date);
return new CandleData(tick, open, close, high, low, averagePrice, accumulatedAmount, accumulatedVolume,
isBullish, dateString);
} }
long getTickFromTime(long tradeDateAsTime, TickUnit tickUnit) { long getTickFromTime(long tradeDateAsTime, TickUnit tickUnit) {
@ -267,4 +326,12 @@ class TradesChartsViewModel extends ActivatableViewModel {
long tick = now - (maxTicks - index); long tick = now - (maxTicks - index);
return getTimeFromTick(tick, tickUnit); return getTimeFromTick(tick, tickUnit);
} }
private boolean isShowAllEntry(String id) {
return id.equals(GUIUtil.SHOW_ALL_FLAG);
}
private boolean isEditEntry(String id) {
return id.equals(GUIUtil.EDIT_FLAG);
}
} }

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.markets.trades.charts; package io.bitsquare.gui.main.market.trades.charts;
public class CandleData { public class CandleData {
public final long tick; // Is the time tick in the chosen time interval public final long tick; // Is the time tick in the chosen time interval
@ -27,8 +27,9 @@ public class CandleData {
public final long accumulatedAmount; public final long accumulatedAmount;
public final long accumulatedVolume; public final long accumulatedVolume;
public final boolean isBullish; public final boolean isBullish;
public final String date;
public CandleData(long tick, long open, long close, long high, long low, long average, long accumulatedAmount, long accumulatedVolume, boolean isBullish) { public CandleData(long tick, long open, long close, long high, long low, long average, long accumulatedAmount, long accumulatedVolume, boolean isBullish, String date) {
this.tick = tick; this.tick = tick;
this.open = open; this.open = open;
this.close = close; this.close = close;
@ -38,5 +39,6 @@ public class CandleData {
this.accumulatedAmount = accumulatedAmount; this.accumulatedAmount = accumulatedAmount;
this.accumulatedVolume = accumulatedVolume; this.accumulatedVolume = accumulatedVolume;
this.isBullish = isBullish; this.isBullish = isBullish;
this.date = date;
} }
} }

View file

@ -29,9 +29,9 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package io.bitsquare.gui.main.markets.trades.charts.price; package io.bitsquare.gui.main.market.trades.charts.price;
import io.bitsquare.gui.main.markets.trades.charts.CandleData; import io.bitsquare.gui.main.market.trades.charts.CandleData;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
@ -48,7 +48,7 @@ public class Candle extends Group {
private String seriesStyleClass; private String seriesStyleClass;
private String dataStyleClass; private String dataStyleClass;
private final TooltipContent tooltipContent; private final CandleTooltip candleTooltip;
private final Line highLowLine = new Line(); private final Line highLowLine = new Line();
private final Region bar = new Region(); private final Region bar = new Region();
@ -65,8 +65,8 @@ public class Candle extends Group {
getStyleClass().setAll("candlestick-candle", seriesStyleClass, dataStyleClass); getStyleClass().setAll("candlestick-candle", seriesStyleClass, dataStyleClass);
updateStyleClasses(); updateStyleClasses();
tooltipContent = new TooltipContent(priceStringConverter); candleTooltip = new CandleTooltip(priceStringConverter);
tooltip.setGraphic(tooltipContent); tooltip.setGraphic(candleTooltip);
Tooltip.install(this, tooltip); Tooltip.install(this, tooltip);
} }
@ -91,7 +91,7 @@ public class Candle extends Group {
} }
public void updateTooltip(CandleData candleData) { public void updateTooltip(CandleData candleData) {
tooltipContent.update(candleData); candleTooltip.update(candleData);
} }
private void updateStyleClasses() { private void updateStyleClasses() {

View file

@ -29,9 +29,9 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package io.bitsquare.gui.main.markets.trades.charts.price; package io.bitsquare.gui.main.market.trades.charts.price;
import io.bitsquare.gui.main.markets.trades.charts.CandleData; import io.bitsquare.gui.main.market.trades.charts.CandleData;
import javafx.animation.FadeTransition; import javafx.animation.FadeTransition;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.scene.Node; import javafx.scene.Node;
@ -70,16 +70,13 @@ public class CandleStickChart extends XYChart<Number, Number> {
* @param xAxis The x axis to use * @param xAxis The x axis to use
* @param yAxis The y axis to use * @param yAxis The y axis to use
*/ */
public CandleStickChart(Axis<Number> xAxis, Axis<Number> yAxis) { public CandleStickChart(Axis<Number> xAxis, Axis<Number> yAxis, StringConverter<Number> priceStringConverter) {
super(xAxis, yAxis); super(xAxis, yAxis);
this.priceStringConverter = priceStringConverter;
} }
// -------------- METHODS ------------------------------------------------------------------------------------------ // -------------- METHODS ------------------------------------------------------------------------------------------
public final void setToolTipStringConverter(StringConverter<Number> priceStringConverter) {
this.priceStringConverter = priceStringConverter;
}
/** /**
* Called to update and layout the content for the plot * Called to update and layout the content for the plot
*/ */

View file

@ -29,29 +29,34 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package io.bitsquare.gui.main.markets.trades.charts.price; package io.bitsquare.gui.main.market.trades.charts.price;
import io.bitsquare.gui.main.markets.trades.charts.CandleData; import io.bitsquare.gui.main.market.trades.charts.CandleData;
import io.bitsquare.gui.util.Layout; import io.bitsquare.gui.util.Layout;
import javafx.geometry.HPos;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.util.StringConverter; import javafx.util.StringConverter;
/** /**
* The content for Candle tool tips * The content for Candle tool tips
*/ */
public class TooltipContent extends GridPane { public class CandleTooltip extends GridPane {
private final StringConverter<Number> priceStringConverter; private final StringConverter<Number> priceStringConverter;
private final Label openValue = new Label(); private final Label openValue = new Label();
private final Label closeValue = new Label(); private final Label closeValue = new Label();
private final Label highValue = new Label(); private final Label highValue = new Label();
private final Label lowValue = new Label(); private final Label lowValue = new Label();
private final Label averageValue = new Label(); private final Label averageValue = new Label();
private final Label dateValue = new Label();
TooltipContent(StringConverter<Number> priceStringConverter) { CandleTooltip(StringConverter<Number> priceStringConverter) {
this.priceStringConverter = priceStringConverter; this.priceStringConverter = priceStringConverter;
setHgap(Layout.GRID_GAP); setHgap(Layout.GRID_GAP);
setVgap(2); setVgap(2);
Label open = new Label("Open:"); Label open = new Label("Open:");
@ -59,10 +64,7 @@ public class TooltipContent extends GridPane {
Label high = new Label("High:"); Label high = new Label("High:");
Label low = new Label("Low:"); Label low = new Label("Low:");
Label average = new Label("Average:"); Label average = new Label("Average:");
/* open.getStyleClass().add("candlestick-tooltip-label"); Label date = new Label("Date:");
close.getStyleClass().add("candlestick-tooltip-label");
high.getStyleClass().add("candlestick-tooltip-label");
low.getStyleClass().add("candlestick-tooltip-label");*/
setConstraints(open, 0, 0); setConstraints(open, 0, 0);
setConstraints(openValue, 1, 0); setConstraints(openValue, 1, 0);
setConstraints(close, 0, 1); setConstraints(close, 0, 1);
@ -73,7 +75,17 @@ public class TooltipContent extends GridPane {
setConstraints(lowValue, 1, 3); setConstraints(lowValue, 1, 3);
setConstraints(average, 0, 4); setConstraints(average, 0, 4);
setConstraints(averageValue, 1, 4); setConstraints(averageValue, 1, 4);
getChildren().addAll(open, openValue, close, closeValue, high, highValue, low, lowValue, average, averageValue); setConstraints(date, 0, 5);
setConstraints(dateValue, 1, 5);
ColumnConstraints columnConstraints1 = new ColumnConstraints();
columnConstraints1.setHalignment(HPos.RIGHT);
columnConstraints1.setHgrow(Priority.NEVER);
ColumnConstraints columnConstraints2 = new ColumnConstraints();
columnConstraints2.setHgrow(Priority.ALWAYS);
getColumnConstraints().addAll(columnConstraints1, columnConstraints2);
getChildren().addAll(open, openValue, close, closeValue, high, highValue, low, lowValue, average, averageValue, date, dateValue);
} }
public void update(CandleData candleData) { public void update(CandleData candleData) {
@ -82,5 +94,6 @@ public class TooltipContent extends GridPane {
highValue.setText(priceStringConverter.toString(candleData.high)); highValue.setText(priceStringConverter.toString(candleData.high));
lowValue.setText(priceStringConverter.toString(candleData.low)); lowValue.setText(priceStringConverter.toString(candleData.low));
averageValue.setText(priceStringConverter.toString(candleData.average)); averageValue.setText(priceStringConverter.toString(candleData.average));
dateValue.setText(candleData.date);
} }
} }

View file

@ -14,8 +14,9 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.markets.trades.charts.volume; package io.bitsquare.gui.main.market.trades.charts.volume;
import io.bitsquare.gui.main.market.trades.charts.CandleData;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
@ -51,9 +52,10 @@ public class VolumeBar extends Group {
updateStyleClasses(); updateStyleClasses();
} }
public void update(double height, double candleWidth, double accumulatedAmount) { public void update(double height, double candleWidth, CandleData candleData) {
bar.resizeRelocate(-candleWidth / 2, 0, candleWidth, height); bar.resizeRelocate(-candleWidth / 2, 0, candleWidth, height);
tooltip.setText("Volume: " + volumeStringConverter.toString(accumulatedAmount)); tooltip.setText("Volume: " + volumeStringConverter.toString(candleData.accumulatedAmount) + "\n" +
"Date: " + candleData.date);
} }
private void updateStyleClasses() { private void updateStyleClasses() {

View file

@ -14,10 +14,10 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bitsquare.gui.main.markets.trades.charts.volume; package io.bitsquare.gui.main.market.trades.charts.volume;
import io.bitsquare.gui.main.markets.trades.charts.CandleData; import io.bitsquare.gui.main.market.trades.charts.CandleData;
import io.bitsquare.gui.main.markets.trades.charts.price.CandleStickChart; import io.bitsquare.gui.main.market.trades.charts.price.CandleStickChart;
import javafx.animation.FadeTransition; import javafx.animation.FadeTransition;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.scene.Node; import javafx.scene.Node;
@ -38,11 +38,8 @@ public class VolumeChart extends XYChart<Number, Number> {
private StringConverter<Number> toolTipStringConverter; private StringConverter<Number> toolTipStringConverter;
public VolumeChart(Axis<Number> xAxis, Axis<Number> yAxis) { public VolumeChart(Axis<Number> xAxis, Axis<Number> yAxis, StringConverter<Number> toolTipStringConverter) {
super(xAxis, yAxis); super(xAxis, yAxis);
}
public final void setToolTipStringConverter(StringConverter<Number> toolTipStringConverter) {
this.toolTipStringConverter = toolTipStringConverter; this.toolTipStringConverter = toolTipStringConverter;
} }
@ -73,7 +70,7 @@ public class VolumeChart extends XYChart<Number, Number> {
// Did not find a way how to request the chart data height // Did not find a way how to request the chart data height
final double height = getHeight() - 43; final double height = getHeight() - 43;
double upperYPos = Math.min(height - 5, y); // We want min 5px height to allow tooltips double upperYPos = Math.min(height - 5, y); // We want min 5px height to allow tooltips
volumeBar.update(height - upperYPos, candleWidth, candleData.accumulatedAmount); volumeBar.update(height - upperYPos, candleWidth, candleData);
volumeBar.setLayoutX(x); volumeBar.setLayoutX(x);
volumeBar.setLayoutY(upperYPos); volumeBar.setLayoutY(upperYPos);
} }

View file

@ -20,7 +20,7 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<VBox fx:id="root" fx:controller="io.bitsquare.gui.main.markets.charts.MarketsChartsView" <VBox fx:id="root" fx:controller="io.bitsquare.gui.main.markets.offerbook.OfferBookChartView"
spacing="20.0" fillWidth="true" spacing="20.0" fillWidth="true"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"

View file

@ -333,7 +333,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
"When another trader wants to take your offer it requires that your application is online and able to react.\n" + "When another trader wants to take your offer it requires that your application is online and able to react.\n" +
"Be sure that you have standby mode deactivated as that would disconnect your client from the network (standby of the monitor is not a problem).") "Be sure that you have standby mode deactivated as that would disconnect your client from the network (standby of the monitor is not a problem).")
.actionButtonText("Visit FAQ web page") .actionButtonText("Visit FAQ web page")
.onAction(() -> Utilities.openWebPage("https://bitsquare.io/faq#6")) .onAction(() -> GUIUtil.openWebPage("https://bitsquare.io/faq#6"))
.closeButtonText("I understand") .closeButtonText("I understand")
.dontShowAgainId(key, preferences) .dontShowAgainId(key, preferences)
.show(); .show();

View file

@ -22,7 +22,6 @@ import io.bitsquare.btc.pricefeed.MarketPrice;
import io.bitsquare.btc.pricefeed.PriceFeedService; import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.common.Timer; import io.bitsquare.common.Timer;
import io.bitsquare.common.UserThread; import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.Navigation; import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ActivatableWithDataModel; import io.bitsquare.gui.common.model.ActivatableWithDataModel;
import io.bitsquare.gui.common.model.ViewModel; import io.bitsquare.gui.common.model.ViewModel;
@ -33,6 +32,7 @@ import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.gui.main.settings.SettingsView; import io.bitsquare.gui.main.settings.SettingsView;
import io.bitsquare.gui.main.settings.preferences.PreferencesView; import io.bitsquare.gui.main.settings.preferences.PreferencesView;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.gui.util.validation.BtcValidator; import io.bitsquare.gui.util.validation.BtcValidator;
import io.bitsquare.gui.util.validation.FiatValidator; import io.bitsquare.gui.util.validation.FiatValidator;
import io.bitsquare.gui.util.validation.InputValidator; import io.bitsquare.gui.util.validation.InputValidator;
@ -355,7 +355,7 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
"Be sure you fully understand the situation and check out the information on the \"Ethereum Classic\" and \"Ethereum\" project web pages.\n\n" + "Be sure you fully understand the situation and check out the information on the \"Ethereum Classic\" and \"Ethereum\" project web pages.\n\n" +
"Please note, that the price is denominated as ETC/BTC not BTC/ETC!") "Please note, that the price is denominated as ETC/BTC not BTC/ETC!")
.closeButtonText("I understand") .closeButtonText("I understand")
.onAction(() -> Utilities.openWebPage("https://ethereumclassic.github.io/")) .onAction(() -> GUIUtil.openWebPage("https://ethereumclassic.github.io/"))
.actionButtonText("Open Ethereum Classic web page") .actionButtonText("Open Ethereum Classic web page")
.dontShowAgainId(key, preferences) .dontShowAgainId(key, preferences)
.show(); .show();

View file

@ -35,9 +35,9 @@ import io.bitsquare.gui.main.offer.OfferView;
import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow; import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.gui.util.Layout; import io.bitsquare.gui.util.Layout;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
import io.bitsquare.locale.CryptoCurrency;
import io.bitsquare.locale.FiatCurrency; import io.bitsquare.locale.FiatCurrency;
import io.bitsquare.locale.TradeCurrency; import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.payment.PaymentMethod; import io.bitsquare.payment.PaymentMethod;
@ -107,28 +107,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
currencyComboBox = addLabelComboBox(root, gridRow, "Filter by currency:", Layout.FIRST_ROW_DISTANCE).second; currencyComboBox = addLabelComboBox(root, gridRow, "Filter by currency:", Layout.FIRST_ROW_DISTANCE).second;
currencyComboBox.setPromptText("Select currency"); currencyComboBox.setPromptText("Select currency");
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() { currencyComboBox.setConverter(GUIUtil.getCurrencyListConverter());
@Override
public String toString(TradeCurrency tradeCurrency) {
String code = tradeCurrency.getCode();
// http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618
if (code.equals(OfferBookViewModel.SHOW_ALL_FLAG))
return "▶ Show all";
else if (code.equals(OfferBookViewModel.EDIT_FLAG))
return "▼ Edit currency list";
else if (tradeCurrency instanceof FiatCurrency)
return "" + tradeCurrency.getNameAndCode();
else if (tradeCurrency instanceof CryptoCurrency)
return "" + tradeCurrency.getNameAndCode();
else
return "-";
}
@Override
public TradeCurrency fromString(String s) {
return null;
}
});
paymentMethodComboBox = addLabelComboBox(root, ++gridRow, "Filter by payment method:").second; paymentMethodComboBox = addLabelComboBox(root, ++gridRow, "Filter by payment method:").second;
paymentMethodComboBox.setPromptText("Select payment method"); paymentMethodComboBox.setPromptText("Select payment method");
@ -136,7 +115,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
@Override @Override
public String toString(PaymentMethod paymentMethod) { public String toString(PaymentMethod paymentMethod) {
String id = paymentMethod.getId(); String id = paymentMethod.getId();
if (id.equals(OfferBookViewModel.SHOW_ALL_FLAG)) if (id.equals(GUIUtil.SHOW_ALL_FLAG))
return "▶ Show all"; return "▶ Show all";
else if (paymentMethod.equals(PaymentMethod.BLOCK_CHAINS)) else if (paymentMethod.equals(PaymentMethod.BLOCK_CHAINS))
return "" + BSResources.get(id); return "" + BSResources.get(id);

View file

@ -30,6 +30,7 @@ import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.main.settings.SettingsView; import io.bitsquare.gui.main.settings.SettingsView;
import io.bitsquare.gui.main.settings.preferences.PreferencesView; import io.bitsquare.gui.main.settings.preferences.PreferencesView;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.locale.*; import io.bitsquare.locale.*;
import io.bitsquare.p2p.NodeAddress; import io.bitsquare.p2p.NodeAddress;
import io.bitsquare.p2p.P2PService; import io.bitsquare.p2p.P2PService;
@ -60,9 +61,6 @@ import java.util.stream.Collectors;
class OfferBookViewModel extends ActivatableViewModel { class OfferBookViewModel extends ActivatableViewModel {
protected final static Logger log = LoggerFactory.getLogger(OfferBookViewModel.class); protected final static Logger log = LoggerFactory.getLogger(OfferBookViewModel.class);
final static String SHOW_ALL_FLAG = "SHOW_ALL_FLAG";
final static String EDIT_FLAG = "EDIT_FLAG";
private final OpenOfferManager openOfferManager; private final OpenOfferManager openOfferManager;
private final User user; private final User user;
private final OfferBook offerBook; private final OfferBook offerBook;
@ -87,8 +85,7 @@ class OfferBookViewModel extends ActivatableViewModel {
// If id is empty string we ignore filter (display all methods) // If id is empty string we ignore filter (display all methods)
PaymentMethod selectedPaymentMethod = new PaymentMethod(SHOW_ALL_FLAG, 0, 0, null); PaymentMethod selectedPaymentMethod = new PaymentMethod(GUIUtil.SHOW_ALL_FLAG, 0, 0, null);
private CryptoCurrency showAllCurrenciesItem = new CryptoCurrency(SHOW_ALL_FLAG, SHOW_ALL_FLAG);
private final ObservableList<OfferBookListItem> offerBookListItems; private final ObservableList<OfferBookListItem> offerBookListItems;
private boolean isTabSelected; private boolean isTabSelected;
@ -146,9 +143,9 @@ class OfferBookViewModel extends ActivatableViewModel {
private void fillAllTradeCurrencies() { private void fillAllTradeCurrencies() {
allTradeCurrencies.clear(); allTradeCurrencies.clear();
// Used for ignoring filter (show all) // Used for ignoring filter (show all)
allTradeCurrencies.add(showAllCurrenciesItem); allTradeCurrencies.add(new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, GUIUtil.SHOW_ALL_FLAG));
allTradeCurrencies.addAll(preferences.getTradeCurrenciesAsObservable()); allTradeCurrencies.addAll(preferences.getTradeCurrenciesAsObservable());
allTradeCurrencies.add(new CryptoCurrency(EDIT_FLAG, EDIT_FLAG)); allTradeCurrencies.add(new CryptoCurrency(GUIUtil.EDIT_FLAG, GUIUtil.EDIT_FLAG));
} }
private void setMarketPriceFeedCurrency() { private void setMarketPriceFeedCurrency() {
@ -254,7 +251,7 @@ class OfferBookViewModel extends ActivatableViewModel {
public ObservableList<PaymentMethod> getPaymentMethods() { public ObservableList<PaymentMethod> getPaymentMethods() {
ObservableList<PaymentMethod> list = FXCollections.observableArrayList(PaymentMethod.ALL_VALUES); ObservableList<PaymentMethod> list = FXCollections.observableArrayList(PaymentMethod.ALL_VALUES);
list.add(0, new PaymentMethod(SHOW_ALL_FLAG, 0, 0, null)); list.add(0, new PaymentMethod(GUIUtil.SHOW_ALL_FLAG, 0, 0, null));
return list; return list;
} }
@ -418,11 +415,11 @@ class OfferBookViewModel extends ActivatableViewModel {
} }
private boolean isShowAllEntry(String id) { private boolean isShowAllEntry(String id) {
return id.equals(SHOW_ALL_FLAG); return id.equals(GUIUtil.SHOW_ALL_FLAG);
} }
private boolean isEditEntry(String id) { private boolean isEditEntry(String id) {
return id.equals(EDIT_FLAG); return id.equals(GUIUtil.EDIT_FLAG);
} }
int getNumPastTrades(Offer offer) { int getNumPastTrades(Offer offer) {

View file

@ -334,7 +334,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
"The deposit will stay in your local trading wallet until the offer gets accepted by another trader.\n" + "The deposit will stay in your local trading wallet until the offer gets accepted by another trader.\n" +
"It will be refunded to you after the trade has successfully completed.") "It will be refunded to you after the trade has successfully completed.")
.actionButtonText("Visit FAQ web page") .actionButtonText("Visit FAQ web page")
.onAction(() -> Utilities.openWebPage("https://bitsquare.io/faq#6")) .onAction(() -> GUIUtil.openWebPage("https://bitsquare.io/faq#6"))
.closeButtonText("I understand") .closeButtonText("I understand")
.dontShowAgainId(key, preferences) .dontShowAgainId(key, preferences)
.show(); .show();

View file

@ -19,7 +19,6 @@ package io.bitsquare.gui.main.offer.takeoffer;
import io.bitsquare.arbitration.Arbitrator; import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.btc.pricefeed.PriceFeedService; import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.Navigation; import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ActivatableWithDataModel; import io.bitsquare.gui.common.model.ActivatableWithDataModel;
import io.bitsquare.gui.common.model.ViewModel; import io.bitsquare.gui.common.model.ViewModel;
@ -28,6 +27,7 @@ import io.bitsquare.gui.main.funds.FundsView;
import io.bitsquare.gui.main.funds.deposit.DepositView; import io.bitsquare.gui.main.funds.deposit.DepositView;
import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.gui.util.validation.BtcValidator; import io.bitsquare.gui.util.validation.BtcValidator;
import io.bitsquare.gui.util.validation.InputValidator; import io.bitsquare.gui.util.validation.InputValidator;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
@ -148,7 +148,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
"Be sure you fully understand the situation and check out the information on the \"Ethereum Classic\" and \"Ethereum\" project web pages.\n\n" + "Be sure you fully understand the situation and check out the information on the \"Ethereum Classic\" and \"Ethereum\" project web pages.\n\n" +
"Please note, that the price is denominated as ETC/BTC not BTC/ETC!") "Please note, that the price is denominated as ETC/BTC not BTC/ETC!")
.closeButtonText("I understand") .closeButtonText("I understand")
.onAction(() -> Utilities.openWebPage("https://ethereumclassic.github.io/")) .onAction(() -> GUIUtil.openWebPage("https://ethereumclassic.github.io/"))
.actionButtonText("Open Ethereum Classic web page") .actionButtonText("Open Ethereum Classic web page")
.dontShowAgainId(key, dataModel.getPreferences()) .dontShowAgainId(key, dataModel.getPreferences())
.show(); .show();

View file

@ -22,6 +22,7 @@ import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Utilities; import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.components.BusyAnimation; import io.bitsquare.gui.components.BusyAnimation;
import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.MainView;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.gui.util.Transitions; import io.bitsquare.gui.util.Transitions;
import io.bitsquare.locale.BSResources; import io.bitsquare.locale.BSResources;
import io.bitsquare.user.Preferences; import io.bitsquare.user.Preferences;
@ -680,7 +681,7 @@ public abstract class Overlay<T extends Overlay> {
githubButton.setOnAction(event -> { githubButton.setOnAction(event -> {
Utilities.copyToClipboard(message); Utilities.copyToClipboard(message);
Utilities.openWebPage("https://github.com/bitsquare/bitsquare/issues"); GUIUtil.openWebPage("https://github.com/bitsquare/bitsquare/issues");
}); });
Button mailButton = new Button("Report by email"); Button mailButton = new Button("Report by email");
@ -690,7 +691,7 @@ public abstract class Overlay<T extends Overlay> {
gridPane.getChildren().add(mailButton); gridPane.getChildren().add(mailButton);
mailButton.setOnAction(event -> { mailButton.setOnAction(event -> {
Utilities.copyToClipboard(message); Utilities.copyToClipboard(message);
Utilities.openMail("manfred@bitsquare.io", GUIUtil.openMail("manfred@bitsquare.io",
"Error report", "Error report",
"Error message:\n" + message); "Error message:\n" + message);
}); });

View file

@ -19,8 +19,8 @@ package io.bitsquare.gui.main.overlays.windows;
import io.bitsquare.alert.Alert; import io.bitsquare.alert.Alert;
import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple2;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.main.overlays.Overlay; import io.bitsquare.gui.main.overlays.Overlay;
import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.user.Preferences; import io.bitsquare.user.Preferences;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.geometry.Insets; import javafx.geometry.Insets;
@ -90,7 +90,7 @@ public class AddBridgeEntriesWindow extends Overlay<AddBridgeEntriesWindow> {
actionButton.setOnAction(event -> save()); actionButton.setOnAction(event -> save());
Button urlButton = new Button("Open Tor project web page"); Button urlButton = new Button("Open Tor project web page");
urlButton.setOnAction(event -> Utilities.openWebPage("https://bridges.torproject.org/bridges")); urlButton.setOnAction(event -> GUIUtil.openWebPage("https://bridges.torproject.org/bridges"));
Pane spacer = new Pane(); Pane spacer = new Pane();
HBox hBox = new HBox(); HBox hBox = new HBox();

View file

@ -199,18 +199,23 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
final PaymentMethod paymentMethod = offer.getPaymentMethod(); final PaymentMethod paymentMethod = offer.getPaymentMethod();
final String offererPaymentAccountId = offer.getOffererPaymentAccountId(); final String offererPaymentAccountId = offer.getOffererPaymentAccountId();
final PaymentAccount paymentAccount = user.getPaymentAccount(offererPaymentAccountId); final PaymentAccount paymentAccount = user.getPaymentAccount(offererPaymentAccountId);
final String bankId = offer.getBankId(); String bankId = offer.getBankId();
if (bankId == null || bankId.equals("null"))
bankId = "";
else
bankId = " (" + bankId + ")";
final boolean isSpecificBanks = paymentMethod.equals(PaymentMethod.SPECIFIC_BANKS); final boolean isSpecificBanks = paymentMethod.equals(PaymentMethod.SPECIFIC_BANKS);
final boolean isNationalBanks = paymentMethod.equals(PaymentMethod.NATIONAL_BANK); final boolean isNationalBanks = paymentMethod.equals(PaymentMethod.NATIONAL_BANK);
final boolean isSepa = paymentMethod.equals(PaymentMethod.SEPA);
if (offer.isMyOffer(keyRing) && offererPaymentAccountId != null && paymentAccount != null) { if (offer.isMyOffer(keyRing) && offererPaymentAccountId != null && paymentAccount != null) {
addLabelTextField(gridPane, ++rowIndex, "Payment account:", paymentAccount.getAccountName()); addLabelTextField(gridPane, ++rowIndex, "Payment account:", paymentAccount.getAccountName());
} else { } else {
final String method = BSResources.get(paymentMethod.getId()); final String method = BSResources.get(paymentMethod.getId());
if (isNationalBanks || isSpecificBanks) { if (isNationalBanks || isSpecificBanks || isSepa) {
if (BankUtil.isBankIdRequired(offer.getCountryCode())) if (BankUtil.isBankIdRequired(offer.getCountryCode()))
addLabelTextField(gridPane, ++rowIndex, "Payment method (offerers bank ID):", method + " (" + bankId + ")"); addLabelTextField(gridPane, ++rowIndex, "Payment method (offerers bank ID):", method + bankId);
else if (BankUtil.isBankNameRequired(offer.getCountryCode())) else if (BankUtil.isBankNameRequired(offer.getCountryCode()))
addLabelTextField(gridPane, ++rowIndex, "Payment method (offerers bank name):", method + " (" + bankId + ")"); addLabelTextField(gridPane, ++rowIndex, "Payment method (offerers bank name):", method + bankId);
} else { } else {
addLabelTextField(gridPane, ++rowIndex, "Payment method:", method); addLabelTextField(gridPane, ++rowIndex, "Payment method:", method);
} }

View file

@ -372,7 +372,6 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
} }
private void doRestore() { private void doRestore() {
log.info("Attempting wallet restore using seed '{}' from date {}", restoreSeedWordsTextArea.getText(), restoreDatePicker.getValue());
long date = restoreDatePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC); long date = restoreDatePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC);
DeterministicSeed seed = new DeterministicSeed(Splitter.on(" ").splitToList(restoreSeedWordsTextArea.getText()), null, "", date); DeterministicSeed seed = new DeterministicSeed(Splitter.on(" ").splitToList(restoreSeedWordsTextArea.getText()), null, "", date);
walletService.restoreSeedWords(seed, walletService.restoreSeedWords(seed,

View file

@ -92,14 +92,15 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
dateColumn.setComparator((o1, o2) -> o1.getTradable().getDate().compareTo(o2.getTradable().getDate())); dateColumn.setComparator((o1, o2) -> o1.getTradable().getDate().compareTo(o2.getTradable().getDate()));
directionColumn.setComparator((o1, o2) -> o1.getTradable().getOffer().getDirection().compareTo(o2.getTradable().getOffer().getDirection())); directionColumn.setComparator((o1, o2) -> o1.getTradable().getOffer().getDirection().compareTo(o2.getTradable().getOffer().getDirection()));
priceColumn.setComparator((o1, o2) -> { priceColumn.setComparator((o1, o2) -> {
Tradable tradable = o1.getTradable(); final Tradable tradable1 = o1.getTradable();
if (tradable instanceof Trade) final Tradable tradable2 = o2.getTradable();
return ((Trade) o1.getTradable()).getTradePrice().compareTo(((Trade) o2.getTradable()).getTradePrice()); Fiat price1 = null;
else { Fiat price2 = null;
Fiat price1 = o1.getTradable().getOffer().getPrice(); if (tradable1 != null)
Fiat price2 = o2.getTradable().getOffer().getPrice(); price1 = tradable1 instanceof Trade ? ((Trade) tradable1).getTradePrice() : tradable1.getOffer().getPrice();
return price1 != null && price2 != null ? price1.compareTo(price2) : 0; if (tradable2 != null)
} price2 = tradable2 instanceof Trade ? ((Trade) tradable2).getTradePrice() : tradable2.getOffer().getPrice();
return price1 != null && price2 != null ? price1.compareTo(price2) : 0;
}); });
volumeColumn.setComparator((o1, o2) -> { volumeColumn.setComparator((o1, o2) -> {
if (o1.getTradable() instanceof Trade && o2.getTradable() instanceof Trade) { if (o1.getTradable() instanceof Trade && o2.getTradable() instanceof Trade) {

View file

@ -304,7 +304,7 @@ public class PendingTradesDataModel extends ActivatableDataModel {
if (depositTx != null) { if (depositTx != null) {
doOpenDispute(isSupportTicket, getTrade().getDepositTx()); doOpenDispute(isSupportTicket, getTrade().getDepositTx());
} else { } else {
log.warn("Trade.depositTx is null. We try to find the tx in our wallet."); log.info("Trade.depositTx is null. We try to find the tx in our wallet.");
List<Transaction> candidates = new ArrayList<>(); List<Transaction> candidates = new ArrayList<>();
List<Transaction> transactions = walletService.getWallet().getRecentTransactions(100, true); List<Transaction> transactions = walletService.getWallet().getRecentTransactions(100, true);
transactions.stream().forEach(transaction -> { transactions.stream().forEach(transaction -> {

View file

@ -21,7 +21,6 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple2;
import io.bitsquare.common.util.Tuple3; import io.bitsquare.common.util.Tuple3;
import io.bitsquare.common.util.Tuple4; import io.bitsquare.common.util.Tuple4;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.components.*; import io.bitsquare.gui.components.*;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.geometry.Insets; import javafx.geometry.Insets;
@ -170,7 +169,7 @@ public class FormBuilder {
public static HyperlinkWithIcon addHyperlinkWithIcon(GridPane gridPane, int rowIndex, String title, String url, double top) { public static HyperlinkWithIcon addHyperlinkWithIcon(GridPane gridPane, int rowIndex, String title, String url, double top) {
HyperlinkWithIcon hyperlinkWithIcon = new HyperlinkWithIcon(title, AwesomeIcon.EXTERNAL_LINK); HyperlinkWithIcon hyperlinkWithIcon = new HyperlinkWithIcon(title, AwesomeIcon.EXTERNAL_LINK);
hyperlinkWithIcon.setOnAction(e -> Utilities.openWebPage(url)); hyperlinkWithIcon.setOnAction(e -> GUIUtil.openWebPage(url));
GridPane.setRowIndex(hyperlinkWithIcon, rowIndex); GridPane.setRowIndex(hyperlinkWithIcon, rowIndex);
GridPane.setColumnIndex(hyperlinkWithIcon, 0); GridPane.setColumnIndex(hyperlinkWithIcon, 0);
GridPane.setMargin(hyperlinkWithIcon, new Insets(top, 0, 0, -4)); GridPane.setMargin(hyperlinkWithIcon, new Insets(top, 0, 0, -4));
@ -191,7 +190,7 @@ public class FormBuilder {
Label label = addLabel(gridPane, rowIndex, labelTitle, top); Label label = addLabel(gridPane, rowIndex, labelTitle, top);
HyperlinkWithIcon hyperlinkWithIcon = new HyperlinkWithIcon(title, AwesomeIcon.EXTERNAL_LINK); HyperlinkWithIcon hyperlinkWithIcon = new HyperlinkWithIcon(title, AwesomeIcon.EXTERNAL_LINK);
hyperlinkWithIcon.setOnAction(e -> Utilities.openWebPage(url)); hyperlinkWithIcon.setOnAction(e -> GUIUtil.openWebPage(url));
GridPane.setRowIndex(hyperlinkWithIcon, rowIndex); GridPane.setRowIndex(hyperlinkWithIcon, rowIndex);
GridPane.setColumnIndex(hyperlinkWithIcon, 1); GridPane.setColumnIndex(hyperlinkWithIcon, 1);
GridPane.setMargin(hyperlinkWithIcon, new Insets(top, 0, 0, -4)); GridPane.setMargin(hyperlinkWithIcon, new Insets(top, 0, 0, -4));

View file

@ -23,7 +23,11 @@ import com.googlecode.jcsv.writer.CSVEntryConverter;
import com.googlecode.jcsv.writer.CSVWriter; import com.googlecode.jcsv.writer.CSVWriter;
import com.googlecode.jcsv.writer.internal.CSVWriterBuilder; import com.googlecode.jcsv.writer.internal.CSVWriterBuilder;
import io.bitsquare.app.DevFlags; import io.bitsquare.app.DevFlags;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.locale.CryptoCurrency;
import io.bitsquare.locale.FiatCurrency;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.payment.PaymentAccount; import io.bitsquare.payment.PaymentAccount;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
import io.bitsquare.user.Preferences; import io.bitsquare.user.Preferences;
@ -34,6 +38,7 @@ import javafx.scene.control.ScrollBar;
import javafx.stage.DirectoryChooser; import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.util.StringConverter;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -41,6 +46,9 @@ import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -48,6 +56,9 @@ import java.util.List;
public class GUIUtil { public class GUIUtil {
private static final Logger log = LoggerFactory.getLogger(GUIUtil.class); private static final Logger log = LoggerFactory.getLogger(GUIUtil.class);
public final static String SHOW_ALL_FLAG = "SHOW_ALL_FLAG";
public final static String EDIT_FLAG = "EDIT_FLAG";
public static double getScrollbarWidth(Node scrollablePane) { public static double getScrollbarWidth(Node scrollablePane) {
Node node = scrollablePane.lookup(".scroll-bar"); Node node = scrollablePane.lookup(".scroll-bar");
if (node instanceof ScrollBar) { if (node instanceof ScrollBar) {
@ -81,7 +92,7 @@ public class GUIUtil {
String directory = getDirectoryFormChooser(preferences, stage); String directory = getDirectoryFormChooser(preferences, stage);
Storage<ArrayList<PaymentAccount>> paymentAccountsStorage = new Storage<>(new File(directory)); Storage<ArrayList<PaymentAccount>> paymentAccountsStorage = new Storage<>(new File(directory));
paymentAccountsStorage.initAndGetPersisted(accounts, fileName); paymentAccountsStorage.initAndGetPersisted(accounts, fileName);
paymentAccountsStorage.queueUpForSave(20); paymentAccountsStorage.queueUpForSave();
new Popup<>().feedback("Payment accounts saved to path:\n" + Paths.get(directory, fileName).toAbsolutePath()).show(); new Popup<>().feedback("Payment accounts saved to path:\n" + Paths.get(directory, fileName).toAbsolutePath()).show();
} else { } else {
new Popup<>().warning("You don't have payment accounts set up for exporting.").show(); new Popup<>().warning("You don't have payment accounts set up for exporting.").show();
@ -163,4 +174,73 @@ public class GUIUtil {
return ""; return "";
} }
} }
public static StringConverter<TradeCurrency> getCurrencyListConverter() {
return new StringConverter<TradeCurrency>() {
@Override
public String toString(TradeCurrency tradeCurrency) {
String code = tradeCurrency.getCode();
// http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618
if (code.equals(GUIUtil.SHOW_ALL_FLAG))
return "▶ Show all";
else if (code.equals(GUIUtil.EDIT_FLAG))
return "▼ Edit currency list";
else if (tradeCurrency instanceof FiatCurrency)
return "" + tradeCurrency.getNameAndCode();
else if (tradeCurrency instanceof CryptoCurrency)
return "" + tradeCurrency.getNameAndCode();
else
return "-";
}
@Override
public TradeCurrency fromString(String s) {
return null;
}
};
}
public static void openWebPage(String target) {
String key = "warnOpenURLWhenTorEnabled";
final Preferences preferences = Preferences.INSTANCE;
if (preferences.getUseTorForHttpRequests() && preferences.showAgain(key)) {
new Popup<>().information("You have Tor enabled for Http requests and are going to open a web page " +
"in your system web browser.\n" +
"Do you want to open the web page now?\n\n" +
"If you are not using the \"Tor Browser\" as your default system web browser you " +
"will connect to the web page in clear net.\n\n" +
"URL: \"" + target)
.actionButtonText("Open the web page and don't ask again")
.onAction(() -> {
preferences.dontShowAgain(key, true);
doOpenWebPage(target);
})
.closeButtonText("Copy URL and cancel")
.onClose(() -> Utilities.copyToClipboard(target))
.show();
} else {
doOpenWebPage(target);
}
}
private static void doOpenWebPage(String target) {
try {
Utilities.openURI(new URI(target));
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage());
}
}
public static void openMail(String to, String subject, String body) {
try {
subject = URLEncoder.encode(subject, "UTF-8").replace("+", "%20");
body = URLEncoder.encode(body, "UTF-8").replace("+", "%20");
Utilities.openURI(new URI("mailto:" + to + "?subject=" + subject + "&body=" + body));
} catch (IOException | URISyntaxException e) {
log.error("openMail failed " + e.getMessage());
e.printStackTrace();
}
}
} }

View file

@ -57,7 +57,7 @@ public class ImageUtil {
public static boolean isRetina() { public static boolean isRetina() {
float maxRenderScale = ((QuantumToolkit) QuantumToolkit.getToolkit()).getMaxRenderScale(); float maxRenderScale = ((QuantumToolkit) QuantumToolkit.getToolkit()).getMaxRenderScale();
boolean isRetina = maxRenderScale > 1.9f; boolean isRetina = maxRenderScale > 1.9f;
//log.info("isRetina=" + isRetina + " / maxRenderScale=" + maxRenderScale); //log.debug("isRetina=" + isRetina + " / maxRenderScale=" + maxRenderScale);
return isRetina; return isRetina;
} }
} }

View file

@ -10,21 +10,21 @@
<appender-ref ref="CONSOLE_APPENDER"/> <appender-ref ref="CONSOLE_APPENDER"/>
</root> </root>
<logger name="io.bitsquare.storage.Storage" level="WARN"/> <!-- <logger name="io.bitsquare.storage.Storage" level="WARN"/>
<logger name="io.bitsquare.storage.FileManager" level="WARN"/> <logger name="io.bitsquare.storage.FileManager" level="WARN"/>
<logger name="io.bitsquare.locale.BSResources" level="ERROR"/> <logger name="io.bitsquare.locale.BSResources" level="ERROR"/>
<!--<logger name="io.bitsquare.p2p" level="WARN"/>--> &lt;!&ndash;<logger name="io.bitsquare.p2p" level="WARN"/>&ndash;&gt;
<logger name="io.bitsquare.btc.pricefeed" level="WARN"/> <logger name="io.bitsquare.btc.pricefeed" level="WARN"/>
<logger name="io.bitsquare.storage.Storage" level="WARN"/> <logger name="io.bitsquare.storage.Storage" level="WARN"/>
<logger name="io.bitsquare.storage.FileManager" level="WARN"/> <logger name="io.bitsquare.storage.FileManager" level="WARN"/>
<logger name="io.bitsquare.p2p.peers" level="WARN"/> <logger name="io.bitsquare.p2p.peers" level="WARN"/>
<logger name="io.bitsquare.p2p.peers.getdata" level="WARN"/> <logger name="io.bitsquare.p2p.peers.getdata" level="WARN"/>
<logger name="io.bitsquare.p2p.peers.keepalive" level="WARN"/> <logger name="io.bitsquare.p2p.peers.keepalive" level="WARN"/>
<logger name="io.bitsquare.p2p.peers.peerexchange" level="WARN"/> <logger name="io.bitsquare.p2p.peers.peerexchange" level="WARN"/>-->
<!--<logger name="io.bitsquare.p2p.network" level="WARN"/>--> <!--<logger name="io.bitsquare.p2p.network" level="WARN"/>-->
<!-- <logger name="io.bitsquare.p2p.P2PService" level="WARN"/>--> <!-- <logger name="io.bitsquare.p2p.P2PService" level="WARN"/>-->

View file

@ -1,6 +1,6 @@
package io.bitsquare.gui.main.markets.trades; package io.bitsquare.gui.main.market.trades;
import io.bitsquare.gui.main.markets.trades.charts.CandleData; import io.bitsquare.gui.main.market.trades.charts.CandleData;
import io.bitsquare.trade.offer.Offer; import io.bitsquare.trade.offer.Offer;
import io.bitsquare.trade.statistics.TradeStatistics; import io.bitsquare.trade.statistics.TradeStatistics;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;

View file

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.9.1</version> <version>0.4.9.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View file

@ -127,7 +127,7 @@ public class Headless {
public void shutDown() { public void shutDown() {
gracefulShutDown(() -> { gracefulShutDown(() -> {
log.info("Shutdown complete"); log.debug("Shutdown complete");
System.exit(0); System.exit(0);
}); });
} }
@ -141,7 +141,7 @@ public class Headless {
injector.getInstance(P2PService.class).shutDown(() -> { injector.getInstance(P2PService.class).shutDown(() -> {
injector.getInstance(WalletService.class).shutDownDone.addListener((ov, o, n) -> { injector.getInstance(WalletService.class).shutDownDone.addListener((ov, o, n) -> {
headlessModule.close(injector); headlessModule.close(injector);
log.info("Graceful shutdown completed"); log.debug("Graceful shutdown completed");
resultHandler.handleResult(); resultHandler.handleResult();
}); });
injector.getInstance(WalletService.class).shutDown(); injector.getInstance(WalletService.class).shutDown();
@ -153,7 +153,7 @@ public class Headless {
UserThread.runAfter(resultHandler::handleResult, 1); UserThread.runAfter(resultHandler::handleResult, 1);
} }
} catch (Throwable t) { } catch (Throwable t) {
log.info("App shutdown failed with exception"); log.debug("App shutdown failed with exception");
t.printStackTrace(); t.printStackTrace();
System.exit(1); System.exit(1);
} }

View file

@ -22,7 +22,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.9.1</version> <version>0.4.9.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View file

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.9.1</version> <version>0.4.9.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View file

@ -257,7 +257,7 @@ public class SOCKS {
// ///////////////// // /////////////////
static void inform(String s) { static void inform(String s) {
log.info(s); log.debug(s);
} }
static void exit(String msg) { static void exit(String msg) {

View file

@ -158,13 +158,13 @@ public class ProxyServer implements Runnable {
ss = new ServerSocket(port, backlog, localIP); ss = new ServerSocket(port, backlog, localIP);
final String address = ss.getInetAddress().getHostAddress(); final String address = ss.getInetAddress().getHostAddress();
final int localPort = ss.getLocalPort(); final int localPort = ss.getLocalPort();
log.info("Starting SOCKS Proxy on: {}:{}", address, localPort); log.debug("Starting SOCKS Proxy on: {}:{}", address, localPort);
while (true) { while (true) {
final Socket s = ss.accept(); final Socket s = ss.accept();
final String hostName = s.getInetAddress().getHostName(); final String hostName = s.getInetAddress().getHostName();
final int port2 = s.getPort(); final int port2 = s.getPort();
log.info("Accepted from:{}:{}", hostName, port2); log.debug("Accepted from:{}:{}", hostName, port2);
final ProxyServer ps = new ProxyServer(auth, s); final ProxyServer ps = new ProxyServer(auth, s);
(new Thread(ps)).start(); (new Thread(ps)).start();
@ -203,7 +203,7 @@ public class ProxyServer implements Runnable {
if (auth != null) { if (auth != null) {
auth.endSession(); auth.endSession();
} }
log.info("Main thread(client->remote)stopped."); log.debug("Main thread(client->remote)stopped.");
} }
break; break;
case ACCEPT_MODE: case ACCEPT_MODE:
@ -219,7 +219,7 @@ public class ProxyServer implements Runnable {
handleException(ioe); handleException(ioe);
} finally { } finally {
abort(); abort();
log.info("Accept thread(remote->client) stopped"); log.debug("Accept thread(remote->client) stopped");
} }
break; break;
case PIPE_MODE: case PIPE_MODE:
@ -228,7 +228,7 @@ public class ProxyServer implements Runnable {
} catch (final IOException ioe) { } catch (final IOException ioe) {
} finally { } finally {
abort(); abort();
log.info("Support thread(remote->client) stopped"); log.debug("Support thread(remote->client) stopped");
} }
break; break;
case ABORT_MODE: case ABORT_MODE:
@ -252,7 +252,7 @@ public class ProxyServer implements Runnable {
} }
if (auth == null) { // Authentication failed if (auth == null) { // Authentication failed
log.info("Authentication failed"); log.debug("Authentication failed");
return; return;
} }
@ -336,7 +336,7 @@ public class ProxyServer implements Runnable {
s = new SocksSocket(proxy, msg.ip, msg.port); s = new SocksSocket(proxy, msg.ip, msg.port);
} }
log.info("Connected to " + s.getInetAddress() + ":" + s.getPort()); log.debug("Connected to " + s.getInetAddress() + ":" + s.getPort());
ProxyMessage response = null; ProxyMessage response = null;
final InetAddress localAddress = s.getLocalAddress(); final InetAddress localAddress = s.getLocalAddress();
@ -367,7 +367,7 @@ public class ProxyServer implements Runnable {
final InetAddress inetAddress = ss.getInetAddress(); final InetAddress inetAddress = ss.getInetAddress();
final int localPort = ss.getLocalPort(); final int localPort = ss.getLocalPort();
log.info("Trying accept on {}:{}", inetAddress, localPort); log.debug("Trying accept on {}:{}", inetAddress, localPort);
if (msg.version == 5) { if (msg.version == 5) {
final int cmd = SocksProxyBase.SOCKS_SUCCESS; final int cmd = SocksProxyBase.SOCKS_SUCCESS;
@ -425,7 +425,7 @@ public class ProxyServer implements Runnable {
if (msg.ip.getHostAddress().equals("0.0.0.0")) { if (msg.ip.getHostAddress().equals("0.0.0.0")) {
msg.ip = sock.getInetAddress(); msg.ip = sock.getInetAddress();
} }
log.info("Creating UDP relay server for {}:{}", msg.ip, msg.port); log.debug("Creating UDP relay server for {}:{}", msg.ip, msg.port);
relayServer = new UDPRelayServer(msg.ip, msg.port, relayServer = new UDPRelayServer(msg.ip, msg.port,
Thread.currentThread(), sock, auth); Thread.currentThread(), sock, auth);
@ -494,7 +494,7 @@ public class ProxyServer implements Runnable {
final InetAddress inetAddress = s.getInetAddress(); final InetAddress inetAddress = s.getInetAddress();
final int port = s.getPort(); final int port = s.getPort();
log.info("Accepted from {}:{}", s.getInetAddress(), port); log.debug("Accepted from {}:{}", s.getInetAddress(), port);
ProxyMessage response; ProxyMessage response;
@ -564,7 +564,7 @@ public class ProxyServer implements Runnable {
} }
mode = ABORT_MODE; mode = ABORT_MODE;
try { try {
log.info("Aborting operation"); log.debug("Aborting operation");
if (remote_sock != null) { if (remote_sock != null) {
remote_sock.close(); remote_sock.close();
} }

View file

@ -115,8 +115,8 @@ class UDPRelayServer implements Runnable {
remote_sock.setSoTimeout(iddleTimeout); remote_sock.setSoTimeout(iddleTimeout);
client_sock.setSoTimeout(iddleTimeout); client_sock.setSoTimeout(iddleTimeout);
log.info("Starting UDP relay server on {}:{}", relayIP, relayPort); log.debug("Starting UDP relay server on {}:{}", relayIP, relayPort);
log.info("Remote socket {}:{}", remote_sock.getLocalAddress(), log.debug("Remote socket {}:{}", remote_sock.getLocalAddress(),
remote_sock.getLocalPort()); remote_sock.getLocalPort());
pipe_thread1 = new Thread(this, "pipe1"); pipe_thread1 = new Thread(this, "pipe1");
@ -151,7 +151,7 @@ class UDPRelayServer implements Runnable {
} catch (final IOException ioe) { } catch (final IOException ioe) {
} finally { } finally {
abort(); abort();
log.info("UDP Pipe thread " + Thread.currentThread().getName() log.debug("UDP Pipe thread " + Thread.currentThread().getName()
+ " stopped."); + " stopped.");
} }
@ -164,7 +164,7 @@ class UDPRelayServer implements Runnable {
return; return;
} }
log.info("Aborting UDP Relay Server"); log.debug("Aborting UDP Relay Server");
remote_sock.close(); remote_sock.close();
client_sock.close(); client_sock.close();
@ -201,7 +201,7 @@ class UDPRelayServer implements Runnable {
} }
} catch (final UnknownHostException uhe) { } catch (final UnknownHostException uhe) {
log.info("Dropping datagram for unknown host"); log.debug("Dropping datagram for unknown host");
} catch (final InterruptedIOException iioe) { } catch (final InterruptedIOException iioe) {
// log("Interrupted: "+iioe); // log("Interrupted: "+iioe);
// If we were interrupted by other thread. // If we were interrupted by other thread.

View file

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.9.1</version> <version>0.4.9.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View file

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId> <groupId>io.bitsquare</groupId>
<version>0.4.9.1</version> <version>0.4.9.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

Some files were not shown because too many files have changed in this diff Show more