mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Merge pull request #4933 from chimp1984/add-num-items-to-tables
Improve funds and portfolio screens
This commit is contained in:
commit
7d12b94c6a
@ -377,11 +377,15 @@ public class OfferUtil {
|
||||
tradeStatisticsManager,
|
||||
30);
|
||||
Price bsqPrice = tuple.second;
|
||||
if (bsqPrice.isPositive()) {
|
||||
String inputValue = bsqFormatter.formatCoin(makerFee);
|
||||
Volume makerFeeAsVolume = Volume.parse(inputValue, "BSQ");
|
||||
Coin requiredBtc = bsqPrice.getAmountByVolume(makerFeeAsVolume);
|
||||
Volume volumeByAmount = userCurrencyPrice.getVolumeByAmount(requiredBtc);
|
||||
return Optional.of(volumeByAmount);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Optional.empty();
|
||||
|
@ -335,6 +335,10 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
|
||||
return id.compareTo(other.id);
|
||||
}
|
||||
|
||||
public String getDisplayString() {
|
||||
return Res.get(id);
|
||||
}
|
||||
|
||||
public boolean isAsset() {
|
||||
return this.equals(BLOCK_CHAINS_INSTANT) || this.equals(BLOCK_CHAINS);
|
||||
}
|
||||
|
@ -40,8 +40,6 @@ public class TradePresentation {
|
||||
long numPendingTrades = (long) newValue;
|
||||
if (numPendingTrades > 0)
|
||||
this.numPendingTrades.set(String.valueOf(numPendingTrades));
|
||||
if (numPendingTrades > 9)
|
||||
this.numPendingTrades.set("★");
|
||||
|
||||
showPendingTradesNotification.set(numPendingTrades > 0);
|
||||
});
|
||||
|
@ -219,6 +219,9 @@ shared.refundAgentForSupportStaff=Refund agent
|
||||
shared.delayedPayoutTxId=Delayed payout transaction ID
|
||||
shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
|
||||
shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later.
|
||||
shared.numItemsLabel=Number of entries: {0}
|
||||
shared.filter=Filter
|
||||
shared.enabled=Enabled
|
||||
|
||||
|
||||
####################################################################
|
||||
@ -1053,7 +1056,6 @@ funds.tx.dustAttackTx.popup=This transaction is sending a very small BTC amount
|
||||
To protect your privacy the Bisq wallet ignores such dust outputs for spending purposes and in the balance display. \
|
||||
You can set the threshold amount when an output is considered dust in the settings.
|
||||
|
||||
|
||||
####################################################################
|
||||
# Support
|
||||
####################################################################
|
||||
|
@ -353,10 +353,16 @@ public class PeerInfoIcon extends Group {
|
||||
if (!tag.isEmpty())
|
||||
tagLabel.setText(tag.substring(0, 1));
|
||||
|
||||
if (numTrades < 10)
|
||||
if (numTrades > 0) {
|
||||
numTradesLabel.setText(String.valueOf(numTrades));
|
||||
else
|
||||
numTradesLabel.setText("★");
|
||||
|
||||
double scaleFactor = getScaleFactor();
|
||||
if (numTrades > 9) {
|
||||
numTradesLabel.relocate(scaleFactor * 2, scaleFactor * 1);
|
||||
} else {
|
||||
numTradesLabel.relocate(scaleFactor * 5, scaleFactor * 1);
|
||||
}
|
||||
}
|
||||
|
||||
numTradesPane.setVisible(numTrades > 0);
|
||||
|
||||
|
@ -18,12 +18,13 @@
|
||||
package bisq.desktop.main.funds.locked;
|
||||
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
|
||||
import bisq.core.btc.listeners.BalanceListener;
|
||||
import bisq.core.btc.model.AddressEntry;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.btc.wallet.WalletService;
|
||||
import bisq.core.trade.Tradable;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
@ -33,21 +34,34 @@ import org.bitcoinj.core.Transaction;
|
||||
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
class LockedListItem {
|
||||
private final BalanceListener balanceListener;
|
||||
private final Label balanceLabel;
|
||||
private final Trade trade;
|
||||
private final AddressEntry addressEntry;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final CoinFormatter formatter;
|
||||
|
||||
@Getter
|
||||
private final Label balanceLabel;
|
||||
@Getter
|
||||
private final Trade trade;
|
||||
@Getter
|
||||
private final AddressEntry addressEntry;
|
||||
@Getter
|
||||
private final String addressString;
|
||||
@Nullable
|
||||
private final Address address;
|
||||
@Getter
|
||||
private Coin balance;
|
||||
@Getter
|
||||
private String balanceString;
|
||||
|
||||
public LockedListItem(Trade trade, AddressEntry addressEntry, BtcWalletService btcWalletService, CoinFormatter formatter) {
|
||||
public LockedListItem(Trade trade,
|
||||
AddressEntry addressEntry,
|
||||
BtcWalletService btcWalletService,
|
||||
CoinFormatter formatter) {
|
||||
this.trade = trade;
|
||||
this.addressEntry = addressEntry;
|
||||
this.btcWalletService = btcWalletService;
|
||||
@ -55,15 +69,13 @@ class LockedListItem {
|
||||
|
||||
if (trade.getDepositTx() != null && !trade.getDepositTx().getOutputs().isEmpty()) {
|
||||
address = WalletService.getAddressFromOutput(trade.getDepositTx().getOutput(0));
|
||||
addressString = address.toString();
|
||||
addressString = address != null ? address.toString() : "";
|
||||
} else {
|
||||
address = null;
|
||||
addressString = "";
|
||||
}
|
||||
|
||||
// balance
|
||||
balanceLabel = new AutoTooltipLabel();
|
||||
balanceListener = new BalanceListener(getAddress()) {
|
||||
balanceListener = new BalanceListener(address) {
|
||||
@Override
|
||||
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||
updateBalance();
|
||||
@ -73,38 +85,36 @@ class LockedListItem {
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
LockedListItem() {
|
||||
this.trade = null;
|
||||
this.addressEntry = null;
|
||||
this.btcWalletService = null;
|
||||
this.formatter = null;
|
||||
addressString = null;
|
||||
address = null;
|
||||
balanceLabel = null;
|
||||
balanceListener = null;
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
btcWalletService.removeBalanceListener(balanceListener);
|
||||
}
|
||||
|
||||
private void updateBalance() {
|
||||
balance = addressEntry.getCoinLockedInMultiSigAsCoin();
|
||||
balanceLabel.setText(formatter.formatCoin(this.balance));
|
||||
balanceString = formatter.formatCoin(this.balance);
|
||||
balanceLabel.setText(balanceString);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Address getAddress() {
|
||||
return address;
|
||||
public String getDetails() {
|
||||
return trade != null ?
|
||||
Res.get("funds.locked.locked", trade.getShortId()) :
|
||||
Res.get("shared.noDetailsAvailable");
|
||||
}
|
||||
|
||||
public AddressEntry getAddressEntry() {
|
||||
return addressEntry;
|
||||
public String getDateString() {
|
||||
return trade != null ?
|
||||
DisplayUtils.formatDateTime(trade.getDate()) :
|
||||
Res.get("shared.noDateAvailable");
|
||||
}
|
||||
|
||||
public Label getBalanceLabel() {
|
||||
return balanceLabel;
|
||||
}
|
||||
|
||||
public Coin getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
public String getAddressString() {
|
||||
return addressString;
|
||||
}
|
||||
|
||||
public Tradable getTrade() {
|
||||
return trade;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,8 +17,12 @@
|
||||
~ along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<?import bisq.desktop.components.AutoTooltipButton?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.funds.locked.LockedView"
|
||||
@ -35,5 +39,9 @@
|
||||
<TableColumn fx:id="balanceColumn" minWidth="110"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
|
||||
<HBox spacing="10">
|
||||
<Label fx:id="numItems"/>
|
||||
<Region fx:id="spacer"/>
|
||||
<AutoTooltipButton fx:id="exportButton"/>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
@ -19,12 +19,12 @@ package bisq.desktop.main.funds.locked;
|
||||
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.AutoTooltipButton;
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.ExternalHyperlink;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
|
||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.btc.listeners.BalanceListener;
|
||||
@ -43,6 +43,8 @@ import bisq.core.util.coin.CoinFormatter;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import com.googlecode.jcsv.writer.CSVEntryConverter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
@ -50,12 +52,20 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
@ -77,6 +87,12 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
||||
TableView<LockedListItem> tableView;
|
||||
@FXML
|
||||
TableColumn<LockedListItem, LockedListItem> dateColumn, detailsColumn, addressColumn, balanceColumn;
|
||||
@FXML
|
||||
Label numItems;
|
||||
@FXML
|
||||
Region spacer;
|
||||
@FXML
|
||||
AutoTooltipButton exportButton;
|
||||
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final TradeManager tradeManager;
|
||||
@ -97,8 +113,13 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private LockedView(BtcWalletService btcWalletService, TradeManager tradeManager, OpenOfferManager openOfferManager, Preferences preferences,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, OfferDetailsWindow offerDetailsWindow, TradeDetailsWindow tradeDetailsWindow) {
|
||||
private LockedView(BtcWalletService btcWalletService,
|
||||
TradeManager tradeManager,
|
||||
OpenOfferManager openOfferManager,
|
||||
Preferences preferences,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
|
||||
OfferDetailsWindow offerDetailsWindow,
|
||||
TradeDetailsWindow tradeDetailsWindow) {
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.tradeManager = tradeManager;
|
||||
this.openOfferManager = openOfferManager;
|
||||
@ -138,6 +159,10 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
||||
};
|
||||
openOfferListChangeListener = c -> updateList();
|
||||
tradeListChangeListener = c -> updateList();
|
||||
|
||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||
numItems.setPadding(new Insets(-5, 0, 0, 10));
|
||||
exportButton.updateText(Res.get("shared.exportCSV"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -149,6 +174,33 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
||||
updateList();
|
||||
|
||||
btcWalletService.addBalanceListener(balanceListener);
|
||||
|
||||
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
||||
exportButton.setOnAction(event -> {
|
||||
ObservableList<TableColumn<LockedListItem, ?>> tableColumns = tableView.getColumns();
|
||||
int reportColumns = tableColumns.size();
|
||||
CSVEntryConverter<LockedListItem> headerConverter = transactionsListItem -> {
|
||||
String[] columns = new String[reportColumns];
|
||||
for (int i = 0; i < columns.length; i++)
|
||||
columns[i] = ((AutoTooltipLabel) tableColumns.get(i).getGraphic()).getText();
|
||||
return columns;
|
||||
};
|
||||
CSVEntryConverter<LockedListItem> contentConverter = item -> {
|
||||
String[] columns = new String[reportColumns];
|
||||
columns[0] = item.getDateString();
|
||||
columns[1] = item.getDetails();
|
||||
columns[2] = item.getAddressString();
|
||||
columns[3] = item.getBalanceString();
|
||||
return columns;
|
||||
};
|
||||
|
||||
GUIUtil.exportCSV("lockedInTradesFunds.csv",
|
||||
headerConverter,
|
||||
contentConverter,
|
||||
new LockedListItem(),
|
||||
sortedList,
|
||||
(Stage) root.getScene().getWindow());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -158,6 +210,7 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
||||
sortedList.comparatorProperty().unbind();
|
||||
observableList.forEach(LockedListItem::cleanup);
|
||||
btcWalletService.removeBalanceListener(balanceListener);
|
||||
exportButton.setOnAction(null);
|
||||
}
|
||||
|
||||
|
||||
@ -169,7 +222,8 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
||||
observableList.forEach(LockedListItem::cleanup);
|
||||
observableList.setAll(tradeManager.getTradesStreamWithFundsLockedIn()
|
||||
.map(trade -> {
|
||||
final Optional<AddressEntry> addressEntryOptional = btcWalletService.getAddressEntry(trade.getId(), AddressEntry.Context.MULTI_SIG);
|
||||
Optional<AddressEntry> addressEntryOptional = btcWalletService.getAddressEntry(trade.getId(),
|
||||
AddressEntry.Context.MULTI_SIG);
|
||||
return addressEntryOptional.map(addressEntry -> new LockedListItem(trade,
|
||||
addressEntry,
|
||||
btcWalletService,
|
||||
@ -227,9 +281,9 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty) {
|
||||
if (getTradable(item).isPresent())
|
||||
setGraphic(new AutoTooltipLabel(DisplayUtils.formatDateTime(getTradable(item).get().getDate())));
|
||||
setGraphic(new AutoTooltipLabel(item.getDateString()));
|
||||
else
|
||||
setGraphic(new AutoTooltipLabel(Res.get("shared.noDateAvailable")));
|
||||
setGraphic(new AutoTooltipLabel(item.getDateString()));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
@ -257,13 +311,13 @@ public class LockedView extends ActivatableView<VBox, Void> {
|
||||
if (item != null && !empty) {
|
||||
Optional<Tradable> tradableOptional = getTradable(item);
|
||||
if (tradableOptional.isPresent()) {
|
||||
field = new HyperlinkWithIcon(Res.get("funds.locked.locked", item.getTrade().getShortId()),
|
||||
field = new HyperlinkWithIcon(item.getDetails(),
|
||||
AwesomeIcon.INFO_SIGN);
|
||||
field.setOnAction(event -> openDetailPopup(item));
|
||||
field.setTooltip(new Tooltip(Res.get("tooltip.openPopupForDetails")));
|
||||
setGraphic(field);
|
||||
} else {
|
||||
setGraphic(new AutoTooltipLabel(Res.get("shared.noDetailsAvailable")));
|
||||
setGraphic(new AutoTooltipLabel(item.getDetails()));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -18,12 +18,13 @@
|
||||
package bisq.desktop.main.funds.reserved;
|
||||
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
|
||||
import bisq.core.btc.listeners.BalanceListener;
|
||||
import bisq.core.btc.model.AddressEntry;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.trade.Tradable;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import org.bitcoinj.core.Address;
|
||||
@ -34,26 +35,40 @@ import javafx.scene.control.Label;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
class ReservedListItem {
|
||||
private final BalanceListener balanceListener;
|
||||
private final Label balanceLabel;
|
||||
private final OpenOffer openOffer;
|
||||
private final AddressEntry addressEntry;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final CoinFormatter formatter;
|
||||
private final String addressString;
|
||||
private Coin balance;
|
||||
|
||||
public ReservedListItem(OpenOffer openOffer, AddressEntry addressEntry, BtcWalletService btcWalletService, CoinFormatter formatter) {
|
||||
@Getter
|
||||
private final Label balanceLabel;
|
||||
@Getter
|
||||
private final OpenOffer openOffer;
|
||||
@Getter
|
||||
private final AddressEntry addressEntry;
|
||||
@Getter
|
||||
private final String addressString;
|
||||
@Getter
|
||||
private final Address address;
|
||||
@Getter
|
||||
private Coin balance;
|
||||
@Getter
|
||||
private String balanceString;
|
||||
|
||||
public ReservedListItem(OpenOffer openOffer,
|
||||
AddressEntry addressEntry,
|
||||
BtcWalletService btcWalletService,
|
||||
CoinFormatter formatter) {
|
||||
this.openOffer = openOffer;
|
||||
this.addressEntry = addressEntry;
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.formatter = formatter;
|
||||
addressString = addressEntry.getAddressString();
|
||||
|
||||
// balance
|
||||
address = addressEntry.getAddress();
|
||||
balanceLabel = new AutoTooltipLabel();
|
||||
balanceListener = new BalanceListener(getAddress()) {
|
||||
balanceListener = new BalanceListener(address) {
|
||||
@Override
|
||||
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||
updateBalance();
|
||||
@ -63,41 +78,40 @@ class ReservedListItem {
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
ReservedListItem() {
|
||||
this.openOffer = null;
|
||||
this.addressEntry = null;
|
||||
this.btcWalletService = null;
|
||||
this.formatter = null;
|
||||
addressString = null;
|
||||
address = null;
|
||||
balanceLabel = null;
|
||||
balanceListener = null;
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
btcWalletService.removeBalanceListener(balanceListener);
|
||||
}
|
||||
|
||||
private void updateBalance() {
|
||||
final Optional<AddressEntry> addressEntryOptional = btcWalletService.getAddressEntry(openOffer.getId(), AddressEntry.Context.RESERVED_FOR_TRADE);
|
||||
Optional<AddressEntry> addressEntryOptional = btcWalletService.getAddressEntry(openOffer.getId(),
|
||||
AddressEntry.Context.RESERVED_FOR_TRADE);
|
||||
addressEntryOptional.ifPresent(addressEntry -> {
|
||||
balance = btcWalletService.getBalanceForAddress(addressEntry.getAddress());
|
||||
if (balance != null)
|
||||
balanceLabel.setText(formatter.formatCoin(balance));
|
||||
if (balance != null) {
|
||||
balanceString = formatter.formatCoin(balance);
|
||||
balanceLabel.setText(balanceString);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Address getAddress() {
|
||||
return addressEntry.getAddress();
|
||||
public String getDateAsString() {
|
||||
return DisplayUtils.formatDateTime(openOffer.getDate());
|
||||
}
|
||||
|
||||
public AddressEntry getAddressEntry() {
|
||||
return addressEntry;
|
||||
public String getDetails() {
|
||||
return openOffer != null ?
|
||||
Res.get("funds.reserved.reserved", openOffer.getShortId()) :
|
||||
Res.get("shared.noDetailsAvailable");
|
||||
}
|
||||
|
||||
public Label getBalanceLabel() {
|
||||
return balanceLabel;
|
||||
}
|
||||
|
||||
public Coin getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
public String getAddressString() {
|
||||
return addressString;
|
||||
}
|
||||
|
||||
public Tradable getOpenOffer() {
|
||||
return openOffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,8 +17,12 @@
|
||||
~ along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<?import bisq.desktop.components.AutoTooltipButton?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.funds.reserved.ReservedView"
|
||||
@ -35,5 +39,9 @@
|
||||
<TableColumn fx:id="balanceColumn" minWidth="110"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
|
||||
<HBox spacing="10">
|
||||
<Label fx:id="numItems"/>
|
||||
<Region fx:id="spacer"/>
|
||||
<AutoTooltipButton fx:id="exportButton"/>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
@ -19,12 +19,12 @@ package bisq.desktop.main.funds.reserved;
|
||||
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.AutoTooltipButton;
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.ExternalHyperlink;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
|
||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.btc.listeners.BalanceListener;
|
||||
@ -43,6 +43,8 @@ import bisq.core.util.coin.CoinFormatter;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import com.googlecode.jcsv.writer.CSVEntryConverter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
@ -50,12 +52,20 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
@ -77,6 +87,12 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||
TableView<ReservedListItem> tableView;
|
||||
@FXML
|
||||
TableColumn<ReservedListItem, ReservedListItem> dateColumn, detailsColumn, addressColumn, balanceColumn;
|
||||
@FXML
|
||||
Label numItems;
|
||||
@FXML
|
||||
Region spacer;
|
||||
@FXML
|
||||
AutoTooltipButton exportButton;
|
||||
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final TradeManager tradeManager;
|
||||
@ -97,8 +113,13 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private ReservedView(BtcWalletService btcWalletService, TradeManager tradeManager, OpenOfferManager openOfferManager, Preferences preferences,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, OfferDetailsWindow offerDetailsWindow, TradeDetailsWindow tradeDetailsWindow) {
|
||||
private ReservedView(BtcWalletService btcWalletService,
|
||||
TradeManager tradeManager,
|
||||
OpenOfferManager openOfferManager,
|
||||
Preferences preferences,
|
||||
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
|
||||
OfferDetailsWindow offerDetailsWindow,
|
||||
TradeDetailsWindow tradeDetailsWindow) {
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.tradeManager = tradeManager;
|
||||
this.openOfferManager = openOfferManager;
|
||||
@ -138,6 +159,10 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||
};
|
||||
openOfferListChangeListener = c -> updateList();
|
||||
tradeListChangeListener = c -> updateList();
|
||||
|
||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||
numItems.setPadding(new Insets(-5, 0, 0, 10));
|
||||
exportButton.updateText(Res.get("shared.exportCSV"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -149,6 +174,33 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||
updateList();
|
||||
|
||||
btcWalletService.addBalanceListener(balanceListener);
|
||||
|
||||
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
||||
exportButton.setOnAction(event -> {
|
||||
ObservableList<TableColumn<ReservedListItem, ?>> tableColumns = tableView.getColumns();
|
||||
int reportColumns = tableColumns.size();
|
||||
CSVEntryConverter<ReservedListItem> headerConverter = transactionsListItem -> {
|
||||
String[] columns = new String[reportColumns];
|
||||
for (int i = 0; i < columns.length; i++)
|
||||
columns[i] = ((AutoTooltipLabel) tableColumns.get(i).getGraphic()).getText();
|
||||
return columns;
|
||||
};
|
||||
CSVEntryConverter<ReservedListItem> contentConverter = item -> {
|
||||
String[] columns = new String[reportColumns];
|
||||
columns[0] = item.getDateAsString();
|
||||
columns[1] = item.getDetails();
|
||||
columns[2] = item.getAddressString();
|
||||
columns[3] = item.getBalanceString();
|
||||
return columns;
|
||||
};
|
||||
|
||||
GUIUtil.exportCSV("reservedInOffersFunds.csv",
|
||||
headerConverter,
|
||||
contentConverter,
|
||||
new ReservedListItem(),
|
||||
sortedList,
|
||||
(Stage) root.getScene().getWindow());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -158,6 +210,7 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||
sortedList.comparatorProperty().unbind();
|
||||
observableList.forEach(ReservedListItem::cleanup);
|
||||
btcWalletService.removeBalanceListener(balanceListener);
|
||||
exportButton.setOnAction(null);
|
||||
}
|
||||
|
||||
|
||||
@ -226,9 +279,9 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||
public void updateItem(final ReservedListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty) {
|
||||
if (getTradable(item).isPresent())
|
||||
setGraphic(new AutoTooltipLabel(DisplayUtils.formatDateTime(getTradable(item).get().getDate())));
|
||||
else
|
||||
if (getTradable(item).isPresent()) {
|
||||
setGraphic(new AutoTooltipLabel(item.getDateAsString()));
|
||||
} else
|
||||
setGraphic(new AutoTooltipLabel(Res.get("shared.noDateAvailable")));
|
||||
} else {
|
||||
setGraphic(null);
|
||||
@ -257,13 +310,12 @@ public class ReservedView extends ActivatableView<VBox, Void> {
|
||||
if (item != null && !empty) {
|
||||
Optional<Tradable> tradableOptional = getTradable(item);
|
||||
if (tradableOptional.isPresent()) {
|
||||
field = new HyperlinkWithIcon(Res.get("funds.reserved.reserved", item.getOpenOffer().getShortId()),
|
||||
AwesomeIcon.INFO_SIGN);
|
||||
field = new HyperlinkWithIcon(item.getDetails(), AwesomeIcon.INFO_SIGN);
|
||||
field.setOnAction(event -> openDetailPopup(item));
|
||||
field.setTooltip(new Tooltip(Res.get("tooltip.openPopupForDetails")));
|
||||
setGraphic(field);
|
||||
} else {
|
||||
setGraphic(new AutoTooltipLabel(Res.get("shared.noDetailsAvailable")));
|
||||
setGraphic(new AutoTooltipLabel(item.getDetails()));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -18,8 +18,11 @@
|
||||
-->
|
||||
|
||||
<?import bisq.desktop.components.AutoTooltipButton?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.funds.transactions.TransactionsView"
|
||||
@ -34,10 +37,14 @@
|
||||
<TableColumn fx:id="addressColumn" minWidth="260"/>
|
||||
<TableColumn fx:id="transactionColumn" minWidth="180"/>
|
||||
<TableColumn fx:id="amountColumn" minWidth="130" maxWidth="130"/>
|
||||
<TableColumn fx:id="memoColumn" minWidth="50" maxWidth="50"/>
|
||||
<TableColumn fx:id="confidenceColumn" minWidth="130" maxWidth="130"/>
|
||||
<TableColumn fx:id="memoColumn" minWidth="40"/>
|
||||
<TableColumn fx:id="confidenceColumn" minWidth="120" maxWidth="130"/>
|
||||
<TableColumn fx:id="revertTxColumn" sortable="false" minWidth="110" maxWidth="110" visible="false"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
<HBox spacing="10">
|
||||
<Label fx:id="numItems"/>
|
||||
<Region fx:id="spacer"/>
|
||||
<AutoTooltipButton fx:id="exportButton"/>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
@ -56,14 +56,20 @@ import javafx.stage.Stage;
|
||||
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
|
||||
import javafx.event.EventHandler;
|
||||
@ -80,11 +86,16 @@ import javax.annotation.Nullable;
|
||||
@FxmlView
|
||||
public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
|
||||
|
||||
@FXML
|
||||
TableView<TransactionsListItem> tableView;
|
||||
@FXML
|
||||
TableColumn<TransactionsListItem, TransactionsListItem> dateColumn, detailsColumn, addressColumn, transactionColumn, amountColumn, memoColumn, confidenceColumn, revertTxColumn;
|
||||
@FXML
|
||||
Label numItems;
|
||||
@FXML
|
||||
Region spacer;
|
||||
@FXML
|
||||
AutoTooltipButton exportButton;
|
||||
|
||||
private final DisplayedTransactions displayedTransactions;
|
||||
@ -180,6 +191,8 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
}
|
||||
};
|
||||
|
||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||
numItems.setPadding(new Insets(-5, 0, 0, 10));
|
||||
exportButton.updateText(Res.get("shared.exportCSV"));
|
||||
}
|
||||
|
||||
@ -195,6 +208,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
if (scene != null)
|
||||
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
|
||||
numItems.setText(Res.get("shared.numItemsLabel", sortedDisplayedTransactions.size()));
|
||||
exportButton.setOnAction(event -> {
|
||||
final ObservableList<TableColumn<TransactionsListItem, ?>> tableColumns = tableView.getColumns();
|
||||
final int reportColumns = tableColumns.size() - 1; // CSV report excludes the last column (an icon)
|
||||
|
@ -20,10 +20,12 @@
|
||||
<?import bisq.desktop.components.AutoTooltipButton?>
|
||||
<?import bisq.desktop.components.AutoTooltipLabel?>
|
||||
<?import bisq.desktop.components.InputTextField?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.portfolio.closedtrades.ClosedTradesView"
|
||||
@ -32,6 +34,12 @@
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
|
||||
<HBox fx:id="searchBox">
|
||||
<AutoTooltipLabel fx:id="filterLabel"/>
|
||||
<InputTextField fx:id="filterTextField" minWidth="500"/>
|
||||
<Pane fx:id="searchBoxSpacer"/>
|
||||
</HBox>
|
||||
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="tradeIdColumn" minWidth="110" maxWidth="120"/>
|
||||
@ -50,10 +58,10 @@
|
||||
<TableColumn fx:id="avatarColumn" minWidth="40" maxWidth="40"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
<HBox fx:id="footerBox">
|
||||
<AutoTooltipLabel fx:id="filterLabel"/>
|
||||
<InputTextField fx:id="filterTextField" minWidth="300"/>
|
||||
<Pane fx:id="spacer"/>
|
||||
|
||||
<HBox spacing="10">
|
||||
<Label fx:id="numItems"/>
|
||||
<Region fx:id="footerSpacer"/>
|
||||
<AutoTooltipButton fx:id="exportButton"/>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
@ -27,7 +27,6 @@ import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.components.PeerInfoIcon;
|
||||
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
|
||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.alert.PrivateNotificationManager;
|
||||
@ -53,6 +52,7 @@ import javafx.fxml.FXML;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
@ -60,6 +60,7 @@ import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
@ -114,15 +115,19 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||
txFeeColumn, tradeFeeColumn, buyerSecurityDepositColumn, sellerSecurityDepositColumn,
|
||||
marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn, avatarColumn;
|
||||
@FXML
|
||||
HBox footerBox;
|
||||
HBox searchBox;
|
||||
@FXML
|
||||
AutoTooltipLabel filterLabel;
|
||||
@FXML
|
||||
InputTextField filterTextField;
|
||||
@FXML
|
||||
Pane spacer;
|
||||
Pane searchBoxSpacer;
|
||||
@FXML
|
||||
AutoTooltipButton exportButton;
|
||||
@FXML
|
||||
Label numItems;
|
||||
@FXML
|
||||
Region footerSpacer;
|
||||
|
||||
private final OfferDetailsWindow offerDetailsWindow;
|
||||
private final Preferences preferences;
|
||||
@ -225,14 +230,16 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||
tableView.getSortOrder().add(dateColumn);
|
||||
|
||||
filterLabel.setText(Res.getWithCol("support.filter"));
|
||||
filterTextField.setPromptText(Res.get("support.filter.prompt"));
|
||||
filterLabel.setText(Res.get("shared.filter"));
|
||||
HBox.setMargin(filterLabel, new Insets(5, 0, 0, 10));
|
||||
filterTextFieldListener = (observable, oldValue, newValue) -> applyFilteredListPredicate(filterTextField.getText());
|
||||
footerBox.setSpacing(5);
|
||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||
exportButton.updateText(Res.get("shared.exportCSV"));
|
||||
searchBox.setSpacing(5);
|
||||
HBox.setHgrow(searchBoxSpacer, Priority.ALWAYS);
|
||||
|
||||
numItems.setPadding(new Insets(-5, 0, 0, 10));
|
||||
HBox.setHgrow(footerSpacer, Priority.ALWAYS);
|
||||
HBox.setMargin(exportButton, new Insets(0, 10, 0, 0));
|
||||
exportButton.updateText(Res.get("shared.exportCSV"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -244,6 +251,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||
|
||||
tableView.setItems(sortedList);
|
||||
|
||||
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
||||
exportButton.setOnAction(event -> {
|
||||
final ObservableList<TableColumn<ClosedTradableListItem, ?>> tableColumns = tableView.getColumns();
|
||||
CSVEntryConverter<ClosedTradableListItem> headerConverter = transactionsListItem -> {
|
||||
@ -317,31 +325,82 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
||||
if (filterString.isEmpty())
|
||||
return true;
|
||||
|
||||
Offer offer = item.getTradable().getOffer();
|
||||
boolean matchesId = offer.getId().contains(filterString);
|
||||
boolean matchesOfferDate = DisplayUtils.formatDate(offer.getDate()).contains(filterString);
|
||||
boolean isMakerOnion = offer.getMakerNodeAddress().getFullAddress().contains(filterString);
|
||||
Tradable tradable = item.getTradable();
|
||||
Offer offer = tradable.getOffer();
|
||||
if (offer.getId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDate(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getMarketLabel(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPrice(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPriceDeviation(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.getTradable() instanceof Trade) {
|
||||
if (model.getVolume(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getAmount(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getTradeFee(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getTxFee(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getBuyerSecurityDeposit(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getSellerSecurityDeposit(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getState(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDirectionLabel(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (offer.getPaymentMethod().getDisplayString().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (offer.getOfferFeePaymentTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tradable instanceof Trade) {
|
||||
Trade trade = (Trade) tradable;
|
||||
if (trade.getTakerFeeTxId() != null && trade.getTakerFeeTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (trade.getDepositTxId() != null && trade.getDepositTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (trade.getPayoutTxId() != null && trade.getPayoutTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Contract contract = trade.getContract();
|
||||
boolean isBuyerOnion = false;
|
||||
boolean isSellerOnion = false;
|
||||
boolean matchesBuyersPaymentAccountData = false;
|
||||
boolean matchesSellersPaymentAccountData = false;
|
||||
|
||||
Trade trade = (Trade) item.getTradable();
|
||||
boolean matchesTradeDate = DisplayUtils.formatDate(trade.getTakeOfferDate()).contains(filterString);
|
||||
Contract contract = trade.getContract();
|
||||
if (contract != null) {
|
||||
isBuyerOnion = contract.getBuyerNodeAddress().getFullAddress().contains(filterString);
|
||||
isSellerOnion = contract.getSellerNodeAddress().getFullAddress().contains(filterString);
|
||||
matchesBuyersPaymentAccountData = contract.getBuyerPaymentAccountPayload().getPaymentDetails().contains(filterString);
|
||||
matchesSellersPaymentAccountData = contract.getSellerPaymentAccountPayload().getPaymentDetails().contains(filterString);
|
||||
}
|
||||
return matchesId || matchesOfferDate || isMakerOnion ||
|
||||
matchesTradeDate || isBuyerOnion || isSellerOnion ||
|
||||
return isBuyerOnion || isSellerOnion ||
|
||||
matchesBuyersPaymentAccountData || matchesSellersPaymentAccountData;
|
||||
} else {
|
||||
return matchesId || matchesOfferDate || isMakerOnion;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -19,18 +19,17 @@ package bisq.desktop.main.portfolio.failedtrades;
|
||||
|
||||
import bisq.core.trade.Trade;
|
||||
|
||||
/**
|
||||
* We could remove that wrapper if it is not needed for additional UI only fields.
|
||||
*/
|
||||
class FailedTradesListItem {
|
||||
import lombok.Getter;
|
||||
|
||||
class FailedTradesListItem {
|
||||
@Getter
|
||||
private final Trade trade;
|
||||
|
||||
FailedTradesListItem(Trade trade) {
|
||||
this.trade = trade;
|
||||
}
|
||||
|
||||
Trade getTrade() {
|
||||
return trade;
|
||||
FailedTradesListItem() {
|
||||
this.trade = null;
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,15 @@
|
||||
~ along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<?import bisq.desktop.components.AutoTooltipButton?>
|
||||
<?import bisq.desktop.components.AutoTooltipLabel?>
|
||||
<?import bisq.desktop.components.InputTextField?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.portfolio.failedtrades.FailedTradesView"
|
||||
@ -26,7 +33,11 @@
|
||||
<padding>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
|
||||
<HBox fx:id="searchBox">
|
||||
<AutoTooltipLabel fx:id="filterLabel"/>
|
||||
<InputTextField fx:id="filterTextField" minWidth="500"/>
|
||||
<Pane fx:id="searchBoxSpacer"/>
|
||||
</HBox>
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="tradeIdColumn" minWidth="120" maxWidth="120"/>
|
||||
@ -40,4 +51,9 @@
|
||||
<TableColumn fx:id="removeTradeColumn" minWidth="40" maxWidth="40"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
<HBox spacing="10">
|
||||
<Label fx:id="numItems"/>
|
||||
<Region fx:id="footerSpacer"/>
|
||||
<AutoTooltipButton fx:id="exportButton"/>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
@ -19,18 +19,25 @@ package bisq.desktop.main.portfolio.failedtrades;
|
||||
|
||||
import bisq.desktop.common.view.ActivatableViewAndModel;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.AutoTooltipButton;
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||
import bisq.desktop.util.FormBuilder;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.trade.Contract;
|
||||
import bisq.core.trade.Trade;
|
||||
|
||||
import bisq.common.config.Config;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import com.googlecode.jcsv.writer.CSVEntryConverter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
@ -40,6 +47,8 @@ import com.jfoenix.controls.JFXButton;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableCell;
|
||||
@ -48,12 +57,21 @@ import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import javafx.event.EventHandler;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
@ -68,9 +86,26 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
||||
@FXML
|
||||
TableColumn<FailedTradesListItem, FailedTradesListItem> priceColumn, amountColumn, volumeColumn,
|
||||
marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn, removeTradeColumn;
|
||||
@FXML
|
||||
HBox searchBox;
|
||||
@FXML
|
||||
AutoTooltipLabel filterLabel;
|
||||
@FXML
|
||||
InputTextField filterTextField;
|
||||
@FXML
|
||||
Pane searchBoxSpacer;
|
||||
@FXML
|
||||
Label numItems;
|
||||
@FXML
|
||||
Region footerSpacer;
|
||||
@FXML
|
||||
AutoTooltipButton exportButton;
|
||||
|
||||
private final TradeDetailsWindow tradeDetailsWindow;
|
||||
private SortedList<FailedTradesListItem> sortedList;
|
||||
private FilteredList<FailedTradesListItem> filteredList;
|
||||
private EventHandler<KeyEvent> keyEventEventHandler;
|
||||
private ChangeListener<String> filterTextFieldListener;
|
||||
private Scene scene;
|
||||
private final boolean allowFaultyDelayedTxs;
|
||||
|
||||
@ -137,6 +172,137 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
filterLabel.setText(Res.get("shared.filter"));
|
||||
HBox.setMargin(filterLabel, new Insets(5, 0, 0, 10));
|
||||
filterTextFieldListener = (observable, oldValue, newValue) -> applyFilteredListPredicate(filterTextField.getText());
|
||||
searchBox.setSpacing(5);
|
||||
HBox.setHgrow(searchBoxSpacer, Priority.ALWAYS);
|
||||
|
||||
numItems.setPadding(new Insets(-5, 0, 0, 10));
|
||||
HBox.setHgrow(footerSpacer, Priority.ALWAYS);
|
||||
HBox.setMargin(exportButton, new Insets(0, 10, 0, 0));
|
||||
exportButton.updateText(Res.get("shared.exportCSV"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
scene = root.getScene();
|
||||
if (scene != null) {
|
||||
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
}
|
||||
|
||||
filteredList = new FilteredList<>(model.getList());
|
||||
sortedList = new SortedList<>(filteredList);
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
tableView.setItems(sortedList);
|
||||
|
||||
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
||||
exportButton.setOnAction(event -> {
|
||||
ObservableList<TableColumn<FailedTradesListItem, ?>> tableColumns = tableView.getColumns();
|
||||
int reportColumns = tableColumns.size() - 1; // CSV report excludes the last column (an icon)
|
||||
CSVEntryConverter<FailedTradesListItem> headerConverter = transactionsListItem -> {
|
||||
String[] columns = new String[reportColumns];
|
||||
for (int i = 0; i < columns.length; i++)
|
||||
columns[i] = ((AutoTooltipLabel) tableColumns.get(i).getGraphic()).getText();
|
||||
return columns;
|
||||
};
|
||||
CSVEntryConverter<FailedTradesListItem> contentConverter = item -> {
|
||||
String[] columns = new String[reportColumns];
|
||||
columns[0] = model.getTradeId(item);
|
||||
columns[1] = model.getDate(item);
|
||||
columns[2] = model.getMarketLabel(item);
|
||||
columns[3] = model.getPrice(item);
|
||||
columns[4] = model.getAmount(item);
|
||||
columns[5] = model.getVolume(item);
|
||||
columns[6] = model.getDirectionLabel(item);
|
||||
columns[7] = model.getState(item);
|
||||
return columns;
|
||||
};
|
||||
|
||||
GUIUtil.exportCSV("failedTrades.csv",
|
||||
headerConverter,
|
||||
contentConverter,
|
||||
new FailedTradesListItem(),
|
||||
sortedList,
|
||||
(Stage) root.getScene().getWindow());
|
||||
});
|
||||
|
||||
filterTextField.textProperty().addListener(filterTextFieldListener);
|
||||
applyFilteredListPredicate(filterTextField.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
if (scene != null) {
|
||||
scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
}
|
||||
|
||||
sortedList.comparatorProperty().unbind();
|
||||
exportButton.setOnAction(null);
|
||||
|
||||
filterTextField.textProperty().removeListener(filterTextFieldListener);
|
||||
}
|
||||
|
||||
private void applyFilteredListPredicate(String filterString) {
|
||||
filteredList.setPredicate(item -> {
|
||||
if (filterString.isEmpty())
|
||||
return true;
|
||||
|
||||
Offer offer = item.getTrade().getOffer();
|
||||
|
||||
if (offer.getId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDate(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getMarketLabel(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPrice(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getVolume(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getAmount(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDirectionLabel(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (offer.getOfferFeePaymentTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Trade trade = item.getTrade();
|
||||
|
||||
if (trade.getTakerFeeTxId() != null && trade.getTakerFeeTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (trade.getDepositTxId() != null && trade.getDepositTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (trade.getPayoutTxId() != null && trade.getPayoutTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Contract contract = trade.getContract();
|
||||
|
||||
boolean isBuyerOnion = false;
|
||||
boolean isSellerOnion = false;
|
||||
boolean matchesBuyersPaymentAccountData = false;
|
||||
boolean matchesSellersPaymentAccountData = false;
|
||||
if (contract != null) {
|
||||
isBuyerOnion = contract.getBuyerNodeAddress().getFullAddress().contains(filterString);
|
||||
isSellerOnion = contract.getSellerNodeAddress().getFullAddress().contains(filterString);
|
||||
matchesBuyersPaymentAccountData = contract.getBuyerPaymentAccountPayload().getPaymentDetails().contains(filterString);
|
||||
matchesSellersPaymentAccountData = contract.getSellerPaymentAccountPayload().getPaymentDetails().contains(filterString);
|
||||
}
|
||||
return isBuyerOnion || isSellerOnion ||
|
||||
matchesBuyersPaymentAccountData || matchesSellersPaymentAccountData;
|
||||
});
|
||||
}
|
||||
|
||||
private void onUnfail() {
|
||||
@ -165,25 +331,6 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
scene = root.getScene();
|
||||
if (scene != null) {
|
||||
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
}
|
||||
sortedList = new SortedList<>(model.getList());
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
tableView.setItems(sortedList);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
if (scene != null) {
|
||||
scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
}
|
||||
sortedList.comparatorProperty().unbind();
|
||||
}
|
||||
|
||||
private void onRevertTrade(Trade trade) {
|
||||
new Popup().attention(Res.get("portfolio.failed.revertToPending.popup"))
|
||||
.onAction(() -> onMoveTradeToPendingTrades(trade))
|
||||
|
@ -20,19 +20,21 @@ package bisq.desktop.main.portfolio.openoffer;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OpenOffer;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* We could remove that wrapper if it is not needed for additional UI only fields.
|
||||
*/
|
||||
class OpenOfferListItem {
|
||||
|
||||
@Getter
|
||||
private final OpenOffer openOffer;
|
||||
|
||||
public OpenOfferListItem(OpenOffer openOffer) {
|
||||
OpenOfferListItem(OpenOffer openOffer) {
|
||||
this.openOffer = openOffer;
|
||||
}
|
||||
|
||||
public OpenOffer getOpenOffer() {
|
||||
return openOffer;
|
||||
OpenOfferListItem() {
|
||||
openOffer = null;
|
||||
}
|
||||
|
||||
public Offer getOffer() {
|
||||
|
@ -17,8 +17,16 @@
|
||||
~ along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<?import bisq.desktop.components.AutoTooltipButton?>
|
||||
<?import bisq.desktop.components.AutoTooltipLabel?>
|
||||
<?import bisq.desktop.components.AutoTooltipSlideToggleButton?>
|
||||
<?import bisq.desktop.components.InputTextField?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<VBox fx:id="root" fx:controller="bisq.desktop.main.portfolio.openoffer.OpenOffersView"
|
||||
@ -26,7 +34,12 @@
|
||||
<padding>
|
||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
|
||||
</padding>
|
||||
|
||||
<HBox fx:id="searchBox">
|
||||
<AutoTooltipLabel fx:id="filterLabel"/>
|
||||
<InputTextField fx:id="filterTextField" minWidth="500"/>
|
||||
<Pane fx:id="searchBoxSpacer"/>
|
||||
<AutoTooltipSlideToggleButton fx:id="selectToggleButton"/>
|
||||
</HBox>
|
||||
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="offerIdColumn" minWidth="110" maxWidth="120"/>
|
||||
@ -43,5 +56,9 @@
|
||||
<TableColumn fx:id="removeItemColumn" minWidth="50" maxWidth="60" sortable="false"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
|
||||
<HBox spacing="10">
|
||||
<Label fx:id="numItems"/>
|
||||
<Region fx:id="footerSpacer"/>
|
||||
<AutoTooltipButton fx:id="exportButton"/>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
@ -20,38 +20,57 @@ package bisq.desktop.main.portfolio.openoffer;
|
||||
import bisq.desktop.Navigation;
|
||||
import bisq.desktop.common.view.ActivatableViewAndModel;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.AutoTooltipCheckBox;
|
||||
import bisq.desktop.components.AutoTooltipButton;
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.AutoTooltipSlideToggleButton;
|
||||
import bisq.desktop.components.AutoTooltipTableColumn;
|
||||
import bisq.desktop.components.HyperlinkWithIcon;
|
||||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.funds.FundsView;
|
||||
import bisq.desktop.main.funds.withdrawal.WithdrawalView;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.overlays.windows.OfferDetailsWindow;
|
||||
import bisq.desktop.main.portfolio.PortfolioView;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.user.DontShowAgainLookup;
|
||||
|
||||
import com.googlecode.jcsv.writer.CSVEntryConverter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.geometry.Insets;
|
||||
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
|
||||
import javafx.util.Callback;
|
||||
@ -71,9 +90,28 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
TableColumn<OpenOfferListItem, OpenOfferListItem> priceColumn, deviationColumn, amountColumn, volumeColumn,
|
||||
marketColumn, directionColumn, dateColumn, offerIdColumn, deactivateItemColumn,
|
||||
removeItemColumn, editItemColumn, paymentMethodColumn;
|
||||
@FXML
|
||||
HBox searchBox;
|
||||
@FXML
|
||||
AutoTooltipLabel filterLabel;
|
||||
@FXML
|
||||
InputTextField filterTextField;
|
||||
@FXML
|
||||
Pane searchBoxSpacer;
|
||||
@FXML
|
||||
Label numItems;
|
||||
@FXML
|
||||
Region footerSpacer;
|
||||
@FXML
|
||||
AutoTooltipButton exportButton;
|
||||
@FXML
|
||||
AutoTooltipSlideToggleButton selectToggleButton;
|
||||
|
||||
private final Navigation navigation;
|
||||
private final OfferDetailsWindow offerDetailsWindow;
|
||||
private SortedList<OpenOfferListItem> sortedList;
|
||||
private FilteredList<OpenOfferListItem> filteredList;
|
||||
private ChangeListener<String> filterTextFieldListener;
|
||||
private PortfolioView.OpenOfferActionHandler openOfferActionHandler;
|
||||
|
||||
@Inject
|
||||
@ -95,7 +133,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
directionColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.offerType")));
|
||||
dateColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.dateTime")));
|
||||
offerIdColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.offerId")));
|
||||
deactivateItemColumn.setGraphic(new AutoTooltipLabel("Enabled"));
|
||||
deactivateItemColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.enabled")));
|
||||
editItemColumn.setGraphic(new AutoTooltipLabel(""));
|
||||
removeItemColumn.setGraphic(new AutoTooltipLabel(""));
|
||||
|
||||
@ -129,18 +167,151 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
|
||||
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||
tableView.getSortOrder().add(dateColumn);
|
||||
|
||||
filterLabel.setText(Res.get("shared.filter"));
|
||||
HBox.setMargin(filterLabel, new Insets(5, 0, 0, 10));
|
||||
filterTextFieldListener = (observable, oldValue, newValue) -> applyFilteredListPredicate(filterTextField.getText());
|
||||
searchBox.setSpacing(5);
|
||||
HBox.setHgrow(searchBoxSpacer, Priority.ALWAYS);
|
||||
|
||||
selectToggleButton.setPadding(new Insets(0, 60, -20, 0));
|
||||
selectToggleButton.setText(Res.get("shared.enabled"));
|
||||
selectToggleButton.setDisable(true);
|
||||
|
||||
numItems.setPadding(new Insets(-5, 0, 0, 10));
|
||||
HBox.setHgrow(footerSpacer, Priority.ALWAYS);
|
||||
HBox.setMargin(exportButton, new Insets(0, 10, 0, 0));
|
||||
exportButton.updateText(Res.get("shared.exportCSV"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
sortedList = new SortedList<>(model.getList());
|
||||
filteredList = new FilteredList<>(model.getList());
|
||||
sortedList = new SortedList<>(filteredList);
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
tableView.setItems(sortedList);
|
||||
|
||||
updateSelectToggleButtonState();
|
||||
|
||||
selectToggleButton.setOnAction(event -> {
|
||||
if (selectToggleButton.isSelected()) {
|
||||
sortedList.forEach(openOfferListItem -> onActivateOpenOffer(openOfferListItem.getOpenOffer()));
|
||||
} else {
|
||||
sortedList.forEach(openOfferListItem -> onDeactivateOpenOffer(openOfferListItem.getOpenOffer()));
|
||||
}
|
||||
tableView.refresh();
|
||||
});
|
||||
|
||||
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
||||
exportButton.setOnAction(event -> {
|
||||
ObservableList<TableColumn<OpenOfferListItem, ?>> tableColumns = tableView.getColumns();
|
||||
int reportColumns = tableColumns.size() - 2; // CSV report excludes the last columns (icons)
|
||||
CSVEntryConverter<OpenOfferListItem> headerConverter = transactionsListItem -> {
|
||||
String[] columns = new String[reportColumns];
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
Node graphic = tableColumns.get(i).getGraphic();
|
||||
if (graphic instanceof AutoTooltipLabel) {
|
||||
columns[i] = ((AutoTooltipLabel) graphic).getText();
|
||||
} else if (graphic instanceof HBox) {
|
||||
// Deviation has a Hbox with AutoTooltipLabel as first child in header
|
||||
columns[i] = ((AutoTooltipLabel) ((Parent) graphic).getChildrenUnmodifiable().get(0)).getText();
|
||||
} else {
|
||||
// Not expected
|
||||
columns[i] = "N/A";
|
||||
}
|
||||
}
|
||||
return columns;
|
||||
};
|
||||
CSVEntryConverter<OpenOfferListItem> contentConverter = item -> {
|
||||
String[] columns = new String[reportColumns];
|
||||
columns[0] = model.getOfferId(item);
|
||||
columns[1] = model.getDate(item);
|
||||
columns[2] = model.getMarketLabel(item);
|
||||
columns[3] = model.getPrice(item);
|
||||
columns[4] = model.getPriceDeviation(item);
|
||||
columns[5] = model.getAmount(item);
|
||||
columns[6] = model.getVolume(item);
|
||||
columns[7] = model.getPaymentMethod(item);
|
||||
columns[8] = model.getDirectionLabel(item);
|
||||
columns[9] = String.valueOf(!item.getOpenOffer().isDeactivated());
|
||||
return columns;
|
||||
};
|
||||
|
||||
GUIUtil.exportCSV("openOffers.csv",
|
||||
headerConverter,
|
||||
contentConverter,
|
||||
new OpenOfferListItem(),
|
||||
sortedList,
|
||||
(Stage) root.getScene().getWindow());
|
||||
});
|
||||
|
||||
filterTextField.textProperty().addListener(filterTextFieldListener);
|
||||
applyFilteredListPredicate(filterTextField.getText());
|
||||
}
|
||||
|
||||
private void updateSelectToggleButtonState() {
|
||||
if (sortedList.size() == 0) {
|
||||
selectToggleButton.setDisable(true);
|
||||
selectToggleButton.setSelected(false);
|
||||
} else {
|
||||
selectToggleButton.setDisable(false);
|
||||
long numDeactivated = sortedList.stream()
|
||||
.filter(openOfferListItem -> openOfferListItem.getOpenOffer().isDeactivated())
|
||||
.count();
|
||||
if (numDeactivated == sortedList.size()) {
|
||||
selectToggleButton.setSelected(false);
|
||||
} else if (numDeactivated == 0) {
|
||||
selectToggleButton.setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
sortedList.comparatorProperty().unbind();
|
||||
exportButton.setOnAction(null);
|
||||
|
||||
filterTextField.textProperty().removeListener(filterTextFieldListener);
|
||||
}
|
||||
|
||||
private void applyFilteredListPredicate(String filterString) {
|
||||
filteredList.setPredicate(item -> {
|
||||
if (filterString.isEmpty())
|
||||
return true;
|
||||
|
||||
Offer offer = item.getOpenOffer().getOffer();
|
||||
if (offer.getId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDate(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getMarketLabel(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPrice(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPriceDeviation(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getPaymentMethod(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getVolume(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getAmount(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (model.getDirectionLabel(item).contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
if (offer.getOfferFeePaymentTxId().contains(filterString)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private void onDeactivateOpenOffer(OpenOffer openOffer) {
|
||||
@ -151,6 +322,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
log.error(message);
|
||||
new Popup().warning(Res.get("offerbook.deactivateOffer.failed", message)).show();
|
||||
});
|
||||
updateSelectToggleButtonState();
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,6 +334,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
log.error(message);
|
||||
new Popup().warning(Res.get("offerbook.activateOffer.failed", message)).show();
|
||||
});
|
||||
updateSelectToggleButtonState();
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,6 +351,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
} else {
|
||||
doRemoveOpenOffer(openOffer);
|
||||
}
|
||||
updateSelectToggleButtonState();
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,7 +400,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty) {
|
||||
field = new HyperlinkWithIcon(model.getTradeId(item));
|
||||
field = new HyperlinkWithIcon(model.getOfferId(item));
|
||||
field.setOnAction(event -> offerDetailsWindow.show(item.getOffer()));
|
||||
field.setTooltip(new Tooltip(Res.get("tooltip.openPopupForDetails")));
|
||||
setGraphic(field);
|
||||
@ -448,14 +622,10 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
public TableCell<OpenOfferListItem, OpenOfferListItem> call(TableColumn<OpenOfferListItem, OpenOfferListItem> column) {
|
||||
return new TableCell<>() {
|
||||
final ImageView iconView = new ImageView();
|
||||
CheckBox checkBox;
|
||||
AutoTooltipSlideToggleButton checkBox;
|
||||
|
||||
private void updateState(@NotNull OpenOffer openOffer) {
|
||||
if (openOffer.isDeactivated()) {
|
||||
checkBox.setSelected(false);
|
||||
} else {
|
||||
checkBox.setSelected(true);
|
||||
}
|
||||
checkBox.setSelected(!openOffer.isDeactivated());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -464,7 +634,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
|
||||
if (item != null && !empty) {
|
||||
if (checkBox == null) {
|
||||
checkBox = new AutoTooltipCheckBox();
|
||||
checkBox = new AutoTooltipSlideToggleButton();
|
||||
checkBox.setGraphic(iconView);
|
||||
}
|
||||
checkBox.setOnAction(event -> {
|
||||
@ -528,10 +698,10 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
private void setEditColumnCellFactory() {
|
||||
editItemColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
|
||||
editItemColumn.setCellFactory(
|
||||
new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() {
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<OpenOfferListItem, OpenOfferListItem> call(TableColumn<OpenOfferListItem, OpenOfferListItem> column) {
|
||||
return new TableCell<OpenOfferListItem, OpenOfferListItem>() {
|
||||
return new TableCell<>() {
|
||||
Button button;
|
||||
|
||||
@Override
|
||||
|
@ -27,8 +27,8 @@ import bisq.core.locale.Res;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OpenOffer;
|
||||
import bisq.core.util.coin.BsqFormatter;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.BsqFormatter;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
@ -78,7 +78,7 @@ class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel>
|
||||
return dataModel.getList();
|
||||
}
|
||||
|
||||
String getTradeId(OpenOfferListItem item) {
|
||||
String getOfferId(OpenOfferListItem item) {
|
||||
return item.getOffer().getShortId();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user