mirror of
https://github.com/monero-project/monero-gui.git
synced 2024-11-17 00:07:51 +00:00
CSV export functionality for transaction history
This commit is contained in:
parent
36eb1f80e1
commit
fd3280c254
4 changed files with 118 additions and 1 deletions
5
main.cpp
5
main.cpp
|
@ -268,6 +268,11 @@ int main(int argc, char *argv[])
|
||||||
engine.rootContext()->setContextProperty("scaleRatio", 1);
|
engine.rootContext()->setContextProperty("scaleRatio", 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef Q_OS_IOS
|
||||||
|
const QString desktopFolder = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||||
|
if (!desktopFolder.isEmpty())
|
||||||
|
engine.rootContext()->setContextProperty("desktopFolder", desktopFolder);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!moneroAccountsRootDir.empty())
|
if (!moneroAccountsRootDir.empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -130,7 +130,7 @@ Rectangle {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
spacing: 0
|
spacing: 10 * scaleRatio
|
||||||
|
|
||||||
GridLayout {
|
GridLayout {
|
||||||
property int column_width: {
|
property int column_width: {
|
||||||
|
@ -147,6 +147,15 @@ Rectangle {
|
||||||
RowLayout {
|
RowLayout {
|
||||||
visible: !isMobile
|
visible: !isMobile
|
||||||
Layout.preferredWidth: parent.column_width
|
Layout.preferredWidth: parent.column_width
|
||||||
|
|
||||||
|
StandardButton {
|
||||||
|
visible: !isIOS
|
||||||
|
small: true
|
||||||
|
text: qsTr("Export") + translationManager.emptyString
|
||||||
|
onClicked: {
|
||||||
|
writeCSVFileDialog.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
@ -363,6 +372,42 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileDialog {
|
||||||
|
id: writeCSVFileDialog
|
||||||
|
title: "Please choose a folder"
|
||||||
|
selectFolder: true
|
||||||
|
onRejected: {
|
||||||
|
console.log("csv write canceled")
|
||||||
|
}
|
||||||
|
onAccepted: {
|
||||||
|
var dataDir = walletManager.urlToLocalPath(writeCSVFileDialog.fileUrl);
|
||||||
|
var written = currentWallet.history.writeCSV(currentWallet.currentSubaddressAccount, dataDir);
|
||||||
|
|
||||||
|
if(written !== ""){
|
||||||
|
confirmationDialog.title = qsTr("Success") + translationManager.emptyString;
|
||||||
|
var text = qsTr("CSV file written to: %1").arg(written) + "\n\n"
|
||||||
|
text += qsTr("Tip: Use your favorite spreadsheet software to sort on blockheight.") + "\n\n" + translationManager.emptyString;
|
||||||
|
confirmationDialog.text = text;
|
||||||
|
confirmationDialog.icon = StandardIcon.Information;
|
||||||
|
} else {
|
||||||
|
confirmationDialog.title = qsTr("Error") + translationManager.emptyString;
|
||||||
|
confirmationDialog.text = qsTr("Error exporting transaction data.") + "\n\n" + translationManager.emptyString;
|
||||||
|
confirmationDialog.icon = StandardIcon.Critical;
|
||||||
|
}
|
||||||
|
confirmationDialog.open()
|
||||||
|
}
|
||||||
|
Component.onCompleted: {
|
||||||
|
var _folder = 'file://' + moneroAccountsDir;
|
||||||
|
try {
|
||||||
|
_folder = 'file://' + desktopFolder;
|
||||||
|
}
|
||||||
|
catch(err) {}
|
||||||
|
finally {
|
||||||
|
writeCSVFileDialog.folder = _folder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onPageCompleted() {
|
function onPageCompleted() {
|
||||||
if(currentWallet != null && typeof currentWallet.history !== "undefined" ) {
|
if(currentWallet != null && typeof currentWallet.history !== "undefined" ) {
|
||||||
currentWallet.history.refresh(currentWallet.currentSubaddressAccount)
|
currentWallet.history.refresh(currentWallet.currentSubaddressAccount)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "TransactionInfo.h"
|
#include "TransactionInfo.h"
|
||||||
#include <wallet/api/wallet2_api.h>
|
#include <wallet/api/wallet2_api.h>
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,3 +114,68 @@ TransactionHistory::TransactionHistory(Monero::TransactionHistory *pimpl, QObjec
|
||||||
m_firstDateTime = QDateTime(QDate(2014, 4, 18)); // the genesis block
|
m_firstDateTime = QDateTime(QDate(2014, 4, 18)); // the genesis block
|
||||||
m_lastDateTime = QDateTime::currentDateTime().addDays(1); // tomorrow (guard against jitter and timezones)
|
m_lastDateTime = QDateTime::currentDateTime().addDays(1); // tomorrow (guard against jitter and timezones)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString TransactionHistory::writeCSV(quint32 accountIndex, QString out)
|
||||||
|
{
|
||||||
|
QList<TransactionInfo *> history = this->getAll(accountIndex);
|
||||||
|
if(history.count() < 1){
|
||||||
|
return QString("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct filename
|
||||||
|
qint64 now = QDateTime::currentDateTime().currentMSecsSinceEpoch();
|
||||||
|
QString fn = QString(QString("%1/monero-txs_%2.csv").arg(out, QString::number(now / 1000)));
|
||||||
|
|
||||||
|
// open file
|
||||||
|
QFile data(fn);
|
||||||
|
if(!data.open(QFile::WriteOnly | QFile::Truncate)){
|
||||||
|
return QString("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// write header
|
||||||
|
QTextStream output(&data);
|
||||||
|
output << "blockHeight,epoch,date,direction,amount,atomicAmount,fee,txid,label,subaddrAccount,paymentId\n";
|
||||||
|
|
||||||
|
foreach(const TransactionInfo *info, history)
|
||||||
|
{
|
||||||
|
// collect column data
|
||||||
|
double amount = info->amount();
|
||||||
|
quint64 atomicAmount = info->atomicAmount();
|
||||||
|
quint32 subaddrAccount = info->subaddrAccount();
|
||||||
|
QString fee = info->fee();
|
||||||
|
QString direction = QString("");
|
||||||
|
TransactionInfo::Direction _direction = info->direction();
|
||||||
|
if(_direction == TransactionInfo::Direction_In)
|
||||||
|
{
|
||||||
|
direction = QString("in");
|
||||||
|
}
|
||||||
|
else if(_direction == TransactionInfo::Direction_Out){
|
||||||
|
direction = QString("out");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
continue; // skip TransactionInfo::Direction_Both
|
||||||
|
}
|
||||||
|
QString label = info->label();
|
||||||
|
label.remove(QChar('"')); // reserved
|
||||||
|
quint64 blockHeight = info->blockHeight();
|
||||||
|
QDateTime timeStamp = info->timestamp();
|
||||||
|
QString date = info->date() + " " + info->time();
|
||||||
|
uint epoch = timeStamp.toTime_t();
|
||||||
|
QString displayAmount = info->displayAmount();
|
||||||
|
QString paymentId = info->paymentId();
|
||||||
|
if(paymentId == "0000000000000000"){
|
||||||
|
paymentId = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// format and write
|
||||||
|
QString line = QString("%1,%2,%3,%4,%5,%6,%7,%8,\"%9\",%10,%11\n")
|
||||||
|
.arg(QString::number(blockHeight), QString::number(epoch), date)
|
||||||
|
.arg(direction, QString::number(amount), QString::number(atomicAmount))
|
||||||
|
.arg(info->fee(), info->hash(), label, QString::number(subaddrAccount))
|
||||||
|
.arg(paymentId);
|
||||||
|
output << line;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.close();
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ public:
|
||||||
// Q_INVOKABLE TransactionInfo * transaction(const QString &id);
|
// Q_INVOKABLE TransactionInfo * transaction(const QString &id);
|
||||||
Q_INVOKABLE QList<TransactionInfo*> getAll(quint32 accountIndex) const;
|
Q_INVOKABLE QList<TransactionInfo*> getAll(quint32 accountIndex) const;
|
||||||
Q_INVOKABLE void refresh(quint32 accountIndex);
|
Q_INVOKABLE void refresh(quint32 accountIndex);
|
||||||
|
Q_INVOKABLE QString writeCSV(quint32 accountIndex, QString out);
|
||||||
quint64 count() const;
|
quint64 count() const;
|
||||||
QDateTime firstDateTime() const;
|
QDateTime firstDateTime() const;
|
||||||
QDateTime lastDateTime() const;
|
QDateTime lastDateTime() const;
|
||||||
|
|
Loading…
Reference in a new issue