You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

receivecoinsdialog.cpp 10.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // Copyright (c) 2011-2017 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. #include <wallet/wallet.h>
  5. #include <qt/receivecoinsdialog.h>
  6. #include <qt/forms/ui_receivecoinsdialog.h>
  7. #include <qt/addressbookpage.h>
  8. #include <qt/addresstablemodel.h>
  9. #include <qt/bitcoinunits.h>
  10. #include <qt/optionsmodel.h>
  11. #include <qt/platformstyle.h>
  12. #include <qt/receiverequestdialog.h>
  13. #include <qt/recentrequeststablemodel.h>
  14. #include <qt/walletmodel.h>
  15. #include <QAction>
  16. #include <QCursor>
  17. #include <QMessageBox>
  18. #include <QScrollBar>
  19. #include <QTextDocument>
  20. ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
  21. QDialog(parent),
  22. ui(new Ui::ReceiveCoinsDialog),
  23. columnResizingFixer(0),
  24. model(0),
  25. platformStyle(_platformStyle)
  26. {
  27. ui->setupUi(this);
  28. if (!_platformStyle->getImagesOnButtons()) {
  29. ui->clearButton->setIcon(QIcon());
  30. ui->receiveButton->setIcon(QIcon());
  31. ui->showRequestButton->setIcon(QIcon());
  32. ui->removeRequestButton->setIcon(QIcon());
  33. } else {
  34. ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
  35. ui->receiveButton->setIcon(_platformStyle->SingleColorIcon(":/icons/receiving_addresses"));
  36. ui->showRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/edit"));
  37. ui->removeRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
  38. }
  39. // context menu actions
  40. QAction *copyURIAction = new QAction(tr("Copy URI"), this);
  41. QAction *copyLabelAction = new QAction(tr("Copy label"), this);
  42. QAction *copyMessageAction = new QAction(tr("Copy message"), this);
  43. QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
  44. // context menu
  45. contextMenu = new QMenu(this);
  46. contextMenu->addAction(copyURIAction);
  47. contextMenu->addAction(copyLabelAction);
  48. contextMenu->addAction(copyMessageAction);
  49. contextMenu->addAction(copyAmountAction);
  50. // context menu signals
  51. connect(ui->recentRequestsView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));
  52. connect(copyURIAction, SIGNAL(triggered()), this, SLOT(copyURI()));
  53. connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
  54. connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage()));
  55. connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
  56. connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
  57. }
  58. void ReceiveCoinsDialog::setModel(WalletModel *_model)
  59. {
  60. this->model = _model;
  61. if(_model && _model->getOptionsModel())
  62. {
  63. _model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
  64. connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
  65. updateDisplayUnit();
  66. QTableView* tableView = ui->recentRequestsView;
  67. tableView->verticalHeader()->hide();
  68. tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  69. tableView->setModel(_model->getRecentRequestsTableModel());
  70. tableView->setAlternatingRowColors(true);
  71. tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
  72. tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
  73. tableView->setColumnWidth(RecentRequestsTableModel::Date, DATE_COLUMN_WIDTH);
  74. tableView->setColumnWidth(RecentRequestsTableModel::Label, LABEL_COLUMN_WIDTH);
  75. tableView->setColumnWidth(RecentRequestsTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH);
  76. connect(tableView->selectionModel(),
  77. SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this,
  78. SLOT(recentRequestsView_selectionChanged(QItemSelection, QItemSelection)));
  79. // Last 2 columns are set by the columnResizingFixer, when the table geometry is ready.
  80. columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this);
  81. if (model->getDefaultAddressType() == OUTPUT_TYPE_BECH32) {
  82. ui->useBech32->setCheckState(Qt::Checked);
  83. } else {
  84. ui->useBech32->setCheckState(Qt::Unchecked);
  85. }
  86. }
  87. }
  88. ReceiveCoinsDialog::~ReceiveCoinsDialog()
  89. {
  90. delete ui;
  91. }
  92. void ReceiveCoinsDialog::clear()
  93. {
  94. ui->reqAmount->clear();
  95. ui->reqLabel->setText("");
  96. ui->reqMessage->setText("");
  97. updateDisplayUnit();
  98. }
  99. void ReceiveCoinsDialog::reject()
  100. {
  101. clear();
  102. }
  103. void ReceiveCoinsDialog::accept()
  104. {
  105. clear();
  106. }
  107. void ReceiveCoinsDialog::updateDisplayUnit()
  108. {
  109. if(model && model->getOptionsModel())
  110. {
  111. ui->reqAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
  112. }
  113. }
  114. void ReceiveCoinsDialog::on_receiveButton_clicked()
  115. {
  116. if(!model || !model->getOptionsModel() || !model->getAddressTableModel() || !model->getRecentRequestsTableModel())
  117. return;
  118. QString address;
  119. QString label = ui->reqLabel->text();
  120. /* Generate new receiving address */
  121. OutputType address_type;
  122. if (ui->useBech32->isChecked()) {
  123. address_type = OUTPUT_TYPE_BECH32;
  124. } else {
  125. address_type = model->getDefaultAddressType();
  126. if (address_type == OUTPUT_TYPE_BECH32) {
  127. address_type = OUTPUT_TYPE_P2SH_SEGWIT;
  128. }
  129. }
  130. address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", address_type);
  131. SendCoinsRecipient info(address, label,
  132. ui->reqAmount->value(), ui->reqMessage->text());
  133. ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
  134. dialog->setAttribute(Qt::WA_DeleteOnClose);
  135. dialog->setModel(model->getOptionsModel());
  136. dialog->setInfo(info);
  137. dialog->show();
  138. clear();
  139. /* Store request for later reference */
  140. model->getRecentRequestsTableModel()->addNewRequest(info);
  141. }
  142. void ReceiveCoinsDialog::on_recentRequestsView_doubleClicked(const QModelIndex &index)
  143. {
  144. const RecentRequestsTableModel *submodel = model->getRecentRequestsTableModel();
  145. ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
  146. dialog->setModel(model->getOptionsModel());
  147. dialog->setInfo(submodel->entry(index.row()).recipient);
  148. dialog->setAttribute(Qt::WA_DeleteOnClose);
  149. dialog->show();
  150. }
  151. void ReceiveCoinsDialog::recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
  152. {
  153. // Enable Show/Remove buttons only if anything is selected.
  154. bool enable = !ui->recentRequestsView->selectionModel()->selectedRows().isEmpty();
  155. ui->showRequestButton->setEnabled(enable);
  156. ui->removeRequestButton->setEnabled(enable);
  157. }
  158. void ReceiveCoinsDialog::on_showRequestButton_clicked()
  159. {
  160. if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
  161. return;
  162. QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
  163. for (const QModelIndex& index : selection) {
  164. on_recentRequestsView_doubleClicked(index);
  165. }
  166. }
  167. void ReceiveCoinsDialog::on_removeRequestButton_clicked()
  168. {
  169. if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
  170. return;
  171. QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
  172. if(selection.empty())
  173. return;
  174. // correct for selection mode ContiguousSelection
  175. QModelIndex firstIndex = selection.at(0);
  176. model->getRecentRequestsTableModel()->removeRows(firstIndex.row(), selection.length(), firstIndex.parent());
  177. }
  178. // We override the virtual resizeEvent of the QWidget to adjust tables column
  179. // sizes as the tables width is proportional to the dialogs width.
  180. void ReceiveCoinsDialog::resizeEvent(QResizeEvent *event)
  181. {
  182. QWidget::resizeEvent(event);
  183. columnResizingFixer->stretchColumnWidth(RecentRequestsTableModel::Message);
  184. }
  185. void ReceiveCoinsDialog::keyPressEvent(QKeyEvent *event)
  186. {
  187. if (event->key() == Qt::Key_Return)
  188. {
  189. // press return -> submit form
  190. if (ui->reqLabel->hasFocus() || ui->reqAmount->hasFocus() || ui->reqMessage->hasFocus())
  191. {
  192. event->ignore();
  193. on_receiveButton_clicked();
  194. return;
  195. }
  196. }
  197. this->QDialog::keyPressEvent(event);
  198. }
  199. QModelIndex ReceiveCoinsDialog::selectedRow()
  200. {
  201. if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
  202. return QModelIndex();
  203. QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
  204. if(selection.empty())
  205. return QModelIndex();
  206. // correct for selection mode ContiguousSelection
  207. QModelIndex firstIndex = selection.at(0);
  208. return firstIndex;
  209. }
  210. // copy column of selected row to clipboard
  211. void ReceiveCoinsDialog::copyColumnToClipboard(int column)
  212. {
  213. QModelIndex firstIndex = selectedRow();
  214. if (!firstIndex.isValid()) {
  215. return;
  216. }
  217. GUIUtil::setClipboard(model->getRecentRequestsTableModel()->data(firstIndex.child(firstIndex.row(), column), Qt::EditRole).toString());
  218. }
  219. // context menu
  220. void ReceiveCoinsDialog::showMenu(const QPoint &point)
  221. {
  222. if (!selectedRow().isValid()) {
  223. return;
  224. }
  225. contextMenu->exec(QCursor::pos());
  226. }
  227. // context menu action: copy URI
  228. void ReceiveCoinsDialog::copyURI()
  229. {
  230. QModelIndex sel = selectedRow();
  231. if (!sel.isValid()) {
  232. return;
  233. }
  234. const RecentRequestsTableModel * const submodel = model->getRecentRequestsTableModel();
  235. const QString uri = GUIUtil::formatBitcoinURI(submodel->entry(sel.row()).recipient);
  236. GUIUtil::setClipboard(uri);
  237. }
  238. // context menu action: copy label
  239. void ReceiveCoinsDialog::copyLabel()
  240. {
  241. copyColumnToClipboard(RecentRequestsTableModel::Label);
  242. }
  243. // context menu action: copy message
  244. void ReceiveCoinsDialog::copyMessage()
  245. {
  246. copyColumnToClipboard(RecentRequestsTableModel::Message);
  247. }
  248. // context menu action: copy amount
  249. void ReceiveCoinsDialog::copyAmount()
  250. {
  251. copyColumnToClipboard(RecentRequestsTableModel::Amount);
  252. }