mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-23 23:06:39 +01:00
Added csv export for tx history and trade history
This commit is contained in:
parent
925f59a9ea
commit
37bd2fa5f3
8 changed files with 149 additions and 31 deletions
|
@ -7,5 +7,5 @@ public class DevFlags {
|
|||
private static final Logger log = LoggerFactory.getLogger(DevFlags.class);
|
||||
|
||||
public static final boolean STRESS_TEST_MODE = false;
|
||||
public static final boolean DEV_MODE = STRESS_TEST_MODE || false;
|
||||
public static final boolean DEV_MODE = STRESS_TEST_MODE || true;
|
||||
}
|
||||
|
|
|
@ -142,19 +142,11 @@
|
|||
<version>0.4.1</version>
|
||||
</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.opencsv</groupId>
|
||||
<artifactId>opencsv</artifactId>
|
||||
<version>3.8</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.googlecode.jcsv/jcsv -->
|
||||
<dependency>
|
||||
<groupId>com.googlecode.jcsv</groupId>
|
||||
<artifactId>jcsv</artifactId>
|
||||
<version>1.4.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</project>
|
|
@ -52,6 +52,15 @@ public class TransactionsListItem {
|
|||
private boolean detailsAvailable;
|
||||
private Coin amountAsCoin = Coin.ZERO;
|
||||
private BSFormatter formatter;
|
||||
private int confirmations = 0;
|
||||
|
||||
public TransactionsListItem() {
|
||||
date = null;
|
||||
walletService = null;
|
||||
txConfidenceIndicator = null;
|
||||
tooltip = null;
|
||||
txId = null;
|
||||
}
|
||||
|
||||
public TransactionsListItem(Transaction transaction, WalletService walletService, Optional<Tradable> tradableOptional, BSFormatter formatter) {
|
||||
this.formatter = formatter;
|
||||
|
@ -176,6 +185,7 @@ public class TransactionsListItem {
|
|||
}
|
||||
|
||||
private void updateConfidence(TransactionConfidence confidence) {
|
||||
confirmations = confidence.getDepthInBlocks();
|
||||
if (confidence != null) {
|
||||
switch (confidence.getConfidenceType()) {
|
||||
case UNKNOWN:
|
||||
|
@ -251,5 +261,9 @@ public class TransactionsListItem {
|
|||
public Tradable getTradable() {
|
||||
return tradable;
|
||||
}
|
||||
|
||||
public String getNumConfirmations() {
|
||||
return String.valueOf(confirmations);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<VBox fx:id="root" fx:controller="io.bitsquare.gui.main.funds.transactions.TransactionsView"
|
||||
spacing="10" xmlns:fx="http://javafx.com/fxml">
|
||||
spacing="10" alignment="CENTER_RIGHT" xmlns:fx="http://javafx.com/fxml">
|
||||
<padding>
|
||||
<Insets bottom="0.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</padding>
|
||||
|
@ -30,11 +30,12 @@
|
|||
<TableColumn text="Date/Time" fx:id="dateColumn" minWidth="180" maxWidth="180"/>
|
||||
<TableColumn text="Details" fx:id="detailsColumn" minWidth="220" maxWidth="220"/>
|
||||
<TableColumn text="Address" fx:id="addressColumn" minWidth="260"/>
|
||||
<TableColumn text="Transaction" fx:id="transactionColumn" minWidth="180"/>
|
||||
<TableColumn text="Transaction ID" fx:id="transactionColumn" minWidth="180"/>
|
||||
<TableColumn text="Amount (BTC)" fx:id="amountColumn" minWidth="130" maxWidth="130"/>
|
||||
<TableColumn text="Confirmations" fx:id="confidenceColumn" minWidth="130" maxWidth="130"/>
|
||||
<TableColumn text="Revert Tx" fx:id="revertTxColumn" sortable="false" minWidth="110" maxWidth="110"
|
||||
visible="false"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
<Button fx:id="exportButton"/>
|
||||
</VBox>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package io.bitsquare.gui.main.funds.transactions;
|
||||
|
||||
import com.googlecode.jcsv.writer.CSVEntryConverter;
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
import io.bitsquare.arbitration.DisputeManager;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
|
@ -32,6 +33,7 @@ import io.bitsquare.gui.main.overlays.popups.Popup;
|
|||
import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow;
|
||||
import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.gui.util.GUIUtil;
|
||||
import io.bitsquare.trade.Tradable;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.TradeManager;
|
||||
|
@ -53,6 +55,7 @@ import javafx.scene.input.KeyCodeCombination;
|
|||
import javafx.scene.input.KeyCombination;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.util.Callback;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.script.Script;
|
||||
|
@ -71,6 +74,8 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
TableView<TransactionsListItem> tableView;
|
||||
@FXML
|
||||
TableColumn<TransactionsListItem, TransactionsListItem> dateColumn, detailsColumn, addressColumn, transactionColumn, amountColumn, confidenceColumn, revertTxColumn;
|
||||
@FXML
|
||||
Button exportButton;
|
||||
|
||||
private final ObservableList<TransactionsListItem> observableList = FXCollections.observableArrayList();
|
||||
private final SortedList<TransactionsListItem> sortedList = new SortedList<>(observableList);
|
||||
|
@ -84,6 +89,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
private final Preferences preferences;
|
||||
private final TradeDetailsWindow tradeDetailsWindow;
|
||||
private final DisputeManager disputeManager;
|
||||
private Stage stage;
|
||||
private final OfferDetailsWindow offerDetailsWindow;
|
||||
private WalletEventListener walletEventListener;
|
||||
private EventHandler<KeyEvent> keyEventEventHandler;
|
||||
|
@ -97,7 +103,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
private TransactionsView(WalletService walletService, TradeManager tradeManager, OpenOfferManager openOfferManager,
|
||||
ClosedTradableManager closedTradableManager, FailedTradesManager failedTradesManager,
|
||||
BSFormatter formatter, Preferences preferences, TradeDetailsWindow tradeDetailsWindow,
|
||||
DisputeManager disputeManager,
|
||||
DisputeManager disputeManager, Stage stage,
|
||||
OfferDetailsWindow offerDetailsWindow) {
|
||||
this.walletService = walletService;
|
||||
this.tradeManager = tradeManager;
|
||||
|
@ -108,6 +114,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
this.preferences = preferences;
|
||||
this.tradeDetailsWindow = tradeDetailsWindow;
|
||||
this.disputeManager = disputeManager;
|
||||
this.stage = stage;
|
||||
this.offerDetailsWindow = offerDetailsWindow;
|
||||
}
|
||||
|
||||
|
@ -182,6 +189,8 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
else if (new KeyCodeCombination(KeyCode.A, KeyCombination.SHORTCUT_DOWN).match(event))
|
||||
showStatisticsPopup();
|
||||
};
|
||||
|
||||
exportButton.setText("Export to csv");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -195,6 +204,30 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
scene = root.getScene();
|
||||
if (scene != null)
|
||||
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
|
||||
exportButton.setOnAction(event -> {
|
||||
final ObservableList<TableColumn<TransactionsListItem, ?>> tableColumns = tableView.getColumns();
|
||||
CSVEntryConverter<TransactionsListItem> headerConverter = transactionsListItem -> {
|
||||
String[] columns = new String[6];
|
||||
for (int i = 0; i < columns.length; i++)
|
||||
columns[i] = tableColumns.get(i).getText();
|
||||
|
||||
return columns;
|
||||
};
|
||||
CSVEntryConverter<TransactionsListItem> contentConverter = item -> {
|
||||
String[] columns = new String[6];
|
||||
columns[0] = item.getDateString();
|
||||
columns[1] = item.getDetails();
|
||||
columns[2] = item.getDirection() + " " + item.getAddressString();
|
||||
columns[3] = item.getTxId();
|
||||
columns[4] = item.getAmount();
|
||||
columns[5] = item.getNumConfirmations();
|
||||
return columns;
|
||||
};
|
||||
|
||||
GUIUtil.exportCSV("transactions.csv", headerConverter, contentConverter,
|
||||
new TransactionsListItem(), sortedList, stage);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -205,6 +238,8 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
|
||||
if (scene != null)
|
||||
scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
|
||||
|
||||
exportButton.setOnAction(null);
|
||||
}
|
||||
|
||||
|
||||
|
@ -528,7 +563,6 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
|||
walletService.doubleSpendTransaction(txId, () -> {
|
||||
if (tradable != null)
|
||||
walletService.swapAnyTradeEntryContextToAvailableEntry(tradable.getId());
|
||||
|
||||
|
||||
new Popup().information("Transaction successfully sent to a new address in the local Bitsquare wallet.").show();
|
||||
}, errorMessage -> {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<VBox fx:id="root" fx:controller="io.bitsquare.gui.main.portfolio.closedtrades.ClosedTradesView"
|
||||
spacing="10" xmlns:fx="http://javafx.com/fxml">
|
||||
spacing="10" alignment="CENTER_RIGHT" xmlns:fx="http://javafx.com/fxml">
|
||||
<padding>
|
||||
<Insets bottom="0.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</padding>
|
||||
|
@ -38,5 +38,5 @@
|
|||
<TableColumn text="" fx:id="avatarColumn" minWidth="40" maxWidth="40"/>
|
||||
</columns>
|
||||
</TableView>
|
||||
|
||||
<Button fx:id="exportButton"/>
|
||||
</VBox>
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package io.bitsquare.gui.main.portfolio.closedtrades;
|
||||
|
||||
import com.googlecode.jcsv.writer.CSVEntryConverter;
|
||||
import io.bitsquare.alert.PrivateNotificationManager;
|
||||
import io.bitsquare.gui.common.view.ActivatableViewAndModel;
|
||||
import io.bitsquare.gui.common.view.FxmlView;
|
||||
|
@ -25,17 +26,20 @@ import io.bitsquare.gui.components.PeerInfoIcon;
|
|||
import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow;
|
||||
import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.gui.util.GUIUtil;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.trade.Tradable;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.offer.OpenOffer;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.SortedList;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.util.Callback;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.utils.Fiat;
|
||||
|
@ -50,19 +54,24 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
@FXML
|
||||
TableColumn<ClosedTradableListItem, ClosedTradableListItem> priceColumn, amountColumn, volumeColumn,
|
||||
directionColumn, dateColumn, tradeIdColumn, stateColumn, avatarColumn;
|
||||
@FXML
|
||||
Button exportButton;
|
||||
private final BSFormatter formatter;
|
||||
private final OfferDetailsWindow offerDetailsWindow;
|
||||
private final TradeDetailsWindow tradeDetailsWindow;
|
||||
private PrivateNotificationManager privateNotificationManager;
|
||||
private Stage stage;
|
||||
private SortedList<ClosedTradableListItem> sortedList;
|
||||
|
||||
@Inject
|
||||
public ClosedTradesView(ClosedTradesViewModel model, BSFormatter formatter, OfferDetailsWindow offerDetailsWindow, TradeDetailsWindow tradeDetailsWindow, PrivateNotificationManager privateNotificationManager) {
|
||||
public ClosedTradesView(ClosedTradesViewModel model, BSFormatter formatter, OfferDetailsWindow offerDetailsWindow,
|
||||
TradeDetailsWindow tradeDetailsWindow, PrivateNotificationManager privateNotificationManager, Stage stage) {
|
||||
super(model);
|
||||
this.formatter = formatter;
|
||||
this.offerDetailsWindow = offerDetailsWindow;
|
||||
this.tradeDetailsWindow = tradeDetailsWindow;
|
||||
this.privateNotificationManager = privateNotificationManager;
|
||||
this.stage = stage;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -79,9 +88,6 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
setStateColumnCellFactory();
|
||||
setAvatarColumnCellFactory();
|
||||
|
||||
/* , , ,
|
||||
, , , , avatarColumn;
|
||||
*/
|
||||
tradeIdColumn.setComparator((o1, o2) -> o1.getTradable().getId().compareTo(o2.getTradable().getId()));
|
||||
dateColumn.setComparator((o1, o2) -> o1.getTradable().getDate().compareTo(o2.getTradable().getDate()));
|
||||
directionColumn.setComparator((o1, o2) -> o1.getTradable().getOffer().getDirection().compareTo(o2.getTradable().getOffer().getDirection()));
|
||||
|
@ -125,6 +131,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
|
||||
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||
tableView.getSortOrder().add(dateColumn);
|
||||
exportButton.setText("Export to csv");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -132,11 +139,37 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
|
|||
sortedList = new SortedList<>(model.getList());
|
||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||
tableView.setItems(sortedList);
|
||||
|
||||
exportButton.setOnAction(event -> {
|
||||
final ObservableList<TableColumn<ClosedTradableListItem, ?>> tableColumns = tableView.getColumns();
|
||||
CSVEntryConverter<ClosedTradableListItem> headerConverter = transactionsListItem -> {
|
||||
String[] columns = new String[7];
|
||||
for (int i = 0; i < columns.length; i++)
|
||||
columns[i] = tableColumns.get(i).getText();
|
||||
|
||||
return columns;
|
||||
};
|
||||
CSVEntryConverter<ClosedTradableListItem> contentConverter = item -> {
|
||||
String[] columns = new String[7];
|
||||
columns[0] = model.getTradeId(item);
|
||||
columns[1] = model.getDate(item);
|
||||
columns[2] = model.getAmount(item);
|
||||
columns[3] = model.getPrice(item);
|
||||
columns[4] = model.getVolume(item);
|
||||
columns[5] = model.getDirectionLabel(item);
|
||||
columns[6] = model.getState(item);
|
||||
return columns;
|
||||
};
|
||||
|
||||
GUIUtil.exportCSV("tradeHistory.csv", headerConverter, contentConverter,
|
||||
new ClosedTradableListItem(null), sortedList, stage);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
sortedList.comparatorProperty().unbind();
|
||||
exportButton.setOnAction(null);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,11 @@
|
|||
|
||||
package io.bitsquare.gui.util;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.googlecode.jcsv.CSVStrategy;
|
||||
import com.googlecode.jcsv.writer.CSVEntryConverter;
|
||||
import com.googlecode.jcsv.writer.CSVWriter;
|
||||
import com.googlecode.jcsv.writer.internal.CSVWriterBuilder;
|
||||
import io.bitsquare.app.DevFlags;
|
||||
import io.bitsquare.gui.main.overlays.popups.Popup;
|
||||
import io.bitsquare.payment.PaymentAccount;
|
||||
|
@ -33,8 +38,12 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GUIUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(GUIUtil.class);
|
||||
|
@ -69,18 +78,11 @@ public class GUIUtil {
|
|||
|
||||
public static void exportAccounts(ArrayList<PaymentAccount> accounts, String fileName, Preferences preferences, Stage stage) {
|
||||
if (!accounts.isEmpty()) {
|
||||
DirectoryChooser directoryChooser = new DirectoryChooser();
|
||||
directoryChooser.setInitialDirectory(new File(preferences.getDefaultPath()));
|
||||
directoryChooser.setTitle("Select export path");
|
||||
File dir = directoryChooser.showDialog(stage);
|
||||
if (dir != null) {
|
||||
String directory = dir.getAbsolutePath();
|
||||
preferences.setDefaultPath(directory);
|
||||
Storage<ArrayList<PaymentAccount>> paymentAccountsStorage = new Storage<>(new File(directory));
|
||||
paymentAccountsStorage.initAndGetPersisted(accounts, fileName);
|
||||
paymentAccountsStorage.queueUpForSave(20);
|
||||
new Popup<>().feedback("Payment accounts saved to path:\n" + Paths.get(directory, fileName).toAbsolutePath()).show();
|
||||
}
|
||||
String directory = getDirectoryFormChooser(preferences, stage);
|
||||
Storage<ArrayList<PaymentAccount>> paymentAccountsStorage = new Storage<>(new File(directory));
|
||||
paymentAccountsStorage.initAndGetPersisted(accounts, fileName);
|
||||
paymentAccountsStorage.queueUpForSave(20);
|
||||
new Popup<>().feedback("Payment accounts saved to path:\n" + Paths.get(directory, fileName).toAbsolutePath()).show();
|
||||
} else {
|
||||
new Popup<>().warning("You don't have payment accounts set up for exporting.").show();
|
||||
}
|
||||
|
@ -119,4 +121,46 @@ public class GUIUtil {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static <T> void exportCSV(String fileName, CSVEntryConverter<T> headerConverter,
|
||||
CSVEntryConverter<T> contentConverter, T emptyItem,
|
||||
List<T> list, Stage stage) {
|
||||
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setInitialFileName(fileName);
|
||||
File file = fileChooser.showSaveDialog(stage);
|
||||
try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(file, false), Charsets.UTF_8)) {
|
||||
CSVWriter<T> headerWriter = new CSVWriterBuilder<T>(outputStreamWriter)
|
||||
.strategy(CSVStrategy.UK_DEFAULT)
|
||||
.entryConverter(headerConverter)
|
||||
.build();
|
||||
headerWriter.write(emptyItem);
|
||||
|
||||
CSVWriter<T> contentWriter = new CSVWriterBuilder<T>(outputStreamWriter)
|
||||
.strategy(CSVStrategy.UK_DEFAULT)
|
||||
.entryConverter(contentConverter)
|
||||
.build();
|
||||
contentWriter.writeAll(list);
|
||||
} catch (RuntimeException | IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage());
|
||||
new Popup().error("Exporting to CSV failed because of an error.\n" +
|
||||
"Error = " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDirectoryFormChooser(Preferences preferences, Stage stage) {
|
||||
DirectoryChooser directoryChooser = new DirectoryChooser();
|
||||
directoryChooser.setInitialDirectory(new File(preferences.getDefaultPath()));
|
||||
directoryChooser.setTitle("Select export path");
|
||||
File dir = directoryChooser.showDialog(stage);
|
||||
if (dir != null) {
|
||||
String directory = dir.getAbsolutePath();
|
||||
preferences.setDefaultPath(directory);
|
||||
return directory;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue