addressbookpage.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. // ECOin - Copyright (c) - 2014/2024 - GPLv3 - epsylon@riseup.net (https://03c8.net)
  2. #include "addressbookpage.h"
  3. #include "ui_addressbookpage.h"
  4. #include "addresstablemodel.h"
  5. #include "optionsmodel.h"
  6. #include "ecoingui.h"
  7. #include "editaddressdialog.h"
  8. #include "csvmodelwriter.h"
  9. #include "guiutil.h"
  10. #include <QSortFilterProxyModel>
  11. #include <QClipboard>
  12. #include <QMessageBox>
  13. #include <QMenu>
  14. #include <QString>
  15. #include <QUrl>
  16. #ifdef USE_QRCODE
  17. #include "qrcodedialog.h"
  18. #endif
  19. AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
  20. QDialog(parent),
  21. ui(new Ui::AddressBookPage),
  22. model(0),
  23. optionsModel(0),
  24. mode(mode),
  25. tab(tab)
  26. {
  27. ui->setupUi(this);
  28. #ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
  29. ui->newAddressButton->setIcon(QIcon());
  30. ui->copyToClipboard->setIcon(QIcon());
  31. ui->deleteButton->setIcon(QIcon());
  32. #endif
  33. #ifndef USE_QRCODE
  34. ui->showQRCode->setVisible(false);
  35. #endif
  36. switch(mode)
  37. {
  38. case ForSending:
  39. connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
  40. ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
  41. ui->tableView->setFocus();
  42. break;
  43. case ForEditing:
  44. ui->buttonBox->setVisible(false);
  45. break;
  46. }
  47. switch(tab)
  48. {
  49. case SendingTab:
  50. ui->labelExplanation->setVisible(false);
  51. ui->deleteButton->setVisible(true);
  52. ui->signMessage->setVisible(false);
  53. break;
  54. case ReceivingTab:
  55. ui->deleteButton->setVisible(false);
  56. ui->signMessage->setVisible(true);
  57. break;
  58. }
  59. // Context menu actions
  60. QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
  61. QAction *copyAddressAction = new QAction(ui->copyToClipboard->text(), this);
  62. QAction *editAction = new QAction(tr("&Edit"), this);
  63. QAction *showQRCodeAction = new QAction(ui->showQRCode->text(), this);
  64. QAction *signMessageAction = new QAction(ui->signMessage->text(), this);
  65. QAction *verifyMessageAction = new QAction(ui->verifyMessage->text(), this);
  66. deleteAction = new QAction(ui->deleteButton->text(), this);
  67. // Build context menu
  68. contextMenu = new QMenu();
  69. contextMenu->addAction(copyAddressAction);
  70. contextMenu->addAction(copyLabelAction);
  71. contextMenu->addAction(editAction);
  72. if(tab == SendingTab)
  73. contextMenu->addAction(deleteAction);
  74. contextMenu->addSeparator();
  75. contextMenu->addAction(showQRCodeAction);
  76. if(tab == ReceivingTab)
  77. contextMenu->addAction(signMessageAction);
  78. else if(tab == SendingTab)
  79. contextMenu->addAction(verifyMessageAction);
  80. // Connect signals for context menu actions
  81. connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyToClipboard_clicked()));
  82. connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction()));
  83. connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction()));
  84. connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteButton_clicked()));
  85. connect(showQRCodeAction, SIGNAL(triggered()), this, SLOT(on_showQRCode_clicked()));
  86. connect(signMessageAction, SIGNAL(triggered()), this, SLOT(on_signMessage_clicked()));
  87. connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(on_verifyMessage_clicked()));
  88. connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
  89. // Pass through accept action from button box
  90. connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
  91. }
  92. AddressBookPage::~AddressBookPage()
  93. {
  94. delete ui;
  95. }
  96. void AddressBookPage::setModel(AddressTableModel *model)
  97. {
  98. this->model = model;
  99. if(!model)
  100. return;
  101. proxyModel = new QSortFilterProxyModel(this);
  102. proxyModel->setSourceModel(model);
  103. proxyModel->setDynamicSortFilter(true);
  104. proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
  105. proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
  106. switch(tab)
  107. {
  108. case ReceivingTab:
  109. // Receive filter
  110. proxyModel->setFilterRole(AddressTableModel::TypeRole);
  111. proxyModel->setFilterFixedString(AddressTableModel::Receive);
  112. break;
  113. case SendingTab:
  114. // Send filter
  115. proxyModel->setFilterRole(AddressTableModel::TypeRole);
  116. proxyModel->setFilterFixedString(AddressTableModel::Send);
  117. break;
  118. }
  119. ui->tableView->setModel(proxyModel);
  120. ui->tableView->sortByColumn(0, Qt::AscendingOrder);
  121. // Set column widths
  122. ui->tableView->horizontalHeader()->resizeSection(
  123. AddressTableModel::Address, 320);
  124. ui->tableView->horizontalHeader()->setSectionResizeMode(
  125. AddressTableModel::Label, QHeaderView::Stretch);
  126. connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
  127. this, SLOT(selectionChanged()));
  128. // Select row for newly created address
  129. connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
  130. this, SLOT(selectNewAddress(QModelIndex,int,int)));
  131. selectionChanged();
  132. }
  133. void AddressBookPage::setOptionsModel(OptionsModel *optionsModel)
  134. {
  135. this->optionsModel = optionsModel;
  136. }
  137. void AddressBookPage::on_copyToClipboard_clicked()
  138. {
  139. GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
  140. }
  141. void AddressBookPage::onCopyLabelAction()
  142. {
  143. GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
  144. }
  145. void AddressBookPage::onEditAction()
  146. {
  147. if(!ui->tableView->selectionModel())
  148. return;
  149. QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
  150. if(indexes.isEmpty())
  151. return;
  152. EditAddressDialog dlg(
  153. tab == SendingTab ?
  154. EditAddressDialog::EditSendingAddress :
  155. EditAddressDialog::EditReceivingAddress);
  156. dlg.setModel(model);
  157. QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
  158. dlg.loadRow(origIndex.row());
  159. dlg.exec();
  160. }
  161. void AddressBookPage::on_signMessage_clicked()
  162. {
  163. QTableView *table = ui->tableView;
  164. QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
  165. QString addr;
  166. foreach (QModelIndex index, indexes)
  167. {
  168. QVariant address = index.data();
  169. addr = address.toString();
  170. }
  171. emit signMessage(addr);
  172. }
  173. void AddressBookPage::on_verifyMessage_clicked()
  174. {
  175. QTableView *table = ui->tableView;
  176. QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
  177. QString addr;
  178. foreach (QModelIndex index, indexes)
  179. {
  180. QVariant address = index.data();
  181. addr = address.toString();
  182. }
  183. emit verifyMessage(addr);
  184. }
  185. void AddressBookPage::on_newAddressButton_clicked()
  186. {
  187. if(!model)
  188. return;
  189. EditAddressDialog dlg(
  190. tab == SendingTab ?
  191. EditAddressDialog::NewSendingAddress :
  192. EditAddressDialog::NewReceivingAddress, this);
  193. dlg.setModel(model);
  194. if(dlg.exec())
  195. {
  196. newAddressToSelect = dlg.getAddress();
  197. }
  198. }
  199. void AddressBookPage::on_deleteButton_clicked()
  200. {
  201. QTableView *table = ui->tableView;
  202. if(!table->selectionModel())
  203. return;
  204. QModelIndexList indexes = table->selectionModel()->selectedRows();
  205. if(!indexes.isEmpty())
  206. {
  207. table->model()->removeRow(indexes.at(0).row());
  208. }
  209. }
  210. void AddressBookPage::selectionChanged()
  211. {
  212. // Set button states based on selected tab and selection
  213. QTableView *table = ui->tableView;
  214. if(!table->selectionModel())
  215. return;
  216. if(table->selectionModel()->hasSelection())
  217. {
  218. switch(tab)
  219. {
  220. case SendingTab:
  221. // In sending tab, allow deletion of selection
  222. ui->deleteButton->setEnabled(true);
  223. ui->deleteButton->setVisible(true);
  224. deleteAction->setEnabled(true);
  225. ui->signMessage->setEnabled(false);
  226. ui->signMessage->setVisible(false);
  227. ui->verifyMessage->setEnabled(true);
  228. ui->verifyMessage->setVisible(true);
  229. break;
  230. case ReceivingTab:
  231. // Deleting receiving addresses, however, is not allowed
  232. ui->deleteButton->setEnabled(false);
  233. ui->deleteButton->setVisible(false);
  234. deleteAction->setEnabled(false);
  235. ui->signMessage->setEnabled(true);
  236. ui->signMessage->setVisible(true);
  237. ui->verifyMessage->setEnabled(false);
  238. ui->verifyMessage->setVisible(false);
  239. break;
  240. }
  241. ui->copyToClipboard->setEnabled(true);
  242. ui->showQRCode->setEnabled(true);
  243. }
  244. else
  245. {
  246. ui->deleteButton->setEnabled(false);
  247. ui->showQRCode->setEnabled(false);
  248. ui->copyToClipboard->setEnabled(false);
  249. ui->signMessage->setEnabled(false);
  250. ui->verifyMessage->setEnabled(false);
  251. }
  252. }
  253. void AddressBookPage::done(int retval)
  254. {
  255. QTableView *table = ui->tableView;
  256. if(!table->selectionModel() || !table->model())
  257. return;
  258. // When this is a tab/widget and not a model dialog, ignore "done"
  259. if(mode == ForEditing)
  260. return;
  261. // Figure out which address was selected, and return it
  262. QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
  263. foreach (QModelIndex index, indexes)
  264. {
  265. QVariant address = table->model()->data(index);
  266. returnValue = address.toString();
  267. }
  268. if(returnValue.isEmpty())
  269. {
  270. // If no address entry selected, return rejected
  271. retval = Rejected;
  272. }
  273. QDialog::done(retval);
  274. }
  275. void AddressBookPage::exportClicked()
  276. {
  277. // CSV is currently the only supported format
  278. QString filename = GUIUtil::getSaveFileName(
  279. this,
  280. tr("Export Address Book Data"), QString(),
  281. tr("Comma separated file (*.csv)"));
  282. if (filename.isNull()) return;
  283. CSVModelWriter writer(filename);
  284. // name, column, role
  285. writer.setModel(proxyModel);
  286. writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
  287. writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);
  288. if(!writer.write())
  289. {
  290. QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
  291. QMessageBox::Abort, QMessageBox::Abort);
  292. }
  293. }
  294. void AddressBookPage::on_showQRCode_clicked()
  295. {
  296. #ifdef USE_QRCODE
  297. QTableView *table = ui->tableView;
  298. QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
  299. foreach (QModelIndex index, indexes)
  300. {
  301. QString address = index.data().toString(), label = index.sibling(index.row(), 0).data(Qt::EditRole).toString();
  302. QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this);
  303. if(optionsModel)
  304. dialog->setModel(optionsModel);
  305. dialog->setAttribute(Qt::WA_DeleteOnClose);
  306. dialog->show();
  307. }
  308. #endif
  309. }
  310. void AddressBookPage::contextualMenu(const QPoint &point)
  311. {
  312. QModelIndex index = ui->tableView->indexAt(point);
  313. if(index.isValid())
  314. {
  315. contextMenu->exec(QCursor::pos());
  316. }
  317. }
  318. void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int end)
  319. {
  320. QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
  321. if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
  322. {
  323. // Select row of newly created address, once
  324. ui->tableView->setFocus();
  325. ui->tableView->selectRow(idx.row());
  326. newAddressToSelect.clear();
  327. }
  328. }