diff --git a/Project-X-qt.pro b/Project-X-qt.pro index 4832018..082962d 100644 --- a/Project-X-qt.pro +++ b/Project-X-qt.pro @@ -1,6 +1,6 @@ TEMPLATE = app TARGET = Project-X -VERSION = 0.9.1 +VERSION = 0.9.3 INCLUDEPATH += src src/json src/qt QT += core gui network DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE @@ -288,7 +288,8 @@ HEADERS += src/qt/bitcoingui.h \ src/sph_types.h \ src/clientversion.h \ src/clientversion.h \ - src/qt/merchantpage.h + src/qt/merchantpage.h \ + src/qt/stakereportdialog.h SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \ src/qt/transactiontablemodel.cpp \ @@ -353,6 +354,7 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \ src/qt/qtipcserver.cpp \ src/qt/rpcconsole.cpp \ src/qt/multisenddialog.cpp \ + src/qt/stakereportdialog.cpp \ src/noui.cpp \ src/kernel.cpp \ src/scrypt-arm.S \ @@ -390,6 +392,7 @@ FORMS += \ src/qt/forms/rpcconsole.ui \ src/qt/forms/optionsdialog.ui \ src/qt/forms/merchants.ui \ + src/qt/forms/stakereportdialog.ui contains(USE_QRCODE, 1) { HEADERS += src/qt/qrcodedialog.h diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 0779071..26a32b1 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -306,7 +306,8 @@ static const CRPCCommand vRPCCommands[] = { "resendtx", &resendtx, false, true}, { "makekeypair", &makekeypair, false, true}, { "sendalert", &sendalert, false, false}, - { "multisend", &multisend, false, false }, + { "multisend", &multisend, false, false }, + { "getstakereport", &getstakereport, false, false}, }; CRPCTable::CRPCTable() diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index c30c251..1a50f5d 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -219,4 +219,6 @@ extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp) extern json_spirit::Value getblockbynumber(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getcheckpoint(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getstakereport(const json_spirit::Array& params, bool fHelp); + #endif diff --git a/src/clientversion.h b/src/clientversion.h index 6de17d2..4d1733a 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -6,9 +6,9 @@ // // These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it -#define CLIENT_VERSION_MAJOR 1 -#define CLIENT_VERSION_MINOR 1 -#define CLIENT_VERSION_REVISION 0 +#define CLIENT_VERSION_MAJOR 0 +#define CLIENT_VERSION_MINOR 9 +#define CLIENT_VERSION_REVISION 3 #define CLIENT_VERSION_BUILD 0 // Converts the parameter X to a string after macro replacement on X has been performed. diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 3ceec4a..ab08130 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -28,6 +28,7 @@ #include "guiutil.h" #include "rpcconsole.h" #include "wallet.h" +#include "stakereportdialog.h" #ifdef Q_OS_MAC #include "macdockiconhandler.h" @@ -309,6 +310,9 @@ void BitcoinGUI::createActions() signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this); verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this); + stakeReportAction = new QAction(QIcon(":/icons/minting"), tr("Show stake report"), this); + stakeReportAction->setToolTip(tr("Open the Stake Report Box")); + exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this); exportAction->setToolTip(tr("Export the data in the current tab to a file")); openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug Window"), this); @@ -326,6 +330,7 @@ void BitcoinGUI::createActions() connect(lockWalletAction, SIGNAL(triggered()), this, SLOT(lockWallet())); connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab())); connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab())); + connect(stakeReportAction, SIGNAL(triggered()), this, SLOT(stakeReportClicked())); } void BitcoinGUI::createMenuBar() @@ -355,6 +360,9 @@ void BitcoinGUI::createMenuBar() settings->addAction(multiSendAction); settings->addSeparator(); settings->addAction(optionsAction); + + QMenu *information = appMenuBar->addMenu(tr("Information")); + information->addAction(stakeReportAction); QMenu *help = appMenuBar->addMenu(tr("&Help")); help->addAction(openRPCConsoleAction); @@ -528,6 +536,15 @@ void BitcoinGUI::multiSendClicked(QString addr) disconnect(exportAction, SIGNAL(triggered()), 0, 0); } +// Stake report dialog +void BitcoinGUI::stakeReportClicked() +{ + static StakeReportDialog dlg; + dlg.setModel(walletModel); + dlg.show(); +} + + void BitcoinGUI::setNumConnections(int count) { QString icon; diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index c5d3283..4dda181 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -102,6 +102,7 @@ class BitcoinGUI : public QMainWindow QAction *aboutQtAction; QAction *openRPCConsoleAction; QAction * multiSendAction; + QAction *stakeReportAction; QSystemTrayIcon *trayIcon; Notificator *notificator; @@ -185,6 +186,9 @@ private slots: void unlockWallet(); void lockWallet(); + + /** Open stake report dialog */ + void stakeReportClicked(); /** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */ void showNormalIfMinimized(bool fToggleHidden = false); diff --git a/src/qt/forms/stakereportdialog.ui b/src/qt/forms/stakereportdialog.ui new file mode 100644 index 0000000..fbb8f5a --- /dev/null +++ b/src/qt/forms/stakereportdialog.ui @@ -0,0 +1,938 @@ + + + StakeReportDialog + + + + 0 + 0 + 823 + 560 + + + + + 823 + 560 + + + + + 823 + 582 + + + + Stake Report + + + false + + + + + + + 460 + 560 + + + + + 460 + 560 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 200 + 0 + + + + + 12 + 75 + true + + + + Earnings made by stake over time + + + QFrame::NoFrame + + + QFrame::Sunken + + + 2 + + + 3 + + + Stake Report + + + Qt::AlignHCenter|Qt::AlignTop + + + + + + + Qt::Horizontal + + + + + + + 5 + + + + + + 9 + 75 + true + + + + Coin SubTotal + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + 9 + 75 + true + + + + Blocks Staked + + + Stakes + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + 9 + 50 + false + + + + + + + Last 24 Hours + + + 4 + + + + + + + + 9 + 50 + false + false + + + + Coin Earned in last 24H + + + 0.00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + 9 + 50 + false + false + + + + Stake Made in last 24H + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + 9 + 50 + false + + + + + + + Last 7 Days + + + 4 + + + + + + + + 9 + 50 + false + false + + + + Coin Earned in last 7 Days + + + 0.00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + 9 + 50 + false + false + + + + Stake Made in last 7 Days + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + 9 + 50 + false + + + + + + + Last 30 Days + + + 4 + + + + + + + + 9 + 50 + false + false + + + + Coin Earned in last 30 Days + + + 0.00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + 9 + 50 + false + false + + + + Stake Made in last 30 Days + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + 9 + 50 + false + + + + + + + Last 365 Days + + + 4 + + + + + + + + 9 + 50 + false + false + + + + Coin Earned in last 365 Days + + + 0.00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + 9 + 50 + false + false + + + + Stake Made in last 365 Days + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + + Qt::Horizontal + + + + + + + QLayout::SetDefaultConstraint + + + 35 + + + + + + 0 + 0 + + + + + 9 + 50 + false + + + + Date of the last mature Stake + + + Never + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + 0 + 0 + + + + + 9 + 50 + false + false + + + + Coin Earned in last mature Stake + + + 0.00 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + + + 1 + 0 + + + + + 50 + false + + + + true + + + true + + + 30 + + + 3 + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date + + + + 9 + 75 + true + + + + AlignLeft|AlignVCenter + + + + + Amount + + + + 9 + 75 + true + + + + AlignRight|AlignVCenter + + + + + Stakes + + + + 9 + 75 + true + + + + AlignRight|AlignVCenter + + + + + + + + + 9 + + + + ItemIsSelectable|ItemIsUserCheckable|ItemIsEnabled + + + + + 0 + + + + + + + 9 + + + + AlignRight|AlignVCenter + + + ItemIsSelectable|ItemIsUserCheckable|ItemIsEnabled + + + + + 0 + + + + 9 + + + + AlignRight|AlignVCenter + + + ItemIsSelectable|ItemIsUserCheckable|ItemIsEnabled + + + + + + + + 35 + + + + + + 9 + 50 + false + + + + Time took to retrieve the data + + + Wait please... + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + 9 + 50 + false + + + + Time took to refresh dialog + + + Wait please... + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + 9 + 50 + false + + + + Total Stakes Analyzed + + + 0 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + + + + 9 + 50 + false + + + + Data of the current block. + + + Current Chain Block : + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + QLayout::SetDefaultConstraint + + + + + + 0 + 0 + + + + Refresh the data + + + Refresh + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + Copy Report to ClipBoard + + + Copy to clipboard + + + + + + + + 0 + 0 + + + + Close the dialog + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + true + + + + + + + + + + + + + 263 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 276 + 161 + + + + + 276 + 161 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://yobit.net/en/trade/PROFIT/BTC/?bonus=QEOmT"><img src=":/images/res/images/yobit.png" /></a></p></body></html> + + + true + + + + + + + + 276 + 161 + + + + + 276 + 161 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://www.youtube.com/channel/UC-x4N9JU3Aoi8RyBlPQc75Q"><img src=":/images/res/images/youtube.png" /></a></p></body></html> + + + true + + + + + + + + 276 + 161 + + + + + 276 + 161 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://twitter.com/Tillkoeln"><img src=":/images/res/images/twitter.png" /></a></p></body></html> + + + true + + + + + + + + + + + + + + buttonBox + clicked(QAbstractButton*) + StakeReportDialog + close() + + + 338 + 524 + + + 215 + 276 + + + + + diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 1bfa87f..9b29804 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -428,7 +428,8 @@ HelpMessageBox::HelpMessageBox(QWidget *parent) : " -lang= " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" + " -min " + tr("Start minimized") + "\n" + " -splash " + tr("Show splash screen on startup (default: 1)") + "\n"; - + " -disablereportupdate " + tr("Disable auto update of stake report window (default: 0)") + "\n"; + setWindowTitle(tr("Project-X-Qt")); setTextFormat(Qt::PlainText); // setMinimumWidth is ignored for QMessageBox so put in non-breaking spaces to make it wider. diff --git a/src/qt/stakereportdialog.cpp b/src/qt/stakereportdialog.cpp new file mode 100644 index 0000000..598082d --- /dev/null +++ b/src/qt/stakereportdialog.cpp @@ -0,0 +1,281 @@ +//***************************************************** +// +// Dialog which report the earning made with stake over time +// Original coding by Remy5 +// + +#include "stakereportdialog.h" +#include "ui_stakereportdialog.h" + +#include "guiconstants.h" +#include "walletmodel.h" +#include "bitcoinunits.h" +#include "bitcoinrpc.h" +#include "optionsmodel.h" +#include "main.h" // for hashBestChain + +#include +#include +#include +#include + +using namespace json_spirit; +using namespace boost; +using namespace std; + +struct StakePeriodRange_T { + int64_t Start; + int64_t End; + int64_t Total; + int Count; + string Name; +}; + +typedef vector vStakePeriodRange_T; + +extern vStakePeriodRange_T PrepareRangeForStakeReport(); +extern int GetsStakeSubTotal(vStakePeriodRange_T& aRange); + +StakeReportDialog::StakeReportDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::StakeReportDialog) +{ + ui->setupUi(this); + + QTableWidget *TableW = ui->StakeReportTable; + + alreadyConnected = false; + + // fill the table with clone of row 0 + for(int y=TableW->rowCount(); --y >= 1;) + for(int x=TableW->columnCount(); --x >= 0;) + TableW->setItem(y, x, + TableW->item(0, x)->clone()); + + TableW->horizontalHeader()->resizeSection(1,160); + + QApplication::processEvents(); + + updateStakeReportNow(); // 1st update +} + +StakeReportDialog::~StakeReportDialog() +{ + delete ui; +} + +void StakeReportDialog::setModel(WalletModel *model) +{ + this->ex_model = model; + + if(ex_model && ex_model->getOptionsModel() && !alreadyConnected) + { + alreadyConnected = true; + + connect(ex_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit(int))); + connect(ui->button_Refresh, SIGNAL(clicked()), this, SLOT(updateStakeReportNow())); + connect(ui->CopytoClipboard, SIGNAL(clicked()), this, SLOT(CopyAllToClipboard())); + + disablereportupdate = GetBoolArg("-disablereportupdate"); + + if (!disablereportupdate) + { + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(updateStakeReportTimer())); + connect(ex_model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64)), this, SLOT(updateStakeReportbalanceChanged(qint64, qint64, qint64, qint64))); + + timer->start(MODEL_UPDATE_DELAY*5); + } + } +} + +void StakeReportDialog::updateStakeReportbalanceChanged(qint64, qint64, qint64, qint64) +{ + StakeReportDialog::updateStakeReportNow(); +} + +void StakeReportDialog::updateDisplayUnit(int) +{ + StakeReportDialog::updateStakeReportNow(); +} + +void StakeReportDialog::updateStakeReportTimer() +{ + static int lastBest = 0 ; + if (lastBest != nBestHeight) + { + lastBest = nBestHeight; + StakeReportDialog::updateStakeReport(false); + } +} + +void StakeReportDialog::showEvent( QShowEvent* event ) +{ + QWidget::showEvent( event ); + StakeReportDialog::updateStakeReportNow(); +} + +// Extendable localtime format +QString HalfDate(int64_t nTime, QString TimeMode="") +{ + QDateTime OrigDate = QDateTime::fromTime_t((qint32)nTime); + QString LocalDate = OrigDate.date().toString("yyyy-MM-dd"); + if (TimeMode != "") + LocalDate += " " + OrigDate.toString(TimeMode); + + return LocalDate; +} + +// format Bitcoinvalue with all trailing zero +QString Coin_0Pad(int nUnit, int64_t amount) +{ + QString result = BitcoinUnits::format(nUnit, amount); + + int poin = result.indexOf(".") + 1; + poin += BitcoinUnits::decimals(nUnit); + + return result.leftJustified(poin, '0'); +} + +void StakeReportDialog::updateStakeReportNow() +{ + updateStakeReport(true); +} + +void StakeReportDialog::updateStakeReport(bool fImmediate=false) +{ + static vStakePeriodRange_T aRange; + int nItemCounted=0; + + if (fImmediate) nLastReportUpdate = 0; + + if (this->isHidden()) + return; + + int64_t nTook = GetTimeMillis(); + + // Skip report recalc if not immediate or before 5 minutes from last + if (GetTime() - nLastReportUpdate > 300) + { + QApplication::processEvents(); + + ui->TimeTook->setText(tr("Please wait...")); + ui->TimeTook->repaint(); + QApplication::processEvents(); + + aRange = PrepareRangeForStakeReport(); + + // get subtotal calc + nItemCounted = GetsStakeSubTotal(aRange); + + nLastReportUpdate = GetTime(); + + nTook = GetTimeMillis() - nTook; + + } + + int64_t nTook2 = GetTimeMillis(); + + // actually update labels + int nDisplayUnit = BitcoinUnits::BTC; + if (ex_model && ex_model->getOptionsModel()) + nDisplayUnit = ex_model->getOptionsModel()->getDisplayUnit(); + + ui->L_Coin->setText(BitcoinUnits::name(nDisplayUnit) + " " + tr("SubTotal")); + + QTableWidget *TableW = ui->StakeReportTable; + + TableW->horizontalHeaderItem(1)->setText(BitcoinUnits::name(nDisplayUnit) + " " +tr("Amount")); + + int i=30; + + TableW->setSortingEnabled(false); + for(int y=0; yitem(y,0)->setText(HalfDate(aRange[y].Start)); + TableW->item(y,1)->setText(Coin_0Pad(nDisplayUnit, aRange[y].Total)); + TableW->item(y,2)->setText(QString::number(aRange[y].Count)); + } + TableW->setSortingEnabled(true); + + ui->Amount_24H->setText(Coin_0Pad(nDisplayUnit, aRange[i].Total) + tr(" [PROFIT]")); + ui->Stake_24H->setText(QString::number(aRange[i++].Count)); + ui->Amount_7D->setText(Coin_0Pad(nDisplayUnit, aRange[i].Total) + tr(" [PROFIT]")); + ui->Stake_7D->setText(QString::number(aRange[i++].Count)); + ui->Amount_30D->setText(Coin_0Pad(nDisplayUnit, aRange[i].Total) + tr(" [PROFIT]")); + ui->Stake_30D->setText(QString::number(aRange[i++].Count)); + ui->Amount_365D->setText(Coin_0Pad(nDisplayUnit, aRange[i].Total) + tr(" [PROFIT]")); + ui->Stake_365D->setText(QString::number(aRange[i++].Count)); + + ui->Amount_Last->setText(tr("Amount: ") + Coin_0Pad(nDisplayUnit, aRange[i].Total) + tr(" [PROFIT]")); + ui->L_LastStakeTime->setText(tr("Latest stake date: ") + HalfDate(aRange[i].Start, "hh:mm")); + + ui->Stake_Counted->setText(tr("Stakes analysed: ") + QString::number(nItemCounted)); + if (nItemCounted) + ui->TimeTook->setText(tr("Last Recalc took ") + QString::number(nTook) + "ms"); + + ui->TimeTook_2->setText(tr("Refresh took ") + QString::number(GetTimeMillis() -nTook2) + "ms"); + + string sRefreshType = disablereportupdate ? "Manual refresh" : "Auto refresh"; + + string strCurr_block_info = strprintf("%s - %s : %6d @ %s\nhash %s\n", + sRefreshType.c_str(), "Current Block", nBestHeight, + HalfDate(pindexBest->GetBlockTime(), "hh:mm:ss").toStdString().c_str(), + hashBestChain.GetHex().c_str()); + + ui->L_CurrentBlock->setText(strCurr_block_info.c_str() ); + +} + +QString GridGetLabelTextAt(QGridLayout * Grid, int row, int column, QString Empty = "") +{ + if (Grid && Grid->itemAtPosition(row, column) && + Grid->itemAtPosition(row, column)->widget()) + return ((QLabel *) Grid->itemAtPosition(row, column)->widget())->text(); + else + return Empty; +} + +void StakeReportDialog::CopyAllToClipboard() +{ + QString Repo; + + Repo += " Stake Mini Report\n"; + Repo += " ---------------------\n"; + + QString RowForm = "%1 %2 %3\n"; + + for(int y=0; ygridLayout->rowCount(); y++) + { + if (y == 5) + Repo += "\n"; // separator line + else + Repo += RowForm + .arg(GridGetLabelTextAt(ui->gridLayout, y,0), -16) + .arg(GridGetLabelTextAt(ui->gridLayout, y,1), 16) + .arg(GridGetLabelTextAt(ui->gridLayout, y,2), 7); + } + + Repo += "\n"; + + QTableWidget *TableW = ui->StakeReportTable; + RowForm = "%1, %2, %3\n"; + + Repo += RowForm + .arg(TableW->horizontalHeaderItem(0)->text(), -10) + .arg(TableW->horizontalHeaderItem(1)->text(), 16) + .arg(TableW->horizontalHeaderItem(2)->text(), 7); + + for(int y=0; y<30; y++) + { + Repo += RowForm + .arg(TableW->item(y,0)->text(), -10) + .arg(TableW->item(y,1)->text(), 16) + .arg(TableW->item(y,2)->text(), 7); + } + + Repo += "\n" + ui->L_CurrentBlock->text() + "\n"; + + QApplication::clipboard()->setText(Repo); + +} diff --git a/src/qt/stakereportdialog.h b/src/qt/stakereportdialog.h new file mode 100644 index 0000000..775ce12 --- /dev/null +++ b/src/qt/stakereportdialog.h @@ -0,0 +1,49 @@ +//***************************************************** +// +// Dialog which report the earning made with stake over time +// Original coding by Remy5 +// + +#ifndef STAKEREPORTDIALOG_H +#define STAKEREPORTDIALOG_H + +#include + +namespace Ui { +class StakeReportDialog; +} + +class WalletModel; + +class StakeReportDialog : public QDialog +{ + Q_OBJECT + +public: + explicit StakeReportDialog(QWidget *parent = 0); + ~StakeReportDialog(); + + void setModel(WalletModel *model); + void showEvent(QShowEvent* event); + +private: + Ui::StakeReportDialog *ui; + WalletModel *ex_model; + + qint64 nLastReportUpdate; + bool disablereportupdate; + bool alreadyConnected; + + void updateStakeReport(bool fImmediate); + +private slots: + void updateStakeReportTimer(); + +public slots: + void updateStakeReportbalanceChanged(qint64, qint64, qint64, qint64); + void updateStakeReportNow(); + void updateDisplayUnit(int); + void CopyAllToClipboard(); +}; + +#endif // STAKEREPORTDIALOG_H diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 21b03da..643104d 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -2017,4 +2017,170 @@ Value multisend(const Array ¶ms, bool fHelp) } } return printMultiSend(); +} + + +// getstakereport +struct StakePeriodRange_T { + int64_t Start; + int64_t End; + int64_t Total; + int Count; + string Name; +}; + +typedef vector vStakePeriodRange_T; + + // **em52: Get total coins staked on given period + // inspired from CWallet::GetStake() + // Parameter aRange = Vector with given limit date, and result + // return int = Number of Wallet's elements analyzed +int GetsStakeSubTotal(vStakePeriodRange_T& aRange) +{ + int nElement = 0; + int64_t nAmount = 0; + + const CWalletTx* pcoin; + + vStakePeriodRange_T::iterator vIt; + + // scan the entire wallet transactions + for (map::const_iterator it = pwalletMain->mapWallet.begin(); + it != pwalletMain->mapWallet.end(); + ++it) + { + pcoin = &(*it).second; + + // skip orphan block or immature + if ((!pcoin->GetDepthInMainChain()) || (pcoin->GetBlocksToMaturity()>0)) + continue; + + // skip transaction other than POS block + if (!(pcoin->IsCoinStake())) + continue; + + nElement++; + + // use the cached amount if available + if (pcoin->fCreditCached && pcoin->fDebitCached) + nAmount = pcoin->nCreditCached - pcoin->nDebitCached; + else + nAmount = pcoin->GetCredit() - pcoin->GetDebit(); + + // scan the range + for(vIt=aRange.begin(); vIt != aRange.end(); vIt++) + { + if (pcoin->nTime >= vIt->Start) + { + if (! vIt->End) + { // Manage Special case + vIt->Start = pcoin->nTime; + vIt->Total = nAmount; + } + else if (pcoin->nTime <= vIt->End) + { + vIt->Count++; + vIt->Total += nAmount; + } + } + } + + } + return nElement; +} + + // prepare range for stake report +vStakePeriodRange_T PrepareRangeForStakeReport() +{ + vStakePeriodRange_T aRange; + StakePeriodRange_T x; + + struct tm Loc_MidNight; + + int64_t n1Hour = 60*60; + int64_t n1Day = 24 * n1Hour; + + int64_t nToday = GetTime(); + time_t CurTime = nToday; + + localtime_r(&CurTime, &Loc_MidNight); + Loc_MidNight.tm_hour = 0; + Loc_MidNight.tm_min = 0; + Loc_MidNight.tm_sec = 0; // set midnight + + x.Start = mktime(&Loc_MidNight); + x.End = nToday; + x.Count = 0; + x.Total = 0; + + // prepare last single 30 day Range + for(int i=0; i<30; i++) + { + x.Name = DateTimeStrFormat(x.Start); + + aRange.push_back(x); + + x.End = x.Start - 1; + x.Start -= n1Day; + } + + // prepare subtotal range of last 24H, 1 week, 30 days, 1 years + int GroupDays[4][2] = { {1 ,0}, {7 ,0 }, {30, 0}, {365, 0}}; + string sGroupName[] = {"24H", "7 Days", "30 Days", "365 Days" }; + + nToday = GetTime(); + + for(int i=0; i<4; i++) + { + x.Start = nToday - GroupDays[i][0] * n1Day; + x.End = nToday - GroupDays[i][1] * n1Day; + x.Name = "Last " + sGroupName[i]; + + aRange.push_back(x); + } + + // Special case. not a subtotal, but last stake + x.End = 0; + x.Start = 0; + x.Name = "Latest Stake"; + aRange.push_back(x); + +return aRange; +} + + // getstakereport: return SubTotal of the staked coin in last 24H, 7 days, etc.. of all owns address +Value getstakereport(const Array& params, bool fHelp) +{ + if ((params.size()>0) || (fHelp)) + throw runtime_error( + "getstakereport\n" + "List last single 30 day stake subtotal and last 24h, 7, 30, 365 day subtotal.\n"); + + vStakePeriodRange_T aRange = PrepareRangeForStakeReport(); + + // get subtotal calc + int64_t nTook = GetTimeMillis(); + int nItemCounted = GetsStakeSubTotal(aRange); + nTook = GetTimeMillis() - nTook; + + Object result; + + vStakePeriodRange_T::iterator vIt; + + // report it + for(vIt = aRange.begin(); vIt != aRange.end(); vIt++) + { + result.push_back(Pair(vIt->Name, FormatMoney(vIt->Total).c_str())); + } + + vIt--; + result.push_back(Pair("Latest Time", + vIt->Start ? DateTimeStrFormat(vIt->Start).c_str() : + "Never")); + + // report element counted / time took + result.push_back(Pair("Stake counted", nItemCounted)); + result.push_back(Pair("time took (ms)", nTook )); + + return result; } \ No newline at end of file diff --git a/src/version.cpp b/src/version.cpp index 19e6439..bd2211e 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -8,7 +8,7 @@ // Name of client reported in the 'version' message. Report the same name // for both bitcoind and bitcoin-qt, to make it harder for attackers to // target servers or GUI users specifically. -const std::string CLIENT_NAME("NanoX-Hydra"); +const std::string CLIENT_NAME("NanoX-StakeReport"); // Client version number #define CLIENT_VERSION_SUFFIX "" @@ -37,7 +37,7 @@ const std::string CLIENT_NAME("NanoX-Hydra"); #define GIT_ARCHIVE 1 #ifdef GIT_ARCHIVE # define GIT_COMMIT_ID "" -# define GIT_COMMIT_DATE "July 24, 2014" +# define GIT_COMMIT_DATE "December 24, 2018" #endif #define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \