Line data Source code
1 : // Copyright (c) 2011-2013 The Bitcoin Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #include "overviewpage.h"
6 : #include "ui_overviewpage.h"
7 :
8 : #include "bitcoinunits.h"
9 : #include "clientmodel.h"
10 : #include "guiconstants.h"
11 : #include "guiutil.h"
12 : #include "optionsmodel.h"
13 : #include "platformstyle.h"
14 : #include "transactionfilterproxy.h"
15 : #include "transactiontablemodel.h"
16 : #include "walletmodel.h"
17 :
18 : #include <QAbstractItemDelegate>
19 : #include <QPainter>
20 :
21 : #define DECORATION_SIZE 54
22 : #define NUM_ITEMS 5
23 :
24 0 : class TxViewDelegate : public QAbstractItemDelegate
25 : {
26 : Q_OBJECT
27 : public:
28 0 : TxViewDelegate(const PlatformStyle *platformStyle):
29 : QAbstractItemDelegate(), unit(BitcoinUnits::BTC),
30 0 : platformStyle(platformStyle)
31 : {
32 :
33 0 : }
34 :
35 0 : inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
36 : const QModelIndex &index ) const
37 : {
38 0 : painter->save();
39 :
40 0 : QIcon icon = qvariant_cast<QIcon>(index.data(TransactionTableModel::RawDecorationRole));
41 0 : QRect mainRect = option.rect;
42 0 : QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE));
43 0 : int xspace = DECORATION_SIZE + 8;
44 0 : int ypad = 6;
45 0 : int halfheight = (mainRect.height() - 2*ypad)/2;
46 0 : QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight);
47 0 : QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight);
48 0 : icon = platformStyle->SingleColorIcon(icon);
49 0 : icon.paint(painter, decorationRect);
50 :
51 0 : QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime();
52 0 : QString address = index.data(Qt::DisplayRole).toString();
53 0 : qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong();
54 0 : bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool();
55 0 : QVariant value = index.data(Qt::ForegroundRole);
56 0 : QColor foreground = option.palette.color(QPalette::Text);
57 0 : if(value.canConvert<QBrush>())
58 : {
59 0 : QBrush brush = qvariant_cast<QBrush>(value);
60 0 : foreground = brush.color();
61 : }
62 :
63 0 : painter->setPen(foreground);
64 : QRect boundingRect;
65 0 : painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address, &boundingRect);
66 :
67 0 : if (index.data(TransactionTableModel::WatchonlyRole).toBool())
68 : {
69 0 : QIcon iconWatchonly = qvariant_cast<QIcon>(index.data(TransactionTableModel::WatchonlyDecorationRole));
70 0 : QRect watchonlyRect(boundingRect.right() + 5, mainRect.top()+ypad+halfheight, 16, halfheight);
71 0 : iconWatchonly.paint(painter, watchonlyRect);
72 : }
73 :
74 0 : if(amount < 0)
75 : {
76 0 : foreground = COLOR_NEGATIVE;
77 : }
78 0 : else if(!confirmed)
79 : {
80 0 : foreground = COLOR_UNCONFIRMED;
81 : }
82 : else
83 : {
84 0 : foreground = option.palette.color(QPalette::Text);
85 : }
86 0 : painter->setPen(foreground);
87 0 : QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true, BitcoinUnits::separatorAlways);
88 0 : if(!confirmed)
89 : {
90 0 : amountText = QString("[") + amountText + QString("]");
91 : }
92 0 : painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText);
93 :
94 0 : painter->setPen(option.palette.color(QPalette::Text));
95 0 : painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));
96 :
97 0 : painter->restore();
98 0 : }
99 :
100 0 : inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
101 : {
102 0 : return QSize(DECORATION_SIZE, DECORATION_SIZE);
103 : }
104 :
105 : int unit;
106 : const PlatformStyle *platformStyle;
107 :
108 : };
109 : #include "overviewpage.moc"
110 :
111 0 : OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
112 : QWidget(parent),
113 0 : ui(new Ui::OverviewPage),
114 : clientModel(0),
115 : walletModel(0),
116 : currentBalance(-1),
117 : currentUnconfirmedBalance(-1),
118 : currentImmatureBalance(-1),
119 : currentWatchOnlyBalance(-1),
120 : currentWatchUnconfBalance(-1),
121 : currentWatchImmatureBalance(-1),
122 0 : txdelegate(new TxViewDelegate(platformStyle)),
123 0 : filter(0)
124 : {
125 0 : ui->setupUi(this);
126 :
127 : // use a SingleColorIcon for the "out of sync warning" icon
128 0 : QIcon icon = platformStyle->SingleColorIcon(":/icons/warning");
129 0 : icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503)
130 0 : ui->labelTransactionsStatus->setIcon(icon);
131 0 : ui->labelWalletStatus->setIcon(icon);
132 :
133 : // Recent transactions
134 0 : ui->listTransactions->setItemDelegate(txdelegate);
135 0 : ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
136 0 : ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
137 0 : ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);
138 :
139 0 : connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex)));
140 :
141 : // start with displaying the "out of sync" warnings
142 0 : showOutOfSyncWarning(true);
143 0 : }
144 :
145 0 : void OverviewPage::handleTransactionClicked(const QModelIndex &index)
146 : {
147 0 : if(filter)
148 0 : Q_EMIT transactionClicked(filter->mapToSource(index));
149 0 : }
150 :
151 0 : OverviewPage::~OverviewPage()
152 : {
153 0 : delete ui;
154 0 : }
155 :
156 0 : void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance)
157 : {
158 0 : int unit = walletModel->getOptionsModel()->getDisplayUnit();
159 0 : currentBalance = balance;
160 0 : currentUnconfirmedBalance = unconfirmedBalance;
161 0 : currentImmatureBalance = immatureBalance;
162 0 : currentWatchOnlyBalance = watchOnlyBalance;
163 0 : currentWatchUnconfBalance = watchUnconfBalance;
164 0 : currentWatchImmatureBalance = watchImmatureBalance;
165 0 : ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways));
166 0 : ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance, false, BitcoinUnits::separatorAlways));
167 0 : ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, immatureBalance, false, BitcoinUnits::separatorAlways));
168 0 : ui->labelTotal->setText(BitcoinUnits::formatWithUnit(unit, balance + unconfirmedBalance + immatureBalance, false, BitcoinUnits::separatorAlways));
169 0 : ui->labelWatchAvailable->setText(BitcoinUnits::formatWithUnit(unit, watchOnlyBalance, false, BitcoinUnits::separatorAlways));
170 0 : ui->labelWatchPending->setText(BitcoinUnits::formatWithUnit(unit, watchUnconfBalance, false, BitcoinUnits::separatorAlways));
171 0 : ui->labelWatchImmature->setText(BitcoinUnits::formatWithUnit(unit, watchImmatureBalance, false, BitcoinUnits::separatorAlways));
172 0 : ui->labelWatchTotal->setText(BitcoinUnits::formatWithUnit(unit, watchOnlyBalance + watchUnconfBalance + watchImmatureBalance, false, BitcoinUnits::separatorAlways));
173 :
174 : // only show immature (newly mined) balance if it's non-zero, so as not to complicate things
175 : // for the non-mining users
176 0 : bool showImmature = immatureBalance != 0;
177 0 : bool showWatchOnlyImmature = watchImmatureBalance != 0;
178 :
179 : // for symmetry reasons also show immature label when the watch-only one is shown
180 0 : ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature);
181 0 : ui->labelImmatureText->setVisible(showImmature || showWatchOnlyImmature);
182 0 : ui->labelWatchImmature->setVisible(showWatchOnlyImmature); // show watch-only immature balance
183 0 : }
184 :
185 : // show/hide watch-only labels
186 0 : void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly)
187 : {
188 0 : ui->labelSpendable->setVisible(showWatchOnly); // show spendable label (only when watch-only is active)
189 0 : ui->labelWatchonly->setVisible(showWatchOnly); // show watch-only label
190 0 : ui->lineWatchBalance->setVisible(showWatchOnly); // show watch-only balance separator line
191 0 : ui->labelWatchAvailable->setVisible(showWatchOnly); // show watch-only available balance
192 0 : ui->labelWatchPending->setVisible(showWatchOnly); // show watch-only pending balance
193 0 : ui->labelWatchTotal->setVisible(showWatchOnly); // show watch-only total balance
194 :
195 0 : if (!showWatchOnly)
196 0 : ui->labelWatchImmature->hide();
197 0 : }
198 :
199 0 : void OverviewPage::setClientModel(ClientModel *model)
200 : {
201 0 : this->clientModel = model;
202 0 : if(model)
203 : {
204 : // Show warning if this is a prerelease version
205 0 : connect(model, SIGNAL(alertsChanged(QString)), this, SLOT(updateAlerts(QString)));
206 0 : updateAlerts(model->getStatusBarWarnings());
207 : }
208 0 : }
209 :
210 0 : void OverviewPage::setWalletModel(WalletModel *model)
211 : {
212 0 : this->walletModel = model;
213 0 : if(model && model->getOptionsModel())
214 : {
215 : // Set up transaction list
216 0 : filter = new TransactionFilterProxy();
217 0 : filter->setSourceModel(model->getTransactionTableModel());
218 0 : filter->setLimit(NUM_ITEMS);
219 0 : filter->setDynamicSortFilter(true);
220 0 : filter->setSortRole(Qt::EditRole);
221 0 : filter->setShowInactive(false);
222 0 : filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);
223 :
224 0 : ui->listTransactions->setModel(filter);
225 0 : ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
226 :
227 : // Keep up to date with wallet
228 0 : setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(),
229 0 : model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance());
230 0 : connect(model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)));
231 :
232 0 : connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
233 :
234 0 : updateWatchOnlyLabels(model->haveWatchOnly());
235 0 : connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyLabels(bool)));
236 : }
237 :
238 : // update the display unit, to not use the default ("BTC")
239 0 : updateDisplayUnit();
240 0 : }
241 :
242 0 : void OverviewPage::updateDisplayUnit()
243 : {
244 0 : if(walletModel && walletModel->getOptionsModel())
245 : {
246 0 : if(currentBalance != -1)
247 : setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance,
248 0 : currentWatchOnlyBalance, currentWatchUnconfBalance, currentWatchImmatureBalance);
249 :
250 : // Update txdelegate->unit with the current unit
251 0 : txdelegate->unit = walletModel->getOptionsModel()->getDisplayUnit();
252 :
253 0 : ui->listTransactions->update();
254 : }
255 0 : }
256 :
257 0 : void OverviewPage::updateAlerts(const QString &warnings)
258 : {
259 0 : this->ui->labelAlerts->setVisible(!warnings.isEmpty());
260 0 : this->ui->labelAlerts->setText(warnings);
261 0 : }
262 :
263 0 : void OverviewPage::showOutOfSyncWarning(bool fShow)
264 : {
265 0 : ui->labelWalletStatus->setVisible(fShow);
266 0 : ui->labelTransactionsStatus->setVisible(fShow);
267 0 : }
|