1 #include <qt/superstakerpage.h>
2 #include <qt/forms/ui_superstakerpage.h>
3 #include <qt/superstakeritemmodel.h>
4 #include <qt/walletmodel.h>
5 #include <qt/platformstyle.h>
6 #include <qt/styleSheet.h>
7 #include <qt/superstakerlistwidget.h>
8 #include <qt/guiutil.h>
9 #include <qt/editsuperstakerdialog.h>
10 
11 #include <QPainter>
12 #include <QAbstractItemDelegate>
13 #include <QStandardItem>
14 #include <QStandardItemModel>
15 #include <QSortFilterProxyModel>
16 #include <QSizePolicy>
17 #include <QMenu>
18 #include <QMessageBox>
19 
SuperStakerPage(const PlatformStyle * platformStyle,QWidget * parent)20 SuperStakerPage::SuperStakerPage(const PlatformStyle *platformStyle, QWidget *parent) :
21     QWidget(parent),
22     ui(new Ui::SuperStakerPage),
23     m_model(0),
24     m_clientModel(0)
25 {
26     ui->setupUi(this);
27 
28     m_platformStyle = platformStyle;
29 
30     m_configSuperStakerPage = new SuperStakerConfigDialog(this);
31     m_addSuperStakerPage = new AddSuperStakerPage(this);
32     m_delegationsSuperStakerPage = new DelegationsStakerDialog(this);
33     m_splitUtxoPage = new SplitUTXOPage(this, SplitUTXOPage::SuperStaker);
34 
35     m_configSuperStakerPage->setEnabled(false);
36     m_delegationsSuperStakerPage->setEnabled(false);
37     m_splitUtxoPage->setEnabled(false);
38 
39     QAction *copyStakerNameAction = new QAction(tr("Copy staker name"), this);
40     QAction *copyStakerAddressAction = new QAction(tr("Copy staker address"), this);
41     QAction *copyStekerMinFeeAction = new QAction(tr("Copy staker minimum fee"), this);
42     QAction *copyStekerWeightAction = new QAction(tr("Copy staker weight"), this);
43     QAction *copyDelegationsWeightAction = new QAction(tr("Copy delegations weight"), this);
44     QAction *configSuperStakerAction = new QAction(tr("Configure super staker"), this);
45     QAction *editStakerNameAction = new QAction(tr("Edit staker name"), this);
46     QAction *removeSuperStakerAction = new QAction(tr("Remove super staker"), this);
47 
48     m_superStakerList = new SuperStakerListWidget(platformStyle, this);
49     m_superStakerList->setContextMenuPolicy(Qt::CustomContextMenu);
50     new QVBoxLayout(ui->scrollArea);
51     ui->scrollArea->setWidget(m_superStakerList);
52     ui->scrollArea->setWidgetResizable(true);
53     connect(m_superStakerList, &SuperStakerListWidget::configSuperStaker, this, &SuperStakerPage::on_configSuperStaker);
54     connect(m_superStakerList, &SuperStakerListWidget::addSuperStaker, this, &SuperStakerPage::on_addSuperStaker);
55     connect(m_superStakerList, &SuperStakerListWidget::removeSuperStaker, this, &SuperStakerPage::on_removeSuperStaker);
56     connect(m_superStakerList, &SuperStakerListWidget::delegationsSuperStaker, this, &SuperStakerPage::on_delegationsSuperStaker);
57     connect(m_superStakerList, &SuperStakerListWidget::splitCoins, this, &SuperStakerPage::on_splitCoins);
58     connect(m_superStakerList, &SuperStakerListWidget::restoreSuperStakers, this, &SuperStakerPage::on_restoreSuperStakers);
59 
60     contextMenu = new QMenu(m_superStakerList);
61     contextMenu->addAction(copyStakerNameAction);
62     contextMenu->addAction(copyStakerAddressAction);
63     contextMenu->addAction(copyStekerWeightAction);
64     contextMenu->addAction(copyDelegationsWeightAction);
65     contextMenu->addAction(copyStekerMinFeeAction);
66     contextMenu->addAction(configSuperStakerAction);
67     contextMenu->addAction(editStakerNameAction);
68     contextMenu->addAction(removeSuperStakerAction);
69 
70     connect(copyStakerNameAction, &QAction::triggered, this, &SuperStakerPage::copyStakerName);
71     connect(copyStakerAddressAction, &QAction::triggered, this, &SuperStakerPage::copyStakerAddress);
72     connect(copyStekerMinFeeAction, &QAction::triggered, this, &SuperStakerPage::copyStekerMinFee);
73     connect(copyStekerWeightAction, &QAction::triggered, this, &SuperStakerPage::copyStakerWeight);
74     connect(copyDelegationsWeightAction, &QAction::triggered, this, &SuperStakerPage::copyDelegationsWeight);
75     connect(configSuperStakerAction, &QAction::triggered, this, &SuperStakerPage::configSuperStaker);
76     connect(editStakerNameAction, &QAction::triggered, this, &SuperStakerPage::editStakerName);
77     connect(removeSuperStakerAction, &QAction::triggered, this, &SuperStakerPage::removeSuperStaker);
78 
79     connect(m_superStakerList, &SuperStakerListWidget::customContextMenuRequested, this, &SuperStakerPage::contextualMenu);
80 }
81 
~SuperStakerPage()82 SuperStakerPage::~SuperStakerPage()
83 {
84     delete ui;
85 }
86 
setModel(WalletModel * _model)87 void SuperStakerPage::setModel(WalletModel *_model)
88 {
89     m_model = _model;
90     m_addSuperStakerPage->setModel(m_model);
91     m_configSuperStakerPage->setModel(m_model);
92     m_delegationsSuperStakerPage->setModel(m_model);
93     m_superStakerList->setModel(m_model);
94     m_splitUtxoPage->setModel(m_model);
95     if(m_model && m_model->getSuperStakerItemModel())
96     {
97         // Set current super staker
98         connect(m_superStakerList->superStakerModel(), &QAbstractItemModel::dataChanged, this, &SuperStakerPage::on_dataChanged);
99         connect(m_superStakerList->superStakerModel(), &QAbstractItemModel::rowsInserted, this, &SuperStakerPage::on_rowsInserted);
100         if(m_superStakerList->superStakerModel()->rowCount() > 0)
101         {
102             QModelIndex currentSuperStaker(m_superStakerList->superStakerModel()->index(0, 0));
103             on_currentSuperStakerChanged(currentSuperStaker);
104         }
105     }
106 }
107 
setClientModel(ClientModel * _clientModel)108 void SuperStakerPage::setClientModel(ClientModel *_clientModel)
109 {
110     m_clientModel = _clientModel;
111     m_configSuperStakerPage->setClientModel(_clientModel);
112     m_superStakerList->setClientModel(_clientModel);
113 }
114 
on_goToConfigSuperStakerPage()115 void SuperStakerPage::on_goToConfigSuperStakerPage()
116 {
117     m_configSuperStakerPage->show();
118 }
119 
on_goToAddSuperStakerPage()120 void SuperStakerPage::on_goToAddSuperStakerPage()
121 {
122     m_addSuperStakerPage->show();
123 }
124 
on_currentSuperStakerChanged(QModelIndex index)125 void SuperStakerPage::on_currentSuperStakerChanged(QModelIndex index)
126 {
127     if(m_superStakerList->superStakerModel())
128     {
129         if(index.isValid())
130         {
131             QString hash = m_superStakerList->superStakerModel()->data(index, SuperStakerItemModel::HashRole).toString();
132             m_selectedSuperStakerHash = hash;
133             QString address = m_superStakerList->superStakerModel()->data(index, SuperStakerItemModel::StakerAddressRole).toString();
134             QString name = m_superStakerList->superStakerModel()->data(index, SuperStakerItemModel::StakerNameRole).toString();
135             int minFee = m_superStakerList->superStakerModel()->data(index, SuperStakerItemModel::MinFeeRole).toInt();
136             m_configSuperStakerPage->setSuperStakerData(hash);
137             m_delegationsSuperStakerPage->setSuperStakerData(name, address, minFee, hash);
138             m_splitUtxoPage->setAddress(address);
139 
140             if(!m_configSuperStakerPage->isEnabled())
141                 m_configSuperStakerPage->setEnabled(true);
142             if(!m_delegationsSuperStakerPage->isEnabled())
143                 m_delegationsSuperStakerPage->setEnabled(true);
144             if(!m_splitUtxoPage->isEnabled())
145                 m_splitUtxoPage->setEnabled(true);
146         }
147         else
148         {
149             m_configSuperStakerPage->setEnabled(false);
150             m_configSuperStakerPage->setSuperStakerData("");
151             m_delegationsSuperStakerPage->setEnabled(false);
152             m_delegationsSuperStakerPage->setSuperStakerData("", "", 0, "");
153             m_splitUtxoPage->setEnabled(false);
154             m_splitUtxoPage->setAddress("");
155             m_selectedSuperStakerHash = "";
156         }
157     }
158 }
159 
on_dataChanged(const QModelIndex & topLeft,const QModelIndex & bottomRight,const QVector<int> & roles)160 void SuperStakerPage::on_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
161 {
162     Q_UNUSED(bottomRight);
163     Q_UNUSED(roles);
164 
165     if(m_superStakerList->superStakerModel())
166     {
167         QString superStakerHash = m_superStakerList->superStakerModel()->data(topLeft, SuperStakerItemModel::HashRole).toString();
168         if(m_selectedSuperStakerHash.isEmpty() ||
169                 superStakerHash == m_selectedSuperStakerHash)
170         {
171             on_currentSuperStakerChanged(topLeft);
172         }
173     }
174 }
175 
on_currentChanged(QModelIndex current,QModelIndex previous)176 void SuperStakerPage::on_currentChanged(QModelIndex current, QModelIndex previous)
177 {
178     Q_UNUSED(previous);
179 
180     on_currentSuperStakerChanged(current);
181 }
182 
on_rowsInserted(QModelIndex index,int first,int last)183 void SuperStakerPage::on_rowsInserted(QModelIndex index, int first, int last)
184 {
185     Q_UNUSED(index);
186     Q_UNUSED(first);
187     Q_UNUSED(last);
188 
189     if(m_superStakerList->superStakerModel()->rowCount() == 1)
190     {
191         QModelIndex currentSuperStaker(m_superStakerList->superStakerModel()->index(0, 0));
192         on_currentSuperStakerChanged(currentSuperStaker);
193     }
194 }
195 
contextualMenu(const QPoint & point)196 void SuperStakerPage::contextualMenu(const QPoint &point)
197 {
198     QModelIndex index = m_superStakerList->indexAt(point);
199     if(index.isValid())
200     {
201         indexMenu = index;
202         contextMenu->exec(QCursor::pos());
203     }
204 }
205 
copyStekerMinFee()206 void SuperStakerPage::copyStekerMinFee()
207 {
208     if(indexMenu.isValid())
209     {
210         GUIUtil::setClipboard(indexMenu.data(SuperStakerItemModel::FormattedMinFeeRole).toString());
211         indexMenu = QModelIndex();
212     }
213 }
214 
copyStakerName()215 void SuperStakerPage::copyStakerName()
216 {
217     if(indexMenu.isValid())
218     {
219         GUIUtil::setClipboard(indexMenu.data(SuperStakerItemModel::StakerNameRole).toString());
220         indexMenu = QModelIndex();
221     }
222 }
223 
copyStakerAddress()224 void SuperStakerPage::copyStakerAddress()
225 {
226     if(indexMenu.isValid())
227     {
228         GUIUtil::setClipboard(indexMenu.data(SuperStakerItemModel::StakerAddressRole).toString());
229         indexMenu = QModelIndex();
230     }
231 }
232 
copyStakerWeight()233 void SuperStakerPage::copyStakerWeight()
234 {
235     if(indexMenu.isValid())
236     {
237         GUIUtil::setClipboard(indexMenu.data(SuperStakerItemModel::FormattedWeightRole).toString());
238         indexMenu = QModelIndex();
239     }
240 }
241 
copyDelegationsWeight()242 void SuperStakerPage::copyDelegationsWeight()
243 {
244     if(indexMenu.isValid())
245     {
246         GUIUtil::setClipboard(indexMenu.data(SuperStakerItemModel::FormattedDelegationsWeightRole).toString());
247         indexMenu = QModelIndex();
248     }
249 }
250 
configSuperStaker()251 void SuperStakerPage::configSuperStaker()
252 {
253     if(indexMenu.isValid())
254     {
255         on_configSuperStaker(indexMenu);
256         indexMenu = QModelIndex();
257     }
258 }
259 
editStakerName()260 void SuperStakerPage::editStakerName()
261 {
262     if(indexMenu.isValid())
263     {
264         QString stakerName = indexMenu.data(SuperStakerItemModel::StakerNameRole).toString();
265         QString stakerAddress = indexMenu.data(SuperStakerItemModel::StakerAddressRole).toString();
266         QString sHash = indexMenu.data(SuperStakerItemModel::HashRole).toString();
267         uint256 hash;
268         hash.SetHex(sHash.toStdString());
269 
270         EditSuperStakerDialog dlg;
271         dlg.setData(stakerName, stakerAddress);
272 
273         if(dlg.exec())
274         {
275             interfaces::SuperStakerInfo staker = m_model->wallet().getSuperStaker(hash);
276             if(staker.hash == hash)
277             {
278                 staker.staker_name = dlg.getSuperStakerName().toStdString();
279                 m_model->wallet().removeSuperStakerEntry(sHash.toStdString());
280                 m_model->wallet().addSuperStakerEntry(staker);
281             }
282         }
283     }
284 }
285 
on_configSuperStaker(const QModelIndex & index)286 void SuperStakerPage::on_configSuperStaker(const QModelIndex &index)
287 {
288     m_configSuperStakerPage->clearAll();
289     on_currentSuperStakerChanged(index);
290     on_goToConfigSuperStakerPage();
291 }
292 
on_addSuperStaker()293 void SuperStakerPage::on_addSuperStaker()
294 {
295     on_goToAddSuperStakerPage();
296 }
297 
removeSuperStaker()298 void SuperStakerPage::removeSuperStaker()
299 {
300     if(indexMenu.isValid())
301     {
302         on_removeSuperStaker(indexMenu);
303         indexMenu = QModelIndex();
304     }
305 }
306 
on_removeSuperStaker(const QModelIndex & index)307 void SuperStakerPage::on_removeSuperStaker(const QModelIndex &index)
308 {
309     if(index.isValid() && m_model)
310     {
311         QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm super staker removal"), tr("The selected super staker will be removed from the list. Are you sure?"),
312             QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
313 
314         if(btnRetVal == QMessageBox::Yes)
315         {
316             QString hash = m_superStakerList->superStakerModel()->data(index, SuperStakerItemModel::HashRole).toString();
317             m_model->wallet().removeSuperStakerEntry(hash.toStdString());
318         }
319     }
320 }
321 
on_delegationsSuperStaker(const QModelIndex & index)322 void SuperStakerPage::on_delegationsSuperStaker(const QModelIndex &index)
323 {
324     on_currentSuperStakerChanged(index);
325     on_goToDelegationsSuperStakerPage();
326 }
327 
on_restoreSuperStakers()328 void SuperStakerPage::on_restoreSuperStakers()
329 {
330     if(m_model)
331     {
332         bool fSuperStake = m_model->wallet().getEnabledSuperStaking();
333         if(!fSuperStake)
334         {
335             QMessageBox::information(this, tr("Super staking"), tr("Enable super staking from the option menu in order to start the restoration."));
336         }
337         else
338         {
339             QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm super stakers restoration"), tr("Are you sure you wish to restore your super stakers?"),
340                 QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
341 
342             if(btnRetVal == QMessageBox::Yes)
343             {
344                 if(m_model->wallet().restoreSuperStakers() == 0)
345                 {
346                     QMessageBox::information(this, tr("Super stakers not found"), tr("No super stakers found to restore."), QMessageBox::Ok);
347                 }
348             }
349         }
350     }
351 }
352 
on_goToDelegationsSuperStakerPage()353 void SuperStakerPage::on_goToDelegationsSuperStakerPage()
354 {
355     m_delegationsSuperStakerPage->show();
356 }
357 
on_splitCoins(const QModelIndex & index)358 void SuperStakerPage::on_splitCoins(const QModelIndex &index)
359 {
360     on_currentSuperStakerChanged(index);
361     on_goToSplitCoinsPage();
362 }
363 
on_goToSplitCoinsPage()364 void SuperStakerPage::on_goToSplitCoinsPage()
365 {
366     m_splitUtxoPage->show();
367 }
368