Browse Source

WIP: keva page.

kevaview
Just Wonder 4 years ago
parent
commit
c19e18d9bd
  1. 3
      contrib/bitcoin-qt.pro
  2. 7
      src/Makefile.qt.include
  3. 375
      src/qt/forms/kevadialog.ui
  4. 292
      src/qt/kevadialog.cpp
  5. 80
      src/qt/kevadialog.h
  6. 623
      src/qt/kevaview.cpp
  7. 122
      src/qt/kevaview.h
  8. 344
      src/qt/locale/bitcoin_en.ts
  9. 2
      src/qt/test/wallettests.cpp
  10. 24
      src/qt/walletview.cpp
  11. 6
      src/qt/walletview.h

3
contrib/bitcoin-qt.pro

@ -11,8 +11,9 @@ FORMS += \ @@ -11,8 +11,9 @@ FORMS += \
../src/qt/forms/overviewpage.ui \
../src/qt/forms/receivecoinsdialog.ui \
../src/qt/forms/receiverequestdialog.ui \
../src/qt/forms/debugwindow.ui \
../src/qt/forms/sendcoinsdialog.ui \
../src/qt/forms/debugwindow.ui \
../src/qt/forms/kevadialog.ui \
../src/qt/forms/sendcoinsentry.ui \
../src/qt/forms/signverifymessagedialog.ui \
../src/qt/forms/transactiondescdialog.ui \

7
src/Makefile.qt.include

@ -135,6 +135,7 @@ QT_FORMS_UI = \ @@ -135,6 +135,7 @@ QT_FORMS_UI = \
qt/forms/overviewpage.ui \
qt/forms/receivecoinsdialog.ui \
qt/forms/receiverequestdialog.ui \
qt/forms/kevadialog.ui \
qt/forms/debugwindow.ui \
qt/forms/sendcoinsdialog.ui \
qt/forms/sendcoinsentry.ui \
@ -184,7 +185,7 @@ QT_MOC_CPP = \ @@ -184,7 +185,7 @@ QT_MOC_CPP = \
qt/moc_transactionfilterproxy.cpp \
qt/moc_transactiontablemodel.cpp \
qt/moc_transactionview.cpp \
qt/moc_kevaview.cpp \
qt/moc_kevadialog.cpp \
qt/moc_utilitydialog.cpp \
qt/moc_walletframe.cpp \
qt/moc_walletmodel.cpp \
@ -259,7 +260,7 @@ BITCOIN_QT_H = \ @@ -259,7 +260,7 @@ BITCOIN_QT_H = \
qt/transactionrecord.h \
qt/transactiontablemodel.h \
qt/transactionview.h \
qt/kevaview.h \
qt/kevadialog.h \
qt/utilitydialog.h \
qt/walletframe.h \
qt/walletmodel.h \
@ -374,7 +375,7 @@ BITCOIN_QT_WALLET_CPP = \ @@ -374,7 +375,7 @@ BITCOIN_QT_WALLET_CPP = \
qt/transactionrecord.cpp \
qt/transactiontablemodel.cpp \
qt/transactionview.cpp \
qt/kevaview.cpp \
qt/kevadialog.cpp \
qt/walletframe.cpp \
qt/walletmodel.cpp \
qt/walletmodeltransaction.cpp \

375
src/qt/forms/kevadialog.ui

@ -0,0 +1,375 @@ @@ -0,0 +1,375 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KevaDialog</class>
<widget class="QWidget" name="KevaDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>776</width>
<height>396</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1">
<item>
<widget class="QFrame" name="frame2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="0">
<widget class="QLabel" name="label">
<property name="toolTip">
<string>An optional amount to request. Leave this empty or zero to not request a specific amount.</string>
</property>
<property name="text">
<string>&amp;Amount:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>reqAmount</cstring>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_3">
<property name="toolTip">
<string>An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Kevacoin network.</string>
</property>
<property name="text">
<string>&amp;Message:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>reqMessage</cstring>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLineEdit" name="reqLabel">
<property name="toolTip">
<string>An optional label to associate with the new receiving address.</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="toolTip">
<string>An optional label to associate with the new receiving address.</string>
</property>
<property name="text">
<string>&amp;Label:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>reqLabel</cstring>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QLineEdit" name="reqMessage">
<property name="toolTip">
<string>An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Kevacoin network.</string>
</property>
</widget>
</item>
<item row="7" column="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="receiveButton">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>&amp;Request payment</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/receiving_addresses</normaloff>:/icons/receiving_addresses</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Clear all fields of the form.</string>
</property>
<property name="text">
<string>Clear</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="5" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="BitcoinAmountField" name="reqAmount">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>1000</width>
<height>100</height>
</size>
</property>
<property name="toolTip">
<string>An optional amount to request. Leave this empty or zero to not request a specific amount.</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="useBech32">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>1000</width>
<height>16777215</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</string>
</property>
<property name="text">
<string>Generate native segwit (Bech32) address</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_6">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Requested payments history</string>
</property>
</widget>
</item>
<item>
<widget class="QTableView" name="recentRequestsView">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="showRequestButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Show the selected request (does the same as double clicking an entry)</string>
</property>
<property name="text">
<string>Show</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/edit</normaloff>:/icons/edit</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeRequestButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Remove the selected entries from the list</string>
</property>
<property name="text">
<string>Remove</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>BitcoinAmountField</class>
<extends>QLineEdit</extends>
<header>qt/bitcoinamountfield.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>reqLabel</tabstop>
<tabstop>reqAmount</tabstop>
<tabstop>useBech32</tabstop>
<tabstop>reqMessage</tabstop>
<tabstop>receiveButton</tabstop>
<tabstop>clearButton</tabstop>
<tabstop>recentRequestsView</tabstop>
<tabstop>showRequestButton</tabstop>
<tabstop>removeRequestButton</tabstop>
</tabstops>
<resources>
<include location="../bitcoin.qrc"/>
</resources>
<connections/>
</ui>

292
src/qt/kevadialog.cpp

@ -0,0 +1,292 @@ @@ -0,0 +1,292 @@
// Copyright (c) 2011-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <wallet/wallet.h>
#include <qt/kevadialog.h>
#include <qt/forms/ui_kevadialog.h>
#include <qt/addressbookpage.h>
#include <qt/addresstablemodel.h>
#include <qt/bitcoinunits.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/receiverequestdialog.h>
#include <qt/recentrequeststablemodel.h>
#include <qt/walletmodel.h>
#include <QAction>
#include <QCursor>
#include <QMessageBox>
#include <QScrollBar>
#include <QTextDocument>
KevaDialog::KevaDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::KevaDialog),
columnResizingFixer(0),
model(0),
platformStyle(_platformStyle)
{
ui->setupUi(this);
if (!_platformStyle->getImagesOnButtons()) {
ui->clearButton->setIcon(QIcon());
ui->receiveButton->setIcon(QIcon());
ui->showRequestButton->setIcon(QIcon());
ui->removeRequestButton->setIcon(QIcon());
} else {
ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
ui->receiveButton->setIcon(_platformStyle->SingleColorIcon(":/icons/receiving_addresses"));
ui->showRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/edit"));
ui->removeRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
}
// context menu actions
QAction *copyURIAction = new QAction(tr("Copy URI"), this);
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
QAction *copyMessageAction = new QAction(tr("Copy message"), this);
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
// context menu
contextMenu = new QMenu(this);
contextMenu->addAction(copyURIAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(copyMessageAction);
contextMenu->addAction(copyAmountAction);
// context menu signals
connect(ui->recentRequestsView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));
connect(copyURIAction, SIGNAL(triggered()), this, SLOT(copyURI()));
connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage()));
connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
}
void KevaDialog::setModel(WalletModel *_model)
{
this->model = _model;
if(_model && _model->getOptionsModel())
{
_model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
updateDisplayUnit();
QTableView* tableView = ui->recentRequestsView;
tableView->verticalHeader()->hide();
tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
tableView->setModel(_model->getRecentRequestsTableModel());
tableView->setAlternatingRowColors(true);
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
tableView->setColumnWidth(RecentRequestsTableModel::Date, DATE_COLUMN_WIDTH);
tableView->setColumnWidth(RecentRequestsTableModel::Label, LABEL_COLUMN_WIDTH);
tableView->setColumnWidth(RecentRequestsTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH);
connect(tableView->selectionModel(),
SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this,
SLOT(recentRequestsView_selectionChanged(QItemSelection, QItemSelection)));
// Last 2 columns are set by the columnResizingFixer, when the table geometry is ready.
columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this);
if (model->getDefaultAddressType() == OUTPUT_TYPE_BECH32) {
ui->useBech32->setCheckState(Qt::Checked);
} else {
ui->useBech32->setCheckState(Qt::Unchecked);
}
}
}
KevaDialog::~KevaDialog()
{
delete ui;
}
void KevaDialog::clear()
{
ui->reqAmount->clear();
ui->reqLabel->setText("");
ui->reqMessage->setText("");
updateDisplayUnit();
}
void KevaDialog::reject()
{
clear();
}
void KevaDialog::accept()
{
clear();
}
void KevaDialog::updateDisplayUnit()
{
if(model && model->getOptionsModel())
{
ui->reqAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
}
}
void KevaDialog::on_receiveButton_clicked()
{
if(!model || !model->getOptionsModel() || !model->getAddressTableModel() || !model->getRecentRequestsTableModel())
return;
QString address;
QString label = ui->reqLabel->text();
/* Generate new receiving address */
OutputType address_type;
if (ui->useBech32->isChecked()) {
address_type = OUTPUT_TYPE_BECH32;
} else {
address_type = model->getDefaultAddressType();
if (address_type == OUTPUT_TYPE_BECH32) {
address_type = OUTPUT_TYPE_P2SH_SEGWIT;
}
}
address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", address_type);
SendCoinsRecipient info(address, label,
ui->reqAmount->value(), ui->reqMessage->text());
ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setModel(model->getOptionsModel());
dialog->setInfo(info);
dialog->show();
clear();
/* Store request for later reference */
model->getRecentRequestsTableModel()->addNewRequest(info);
}
void KevaDialog::on_recentRequestsView_doubleClicked(const QModelIndex &index)
{
const RecentRequestsTableModel *submodel = model->getRecentRequestsTableModel();
ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
dialog->setModel(model->getOptionsModel());
dialog->setInfo(submodel->entry(index.row()).recipient);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
}
void KevaDialog::recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
// Enable Show/Remove buttons only if anything is selected.
bool enable = !ui->recentRequestsView->selectionModel()->selectedRows().isEmpty();
ui->showRequestButton->setEnabled(enable);
ui->removeRequestButton->setEnabled(enable);
}
void KevaDialog::on_showRequestButton_clicked()
{
if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
return;
QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
for (const QModelIndex& index : selection) {
on_recentRequestsView_doubleClicked(index);
}
}
void KevaDialog::on_removeRequestButton_clicked()
{
if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
return;
QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
if(selection.empty())
return;
// correct for selection mode ContiguousSelection
QModelIndex firstIndex = selection.at(0);
model->getRecentRequestsTableModel()->removeRows(firstIndex.row(), selection.length(), firstIndex.parent());
}
// We override the virtual resizeEvent of the QWidget to adjust tables column
// sizes as the tables width is proportional to the dialogs width.
void KevaDialog::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
columnResizingFixer->stretchColumnWidth(RecentRequestsTableModel::Message);
}
void KevaDialog::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Return)
{
// press return -> submit form
if (ui->reqLabel->hasFocus() || ui->reqAmount->hasFocus() || ui->reqMessage->hasFocus())
{
event->ignore();
on_receiveButton_clicked();
return;
}
}
this->QDialog::keyPressEvent(event);
}
QModelIndex KevaDialog::selectedRow()
{
if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
return QModelIndex();
QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
if(selection.empty())
return QModelIndex();
// correct for selection mode ContiguousSelection
QModelIndex firstIndex = selection.at(0);
return firstIndex;
}
// copy column of selected row to clipboard
void KevaDialog::copyColumnToClipboard(int column)
{
QModelIndex firstIndex = selectedRow();
if (!firstIndex.isValid()) {
return;
}
GUIUtil::setClipboard(model->getRecentRequestsTableModel()->data(firstIndex.child(firstIndex.row(), column), Qt::EditRole).toString());
}
// context menu
void KevaDialog::showMenu(const QPoint &point)
{
if (!selectedRow().isValid()) {
return;
}
contextMenu->exec(QCursor::pos());
}
// context menu action: copy URI
void KevaDialog::copyURI()
{
QModelIndex sel = selectedRow();
if (!sel.isValid()) {
return;
}
const RecentRequestsTableModel * const submodel = model->getRecentRequestsTableModel();
const QString uri = GUIUtil::formatBitcoinURI(submodel->entry(sel.row()).recipient);
GUIUtil::setClipboard(uri);
}
// context menu action: copy label
void KevaDialog::copyLabel()
{
copyColumnToClipboard(RecentRequestsTableModel::Label);
}
// context menu action: copy message
void KevaDialog::copyMessage()
{
copyColumnToClipboard(RecentRequestsTableModel::Message);
}
// context menu action: copy amount
void KevaDialog::copyAmount()
{
copyColumnToClipboard(RecentRequestsTableModel::Amount);
}

80
src/qt/kevadialog.h

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
// Copyright (c) 2011-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_QT_KEVADIALOG_H
#define BITCOIN_QT_KEVADIALOG_H
#include <qt/guiutil.h>
#include <QDialog>
#include <QHeaderView>
#include <QItemSelection>
#include <QKeyEvent>
#include <QMenu>
#include <QPoint>
#include <QVariant>
class PlatformStyle;
class WalletModel;
namespace Ui {
class KevaDialog;
}
QT_BEGIN_NAMESPACE
class QModelIndex;
QT_END_NAMESPACE
/** Dialog for requesting payment of bitcoins */
class KevaDialog : public QDialog
{
Q_OBJECT
public:
enum ColumnWidths {
DATE_COLUMN_WIDTH = 130,
LABEL_COLUMN_WIDTH = 120,
AMOUNT_MINIMUM_COLUMN_WIDTH = 180,
MINIMUM_COLUMN_WIDTH = 130
};
explicit KevaDialog(const PlatformStyle *platformStyle, QWidget *parent = 0);
~KevaDialog();
void setModel(WalletModel *model);
public Q_SLOTS:
void clear();
void reject();
void accept();
protected:
virtual void keyPressEvent(QKeyEvent *event);
private:
Ui::KevaDialog *ui;
GUIUtil::TableViewLastColumnResizingFixer *columnResizingFixer;
WalletModel *model;
QMenu *contextMenu;
const PlatformStyle *platformStyle;
QModelIndex selectedRow();
void copyColumnToClipboard(int column);
virtual void resizeEvent(QResizeEvent *event);
private Q_SLOTS:
void on_receiveButton_clicked();
void on_showRequestButton_clicked();
void on_removeRequestButton_clicked();
void on_recentRequestsView_doubleClicked(const QModelIndex &index);
void recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void updateDisplayUnit();
void showMenu(const QPoint &point);
void copyURI();
void copyLabel();
void copyMessage();
void copyAmount();
};
#endif // BITCOIN_QT_KEVADIALOG_H

623
src/qt/kevaview.cpp

@ -1,623 +0,0 @@ @@ -1,623 +0,0 @@
// Copyright (c) 2011-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <qt/kevaview.h>
#include <qt/addresstablemodel.h>
#include <qt/bitcoinunits.h>
#include <qt/csvmodelwriter.h>
#include <qt/editaddressdialog.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/sendcoinsdialog.h>
#include <qt/transactiondescdialog.h>
#include <qt/transactionfilterproxy.h>
#include <qt/transactionrecord.h>
#include <qt/transactiontablemodel.h>
#include <qt/walletmodel.h>
#include <ui_interface.h>
#include <QComboBox>
#include <QDateTimeEdit>
#include <QDesktopServices>
#include <QDoubleValidator>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QPoint>
#include <QScrollBar>
#include <QSignalMapper>
#include <QTableView>
#include <QTimer>
#include <QUrl>
#include <QVBoxLayout>
KevaView::KevaView(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent), model(0), transactionProxyModel(0),
kevaView(0), abandonAction(0), bumpFeeAction(0), columnResizingFixer(0)
{
// Build filter row
setContentsMargins(0,0,0,0);
QHBoxLayout *hlayout = new QHBoxLayout();
hlayout->setContentsMargins(0,0,0,0);
if (platformStyle->getUseExtraSpacing()) {
hlayout->setSpacing(5);
hlayout->addSpacing(26);
} else {
hlayout->setSpacing(0);
hlayout->addSpacing(23);
}
watchOnlyWidget = new QComboBox(this);
watchOnlyWidget->setFixedWidth(24);
watchOnlyWidget->addItem("", TransactionFilterProxy::WatchOnlyFilter_All);
watchOnlyWidget->addItem(platformStyle->SingleColorIcon(":/icons/eye_plus"), "", TransactionFilterProxy::WatchOnlyFilter_Yes);
watchOnlyWidget->addItem(platformStyle->SingleColorIcon(":/icons/eye_minus"), "", TransactionFilterProxy::WatchOnlyFilter_No);
hlayout->addWidget(watchOnlyWidget);
dateWidget = new QComboBox(this);
if (platformStyle->getUseExtraSpacing()) {
dateWidget->setFixedWidth(121);
} else {
dateWidget->setFixedWidth(120);
}
dateWidget->addItem(tr("All"), All);
dateWidget->addItem(tr("Today"), Today);
dateWidget->addItem(tr("This week"), ThisWeek);
dateWidget->addItem(tr("This month"), ThisMonth);
dateWidget->addItem(tr("Last month"), LastMonth);
dateWidget->addItem(tr("This year"), ThisYear);
dateWidget->addItem(tr("Range..."), Range);
hlayout->addWidget(dateWidget);
typeWidget = new QComboBox(this);
if (platformStyle->getUseExtraSpacing()) {
typeWidget->setFixedWidth(121);
} else {
typeWidget->setFixedWidth(120);
}
typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
TransactionFilterProxy::TYPE(TransactionRecord::RecvFromOther));
typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) |
TransactionFilterProxy::TYPE(TransactionRecord::SendToOther));
typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));
hlayout->addWidget(typeWidget);
search_widget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
search_widget->setPlaceholderText(tr("Enter address, transaction id, or label to search"));
#endif
hlayout->addWidget(search_widget);
amountWidget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
amountWidget->setPlaceholderText(tr("Min amount"));
#endif
if (platformStyle->getUseExtraSpacing()) {
amountWidget->setFixedWidth(97);
} else {
amountWidget->setFixedWidth(100);
}
amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
hlayout->addWidget(amountWidget);
// Delay before filtering transactions in ms
static const int input_filter_delay = 200;
QTimer* amount_typing_delay = new QTimer(this);
amount_typing_delay->setSingleShot(true);
amount_typing_delay->setInterval(input_filter_delay);
QTimer* prefix_typing_delay = new QTimer(this);
prefix_typing_delay->setSingleShot(true);
prefix_typing_delay->setInterval(input_filter_delay);
QVBoxLayout *vlayout = new QVBoxLayout(this);
vlayout->setContentsMargins(0,0,0,0);
vlayout->setSpacing(0);
QTableView *view = new QTableView(this);
vlayout->addLayout(hlayout);
vlayout->addWidget(createDateRangeWidget());
vlayout->addWidget(view);
vlayout->setSpacing(0);
int width = view->verticalScrollBar()->sizeHint().width();
// Cover scroll bar width with spacing
if (platformStyle->getUseExtraSpacing()) {
hlayout->addSpacing(width+2);
} else {
hlayout->addSpacing(width);
}
// Always show scroll bar
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
view->setTabKeyNavigation(false);
view->setContextMenuPolicy(Qt::CustomContextMenu);
view->installEventFilter(this);
kevaView = view;
kevaView->setObjectName("KevaView");
// Actions
abandonAction = new QAction(tr("Abandon transaction"), this);
bumpFeeAction = new QAction(tr("Increase transaction fee"), this);
bumpFeeAction->setObjectName("bumpFeeAction");
QAction *copyAddressAction = new QAction(tr("Copy address"), this);
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this);
QAction *copyTxHexAction = new QAction(tr("Copy raw transaction"), this);
QAction *copyTxPlainText = new QAction(tr("Copy full transaction details"), this);
QAction *editLabelAction = new QAction(tr("Edit label"), this);
QAction *showDetailsAction = new QAction(tr("Show transaction details"), this);
contextMenu = new QMenu(this);
contextMenu->setObjectName("contextMenu");
contextMenu->addAction(copyAddressAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(copyAmountAction);
contextMenu->addAction(copyTxIDAction);
contextMenu->addAction(copyTxHexAction);
contextMenu->addAction(copyTxPlainText);
contextMenu->addAction(showDetailsAction);
contextMenu->addSeparator();
contextMenu->addAction(bumpFeeAction);
contextMenu->addAction(abandonAction);
contextMenu->addAction(editLabelAction);
mapperThirdPartyTxUrls = new QSignalMapper(this);
// Connect actions
connect(mapperThirdPartyTxUrls, SIGNAL(mapped(QString)), this, SLOT(openThirdPartyTxUrl(QString)));
connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
connect(watchOnlyWidget, SIGNAL(activated(int)), this, SLOT(chooseWatchonly(int)));
connect(amountWidget, SIGNAL(textChanged(QString)), amount_typing_delay, SLOT(start()));
connect(amount_typing_delay, SIGNAL(timeout()), this, SLOT(changedAmount()));
connect(search_widget, SIGNAL(textChanged(QString)), prefix_typing_delay, SLOT(start()));
connect(prefix_typing_delay, SIGNAL(timeout()), this, SLOT(changedSearch()));
connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
connect(bumpFeeAction, SIGNAL(triggered()), this, SLOT(bumpFee()));
connect(abandonAction, SIGNAL(triggered()), this, SLOT(abandonTx()));
connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID()));
connect(copyTxHexAction, SIGNAL(triggered()), this, SLOT(copyTxHex()));
connect(copyTxPlainText, SIGNAL(triggered()), this, SLOT(copyTxPlainText()));
connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel()));
connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails()));
}
void KevaView::setModel(WalletModel *_model)
{
this->model = _model;
if(_model)
{
transactionProxyModel = new TransactionFilterProxy(this);
transactionProxyModel->setSourceModel(_model->getTransactionTableModel());
transactionProxyModel->setDynamicSortFilter(true);
transactionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
transactionProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
transactionProxyModel->setSortRole(Qt::EditRole);
kevaView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
kevaView->setModel(transactionProxyModel);
kevaView->setAlternatingRowColors(true);
kevaView->setSelectionBehavior(QAbstractItemView::SelectRows);
kevaView->setSelectionMode(QAbstractItemView::ExtendedSelection);
kevaView->setSortingEnabled(true);
kevaView->sortByColumn(TransactionTableModel::Date, Qt::DescendingOrder);
kevaView->verticalHeader()->hide();
kevaView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH);
kevaView->setColumnWidth(TransactionTableModel::Watchonly, WATCHONLY_COLUMN_WIDTH);
kevaView->setColumnWidth(TransactionTableModel::Date, DATE_COLUMN_WIDTH);
kevaView->setColumnWidth(TransactionTableModel::Type, TYPE_COLUMN_WIDTH);
kevaView->setColumnWidth(TransactionTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH);
columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(kevaView, AMOUNT_MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH, this);
if (_model->getOptionsModel())
{
// Add third party transaction URLs to context menu
QStringList listUrls = _model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts);
for (int i = 0; i < listUrls.size(); ++i)
{
QString host = QUrl(listUrls[i].trimmed(), QUrl::StrictMode).host();
if (!host.isEmpty())
{
QAction *thirdPartyTxUrlAction = new QAction(host, this); // use host as menu item label
if (i == 0)
contextMenu->addSeparator();
contextMenu->addAction(thirdPartyTxUrlAction);
connect(thirdPartyTxUrlAction, SIGNAL(triggered()), mapperThirdPartyTxUrls, SLOT(map()));
mapperThirdPartyTxUrls->setMapping(thirdPartyTxUrlAction, listUrls[i].trimmed());
}
}
}
// show/hide column Watch-only
updateWatchOnlyColumn(_model->haveWatchOnly());
// Watch-only signal
connect(_model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool)));
}
}
void KevaView::chooseDate(int idx)
{
if(!transactionProxyModel)
return;
QDate current = QDate::currentDate();
dateRangeWidget->setVisible(false);
switch(dateWidget->itemData(idx).toInt())
{
case All:
transactionProxyModel->setDateRange(
TransactionFilterProxy::MIN_DATE,
TransactionFilterProxy::MAX_DATE);
break;
case Today:
transactionProxyModel->setDateRange(
QDateTime(current),
TransactionFilterProxy::MAX_DATE);
break;
case ThisWeek: {
// Find last Monday
QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1));
transactionProxyModel->setDateRange(
QDateTime(startOfWeek),
TransactionFilterProxy::MAX_DATE);
} break;
case ThisMonth:
transactionProxyModel->setDateRange(
QDateTime(QDate(current.year(), current.month(), 1)),
TransactionFilterProxy::MAX_DATE);
break;
case LastMonth:
transactionProxyModel->setDateRange(
QDateTime(QDate(current.year(), current.month(), 1).addMonths(-1)),
QDateTime(QDate(current.year(), current.month(), 1)));
break;
case ThisYear:
transactionProxyModel->setDateRange(
QDateTime(QDate(current.year(), 1, 1)),
TransactionFilterProxy::MAX_DATE);
break;
case Range:
dateRangeWidget->setVisible(true);
dateRangeChanged();
break;
}
}
void KevaView::chooseType(int idx)
{
if(!transactionProxyModel)
return;
transactionProxyModel->setTypeFilter(
typeWidget->itemData(idx).toInt());
}
void KevaView::chooseWatchonly(int idx)
{
if(!transactionProxyModel)
return;
transactionProxyModel->setWatchOnlyFilter(
(TransactionFilterProxy::WatchOnlyFilter)watchOnlyWidget->itemData(idx).toInt());
}
void KevaView::changedSearch()
{
if(!transactionProxyModel)
return;
transactionProxyModel->setSearchString(search_widget->text());
}
void KevaView::changedAmount()
{
if(!transactionProxyModel)
return;
CAmount amount_parsed = 0;
if (BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amountWidget->text(), &amount_parsed)) {
transactionProxyModel->setMinAmount(amount_parsed);
}
else
{
transactionProxyModel->setMinAmount(0);
}
}
void KevaView::exportClicked()
{
if (!model || !model->getOptionsModel()) {
return;
}
// CSV is currently the only supported format
QString filename = GUIUtil::getSaveFileName(this,
tr("Export Transaction History"), QString(),
tr("Comma separated file (*.csv)"), nullptr);
if (filename.isNull())
return;
CSVModelWriter writer(filename);
// name, column, role
writer.setModel(transactionProxyModel);
writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole);
if (model->haveWatchOnly())
writer.addColumn(tr("Watch-only"), TransactionTableModel::Watchonly);
writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole);
writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole);
writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole);
writer.addColumn(BitcoinUnits::getAmountColumnTitle(model->getOptionsModel()->getDisplayUnit()), 0, TransactionTableModel::FormattedAmountRole);
writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole);
if(!writer.write()) {
Q_EMIT message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename),
CClientUIInterface::MSG_ERROR);
}
else {
Q_EMIT message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename),
CClientUIInterface::MSG_INFORMATION);
}
}
void KevaView::contextualMenu(const QPoint &point)
{
QModelIndex index = kevaView->indexAt(point);
QModelIndexList selection = kevaView->selectionModel()->selectedRows(0);
if (selection.empty())
return;
// check if transaction can be abandoned, disable context menu action in case it doesn't
uint256 hash;
hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString());
abandonAction->setEnabled(model->transactionCanBeAbandoned(hash));
bumpFeeAction->setEnabled(model->transactionCanBeBumped(hash));
if(index.isValid())
{
contextMenu->popup(kevaView->viewport()->mapToGlobal(point));
}
}
void KevaView::abandonTx()
{
if(!kevaView || !kevaView->selectionModel())
return;
QModelIndexList selection = kevaView->selectionModel()->selectedRows(0);
// get the hash from the TxHashRole (QVariant / QString)
uint256 hash;
QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString();
hash.SetHex(hashQStr.toStdString());
// Abandon the wallet transaction over the walletModel
model->abandonTransaction(hash);
// Update the table
model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false);
}
void KevaView::bumpFee()
{
if(!kevaView || !kevaView->selectionModel())
return;
QModelIndexList selection = kevaView->selectionModel()->selectedRows(0);
// get the hash from the TxHashRole (QVariant / QString)
uint256 hash;
QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString();
hash.SetHex(hashQStr.toStdString());
// Bump tx fee over the walletModel
if (model->bumpFee(hash)) {
// Update the table
model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, true);
}
}
void KevaView::copyAddress()
{
GUIUtil::copyEntryData(kevaView, 0, TransactionTableModel::AddressRole);
}
void KevaView::copyLabel()
{
GUIUtil::copyEntryData(kevaView, 0, TransactionTableModel::LabelRole);
}
void KevaView::copyAmount()
{
GUIUtil::copyEntryData(kevaView, 0, TransactionTableModel::FormattedAmountRole);
}
void KevaView::copyTxID()
{
GUIUtil::copyEntryData(kevaView, 0, TransactionTableModel::TxIDRole);
}
void KevaView::copyTxHex()
{
GUIUtil::copyEntryData(kevaView, 0, TransactionTableModel::TxHexRole);
}
void KevaView::copyTxPlainText()
{
GUIUtil::copyEntryData(kevaView, 0, TransactionTableModel::TxPlainTextRole);
}
void KevaView::editLabel()
{
if(!kevaView->selectionModel() ||!model)
return;
QModelIndexList selection = kevaView->selectionModel()->selectedRows();
if(!selection.isEmpty())
{
AddressTableModel *addressBook = model->getAddressTableModel();
if(!addressBook)
return;
QString address = selection.at(0).data(TransactionTableModel::AddressRole).toString();
if(address.isEmpty())
{
// If this transaction has no associated address, exit
return;
}
// Is address in address book? Address book can miss address when a transaction is
// sent from outside the UI.
int idx = addressBook->lookupAddress(address);
if(idx != -1)
{
// Edit sending / receiving address
QModelIndex modelIdx = addressBook->index(idx, 0, QModelIndex());
// Determine type of address, launch appropriate editor dialog type
QString type = modelIdx.data(AddressTableModel::TypeRole).toString();
EditAddressDialog dlg(
type == AddressTableModel::Receive
? EditAddressDialog::EditReceivingAddress
: EditAddressDialog::EditSendingAddress, this);
dlg.setModel(addressBook);
dlg.loadRow(idx);
dlg.exec();
}
else
{
// Add sending address
EditAddressDialog dlg(EditAddressDialog::NewSendingAddress,
this);
dlg.setModel(addressBook);
dlg.setAddress(address);
dlg.exec();
}
}
}
void KevaView::showDetails()
{
if(!kevaView->selectionModel())
return;
QModelIndexList selection = kevaView->selectionModel()->selectedRows();
if(!selection.isEmpty())
{
TransactionDescDialog *dlg = new TransactionDescDialog(selection.at(0));
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show();
}
}
void KevaView::openThirdPartyTxUrl(QString url)
{
if(!kevaView || !kevaView->selectionModel())
return;
QModelIndexList selection = kevaView->selectionModel()->selectedRows(0);
if(!selection.isEmpty())
QDesktopServices::openUrl(QUrl::fromUserInput(url.replace("%s", selection.at(0).data(TransactionTableModel::TxHashRole).toString())));
}
QWidget *KevaView::createDateRangeWidget()
{
dateRangeWidget = new QFrame();
dateRangeWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
dateRangeWidget->setContentsMargins(1,1,1,1);
QHBoxLayout *layout = new QHBoxLayout(dateRangeWidget);
layout->setContentsMargins(0,0,0,0);
layout->addSpacing(23);
layout->addWidget(new QLabel(tr("Range:")));
dateFrom = new QDateTimeEdit(this);
dateFrom->setDisplayFormat("dd/MM/yy");
dateFrom->setCalendarPopup(true);
dateFrom->setMinimumWidth(100);
dateFrom->setDate(QDate::currentDate().addDays(-7));
layout->addWidget(dateFrom);
layout->addWidget(new QLabel(tr("to")));
dateTo = new QDateTimeEdit(this);
dateTo->setDisplayFormat("dd/MM/yy");
dateTo->setCalendarPopup(true);
dateTo->setMinimumWidth(100);
dateTo->setDate(QDate::currentDate());
layout->addWidget(dateTo);
layout->addStretch();
// Hide by default
dateRangeWidget->setVisible(false);
// Notify on change
connect(dateFrom, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));
connect(dateTo, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));
return dateRangeWidget;
}
void KevaView::dateRangeChanged()
{
if(!transactionProxyModel)
return;
transactionProxyModel->setDateRange(
QDateTime(dateFrom->date()),
QDateTime(dateTo->date()).addDays(1));
}
void KevaView::focusTransaction(const QModelIndex &idx)
{
if(!transactionProxyModel)
return;
QModelIndex targetIdx = transactionProxyModel->mapFromSource(idx);
kevaView->scrollTo(targetIdx);
kevaView->setCurrentIndex(targetIdx);
kevaView->setFocus();
}
// We override the virtual resizeEvent of the QWidget to adjust tables column
// sizes as the tables width is proportional to the dialogs width.
void KevaView::resizeEvent(QResizeEvent* event)
{
QWidget::resizeEvent(event);
columnResizingFixer->stretchColumnWidth(TransactionTableModel::ToAddress);
}
// Need to override default Ctrl+C action for amount as default behaviour is just to copy DisplayRole text
bool KevaView::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
if (ke->key() == Qt::Key_C && ke->modifiers().testFlag(Qt::ControlModifier))
{
GUIUtil::copyEntryData(kevaView, 0, TransactionTableModel::TxPlainTextRole);
return true;
}
}
return QWidget::eventFilter(obj, event);
}
// show/hide column Watch-only
void KevaView::updateWatchOnlyColumn(bool fHaveWatchOnly)
{
watchOnlyWidget->setVisible(fHaveWatchOnly);
kevaView->setColumnHidden(TransactionTableModel::Watchonly, !fHaveWatchOnly);
}

122
src/qt/kevaview.h

@ -1,122 +0,0 @@ @@ -1,122 +0,0 @@
// Copyright (c) 2011-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_QT_KevaView_H
#define BITCOIN_QT_KevaView_H
#include <qt/guiutil.h>
#include <QWidget>
#include <QKeyEvent>
class PlatformStyle;
class TransactionFilterProxy;
class WalletModel;
QT_BEGIN_NAMESPACE
class QComboBox;
class QDateTimeEdit;
class QFrame;
class QLineEdit;
class QMenu;
class QModelIndex;
class QSignalMapper;
class QTableView;
QT_END_NAMESPACE
/** Widget showing the transaction list for a wallet, including a filter row.
Using the filter row, the user can view or export a subset of the transactions.
*/
class KevaView : public QWidget
{
Q_OBJECT
public:
explicit KevaView(const PlatformStyle *platformStyle, QWidget *parent = 0);
void setModel(WalletModel *model);
// Date ranges for filter
enum DateEnum
{
All,
Today,
ThisWeek,
ThisMonth,
LastMonth,
ThisYear,
Range
};
enum ColumnWidths {
STATUS_COLUMN_WIDTH = 30,
WATCHONLY_COLUMN_WIDTH = 23,
DATE_COLUMN_WIDTH = 120,
TYPE_COLUMN_WIDTH = 113,
AMOUNT_MINIMUM_COLUMN_WIDTH = 120,
MINIMUM_COLUMN_WIDTH = 23
};
private:
WalletModel *model;
TransactionFilterProxy *transactionProxyModel;
QTableView *kevaView;
QComboBox *dateWidget;
QComboBox *typeWidget;
QComboBox *watchOnlyWidget;
QLineEdit *search_widget;
QLineEdit *amountWidget;
QMenu *contextMenu;
QSignalMapper *mapperThirdPartyTxUrls;
QFrame *dateRangeWidget;
QDateTimeEdit *dateFrom;
QDateTimeEdit *dateTo;
QAction *abandonAction;
QAction *bumpFeeAction;
QWidget *createDateRangeWidget();
GUIUtil::TableViewLastColumnResizingFixer *columnResizingFixer;
virtual void resizeEvent(QResizeEvent* event);
bool eventFilter(QObject *obj, QEvent *event);
private Q_SLOTS:
void contextualMenu(const QPoint &);
void dateRangeChanged();
void showDetails();
void copyAddress();
void editLabel();
void copyLabel();
void copyAmount();
void copyTxID();
void copyTxHex();
void copyTxPlainText();
void openThirdPartyTxUrl(QString url);
void updateWatchOnlyColumn(bool fHaveWatchOnly);
void abandonTx();
void bumpFee();
Q_SIGNALS:
void doubleClicked(const QModelIndex&);
/** Fired when a message should be reported to the user */
void message(const QString &title, const QString &message, unsigned int style);
public Q_SLOTS:
void chooseDate(int idx);
void chooseType(int idx);
void chooseWatchonly(int idx);
void changedAmount();
void changedSearch();
void exportClicked();
void focusTransaction(const QModelIndex&);
};
#endif // BITCOIN_QT_KevaView_H

344
src/qt/locale/bitcoin_en.ts

@ -304,17 +304,17 @@ @@ -304,17 +304,17 @@
<context>
<name>BitcoinGUI</name>
<message>
<location filename="../bitcoingui.cpp" line="+365"/>
<location filename="../bitcoingui.cpp" line="+367"/>
<source>Sign &amp;message...</source>
<translation>Sign &amp;message...</translation>
</message>
<message>
<location line="+431"/>
<location line="+437"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
<location line="-516"/>
<location line="-524"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
@ -349,7 +349,7 @@ @@ -349,7 +349,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<location line="+25"/>
<source>E&amp;xit</source>
<translation>E&amp;xit</translation>
</message>
@ -419,7 +419,7 @@ @@ -419,7 +419,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+361"/>
<location line="+367"/>
<source>Click to disable network activity.</source>
<translation type="unfinished"></translation>
</message>
@ -444,12 +444,12 @@ @@ -444,12 +444,12 @@
<translation>Reindexing blocks on disk...</translation>
</message>
<message>
<location line="-519"/>
<location line="-527"/>
<source>Send coins to a Kevacoin address</source>
<translation>Send coins to a Kevacoin address</translation>
</message>
<message>
<location line="+74"/>
<location line="+76"/>
<source>Backup wallet to another location</source>
<translation>Backup wallet to another location</translation>
</message>
@ -474,12 +474,12 @@ @@ -474,12 +474,12 @@
<translation>&amp;Verify message...</translation>
</message>
<message>
<location line="+518"/>
<location line="+524"/>
<source>Kevacoin</source>
<translation>Kevacoin</translation>
</message>
<message>
<location line="-751"/>
<location line="-759"/>
<source>Wallet</source>
<translation>Wallet</translation>
</message>
@ -494,7 +494,7 @@ @@ -494,7 +494,7 @@
<translation>&amp;Receive</translation>
</message>
<message>
<location line="+57"/>
<location line="+59"/>
<source>&amp;Show / Hide</source>
<translation>&amp;Show / Hide</translation>
</message>
@ -539,12 +539,12 @@ @@ -539,12 +539,12 @@
<translation>Tabs toolbar</translation>
</message>
<message>
<location line="-165"/>
<location line="-167"/>
<source>Request payments (generates QR codes and kevacoin: URIs)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+77"/>
<location line="+79"/>
<source>Show the list of used sending addresses and labels</source>
<translation type="unfinished"></translation>
</message>
@ -564,7 +564,7 @@ @@ -564,7 +564,7 @@
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location line="+358"/>
<location line="+364"/>
<source>%n active connection(s) to Kevacoin network</source>
<translation>
<numerusform>%n active connection to Kevacoin network</numerusform>
@ -625,7 +625,7 @@ @@ -625,7 +625,7 @@
<translation>Up to date</translation>
</message>
<message>
<location line="-442"/>
<location line="-448"/>
<source>Show the %1 help message to get a list with possible Kevacoin command-line options</source>
<translation type="unfinished"></translation>
</message>
@ -635,7 +635,7 @@ @@ -635,7 +635,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+227"/>
<location line="+233"/>
<source>Connecting to peers...</source>
<translation type="unfinished"></translation>
</message>
@ -1159,6 +1159,316 @@ @@ -1159,6 +1159,316 @@
</translation>
</message>
</context>
<context>
<name>KevaDialog</name>
<message>
<location filename="../forms/kevadialog.ui" line="+34"/>
<location line="+153"/>
<source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-150"/>
<source>&amp;Amount:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+13"/>
<location line="+46"/>
<source>An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Kevacoin network.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-43"/>
<source>&amp;Message:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+13"/>
<location line="+14"/>
<source>An optional label to associate with the new receiving address.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-7"/>
<source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>&amp;Label:</source>
<translation type="unfinished">&amp;Label:</translation>
</message>
<message>
<location line="+28"/>
<source>&amp;Request payment</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+17"/>
<source>Clear all fields of the form.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Clear</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+78"/>
<source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don&apos;t support them. When unchecked, an address compatible with older wallets will be created instead.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Generate native segwit (Bech32) address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+61"/>
<source>Requested payments history</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+25"/>
<source>Show the selected request (does the same as double clicking an entry)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Show</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+17"/>
<source>Remove the selected entries from the list</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Remove</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../kevadialog.cpp" line="+47"/>
<source>Copy URI</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy message</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy amount</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>KevaView</name>
<message>
<location filename="../kevaview.cpp" line="+70"/>
<location line="+16"/>
<source>All</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-15"/>
<source>Today</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>This week</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>This month</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Last month</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>This year</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Range...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<source>Received with</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Sent to</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>To yourself</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Mined</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Other</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Enter address, transaction id, or label to search</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>Min amount</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+48"/>
<source>Abandon transaction</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Increase transaction fee</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Copy address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy amount</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy transaction ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy raw transaction</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Copy full transaction details</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Edit label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Show transaction details</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+194"/>
<source>Export Transaction History</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Comma separated file (*.csv)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+9"/>
<source>Confirmed</source>
<translation type="unfinished">Confirmed</translation>
</message>
<message>
<location line="+2"/>
<source>Watch-only</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
<message>
<location line="+1"/>
<source>Type</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>ID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Exporting Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>There was an error trying to save the transaction history to %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Exporting Successful</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>The transaction history was successfully saved to %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+166"/>
<source>Range:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+8"/>
<source>to</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ModalOverlay</name>
<message>
@ -3944,7 +4254,7 @@ @@ -3944,7 +4254,7 @@
<context>
<name>WalletView</name>
<message>
<location filename="../walletview.cpp" line="+46"/>
<location filename="../walletview.cpp" line="+47"/>
<source>&amp;Export</source>
<translation type="unfinished">&amp;Export</translation>
</message>
@ -3954,7 +4264,7 @@ @@ -3954,7 +4264,7 @@
<translation type="unfinished">Export the data in the current tab to a file</translation>
</message>
<message>
<location line="+201"/>
<location line="+209"/>
<source>Backup Wallet</source>
<translation type="unfinished"></translation>
</message>

2
src/qt/test/wallettests.cpp

@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
#include <qt/sendcoinsentry.h>
#include <qt/transactiontablemodel.h>
#include <qt/transactionview.h>
#include <qt/kevaview.h>
#include <qt/kevadialog.h>
#include <qt/walletmodel.h>
#include <test/test_bitcoin.h>
#include <validation.h>

24
src/qt/walletview.cpp

@ -14,10 +14,10 @@ @@ -14,10 +14,10 @@
#include <qt/platformstyle.h>
#include <qt/receivecoinsdialog.h>
#include <qt/sendcoinsdialog.h>
#include <qt/kevadialog.h>
#include <qt/signverifymessagedialog.h>
#include <qt/transactiontablemodel.h>
#include <qt/transactionview.h>
#include <qt/kevaview.h>
#include <qt/walletmodel.h>
#include <ui_interface.h>
@ -54,25 +54,7 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent): @@ -54,25 +54,7 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent):
vbox->addLayout(hbox_buttons);
transactionsPage->setLayout(vbox);
#if 1
{
kevaPage = new QWidget(this);
QVBoxLayout *vbox = new QVBoxLayout();
QHBoxLayout *hbox_buttons = new QHBoxLayout();
kevaView = new KevaView(platformStyle, this);
vbox->addWidget(kevaView);
QPushButton *exportButton = new QPushButton(tr("&Export"), this);
exportButton->setToolTip(tr("Export the data in the current tab to a file"));
if (platformStyle->getImagesOnButtons()) {
exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
}
hbox_buttons->addStretch();
hbox_buttons->addWidget(exportButton);
vbox->addLayout(hbox_buttons);
kevaPage->setLayout(vbox);
}
#endif
kevaPage = new KevaDialog(platformStyle);
receiveCoinsPage = new ReceiveCoinsDialog(platformStyle);
sendCoinsPage = new SendCoinsDialog(platformStyle);
@ -140,7 +122,7 @@ void WalletView::setWalletModel(WalletModel *_walletModel) @@ -140,7 +122,7 @@ void WalletView::setWalletModel(WalletModel *_walletModel)
// Put transaction list in tabs
transactionView->setModel(_walletModel);
kevaView->setModel(_walletModel);
kevaPage->setModel(_walletModel);
overviewPage->setWalletModel(_walletModel);
receiveCoinsPage->setModel(_walletModel);
sendCoinsPage->setModel(_walletModel);

6
src/qt/walletview.h

@ -15,9 +15,9 @@ class OverviewPage; @@ -15,9 +15,9 @@ class OverviewPage;
class PlatformStyle;
class ReceiveCoinsDialog;
class SendCoinsDialog;
class KevaDialog;
class SendCoinsRecipient;
class TransactionView;
class KevaView;
class WalletModel;
class AddressBookPage;
@ -61,16 +61,14 @@ private: @@ -61,16 +61,14 @@ private:
OverviewPage *overviewPage;
QWidget *transactionsPage;
QWidget *kevaPage;
ReceiveCoinsDialog *receiveCoinsPage;
SendCoinsDialog *sendCoinsPage;
KevaDialog *kevaPage;
AddressBookPage *usedSendingAddressesPage;
AddressBookPage *usedReceivingAddressesPage;
TransactionView *transactionView;
KevaView *kevaView;
QProgressDialog *progressDialog;
const PlatformStyle *platformStyle;

Loading…
Cancel
Save