6 #include "ui_dashboardwidget.h"
15 #include <QGraphicsLayout>
17 #include <QModelIndex>
20 #define DECORATION_SIZE 65
22 #define SHOW_EMPTY_CHART_VIEW_THRESHOLD 4000
23 #define REQUEST_LOAD_TASK 1
24 #define CHART_LOAD_MIN_TIME_INTERVAL 15
39 this->setStyleSheet(parent->styleSheet());
40 this->setContentsMargins(0,0,0,0);
44 ui->left->setContentsMargins(0,0,0,0);
62 fontBold.setWeight(QFont::Bold);
71 ui->comboBoxMonths->setView(
new QListView());
72 ui->comboBoxMonths->setStyleSheet(
"selection-background-color:transparent;");
73 ui->comboBoxYears->setView(
new QListView());
74 ui->comboBoxYears->setStyleSheet(
"selection-background-color:transparent;");
75 ui->pushButtonYear->setChecked(
true);
82 ui->right->setContentsMargins(20,20,20,0);
83 connect(
ui->comboBoxYears,
static_cast<void (QComboBox::*)(
const QString&)
>(&QComboBox::currentTextChanged),
84 this, &DashboardWidget::onChartYearChanged);
87 ui->right->setVisible(
false);
100 ui->comboBoxSortType->setCurrentIndex(0);
101 connect(
ui->comboBoxSortType,
static_cast<void (QComboBox::*)(
const QString&)
>(&QComboBox::currentTextChanged),
109 ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect,
false);
110 ui->listTransactions->setSelectionBehavior(QAbstractItemView::SelectRows);
111 ui->listTransactions->setUniformItemSizes(
true);
114 ui->layoutWarning->setVisible(
true);
115 ui->lblWarning->setText(tr(
"Please wait until the wallet is fully synced to see your correct balance"));
120 ui->emptyContainer->setVisible(
false);
132 ui->layoutChart->setVisible(
false);
133 ui->emptyContainerChart->setVisible(
true);
138 bool hasCharts =
false;
143 connect(
ui->pushButtonYear, &QPushButton::clicked, [
this](){setChartShow(YEAR);});
144 connect(
ui->pushButtonMonth, &QPushButton::clicked, [
this](){setChartShow(MONTH);});
145 connect(
ui->pushButtonAll, &QPushButton::clicked, [
this](){setChartShow(ALL);});
151 ui->labelEmptyChart->setText(tr(
"You have no staking rewards"));
153 ui->labelEmptyChart->setText(tr(
"No charts library"));
159 ui->listTransactions->setCurrentIndex(index);
160 QModelIndex rIndex =
filter->mapToSource(index);
168 ui->listTransactions->scrollTo(index);
169 ui->listTransactions->clearSelection();
170 ui->listTransactions->setFocus();
171 dialog->deleteLater();
180 filter->setDynamicSortFilter(
true);
181 filter->setSortCaseSensitivity(Qt::CaseInsensitive);
182 filter->setFilterCaseSensitivity(Qt::CaseInsensitive);
183 filter->setSortRole(Qt::EditRole);
188 int filterIndex =
ui->comboBoxSortType->findData(filterByType);
191 ui->comboBoxSortType->setCurrentIndex(filterIndex);
197 ui->listTransactions->setModel(
filter);
201 ui->emptyContainer->setVisible(
true);
202 ui->listTransactions->setVisible(
false);
203 ui->comboBoxSortType->setVisible(
false);
204 ui->comboBoxSort->setVisible(
false);
207 connect(
ui->pushImgEmpty, &QPushButton::clicked, [
this](){window->openFAQ();});
208 connect(
ui->btnHowTo, &QPushButton::clicked, [
this](){window->openFAQ();});
216 &DashboardWidget::onHideChartsChanged);
226 if (!isVisible())
return;
228 if (isCoinStake || isMNReward) {
230 if (!hasStakes && stakesFilter)
231 hasStakes = stakesFilter->rowCount() > 0;
240 ui->emptyContainer->setVisible(
true);
241 ui->listTransactions->setVisible(
false);
242 ui->comboBoxSortType->setVisible(
false);
243 ui->comboBoxSort->setVisible(
false);
245 ui->emptyContainer->setVisible(
false);
246 ui->listTransactions->setVisible(
true);
247 ui->comboBoxSortType->setVisible(
true);
248 ui->comboBoxSort->setVisible(
true);
257 ui->listTransactions->update();
265 if (!value.isNull()) {
275 Qt::SortOrder order = Qt::DescendingOrder;
277 switch (nSortIndex) {
286 order = Qt::AscendingOrder;
297 order = Qt::AscendingOrder;
302 ui->comboBoxSort->setCurrentIndex(nSortIndex);
303 filter->sort(nColumnIndex, order);
307 settings.setValue(
"transactionSort", nSortIndex);
313 int filterIndex =
ui->comboBoxSortType->currentIndex();
314 int filterByType =
ui->comboBoxSortType->itemData(filterIndex).toInt();
317 ui->listTransactions->update();
320 ui->emptyContainer->setVisible(
true);
321 ui->listTransactions->setVisible(
false);
328 settings.setValue(
"transactionType", filterByType);
333 if (this->
isSync != sync) {
335 ui->layoutWarning->setVisible(!this->
isSync);
337 if (!isVisible())
return;
347 if (chart) this->changeChartColors();
353 void DashboardWidget::tryChartRefresh()
366 if (lastRefreshTime + chartLoadIntervalTime < now) {
367 lastRefreshTime = now;
376 this->chartShow = type;
377 if (chartShow ==
MONTH) {
378 ui->containerChartArrow->setVisible(
true);
380 ui->containerChartArrow->setVisible(
false);
382 if (isChartInitialized) refreshChart();
385 const QStringList monthsNames = {QObject::tr(
"Jan"), QObject::tr(
"Feb"), QObject::tr(
"Mar"), QObject::tr(
"Apr"),
386 QObject::tr(
"May"), QObject::tr(
"Jun"), QObject::tr(
"Jul"), QObject::tr(
"Aug"),
387 QObject::tr(
"Sep"), QObject::tr(
"Oct"), QObject::tr(
"Nov"), QObject::tr(
"Dec")};
393 showHideEmptyChart(
false,
false);
395 QDate currentDate = QDate::currentDate();
396 monthFilter = currentDate.month();
397 yearFilter = currentDate.year();
398 for (
int i = 1; i < 13; ++i)
ui->comboBoxMonths->addItem(QString(monthsNames[i-1]), QVariant(i));
399 ui->comboBoxMonths->setCurrentIndex(monthFilter - 1);
400 connect(
ui->comboBoxMonths,
static_cast<void (QComboBox::*)(
const QString&)
>(&QComboBox::currentTextChanged),
401 this, &DashboardWidget::onChartMonthChanged);
402 connect(
ui->pushButtonChartArrow, &QPushButton::clicked, [
this](){ onChartArrowClicked(true); });
403 connect(
ui->pushButtonChartRight, &QPushButton::clicked, [
this](){ onChartArrowClicked(false); });
408 showHideEmptyChart(
true,
false);
412 void DashboardWidget::showHideEmptyChart(
bool showEmpty,
bool loading,
bool forceView)
415 ui->layoutChart->setVisible(!showEmpty);
416 ui->emptyContainerChart->setVisible(showEmpty);
419 bool invLoading = !loading;
420 ui->comboBoxMonths->setEnabled(invLoading);
421 ui->comboBoxYears->setEnabled(invLoading);
422 ui->pushButtonMonth->setEnabled(invLoading);
423 ui->pushButtonAll->setEnabled(invLoading);
424 ui->pushButtonYear->setEnabled(invLoading);
425 ui->labelEmptyChart->setText(loading ? tr(
"Loading chart..") : tr(
"You have no staking rewards"));
428 void DashboardWidget::initChart()
430 chart =
new QChart();
431 axisX =
new QBarCategoryAxis();
432 axisY =
new QValueAxis();
435 chart->legend()->setVisible(
false);
436 chart->legend()->setAlignment(Qt::AlignTop);
437 chart->layout()->setContentsMargins(0, 0, 0, 0);
438 chart->setMargins({0, 0, 0, 0});
439 chart->setBackgroundRoundness(0);
441 chart->addAxis(axisX, Qt::AlignBottom);
442 chart->addAxis(axisY, Qt::AlignRight);
443 chart->setAnimationOptions(QChart::SeriesAnimations);
445 chartView =
new QChartView(chart);
446 chartView->setRenderHint(QPainter::Antialiasing);
447 chartView->setRubberBand( QChartView::HorizontalRubberBand );
448 chartView->setContentsMargins(0,0,0,0);
450 QHBoxLayout *baseScreensContainer =
new QHBoxLayout(
this);
451 baseScreensContainer->setMargin(0);
452 baseScreensContainer->addWidget(chartView);
453 ui->chartContainer->setLayout(baseScreensContainer);
454 ui->chartContainer->setContentsMargins(0,0,0,0);
458 void DashboardWidget::changeChartColors()
460 QColor gridLineColorX;
461 QColor linePenColorY;
462 QColor backgroundColor;
465 gridLineColorX = QColor(255,255,255);
466 linePenColorY = gridLineColorX;
467 backgroundColor = linePenColorY;
468 axisY->setGridLineColor(QColor(
"#1a000000"));
470 gridY = QColor(
"#40ffffff");
471 axisY->setGridLineColor(gridY);
472 gridLineColorX = QColor(15,11,22);
473 linePenColorY = gridLineColorX;
474 backgroundColor = linePenColorY;
477 axisX->setGridLineColor(gridLineColorX);
478 axisY->setLinePenColor(linePenColorY);
479 chart->setBackgroundBrush(QBrush(backgroundColor));
480 if (set0) set0->setBorderColor(gridLineColorX);
481 if (set1) set1->setBorderColor(gridLineColorX);
484 void DashboardWidget::updateStakeFilter()
486 if (!stakesFilter)
return;
487 if (chartShow !=
ALL) {
488 bool filterByMonth =
false;
489 if (monthFilter != 0 && chartShow ==
MONTH) {
490 filterByMonth =
true;
492 if (yearFilter != 0) {
494 QDate monthFirst = QDate(yearFilter, monthFilter, 1);
495 QDate monthLast = QDate(yearFilter, monthFilter, monthFirst.daysInMonth());
496 stakesFilter->setDateRange(
497 QDateTime(monthFirst),
498 QDateTime(monthLast).addSecs(86399)
501 stakesFilter->setDateRange(
502 QDateTime(QDate(yearFilter, 1, 1)),
503 QDateTime(QDate(yearFilter, 12, 31))
506 }
else if (filterByMonth) {
507 QDate currentDate = QDate::currentDate();
508 QDate monthFirst = QDate(currentDate.year(), monthFilter, 1);
509 stakesFilter->setDateRange(
510 QDateTime(monthFirst),
511 QDateTime(QDate(currentDate.year(), monthFilter, monthFirst.daysInMonth()))
513 ui->comboBoxYears->setCurrentText(QString::number(currentDate.year()));
515 stakesFilter->clearDateRange();
518 stakesFilter->clearDateRange();
523 QMap<int, std::pair<qint64, qint64>> DashboardWidget::getAmountBy()
525 if (filterUpdateNeeded) {
526 filterUpdateNeeded =
false;
529 const int size = stakesFilter->rowCount();
530 QMap<int, std::pair<qint64, qint64>> amountBy;
532 for (
int i = 0; i < size; ++i) {
553 inform(tr(
"Error loading chart, invalid show option"));
556 if (amountBy.contains(time)) {
558 amountBy[time].first += amount;
560 amountBy[time].second += amount;
563 amountBy[time] = std::make_pair(amount, 0);
565 amountBy[time] = std::make_pair(0, amount);
573 bool DashboardWidget::loadChartData(
bool withMonthNames)
581 chartData->amountsByCache = getAmountBy();
583 std::pair<int,int> range = getChartRange(chartData->amountsByCache);
584 if (range.first == 0 && range.second == 0) {
589 bool isOrderedByMonth = chartShow ==
MONTH;
590 int daysInMonth = QDate(yearFilter, monthFilter, 1).daysInMonth();
592 for (
int j = range.first; j < range.second; j++) {
593 int num = (isOrderedByMonth && j > daysInMonth) ? (j % daysInMonth) : j;
596 if (chartData->amountsByCache.contains(num)) {
597 std::pair <qint64, qint64> pair = chartData->amountsByCache[num];
598 piv = (pair.first != 0) ? pair.first / 100000000 : 0;
599 mn = (pair.second != 0) ? pair.second / 100000000 : 0;
600 chartData->totalPiv += pair.first;
601 chartData->totalMN += pair.second;
604 chartData->xLabels << ((withMonthNames) ? monthsNames[num - 1] : QString::number(num));
606 chartData->valuesPiv.append(piv);
607 chartData->valuesMN.append(mn);
609 int max = std::max(piv, mn);
610 if (max > chartData->maxValue) {
611 chartData->maxValue = max;
618 void DashboardWidget::onChartYearChanged(
const QString& yearStr)
620 if (isChartInitialized) {
621 int newYear = yearStr.toInt();
622 if (newYear != yearFilter) {
623 yearFilter = newYear;
624 filterUpdateNeeded =
true;
630 void DashboardWidget::onChartMonthChanged(
const QString& monthStr)
632 if (isChartInitialized) {
633 int newMonth =
ui->comboBoxMonths->currentData().toInt();
634 if (newMonth != monthFilter) {
635 monthFilter = newMonth;
636 filterUpdateNeeded =
true;
640 chart->removeSeries(series);
641 chart->addSeries(series);
647 bool DashboardWidget::refreshChart()
649 if (isLoading)
return false;
651 isChartMin = width() < 1300;
652 isChartInitialized =
false;
653 showHideEmptyChart(
true,
true);
657 void DashboardWidget::onChartRefreshed()
662 series->detachAxis(axisX);
663 series->detachAxis(axisY);
668 set0 =
new QBarSet(tr(
"Stakes"));
669 set1 =
new QBarSet(tr(
"MN"));
670 set0->setColor(QColor(92,75,125));
671 set1->setColor(QColor(176,136,255));
674 series =
new QBarSeries();
675 chart->addSeries(series);
677 series->attachAxis(axisX);
678 series->attachAxis(axisY);
680 set0->append(chartData->valuesPiv);
681 set1->append(chartData->valuesMN);
685 if (chartData->totalPiv > 0 || chartData->totalMN > 0) {
696 series->append(set0);
698 series->append(set1);
701 if (chartShow ==
YEAR)
702 series->setBarWidth(0.8);
704 series->setBarWidth(0.3);
706 axisX->append(chartData->xLabels);
707 axisY->setRange(0, chartData->maxValue);
712 ui->container_chart_dropboxes->setVisible(
false);
716 ui->container_chart_dropboxes->setVisible(
true);
717 ui->containerBoxMonths->setVisible(
false);
721 ui->container_chart_dropboxes->setVisible(
true);
722 ui->containerBoxMonths->setVisible(
true);
730 int currentYear = QDateTime::currentDateTime().date().year();
733 if (
ui->comboBoxYears->count() > 0) {
734 selection =
ui->comboBoxYears->currentText();
735 isChartInitialized =
false;
737 ui->comboBoxYears->clear();
738 if (yearStart == currentYear) {
739 ui->comboBoxYears->addItem(QString::number(currentYear));
741 for (
int i = yearStart; i < (currentYear + 1); ++i)
ui->comboBoxYears->addItem(QString::number(i));
744 if (!selection.isEmpty()) {
745 ui->comboBoxYears->setCurrentText(selection);
746 isChartInitialized =
true;
748 ui->comboBoxYears->setCurrentText(QString::number(currentYear));
752 isChartInitialized =
true;
753 showHideEmptyChart(
false,
false,
true);
757 std::pair<int, int> DashboardWidget::getChartRange(
const QMap<
int, std::pair<qint64, qint64>>& amountsBy)
761 return std::make_pair(1, 13);
763 QList<int> keys = amountsBy.uniqueKeys();
764 if (keys.isEmpty()) {
766 inform(tr(
"Error loading chart, invalid data"));
767 return std::make_pair(0, 0);
769 std::sort(keys.begin(), keys.end());
770 return std::make_pair(keys.first(), keys.last() + 1);
773 return std::make_pair(dayStart, dayStart + 9);
775 inform(tr(
"Error loading chart, invalid show option"));
776 return std::make_pair(0, 0);
780 void DashboardWidget::updateAxisX(
const QStringList* args)
784 std::pair<int,int> range = getChartRange(chartData->amountsByCache);
788 for (
int i = range.first; i < range.second; i++) months << QString::number(i);
790 axisX->append(months);
793 void DashboardWidget::onChartArrowClicked(
bool goLeft)
795 bool updateMonth =
false;
796 bool updateYear =
false;
797 int dataenddate = getChartRange(chartData->amountsByCache).second;
798 QDate currentDate = QDate::currentDate();
803 if (monthFilter == 1) {
811 dayStart = QDate(yearFilter, monthFilter, 1).daysInMonth();
814 int dayInMonth = QDate(yearFilter, monthFilter, dayStart).daysInMonth();
816 if (dayStart > dayInMonth) {
819 if (monthFilter == 12) {
829 filterUpdateNeeded =
true;
832 bool fEndDayisCurrent = dataenddate == currentDate.day() && monthFilter == currentDate.month();
835 ui->comboBoxMonths->setCurrentIndex(monthFilter - 1);
838 ui->comboBoxYears->setCurrentText(QString::number(yearFilter));
841 ui->pushButtonChartRight->setEnabled(!fEndDayisCurrent);
846 void DashboardWidget::windowResizeEvent(QResizeEvent* event)
848 if (hasStakes && axisX) {
849 if (width() > 1300) {
854 updateAxisX(&monthsNames);
863 inform(tr(
"Error loading chart, invalid show option"));
866 chartView->repaint();
877 void DashboardWidget::onHideChartsChanged(
bool fHide)
879 fShowCharts = !fHide;
884 stakesFilter->setDynamicSortFilter(
false);
885 stakesFilter->setSortCaseSensitivity(Qt::CaseInsensitive);
886 stakesFilter->setFilterCaseSensitivity(Qt::CaseInsensitive);
893 stakesFilter->setSourceModel(
txModel);
894 hasStakes = stakesFilter->rowCount() > 0;
895 filterUpdateNeeded =
true;
898 stakesFilter->setSourceModel(
nullptr);
903 ui->right->setVisible(fShowCharts);
904 if (fShowCharts) tryChartRefresh();
913 bool withMonthNames = !isChartMin && (chartShow ==
YEAR);
914 if (loadChartData(withMonthNames))
915 QMetaObject::invokeMethod(
this,
"onChartRefreshed", Qt::QueuedConnection);
bool inInitialBlockDownload() const
Return true if core is doing initial block download.
FurListRow * getRowFactory()
void hideChartsChanged(bool)
void windowResizeEvent(QResizeEvent *event)
Filter the transaction list according to pre-specified rules.
static const quint32 ALL_TYPES
Type filter bit field (all types)
int rowCount(const QModelIndex &parent=QModelIndex()) const
static quint32 TYPE(int type)
void setTypeFilter(quint32 modes)
@ TypeRole
Type of transaction.
@ DateRole
Date and time this transaction was created.
@ AmountRole
Net amount of transaction.
void txArrived(const QString &hash, const bool isCoinStake, const bool isMNReward, const bool isCSAnyType)
bool processingQueuedTransactions() const
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void setData(WalletModel *model, WalletModelTransaction *tx)
void setFilter(TransactionFilterProxy *_filter)
void setDisplayUnit(int displayUnit)
OptionsModel * getOptionsModel()
int64_t getCreationTime() const
TransactionTableModel * getTransactionTableModel()
QString formatBalance(CAmount amount, int nDisplayUnit, bool isZpiv)
void forceUpdateStyle(QWidget *widget, bool forceUpdate)
bool openDialogWithOpaqueBackgroundY(QDialog *widget, PIVXGUI *gui, double posX, int posY, bool hideOpaqueBackground)
void setCssTitleScreen(QLabel *label)
void setSortTxTypeFilter(QComboBox *filter, SortEdit *lineEditType)
void setShadow(QWidget *edit)
void setCssProperty(std::initializer_list< QWidget * > args, const QString &value)
void setCssSubtitleScreen(QWidget *wid)
void setSortTx(QComboBox *filter, SortEdit *lineEdit)
void setCssBtnSecondary(QPushButton *btn, bool forceUpdate)
bool error(const char *fmt, const Args &... args)
int64_t GetTime()
DEPRECATED Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable)