diff --git a/contrib/bitcoin-qt.pro b/contrib/bitcoin-qt.pro
index b8133bf78..2e13d7013 100644
--- a/contrib/bitcoin-qt.pro
+++ b/contrib/bitcoin-qt.pro
@@ -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 \
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 7f8bc1c6d..81181b98d 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -135,6 +135,12 @@ QT_FORMS_UI = \
qt/forms/overviewpage.ui \
qt/forms/receivecoinsdialog.ui \
qt/forms/receiverequestdialog.ui \
+ qt/forms/kevadialog.ui \
+ qt/forms/kevadetaildialog.ui \
+ qt/forms/kevaaddkeydialog.ui \
+ qt/forms/kevabookmarksdialog.ui \
+ qt/forms/kevanewnamespacedialog.ui \
+ qt/forms/kevamynamespacesdialog.ui \
qt/forms/debugwindow.ui \
qt/forms/sendcoinsdialog.ui \
qt/forms/sendcoinsentry.ui \
@@ -173,6 +179,14 @@ QT_MOC_CPP = \
qt/moc_receivecoinsdialog.cpp \
qt/moc_receiverequestdialog.cpp \
qt/moc_recentrequeststablemodel.cpp \
+ qt/moc_kevatablemodel.cpp \
+ qt/moc_kevanamespacemodel.cpp \
+ qt/moc_kevabookmarksmodel.cpp \
+ qt/moc_kevadetaildialog.cpp \
+ qt/moc_kevaaddkeydialog.cpp \
+ qt/moc_kevabookmarksdialog.cpp \
+ qt/moc_kevanewnamespacedialog.cpp \
+ qt/moc_kevamynamespacesdialog.cpp \
qt/moc_rpcconsole.cpp \
qt/moc_sendcoinsdialog.cpp \
qt/moc_sendcoinsentry.cpp \
@@ -184,6 +198,7 @@ QT_MOC_CPP = \
qt/moc_transactionfilterproxy.cpp \
qt/moc_transactiontablemodel.cpp \
qt/moc_transactionview.cpp \
+ qt/moc_kevadialog.cpp \
qt/moc_utilitydialog.cpp \
qt/moc_walletframe.cpp \
qt/moc_walletmodel.cpp \
@@ -258,6 +273,15 @@ BITCOIN_QT_H = \
qt/transactionrecord.h \
qt/transactiontablemodel.h \
qt/transactionview.h \
+ qt/kevadialog.h \
+ qt/kevatablemodel.h \
+ qt/kevanamespacemodel.h \
+ qt/kevabookmarksmodel.h \
+ qt/kevadetaildialog.h \
+ qt/kevaaddkeydialog.h \
+ qt/kevabookmarksdialog.h \
+ qt/kevanewnamespacedialog.h \
+ qt/kevamynamespacesdialog.h \
qt/utilitydialog.h \
qt/walletframe.h \
qt/walletmodel.h \
@@ -301,6 +325,7 @@ RES_ICONS = \
qt/res/icons/history.png \
qt/res/icons/info.png \
qt/res/icons/key.png \
+ qt/res/icons/keva.png \
qt/res/icons/litecoin_splash.png \
qt/res/icons/lock_closed.png \
qt/res/icons/lock_open.png \
@@ -372,6 +397,15 @@ BITCOIN_QT_WALLET_CPP = \
qt/transactionrecord.cpp \
qt/transactiontablemodel.cpp \
qt/transactionview.cpp \
+ qt/kevadialog.cpp \
+ qt/kevatablemodel.cpp \
+ qt/kevanamespacemodel.cpp \
+ qt/kevabookmarksmodel.cpp \
+ qt/kevadetaildialog.cpp \
+ qt/kevaaddkeydialog.cpp \
+ qt/kevabookmarksdialog.cpp \
+ qt/kevanewnamespacedialog.cpp \
+ qt/kevamynamespacesdialog.cpp \
qt/walletframe.cpp \
qt/walletmodel.cpp \
qt/walletmodeltransaction.cpp \
diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc
index 5d4cee07c..6aae59014 100644
--- a/src/qt/bitcoin.qrc
+++ b/src/qt/bitcoin.qrc
@@ -39,6 +39,7 @@
res/icons/lock_closed.png
res/icons/lock_open.png
res/icons/key.png
+ res/icons/keva.png
res/icons/filesave.png
res/icons/debugwindow.png
res/icons/open.png
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 422c90725..53b34cea7 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -313,6 +313,13 @@ void BitcoinGUI::createActions()
historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4));
tabGroup->addAction(historyAction);
+ kevaAction = new QAction(platformStyle->SingleColorIcon(":/icons/keva"), tr("&Keva"), this);
+ kevaAction->setStatusTip(tr("Keva related operations"));
+ kevaAction->setToolTip(kevaAction->statusTip());
+ kevaAction->setCheckable(true);
+ kevaAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5));
+ tabGroup->addAction(kevaAction);
+
#ifdef ENABLE_WALLET
// These showNormalIfMinimized are needed because Send Coins and Receive Coins
// can be triggered from the tray menu, and need to show the GUI to be useful.
@@ -328,6 +335,8 @@ void BitcoinGUI::createActions()
connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
+ connect(kevaAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
+ connect(kevaAction, SIGNAL(triggered()), this, SLOT(gotoKevaPage()));
#endif // ENABLE_WALLET
quitAction = new QAction(platformStyle->TextColorIcon(":/icons/quit"), tr("E&xit"), this);
@@ -462,6 +471,7 @@ void BitcoinGUI::createToolBars()
toolbar->addAction(sendCoinsAction);
toolbar->addAction(receiveCoinsAction);
toolbar->addAction(historyAction);
+ toolbar->addAction(kevaAction);
overviewAction->setChecked(true);
}
}
@@ -498,13 +508,13 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
}
#endif // ENABLE_WALLET
unitDisplayControl->setOptionsModel(_clientModel->getOptionsModel());
-
+
OptionsModel* optionsModel = _clientModel->getOptionsModel();
if(optionsModel)
{
// be aware of the tray icon disable state change reported by the OptionsModel object.
connect(optionsModel,SIGNAL(hideTrayIconChanged(bool)),this,SLOT(setTrayIconVisible(bool)));
-
+
// initialize the disable state of the tray icon with the current value in the model.
setTrayIconVisible(optionsModel->getHideTrayIcon());
}
@@ -691,6 +701,12 @@ void BitcoinGUI::gotoHistoryPage()
if (walletFrame) walletFrame->gotoHistoryPage();
}
+void BitcoinGUI::gotoKevaPage()
+{
+ kevaAction->setChecked(true);
+ if (walletFrame) walletFrame->gotoKevaPage();
+}
+
void BitcoinGUI::gotoReceiveCoinsPage()
{
receiveCoinsAction->setChecked(true);
@@ -1052,7 +1068,7 @@ void BitcoinGUI::setHDStatus(int hdEnabled)
labelWalletHDStatusIcon->setPixmap(platformStyle->SingleColorIcon(hdEnabled ? ":/icons/hd_enabled" : ":/icons/hd_disabled").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelWalletHDStatusIcon->setToolTip(hdEnabled ? tr("HD key generation is enabled") : tr("HD key generation is disabled"));
- // eventually disable the QLabel to set its opacity to 50%
+ // eventually disable the QLabel to set its opacity to 50%
labelWalletHDStatusIcon->setEnabled(hdEnabled);
}
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index ddb7ecb76..feaa27a8a 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -91,6 +91,7 @@ private:
QMenuBar *appMenuBar;
QAction *overviewAction;
+ QAction *kevaAction;
QAction *historyAction;
QAction *quitAction;
QAction *sendCoinsAction;
@@ -195,6 +196,8 @@ private Q_SLOTS:
void gotoOverviewPage();
/** Switch to history (transactions) page */
void gotoHistoryPage();
+ /** Switch to Keva page */
+ void gotoKevaPage();
/** Switch to receive coins page */
void gotoReceiveCoinsPage();
/** Switch to send coins page */
@@ -233,7 +236,7 @@ private Q_SLOTS:
/** Show progress dialog e.g. for verifychain */
void showProgress(const QString &title, int nProgress);
-
+
/** When hideTrayIcon setting is changed in OptionsModel hide or show the icon accordingly. */
void setTrayIconVisible(bool);
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index d6f4e7100..37169f73d 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -9,7 +9,7 @@
#define UNUSED
#endif
static const char UNUSED *bitcoin_strings[] = {
-QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin Core"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Kevacoin Core"),
QT_TRANSLATE_NOOP("bitcoin-core", "The %s developers"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"(1 = keep tx meta data e.g. account owner and payment request information, 2 "
@@ -156,7 +156,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"and enables automatic pruning of old blocks if a target size in MiB is "
"provided. This mode is incompatible with -txindex and -rescan. Warning: "
"Reverting this setting requires re-downloading the entire blockchain. "
-"(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >%u "
+"(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u "
"= automatically prune block files to stay under the specified target size in "
"MiB)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -320,6 +320,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Include IP addresses in debug output (default
QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"),
QT_TRANSLATE_NOOP("bitcoin-core", "Information"),
QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. %s is shutting down."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Input tx is not a keva operation"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Input tx is not mine"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Input tx not found in wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address or hostname: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address or hostname: '%s'"),
diff --git a/src/qt/forms/kevaaddkeydialog.ui b/src/qt/forms/kevaaddkeydialog.ui
new file mode 100644
index 000000000..8f15e1aa0
--- /dev/null
+++ b/src/qt/forms/kevaaddkeydialog.ui
@@ -0,0 +1,71 @@
+
+
+ KevaAddKeyDialog
+
+
+
+ 0
+ 0
+ 800
+ 400
+
+
+
+ Add New Key-Value Pair
+
+
+ -
+
+
+ Key
+
+
+
+ -
+
+
+ New value
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 15
+
+
+
+
+ -
+
+
+ Value
+
+
+
+ -
+
+
+ New value
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Save
+
+
+
+
+
+
+
diff --git a/src/qt/forms/kevabookmarksdialog.ui b/src/qt/forms/kevabookmarksdialog.ui
new file mode 100644
index 000000000..f1b1124a4
--- /dev/null
+++ b/src/qt/forms/kevabookmarksdialog.ui
@@ -0,0 +1,43 @@
+
+
+ KevaBookmarksDialog
+
+
+
+ 0
+ 0
+ 800
+ 400
+
+
+
+ Namespace Bookmarks
+
+
+ -
+
+
+ Qt::CustomContextMenu
+
+
+ false
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Apply|QDialogButtonBox::Cancel
+
+
+
+
+
+
+
diff --git a/src/qt/forms/kevadetaildialog.ui b/src/qt/forms/kevadetaildialog.ui
new file mode 100644
index 000000000..6bb86bbd8
--- /dev/null
+++ b/src/qt/forms/kevadetaildialog.ui
@@ -0,0 +1,74 @@
+
+
+ KevaDetailDialog
+
+
+
+ 0
+ 0
+ 800
+ 400
+
+
+
+ Value
+
+
+ -
+
+
+ This pane shows the value associated with a give key
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Close|QDialogButtonBox::Save
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ KevaDetailDialog
+ accept()
+
+
+ 20
+ 20
+
+
+ 20
+ 20
+
+
+
+
+ buttonBox
+ rejected()
+ KevaDetailDialog
+ reject()
+
+
+ 20
+ 20
+
+
+ 20
+ 20
+
+
+
+
+
diff --git a/src/qt/forms/kevadialog.ui b/src/qt/forms/kevadialog.ui
new file mode 100644
index 000000000..393ad632c
--- /dev/null
+++ b/src/qt/forms/kevadialog.ui
@@ -0,0 +1,329 @@
+
+
+ KevaDialog
+
+
+
+ 0
+ 0
+ 776
+ 396
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Sunken
+
+
+
-
+
+
-
+
+
+ The namespace ID with a prefix "N".
+
+
+
+ -
+
+
+ Use this form to perform Keva database operations.
+
+
+
+ -
+
+
+ The namespace ID with a prefix "N".
+
+
+ Namespace:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ namespace
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Show content of the namespace.
+
+
+ Show
+
+
+
+ :/icons/eye:/icons/eye
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Create a new namespace
+
+
+ &Create namespace
+
+
+
+ :/icons/add:/icons/add
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ List my namespaces
+
+
+ &My Namespaces
+
+
+
+ :/icons/editpaste:/icons/editpaste
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Show bookmarks
+
+
+ &Bookmarks
+
+
+
+ :/icons/address-book:/icons/address-book
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 10
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
-
+
+
+
+ 75
+ true
+
+
+
+ Content of namespace
+
+
+
+ -
+
+
+ Qt::CustomContextMenu
+
+
+ false
+
+
+ true
+
+
+
+ -
+
+
-
+
+
+ false
+
+
+ Show the selected request (does the same as double clicking an entry)
+
+
+ Show
+
+
+
+ :/icons/edit:/icons/edit
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+ Remove the selected entries from the list
+
+
+ Remove
+
+
+
+ :/icons/remove:/icons/remove
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+ Add new key-value pair
+
+
+ Add key-value
+
+
+
+ :/icons/add:/icons/add
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BitcoinAmountField
+ QLineEdit
+
+ 1
+
+
+
+ reqMessage
+ receiveButton
+ clearButton
+ recentRequestsView
+ showValueButton
+ removeButton
+
+
+
+
+
+
diff --git a/src/qt/forms/kevamynamespacesdialog.ui b/src/qt/forms/kevamynamespacesdialog.ui
new file mode 100644
index 000000000..841154035
--- /dev/null
+++ b/src/qt/forms/kevamynamespacesdialog.ui
@@ -0,0 +1,77 @@
+
+
+ KevaMyNamespacesDialog
+
+
+
+ 0
+ 0
+ 800
+ 400
+
+
+
+ My Namespaces
+
+
+ -
+
+
+ Qt::CustomContextMenu
+
+
+ false
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Apply|QDialogButtonBox::Cancel
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ KevaMyNamespacesDialog
+ accept()
+
+
+ 20
+ 20
+
+
+ 20
+ 20
+
+
+
+
+ buttonBox
+ rejected()
+ KevaMyNamespacesDialog
+ reject()
+
+
+ 20
+ 20
+
+
+ 20
+ 20
+
+
+
+
+
diff --git a/src/qt/forms/kevanewnamespacedialog.ui b/src/qt/forms/kevanewnamespacedialog.ui
new file mode 100644
index 000000000..25b9738d4
--- /dev/null
+++ b/src/qt/forms/kevanewnamespacedialog.ui
@@ -0,0 +1,60 @@
+
+
+ KevaNewNamespaceDialog
+
+
+
+ 0
+ 0
+ 400
+ 100
+
+
+
+ Create New Namespace
+
+
+ -
+
+
-
+
+
+ The name of the namespace.
+
+
+ Name:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ namespaceText
+
+
+
+ -
+
+
+ This pane allows the creation of a new Keva namespace
+
+
+ false
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Save
+
+
+
+
+
+
+
diff --git a/src/qt/kevaaddkeydialog.cpp b/src/qt/kevaaddkeydialog.cpp
new file mode 100644
index 000000000..12a71ecbf
--- /dev/null
+++ b/src/qt/kevaaddkeydialog.cpp
@@ -0,0 +1,60 @@
+// 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
+#include
+
+#include
+#include
+
+#include
+
+KevaAddKeyDialog::KevaAddKeyDialog(QWidget *parent, QString &nameSpace) :
+ QDialog(parent),
+ ui(new Ui::KevaAddKeyDialog)
+{
+ ui->setupUi(this);
+ this->nameSpace = nameSpace;
+ connect(ui->buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(cancel()));
+ connect(ui->buttonBox->button(QDialogButtonBox::Save), SIGNAL(clicked()), this, SLOT(create()));
+ connect(ui->keyText, SIGNAL(textChanged(const QString &)), this, SLOT(onKeyChanged(const QString &)));
+ connect(ui->valueText, SIGNAL(textChanged()), this, SLOT(onValueChanged()));
+ ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(false);
+}
+
+KevaAddKeyDialog::~KevaAddKeyDialog()
+{
+ delete ui;
+}
+
+void KevaAddKeyDialog::create()
+{
+ KevaDialog* dialog = (KevaDialog*)this->parentWidget();
+ std::string keyText = ui->keyText->text().toStdString();
+ std::string valueText = ui->valueText->toPlainText().toStdString();
+ std::string ns = nameSpace.toStdString();
+ if (!dialog->addKeyValue(ns, keyText, valueText)) {
+ QDialog::close();
+ return;
+ }
+ dialog->showNamespace(nameSpace);
+ QDialog::close();
+}
+
+void KevaAddKeyDialog::cancel()
+{
+ QDialog::close();
+}
+
+void KevaAddKeyDialog::onKeyChanged(const QString& key)
+{
+ bool enabled = key.length() > 0 && ui->valueText->toPlainText().length() > 0;
+ ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(enabled);
+}
+
+void KevaAddKeyDialog::onValueChanged()
+{
+ bool enabled = ui->valueText->toPlainText().length() > 0 && ui->keyText->text().length() > 0;
+ ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(enabled);
+}
diff --git a/src/qt/kevaaddkeydialog.h b/src/qt/kevaaddkeydialog.h
new file mode 100644
index 000000000..d65db8b86
--- /dev/null
+++ b/src/qt/kevaaddkeydialog.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2011-2014 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_KEVAADDKEYDIALOG_H
+#define BITCOIN_QT_KEVAADDKEYDIALOG_H
+
+#include
+#include
+
+#include
+
+namespace Ui {
+ class KevaAddKeyDialog;
+}
+
+QT_BEGIN_NAMESPACE
+class QModelIndex;
+QT_END_NAMESPACE
+
+/** Dialog add new key-value pair. */
+class KevaAddKeyDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit KevaAddKeyDialog(QWidget *parent, QString &nameSpace);
+ ~KevaAddKeyDialog();
+
+private:
+ Ui::KevaAddKeyDialog *ui;
+ QString nameSpace;
+
+public Q_SLOTS:
+ void create();
+ void cancel();
+ void onKeyChanged(const QString& key);
+ void onValueChanged();
+};
+
+#endif // BITCOIN_QT_KEVAADDKEYDIALOG_H
diff --git a/src/qt/kevabookmarksdialog.cpp b/src/qt/kevabookmarksdialog.cpp
new file mode 100644
index 000000000..0cc46892a
--- /dev/null
+++ b/src/qt/kevabookmarksdialog.cpp
@@ -0,0 +1,78 @@
+// 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
+#include
+
+#include
+#include
+
+#include
+#include
+
+KevaBookmarksDialog::KevaBookmarksDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::KevaBookmarksDialog)
+{
+ ui->setupUi(this);
+ ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
+ ui->buttonBox->button(QDialogButtonBox::Apply)->setText(tr("Show"));
+ connect(ui->buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject()));
+ connect(ui->buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(apply()));
+}
+
+void KevaBookmarksDialog::setModel(WalletModel *_model)
+{
+ this->model = _model;
+
+ if(_model && _model->getOptionsModel())
+ {
+ _model->getKevaBookmarksModel()->sort(KevaBookmarksModel::Name, Qt::DescendingOrder);
+ QTableView* tableView = ui->namespaceView;
+
+ tableView->verticalHeader()->hide();
+ tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ tableView->setModel(_model->getKevaBookmarksModel());
+ tableView->setAlternatingRowColors(true);
+ tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
+ tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
+ tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+
+ connect(tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+ this, SLOT(namespaceView_selectionChanged()));
+ }
+}
+
+
+void KevaBookmarksDialog::namespaceView_selectionChanged()
+{
+ bool enable = !ui->namespaceView->selectionModel()->selectedRows().isEmpty();
+ ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(enable);
+
+ if (enable) {
+ selectedIndex = ui->namespaceView->selectionModel()->currentIndex();
+ } else {
+ QModelIndex empty;
+ selectedIndex = empty;
+ }
+}
+
+void KevaBookmarksDialog::apply()
+{
+ QModelIndex idIdx = selectedIndex.sibling(selectedIndex.row(), KevaBookmarksModel::Id);
+ QString idStr = idIdx.data(Qt::DisplayRole).toString();
+ KevaDialog* dialog = (KevaDialog*)this->parentWidget();
+ dialog->showNamespace(idStr);
+ QDialog::close();
+}
+
+void KevaBookmarksDialog::reject()
+{
+ QDialog::reject();
+}
+
+KevaBookmarksDialog::~KevaBookmarksDialog()
+{
+ delete ui;
+}
\ No newline at end of file
diff --git a/src/qt/kevabookmarksdialog.h b/src/qt/kevabookmarksdialog.h
new file mode 100644
index 000000000..cd96d71f1
--- /dev/null
+++ b/src/qt/kevabookmarksdialog.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2011-2014 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_KEVABOOKMARKSDIALOG_H
+#define BITCOIN_QT_KEVABOOKMARKSDIALOG_H
+
+#include
+#include
+
+#include
+#include
+#include
+
+class WalletModel;
+
+namespace Ui {
+ class KevaBookmarksDialog;
+}
+
+
+/** Dialog showing namepsace creation. */
+class KevaBookmarksDialog : public QDialog
+{
+ Q_OBJECT
+
+ enum ColumnWidths {
+ ID_COLUMN_WIDTH = 260,
+ NAME_COLUMN_WIDTH = 260,
+ MINIMUM_COLUMN_WIDTH = 260
+ };
+
+public:
+ explicit KevaBookmarksDialog(QWidget *parent = 0);
+ ~KevaBookmarksDialog();
+ void setModel(WalletModel *_model);
+
+public Q_SLOTS:
+ void apply();
+ void reject();
+
+private Q_SLOTS:
+ void namespaceView_selectionChanged();
+
+private:
+ Ui::KevaBookmarksDialog *ui;
+ WalletModel *model;
+ QModelIndex selectedIndex;
+};
+
+#endif // BITCOIN_QT_KEVABOOKMARKSDIALOG_H
diff --git a/src/qt/kevabookmarksmodel.cpp b/src/qt/kevabookmarksmodel.cpp
new file mode 100644
index 000000000..9e823f806
--- /dev/null
+++ b/src/qt/kevabookmarksmodel.cpp
@@ -0,0 +1,242 @@
+// 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
+
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+
+KevaBookmarksModel::KevaBookmarksModel(CWallet *wallet, WalletModel *parent) :
+ QAbstractTableModel(parent), walletModel(parent)
+{
+ Q_UNUSED(wallet)
+
+ /* These columns must match the indices in the ColumnIndex enumeration */
+ columns << tr("Id") << tr("Name");
+}
+
+KevaBookmarksModel::~KevaBookmarksModel()
+{
+ /* Intentionally left empty */
+}
+
+int KevaBookmarksModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return list.length();
+}
+
+int KevaBookmarksModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return columns.length();
+}
+
+QVariant KevaBookmarksModel::data(const QModelIndex &index, int role) const
+{
+ if(!index.isValid() || index.row() >= list.length())
+ return QVariant();
+
+ if (role == Qt::TextColorRole)
+ {
+ return QVariant();
+ }
+ else if(role == Qt::DisplayRole || role == Qt::EditRole)
+ {
+ const BookmarkEntry *rec = &list[index.row()];
+ switch(index.column())
+ {
+ case Id:
+ return QString::fromStdString(rec->id);
+ case Name:
+ return QString::fromStdString(rec->name);
+ }
+ }
+ else if (role == Qt::TextAlignmentRole)
+ {
+ return (int)(Qt::AlignLeft|Qt::AlignVCenter);
+ }
+ return QVariant();
+}
+
+bool KevaBookmarksModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ return true;
+}
+
+QVariant KevaBookmarksModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if(orientation == Qt::Horizontal)
+ {
+ if(role == Qt::DisplayRole && section < columns.size())
+ {
+ return columns[section];
+ }
+ }
+ return QVariant();
+}
+
+
+QModelIndex KevaBookmarksModel::index(int row, int column, const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return createIndex(row, column);
+}
+
+bool KevaBookmarksModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ Q_UNUSED(parent);
+
+ if(count > 0 && row >= 0 && (row+count) <= list.size())
+ {
+ beginRemoveRows(parent, row, row + count - 1);
+ list.erase(list.begin() + row, list.begin() + row + count);
+ endRemoveRows();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Qt::ItemFlags KevaBookmarksModel::flags(const QModelIndex &index) const
+{
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+}
+
+// actually add to table in GUI
+void KevaBookmarksModel::setBookmarks(std::vector vBookmarEntries)
+{
+ // Remove the old ones.
+ removeRows(0, list.size());
+ list.clear();
+
+ for (auto it = vBookmarEntries.begin(); it != vBookmarEntries.end(); it++) {
+ beginInsertRows(QModelIndex(), 0, 0);
+ list.prepend(*it);
+ endInsertRows();
+ }
+}
+
+void KevaBookmarksModel::setBookmarks(QJsonArray &array)
+{
+ std::vector vBookmarEntries;
+ for (int i = 0; i < array.size(); ++i) {
+ QJsonObject obj = array[i].toObject();
+ BookmarkEntry entry;
+ entry.id = obj["id"].toString().toStdString();
+ entry.name = obj["name"].toString().toStdString();
+ vBookmarEntries.push_back(entry);
+ }
+ setBookmarks(std::move(vBookmarEntries));
+}
+
+void KevaBookmarksModel::sort(int column, Qt::SortOrder order)
+{
+ qSort(list.begin(), list.end(), BookmarkEntryLessThan(column, order));
+ Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex()));
+}
+
+
+QString KevaBookmarksModel::getBookmarkFile()
+{
+ QString dataDir = GUIUtil::boostPathToQString(GetDataDir());
+ return dataDir + QDir::separator() + QStringLiteral(BOOKMARK_FILE);
+}
+
+int KevaBookmarksModel::loadBookmarks()
+{
+ QJsonArray json;
+ if (loadBookmarks(json)) {
+ setBookmarks(json);
+ return 1;
+ }
+
+ // No bookmark file. Save and load the default ones.
+ QJsonObject entry0;
+ entry0["id"] = "NgKBKkBAJMtzsuit85TpTpo5Xj6UQUg1wr";
+ entry0["name"] = "Kevacoin Official Blog";
+
+ QJsonObject entry1;
+ entry1["id"] = "NV9GkLpCLMh4Nd6nZRkch8iNbuV8w9khTm";
+ entry1["name"] = "Kevacoin官方博客";
+
+ QJsonObject entry2;
+ entry2["id"] = "NfFPgVqzk3H9afHjX8FDoyhkwtwGNanjyG";
+ entry2["name"] = "Официальный блог Kevacoin";
+
+ QJsonArray array;
+ array.append(entry0);
+ array.append(entry1);
+ array.append(entry2);
+
+ if (!saveBookmarks(array)) {
+ return 0;
+ }
+
+ // Load the bookmarks again.
+ if (loadBookmarks(json)) {
+ setBookmarks(json);
+ return 1;
+ }
+ return 0;
+}
+
+
+int KevaBookmarksModel::loadBookmarks(QJsonArray &json)
+{
+ QFile loadFile(getBookmarkFile());
+ if (!loadFile.open(QIODevice::ReadOnly)) {
+ return 0;
+ }
+ QByteArray saveData = loadFile.readAll();
+ QJsonDocument loadDoc(QJsonDocument::fromBinaryData(saveData));
+ json = loadDoc.array();
+ return 1;
+}
+
+int KevaBookmarksModel::saveBookmarks(QJsonArray &json)
+{
+ QFile saveFile(getBookmarkFile());
+ if (!saveFile.open(QIODevice::WriteOnly)) {
+ return 0;
+ }
+
+ QJsonDocument saveDoc(json);
+ saveFile.write(saveDoc.toBinaryData());
+ return 1;
+}
+
+
+bool BookmarkEntryLessThan::operator()(BookmarkEntry &left, BookmarkEntry &right) const
+{
+ BookmarkEntry *pLeft = &left;
+ BookmarkEntry *pRight = &right;
+ if (order == Qt::DescendingOrder)
+ std::swap(pLeft, pRight);
+
+ switch(column)
+ {
+ case KevaBookmarksModel::Id:
+ return pLeft->id < pRight->id;
+ case KevaBookmarksModel::Name:
+ return pLeft->name < pRight->name;
+ default:
+ return pLeft->id < pRight->id;
+ }
+}
diff --git a/src/qt/kevabookmarksmodel.h b/src/qt/kevabookmarksmodel.h
new file mode 100644
index 000000000..b2821b3a1
--- /dev/null
+++ b/src/qt/kevabookmarksmodel.h
@@ -0,0 +1,90 @@
+// 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_KEVABOOKMARKSMODEL_H
+#define BITCOIN_QT_KEVABOOKMARKSMODEL_H
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#define BOOKMARK_FILE "bookmarks.dat"
+
+class CWallet;
+
+class BookmarkEntry
+{
+public:
+ BookmarkEntry() { }
+
+ std::string id;
+ std::string name;
+};
+
+class BookmarkEntryLessThan
+{
+public:
+ BookmarkEntryLessThan(int nColumn, Qt::SortOrder fOrder):
+ column(nColumn), order(fOrder) {}
+ bool operator()(BookmarkEntry &left, BookmarkEntry &right) const;
+
+private:
+ int column;
+ Qt::SortOrder order;
+};
+
+/** Model for list of recently generated payment requests / bitcoin: URIs.
+ * Part of wallet model.
+ */
+class KevaBookmarksModel: public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ explicit KevaBookmarksModel(CWallet *wallet, WalletModel *parent);
+ ~KevaBookmarksModel();
+
+ enum ColumnIndex {
+ Id = 0,
+ Name = 1,
+ NUMBER_OF_COLUMNS
+ };
+
+ /** @name Methods overridden from QAbstractTableModel
+ @{*/
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role);
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ /*@}*/
+
+ const BookmarkEntry &entry(int row) const { return list[row]; }
+ void setBookmarks(std::vector vBookmarkEntries);
+ void setBookmarks(QJsonArray &json);
+
+ int loadBookmarks();
+ int loadBookmarks(QJsonArray &json);
+ int saveBookmarks(QJsonArray &json);
+
+public Q_SLOTS:
+ void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
+
+private:
+ WalletModel *walletModel;
+ QStringList columns;
+ QList list;
+ int64_t nReceiveRequestsMaxId;
+
+ QString getBookmarkFile();
+};
+
+#endif // BITCOIN_QT_KEVABOOKMARKSMODEL_H
diff --git a/src/qt/kevadetaildialog.cpp b/src/qt/kevadetaildialog.cpp
new file mode 100644
index 000000000..8e9376dd4
--- /dev/null
+++ b/src/qt/kevadetaildialog.cpp
@@ -0,0 +1,56 @@
+// 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
+#include
+
+#include
+#include
+
+#include
+#include
+
+
+KevaDetailDialog::KevaDetailDialog(const QModelIndex &idx, QWidget *parent, const QString &nameSpace) :
+ QDialog(parent),
+ ui(new Ui::KevaDetailDialog)
+{
+ ui->setupUi(this);
+ QModelIndex keyIdx = idx.sibling(idx.row(), KevaTableModel::Key);
+ QModelIndex valueIdx = idx.sibling(idx.row(), KevaTableModel::Value);
+ this->nameSpace = nameSpace;
+ key = keyIdx.data(Qt::DisplayRole).toString();
+ setWindowTitle(tr("Value for %1").arg(key));
+ QString desc = valueIdx.data(Qt::DisplayRole).toString();
+ connect(ui->detailText, SIGNAL(textChanged()), this, SLOT(onValueChanged()));
+ //ui->detailText->setHtml(desc);
+ ui->detailText->setPlainText(desc);
+ ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(false);
+ connect(ui->buttonBox->button(QDialogButtonBox::Save), SIGNAL(clicked()), this, SLOT(onSave()));
+}
+
+KevaDetailDialog::~KevaDetailDialog()
+{
+ delete ui;
+}
+
+void KevaDetailDialog::onValueChanged()
+{
+ bool enabled = ui->detailText->toPlainText().length() > 0;
+ ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(enabled);
+}
+
+void KevaDetailDialog::onSave()
+{
+ KevaDialog* dialog = (KevaDialog*)this->parentWidget();
+ std::string keyText = key.toStdString();
+ std::string valueText = ui->detailText->toPlainText().toStdString();
+ std::string ns = nameSpace.toStdString();
+ if (!dialog->addKeyValue(ns, keyText, valueText)) {
+ QDialog::close();
+ return;
+ }
+ dialog->showNamespace(nameSpace);
+ QDialog::close();
+}
diff --git a/src/qt/kevadetaildialog.h b/src/qt/kevadetaildialog.h
new file mode 100644
index 000000000..597eb1bc4
--- /dev/null
+++ b/src/qt/kevadetaildialog.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2011-2014 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_KEVADETAILDIALOG_H
+#define BITCOIN_QT_KEVADETAILDIALOG_H
+
+#include
+#include
+
+#include
+
+namespace Ui {
+ class KevaDetailDialog;
+}
+
+QT_BEGIN_NAMESPACE
+class QModelIndex;
+QT_END_NAMESPACE
+
+/** Dialog showing transaction details. */
+class KevaDetailDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit KevaDetailDialog(const QModelIndex &idx, QWidget *parent, const QString &nameSpace);
+ ~KevaDetailDialog();
+
+public Q_SLOTS:
+ void onValueChanged();
+ void onSave();
+
+private:
+ Ui::KevaDetailDialog *ui;
+ QString nameSpace;
+ QString key;
+};
+
+#endif // BITCOIN_QT_KEVADETAILDIALOG_H
diff --git a/src/qt/kevadialog.cpp b/src/qt/kevadialog.cpp
new file mode 100644
index 000000000..c9e5230ca
--- /dev/null
+++ b/src/qt/kevadialog.cpp
@@ -0,0 +1,425 @@
+// 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
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+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->bookmarksButton->setIcon(QIcon());
+ ui->showValueButton->setIcon(QIcon());
+ ui->removeButton->setIcon(QIcon());
+ } else {
+ ui->bookmarksButton->setIcon(_platformStyle->SingleColorIcon(":/icons/address-book"));
+ ui->showValueButton->setIcon(_platformStyle->SingleColorIcon(":/icons/edit"));
+ ui->removeButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->addKVButton->setIcon(_platformStyle->SingleColorIcon(":/icons/add"));
+ }
+
+ // 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->kevaView, 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->nameSpace, SIGNAL(textChanged(const QString &)), this, SLOT(onNamespaceChanged(const QString &)));
+}
+
+void KevaDialog::setModel(WalletModel *_model)
+{
+ this->model = _model;
+
+ if(_model && _model->getOptionsModel())
+ {
+ _model->getKevaTableModel()->sort(KevaTableModel::Block, Qt::DescendingOrder);
+ QTableView* tableView = ui->kevaView;
+
+ tableView->verticalHeader()->hide();
+ tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ tableView->setModel(_model->getKevaTableModel());
+ tableView->setAlternatingRowColors(true);
+ tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
+ tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
+ tableView->setColumnWidth(KevaTableModel::Date, DATE_COLUMN_WIDTH);
+ tableView->setColumnWidth(KevaTableModel::Key, KEY_COLUMN_WIDTH);
+ tableView->setColumnWidth(KevaTableModel::Block, BLOCK_MINIMUM_COLUMN_WIDTH);
+
+ connect(ui->kevaView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+ this, SLOT(kevaView_selectionChanged()));
+
+ // Last 2 columns are set by the columnResizingFixer, when the table geometry is ready.
+ columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, BLOCK_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this);
+ }
+}
+
+void KevaDialog::showNamespace(QString ns)
+{
+ ui->nameSpace->setText(ns);
+ on_showContent_clicked();
+}
+
+KevaDialog::~KevaDialog()
+{
+ delete ui;
+}
+
+void KevaDialog::clear()
+{
+ ui->nameSpace->setText("");
+ updateDisplayUnit();
+}
+
+void KevaDialog::reject()
+{
+ clear();
+}
+
+void KevaDialog::accept()
+{
+ clear();
+}
+
+void KevaDialog::updateDisplayUnit()
+{
+ if(model && model->getOptionsModel())
+ {
+ }
+}
+
+void KevaDialog::on_createNamespace_clicked()
+{
+ if(!model || !model->getKevaTableModel())
+ return;
+
+ KevaNewNamespaceDialog *dialog = new KevaNewNamespaceDialog(this);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+}
+
+void KevaDialog::onNamespaceChanged(const QString& nameSpace)
+{
+ std::string namespaceStr = nameSpace.toStdString();
+ valtype nameSpaceVal;
+ if (DecodeKevaNamespace(namespaceStr, Params(), nameSpaceVal)) {
+ ui->addKVButton->setEnabled(true);
+ } else {
+ ui->addKVButton->setEnabled(false);
+ }
+}
+
+
+void KevaDialog::on_listNamespaces_clicked()
+{
+ if(!model || !model->getKevaTableModel())
+ return;
+
+ KevaMyNamespacesDialog *dialog = new KevaMyNamespacesDialog(this);
+
+ std::vector vNamespaceEntries;
+ model->getNamespaceEntries(vNamespaceEntries);
+ model->getKevaNamespaceModel()->setNamespace(std::move(vNamespaceEntries));
+ model->getKevaNamespaceModel()->sort(KevaNamespaceModel::Name, Qt::DescendingOrder);
+
+ dialog->setModel(model);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+}
+
+void KevaDialog::on_bookmarksButton_clicked()
+{
+ if(!model || !model->getKevaTableModel())
+ return;
+
+ KevaBookmarksDialog *dialog = new KevaBookmarksDialog(this);
+
+ model->getKevaBookmarksModel()->loadBookmarks();
+ model->getKevaBookmarksModel()->sort(KevaBookmarksModel::Name, Qt::DescendingOrder);
+
+ dialog->setModel(model);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+}
+
+void KevaDialog::on_showContent_clicked()
+{
+ if(!model || !model->getKevaTableModel())
+ return;
+
+ valtype namespaceVal;
+ QString nameSpace = ui->nameSpace->text();
+ if (!DecodeKevaNamespace(nameSpace.toStdString(), Params(), namespaceVal)) {
+ // TODO: show error dialog
+ return;
+ }
+
+ std::vector vKevaEntries;
+ model->getKevaEntries(vKevaEntries, ValtypeToString(namespaceVal));
+ model->getKevaTableModel()->setKeva(std::move(vKevaEntries));
+ model->getKevaTableModel()->sort(KevaTableModel::Date, Qt::DescendingOrder);
+}
+
+void KevaDialog::on_kevaView_doubleClicked(const QModelIndex &index)
+{
+ QString nameSpace = ui->nameSpace->text();
+ KevaDetailDialog *dialog = new KevaDetailDialog(index, this, nameSpace);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+}
+
+void KevaDialog::kevaView_selectionChanged()
+{
+ // Enable Show/Remove buttons only if anything is selected.
+ bool enable = !ui->kevaView->selectionModel()->selectedRows().isEmpty();
+ ui->showValueButton->setEnabled(enable);
+ ui->removeButton->setEnabled(enable);
+ ui->addKVButton->setEnabled(enable);
+}
+
+void KevaDialog::on_showValueButton_clicked()
+{
+ if(!model || !model->getKevaTableModel() || !ui->kevaView->selectionModel())
+ return;
+ QModelIndexList selection = ui->kevaView->selectionModel()->selectedRows();
+
+ for (const QModelIndex& index : selection) {
+ on_kevaView_doubleClicked(index);
+ }
+}
+
+void KevaDialog::on_removeButton_clicked()
+{
+ if(!model || !model->getKevaTableModel() || !ui->kevaView->selectionModel())
+ return;
+ QModelIndexList selection = ui->kevaView->selectionModel()->selectedRows();
+ if(selection.empty())
+ return;
+
+ QMessageBox::StandardButton reply;
+ QModelIndex index = selection.at(0);
+ QModelIndex keyIdx = index.sibling(index.row(), KevaTableModel::Key);
+ QString keyStr = keyIdx.data(Qt::DisplayRole).toString();
+ reply = QMessageBox::warning(this, tr("Warning"), tr("Delete the key \"%1\"?").arg(keyStr),
+ QMessageBox::Cancel|QMessageBox::Ok);
+
+ if (reply == QMessageBox::Cancel) {
+ return;
+ }
+
+ std::string nameSpace = ui->nameSpace->text().toStdString();
+ std::string key = keyStr.toStdString();
+
+ int ret = this->model->deleteKevaEntry(nameSpace, key);
+ if (ret > 0) {
+ QString msg;
+ switch (ret) {
+ case WalletModel::InvalidNamespace:
+ msg = tr("Invalid namespace \"%1\"").arg(ui->nameSpace->text());
+ break;
+ case WalletModel::KeyNotFound:
+ msg = tr("Key not found: \"%1\".").arg(keyStr);
+ break;
+ default:
+ msg = tr("Unknown error.");
+ }
+ QMessageBox::critical(this, tr("Error"), msg, QMessageBox::Ok);
+ return;
+ }
+
+ // correct for selection mode ContiguousSelection
+ QModelIndex firstIndex = selection.at(0);
+ model->getKevaTableModel()->removeRows(firstIndex.row(), selection.length(), firstIndex.parent());
+}
+
+void KevaDialog::on_addKVButton_clicked()
+{
+ QString ns = ui->nameSpace->text();
+ KevaAddKeyDialog *dialog = new KevaAddKeyDialog(this, ns);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+}
+
+// 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(KevaTableModel::Block);
+}
+
+void KevaDialog::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_Return)
+ {
+ // press return -> submit form
+ if (ui->nameSpace->hasFocus())
+ {
+ event->ignore();
+ on_showContent_clicked();
+ return;
+ }
+ }
+
+ this->QDialog::keyPressEvent(event);
+}
+
+QModelIndex KevaDialog::selectedRow()
+{
+ if(!model || !model->getKevaTableModel() || !ui->kevaView->selectionModel())
+ return QModelIndex();
+ QModelIndexList selection = ui->kevaView->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->getKevaTableModel()->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()
+{
+#if 0
+ QModelIndex sel = selectedRow();
+ if (!sel.isValid()) {
+ return;
+ }
+
+ const KevaTableModel * const submodel = model->getKevaTableModel();
+ const QString uri = GUIUtil::formatBitcoinURI(submodel->entry(sel.row()).recipient);
+ GUIUtil::setClipboard(uri);
+#endif
+}
+
+// context menu action: copy label
+void KevaDialog::copyLabel()
+{
+ copyColumnToClipboard(KevaTableModel::Key);
+}
+
+// context menu action: copy message
+void KevaDialog::copyMessage()
+{
+ copyColumnToClipboard(KevaTableModel::Value);
+}
+
+// context menu action: copy amount
+void KevaDialog::copyAmount()
+{
+ copyColumnToClipboard(KevaTableModel::Block);
+}
+
+
+int KevaDialog::createNamespace(std::string displayName, std::string& namespaceId)
+{
+ if (!this->model) {
+ return 0;
+ }
+
+ int ret = this->model->createNamespace(displayName, namespaceId);
+ if (ret > 0) {
+ QString msg;
+ switch (ret) {
+ case WalletModel::NamespaceTooLong:
+ msg = tr("Namespace too long \"%1\"").arg(QString::fromStdString(displayName));
+ break;
+ default:
+ msg = tr("Unknown error.");
+ }
+ QMessageBox::critical(this, tr("Error"), msg, QMessageBox::Ok);
+ return 0;
+ }
+ return 1;
+}
+
+int KevaDialog::addKeyValue(std::string& namespaceId, std::string& key, std::string& value)
+{
+ if (!this->model) {
+ return 0;
+ }
+
+ int ret = this->model->addKeyValue(namespaceId, key, value);
+ if (ret > 0) {
+ QString msg;
+ switch (ret) {
+ case WalletModel::CannotUpdate:
+ msg = tr("Cannot add key-value. Make sure you own this namespace.");
+ break;
+ case WalletModel::KeyTooLong:
+ msg = tr("Key too long.");
+ break;
+ case WalletModel::ValueTooLong:
+ msg = tr("Value too long.");
+ break;
+ default:
+ msg = tr("Unknown error.");
+ }
+ QMessageBox::critical(this, tr("Error"), msg, QMessageBox::Ok);
+ return 0;
+ }
+ return 1;
+}
diff --git a/src/qt/kevadialog.h b/src/qt/kevadialog.h
new file mode 100644
index 000000000..66b9958c2
--- /dev/null
+++ b/src/qt/kevadialog.h
@@ -0,0 +1,88 @@
+// 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
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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,
+ KEY_COLUMN_WIDTH = 120,
+ BLOCK_MINIMUM_COLUMN_WIDTH = 100,
+ MINIMUM_COLUMN_WIDTH = 100
+ };
+
+ explicit KevaDialog(const PlatformStyle *platformStyle, QWidget *parent = 0);
+ ~KevaDialog();
+
+ void setModel(WalletModel *model);
+ void showNamespace(QString ns);
+ int createNamespace(std::string displayName, std::string& namespaceId);
+ int addKeyValue(std::string& namespaceId, std::string& key, std::string& Value);
+
+public Q_SLOTS:
+ void clear();
+ void reject();
+ void accept();
+ void onNamespaceChanged(const QString& nameSpace);
+
+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_showContent_clicked();
+ void on_createNamespace_clicked();
+ void on_listNamespaces_clicked();
+ void on_showValueButton_clicked();
+ void on_removeButton_clicked();
+ void on_addKVButton_clicked();
+ void on_kevaView_doubleClicked(const QModelIndex &index);
+ void kevaView_selectionChanged();
+ void on_bookmarksButton_clicked();
+ void updateDisplayUnit();
+ void showMenu(const QPoint &point);
+ void copyURI();
+ void copyLabel();
+ void copyMessage();
+ void copyAmount();
+};
+
+#endif // BITCOIN_QT_KEVADIALOG_H
diff --git a/src/qt/kevamynamespacesdialog.cpp b/src/qt/kevamynamespacesdialog.cpp
new file mode 100644
index 000000000..191f08612
--- /dev/null
+++ b/src/qt/kevamynamespacesdialog.cpp
@@ -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.
+
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+
+KevaMyNamespacesDialog::KevaMyNamespacesDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::KevaMyNamespacesDialog)
+{
+ ui->setupUi(this);
+ ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
+ ui->buttonBox->button(QDialogButtonBox::Apply)->setText(tr("Show"));
+ connect(ui->buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject()));
+ connect(ui->buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(apply()));
+}
+
+void KevaMyNamespacesDialog::setModel(WalletModel *_model)
+{
+ this->model = _model;
+
+ if(_model && _model->getOptionsModel())
+ {
+ _model->getKevaNamespaceModel()->sort(KevaNamespaceModel::Name, Qt::DescendingOrder);
+ QTableView* tableView = ui->namespaceView;
+
+ tableView->verticalHeader()->hide();
+ tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ tableView->setModel(_model->getKevaNamespaceModel());
+ tableView->setAlternatingRowColors(true);
+ tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
+ tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
+ //tableView->setColumnWidth(KevaNamespaceModel::Id, ID_COLUMN_WIDTH);
+ //tableView->setColumnWidth(KevaNamespaceModel::Name, NAME_COLUMN_WIDTH);
+ tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+
+ connect(tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+ this, SLOT(namespaceView_selectionChanged()));
+ }
+}
+
+
+void KevaMyNamespacesDialog::namespaceView_selectionChanged()
+{
+ bool enable = !ui->namespaceView->selectionModel()->selectedRows().isEmpty();
+ ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(enable);
+
+ if (enable) {
+ selectedIndex = ui->namespaceView->selectionModel()->currentIndex();
+ } else {
+ QModelIndex empty;
+ selectedIndex = empty;
+ }
+}
+
+void KevaMyNamespacesDialog::apply()
+{
+ QModelIndex idIdx = selectedIndex.sibling(selectedIndex.row(), KevaNamespaceModel::Id);
+ QString idStr = idIdx.data(Qt::DisplayRole).toString();
+ KevaDialog* dialog = (KevaDialog*)this->parentWidget();
+ dialog->showNamespace(idStr);
+ QDialog::close();
+}
+
+void KevaMyNamespacesDialog::reject()
+{
+ QDialog::reject();
+}
+
+KevaMyNamespacesDialog::~KevaMyNamespacesDialog()
+{
+ delete ui;
+}
\ No newline at end of file
diff --git a/src/qt/kevamynamespacesdialog.h b/src/qt/kevamynamespacesdialog.h
new file mode 100644
index 000000000..b8ed56cad
--- /dev/null
+++ b/src/qt/kevamynamespacesdialog.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2011-2014 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_KEVAMYNMAESPACESDIALOG_H
+#define BITCOIN_QT_KEVAMYNMAESPACESDIALOG_H
+
+#include
+#include
+
+#include
+#include
+#include
+
+class WalletModel;
+
+namespace Ui {
+ class KevaMyNamespacesDialog;
+}
+
+
+/** Dialog showing namepsace creation. */
+class KevaMyNamespacesDialog : public QDialog
+{
+ Q_OBJECT
+
+ enum ColumnWidths {
+ ID_COLUMN_WIDTH = 260,
+ NAME_COLUMN_WIDTH = 260,
+ MINIMUM_COLUMN_WIDTH = 260
+ };
+
+public:
+ explicit KevaMyNamespacesDialog(QWidget *parent = 0);
+ ~KevaMyNamespacesDialog();
+ void setModel(WalletModel *_model);
+
+public Q_SLOTS:
+ void apply();
+ void reject();
+
+private Q_SLOTS:
+ void namespaceView_selectionChanged();
+
+private:
+ Ui::KevaMyNamespacesDialog *ui;
+ WalletModel *model;
+ QModelIndex selectedIndex;
+};
+
+#endif // BITCOIN_QT_KEVAMYNMAESPACESDIALOG_H
diff --git a/src/qt/kevanamespacemodel.cpp b/src/qt/kevanamespacemodel.cpp
new file mode 100644
index 000000000..ae88e1b4a
--- /dev/null
+++ b/src/qt/kevanamespacemodel.cpp
@@ -0,0 +1,156 @@
+// 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
+
+#include
+#include
+#include
+
+#include
+#include
+
+
+KevaNamespaceModel::KevaNamespaceModel(CWallet *wallet, WalletModel *parent) :
+ QAbstractTableModel(parent), walletModel(parent)
+{
+ Q_UNUSED(wallet)
+
+ /* These columns must match the indices in the ColumnIndex enumeration */
+ columns << tr("Id") << tr("Name");
+}
+
+KevaNamespaceModel::~KevaNamespaceModel()
+{
+ /* Intentionally left empty */
+}
+
+int KevaNamespaceModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return list.length();
+}
+
+int KevaNamespaceModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return columns.length();
+}
+
+QVariant KevaNamespaceModel::data(const QModelIndex &index, int role) const
+{
+ if(!index.isValid() || index.row() >= list.length())
+ return QVariant();
+
+ if (role == Qt::TextColorRole)
+ {
+ const NamespaceEntry *rec = &list[index.row()];
+ if (!rec->confirmed) {
+ return QVariant(QBrush (QColor(Qt::gray)));
+ }
+ return QVariant();
+ }
+ else if(role == Qt::DisplayRole || role == Qt::EditRole)
+ {
+ const NamespaceEntry *rec = &list[index.row()];
+ switch(index.column())
+ {
+ case Id:
+ return QString::fromStdString(rec->id);
+ case Name:
+ return QString::fromStdString(rec->name);
+ }
+ }
+ else if (role == Qt::TextAlignmentRole)
+ {
+ return (int)(Qt::AlignLeft|Qt::AlignVCenter);
+ }
+ return QVariant();
+}
+
+bool KevaNamespaceModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ return true;
+}
+
+QVariant KevaNamespaceModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if(orientation == Qt::Horizontal)
+ {
+ if(role == Qt::DisplayRole && section < columns.size())
+ {
+ return columns[section];
+ }
+ }
+ return QVariant();
+}
+
+
+QModelIndex KevaNamespaceModel::index(int row, int column, const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return createIndex(row, column);
+}
+
+bool KevaNamespaceModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ Q_UNUSED(parent);
+
+ if(count > 0 && row >= 0 && (row+count) <= list.size())
+ {
+ beginRemoveRows(parent, row, row + count - 1);
+ list.erase(list.begin() + row, list.begin() + row + count);
+ endRemoveRows();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Qt::ItemFlags KevaNamespaceModel::flags(const QModelIndex &index) const
+{
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+}
+
+// actually add to table in GUI
+void KevaNamespaceModel::setNamespace(std::vector vNamespaceEntries)
+{
+ // Remove the old ones.
+ removeRows(0, list.size());
+ list.clear();
+
+ for (auto it = vNamespaceEntries.begin(); it != vNamespaceEntries.end(); it++) {
+ beginInsertRows(QModelIndex(), 0, 0);
+ list.prepend(*it);
+ endInsertRows();
+ }
+}
+
+void KevaNamespaceModel::sort(int column, Qt::SortOrder order)
+{
+ qSort(list.begin(), list.end(), NamespaceEntryLessThan(column, order));
+ Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex()));
+}
+
+
+bool NamespaceEntryLessThan::operator()(NamespaceEntry &left, NamespaceEntry &right) const
+{
+ NamespaceEntry *pLeft = &left;
+ NamespaceEntry *pRight = &right;
+ if (order == Qt::DescendingOrder)
+ std::swap(pLeft, pRight);
+
+ switch(column)
+ {
+ case KevaNamespaceModel::Id:
+ return pLeft->id < pRight->id;
+ case KevaNamespaceModel::Name:
+ return pLeft->name < pRight->name;
+ default:
+ return pLeft->id < pRight->id;
+ }
+}
diff --git a/src/qt/kevanamespacemodel.h b/src/qt/kevanamespacemodel.h
new file mode 100644
index 000000000..56b99bdd5
--- /dev/null
+++ b/src/qt/kevanamespacemodel.h
@@ -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_KEVANAMESPACEMODEL_H
+#define BITCOIN_QT_KEVANAMESPACEMODEL_H
+
+#include
+
+#include
+#include
+#include
+
+class CWallet;
+
+class NamespaceEntry
+{
+public:
+ NamespaceEntry():confirmed(true) { }
+
+ std::string id;
+ std::string name;
+ bool confirmed;
+};
+
+class NamespaceEntryLessThan
+{
+public:
+ NamespaceEntryLessThan(int nColumn, Qt::SortOrder fOrder):
+ column(nColumn), order(fOrder) {}
+ bool operator()(NamespaceEntry &left, NamespaceEntry &right) const;
+
+private:
+ int column;
+ Qt::SortOrder order;
+};
+
+/** Model for list of recently generated payment requests / bitcoin: URIs.
+ * Part of wallet model.
+ */
+class KevaNamespaceModel: public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ explicit KevaNamespaceModel(CWallet *wallet, WalletModel *parent);
+ ~KevaNamespaceModel();
+
+ enum ColumnIndex {
+ Id = 0,
+ Name = 1,
+ NUMBER_OF_COLUMNS
+ };
+
+ /** @name Methods overridden from QAbstractTableModel
+ @{*/
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role);
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ /*@}*/
+
+ const NamespaceEntry &entry(int row) const { return list[row]; }
+ void setNamespace(std::vector vNamespaceEntries);
+
+public Q_SLOTS:
+ void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
+
+private:
+ WalletModel *walletModel;
+ QStringList columns;
+ QList list;
+ int64_t nReceiveRequestsMaxId;
+};
+
+#endif // BITCOIN_QT_KEVANAMESPACEMODEL_H
diff --git a/src/qt/kevanewnamespacedialog.cpp b/src/qt/kevanewnamespacedialog.cpp
new file mode 100644
index 000000000..7a54df968
--- /dev/null
+++ b/src/qt/kevanewnamespacedialog.cpp
@@ -0,0 +1,53 @@
+// 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
+#include
+
+#include
+#include
+
+#include
+#include
+
+KevaNewNamespaceDialog::KevaNewNamespaceDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::KevaNewNamespaceDialog)
+{
+ ui->setupUi(this);
+ connect(ui->buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(close()));
+ connect(ui->buttonBox->button(QDialogButtonBox::Save), SIGNAL(clicked()), this, SLOT(create()));
+ connect(ui->namespaceText, SIGNAL(textChanged(const QString &)), this, SLOT(onNamespaceChanged(const QString &)));
+ ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(false);
+}
+
+void KevaNewNamespaceDialog::onNamespaceChanged(const QString & ns)
+{
+ int length = ns.length();
+ bool enabled = length > 0;
+ ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(enabled);
+}
+
+void KevaNewNamespaceDialog::create()
+{
+ KevaDialog* dialog = (KevaDialog*)this->parentWidget();
+ QString nsText = ui->namespaceText->text();
+ std::string namespaceId;
+ if (!dialog->createNamespace(nsText.toStdString(), namespaceId)) {
+ QDialog::close();
+ return;
+ }
+ dialog->showNamespace(QString::fromStdString(namespaceId));
+ QDialog::close();
+}
+
+void KevaNewNamespaceDialog::close()
+{
+ QDialog::close();
+}
+
+KevaNewNamespaceDialog::~KevaNewNamespaceDialog()
+{
+ delete ui;
+}
\ No newline at end of file
diff --git a/src/qt/kevanewnamespacedialog.h b/src/qt/kevanewnamespacedialog.h
new file mode 100644
index 000000000..00407ef91
--- /dev/null
+++ b/src/qt/kevanewnamespacedialog.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2011-2014 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_KEVANEWNMAESPACEDIALOG_H
+#define BITCOIN_QT_KEVANEWNMAESPACEDIALOG_H
+
+#include
+#include
+
+#include
+
+namespace Ui {
+ class KevaNewNamespaceDialog;
+}
+
+
+/** Dialog showing namepsace creation. */
+class KevaNewNamespaceDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit KevaNewNamespaceDialog(QWidget *parent = 0);
+ ~KevaNewNamespaceDialog();
+
+public Q_SLOTS:
+ void create();
+ void close();
+ void onNamespaceChanged(const QString & ns);
+
+private:
+ Ui::KevaNewNamespaceDialog *ui;
+};
+
+#endif // BITCOIN_QT_KEVANEWNMAESPACEDIALOG_H
diff --git a/src/qt/kevatablemodel.cpp b/src/qt/kevatablemodel.cpp
new file mode 100644
index 000000000..08327be60
--- /dev/null
+++ b/src/qt/kevatablemodel.cpp
@@ -0,0 +1,177 @@
+// 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
+
+#include
+#include
+#include
+
+#include
+#include
+
+
+KevaTableModel::KevaTableModel(CWallet *wallet, WalletModel *parent) :
+ QAbstractTableModel(parent), walletModel(parent)
+{
+ Q_UNUSED(wallet)
+
+ /* These columns must match the indices in the ColumnIndex enumeration */
+ columns << tr("Date") << tr("Key") << tr("Value") << tr("Block");
+
+ // TODO: display new keva entry when it arrives.
+ // connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
+}
+
+KevaTableModel::~KevaTableModel()
+{
+ /* Intentionally left empty */
+}
+
+int KevaTableModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return list.length();
+}
+
+int KevaTableModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return columns.length();
+}
+
+QVariant KevaTableModel::data(const QModelIndex &index, int role) const
+{
+ if(!index.isValid() || index.row() >= list.length())
+ return QVariant();
+
+ if (role == Qt::TextColorRole)
+ {
+ const KevaEntry *rec = &list[index.row()];
+ if (rec->block < 0) {
+ return QVariant(QBrush (QColor(Qt::gray)));
+ }
+ return QVariant();
+ }
+ else if(role == Qt::DisplayRole || role == Qt::EditRole)
+ {
+ const KevaEntry *rec = &list[index.row()];
+ switch(index.column())
+ {
+ case Date:
+ return GUIUtil::dateTimeStr(rec->date);
+ case Key:
+ return QString::fromStdString(rec->key);
+ case Value:
+ return QString::fromStdString(rec->value);
+ case Block:
+ return QString::number(rec->block);
+ }
+ }
+ else if (role == Qt::TextAlignmentRole)
+ {
+ if (index.column() == Block)
+ return (int)(Qt::AlignRight|Qt::AlignVCenter);
+ }
+ return QVariant();
+}
+
+bool KevaTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ return true;
+}
+
+QVariant KevaTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if(orientation == Qt::Horizontal)
+ {
+ if(role == Qt::DisplayRole && section < columns.size())
+ {
+ return columns[section];
+ }
+ }
+ return QVariant();
+}
+
+/** Gets title for amount column including current display unit if optionsModel reference available. */
+QString KevaTableModel::getAmountTitle()
+{
+ return (this->walletModel->getOptionsModel() != nullptr) ? tr("Requested") + " ("+BitcoinUnits::shortName(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")" : "";
+}
+
+QModelIndex KevaTableModel::index(int row, int column, const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return createIndex(row, column);
+}
+
+bool KevaTableModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ Q_UNUSED(parent);
+
+ if(count > 0 && row >= 0 && (row+count) <= list.size())
+ {
+ beginRemoveRows(parent, row, row + count - 1);
+ list.erase(list.begin() + row, list.begin() + row + count);
+ endRemoveRows();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Qt::ItemFlags KevaTableModel::flags(const QModelIndex &index) const
+{
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+}
+
+
+// actually add to table in GUI
+void KevaTableModel::setKeva(std::vector vKevaEntries)
+{
+ // Remove the old ones.
+ removeRows(0, list.size());
+ list.clear();
+
+ for (auto it = vKevaEntries.begin(); it != vKevaEntries.end(); it++) {
+ beginInsertRows(QModelIndex(), 0, 0);
+ list.prepend(*it);
+ endInsertRows();
+ }
+}
+
+void KevaTableModel::sort(int column, Qt::SortOrder order)
+{
+ qSort(list.begin(), list.end(), KevaEntryLessThan(column, order));
+ Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex()));
+}
+
+void KevaTableModel::updateDisplayUnit()
+{
+}
+
+bool KevaEntryLessThan::operator()(KevaEntry &left, KevaEntry &right) const
+{
+ KevaEntry *pLeft = &left;
+ KevaEntry *pRight = &right;
+ if (order == Qt::DescendingOrder)
+ std::swap(pLeft, pRight);
+
+ switch(column)
+ {
+ case KevaTableModel::Date:
+ return pLeft->date.toTime_t() < pRight->date.toTime_t();
+ case KevaTableModel::Block:
+ return pLeft->block < pRight->block;
+ case KevaTableModel::Key:
+ return pLeft->key < pRight->key;
+ case KevaTableModel::Value:
+ return pLeft->value < pRight->value;
+ default:
+ return pLeft->block < pRight->block;
+ }
+}
diff --git a/src/qt/kevatablemodel.h b/src/qt/kevatablemodel.h
new file mode 100644
index 000000000..83600bc0b
--- /dev/null
+++ b/src/qt/kevatablemodel.h
@@ -0,0 +1,89 @@
+// 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_KEVATABLEMODEL_H
+#define BITCOIN_QT_KEVATABLEMODEL_H
+
+#include
+
+#include
+#include
+#include
+
+class CWallet;
+
+class KevaEntry
+{
+public:
+ KevaEntry() { }
+
+ std::string key;
+ std::string value;
+ int64_t block;
+ QDateTime date;
+};
+
+class KevaEntryLessThan
+{
+public:
+ KevaEntryLessThan(int nColumn, Qt::SortOrder fOrder):
+ column(nColumn), order(fOrder) {}
+ bool operator()(KevaEntry &left, KevaEntry &right) const;
+
+private:
+ int column;
+ Qt::SortOrder order;
+};
+
+/** Model for list of recently generated payment requests / bitcoin: URIs.
+ * Part of wallet model.
+ */
+class KevaTableModel: public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ explicit KevaTableModel(CWallet *wallet, WalletModel *parent);
+ ~KevaTableModel();
+
+ enum ColumnIndex {
+ Date = 0,
+ Key = 1,
+ Value = 2,
+ Block = 3,
+ NUMBER_OF_COLUMNS
+ };
+
+ /** @name Methods overridden from QAbstractTableModel
+ @{*/
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role);
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ /*@}*/
+
+ const KevaEntry &entry(int row) const { return list[row]; }
+ void setKeva(std::vector vKevaEntries);
+
+public Q_SLOTS:
+ void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
+ void updateDisplayUnit();
+
+private:
+ WalletModel *walletModel;
+ QStringList columns;
+ QList list;
+ int64_t nReceiveRequestsMaxId;
+
+ /** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
+ void updateAmountColumnTitle();
+ /** Gets title for amount column including current display unit if optionsModel reference available. */
+ QString getAmountTitle();
+};
+
+#endif // BITCOIN_QT_KEVATABLEMODEL_H
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 647e8f566..384cb904d 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -85,7 +85,7 @@
- These are your Kevacoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.
+ These are your Kevaoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.
@@ -304,17 +304,17 @@
BitcoinGUI
-
+
Sign &message...
Sign &message...
-
+
Synchronizing with network...
Synchronizing with network...
-
+
&Overview
&Overview
@@ -339,7 +339,17 @@
Browse transaction history
-
+
+ &Keva
+
+
+
+
+ Keva related operations
+
+
+
+
E&xit
E&xit
@@ -409,7 +419,7 @@
-
+
Click to disable network activity.
@@ -434,12 +444,12 @@
Reindexing blocks on disk...
-
+
Send coins to a Kevacoin address
Send coins to a Kevacoin address
-
+
Backup wallet to another location
Backup wallet to another location
@@ -464,12 +474,12 @@
&Verify message...
-
+
Kevacoin
Kevacoin
-
+
Wallet
Wallet
@@ -484,7 +494,7 @@
&Receive
-
+
&Show / Hide
&Show / Hide
@@ -529,12 +539,12 @@
Tabs toolbar
-
+
Request payments (generates QR codes and kevacoin: URIs)
-
+
Show the list of used sending addresses and labels
@@ -554,7 +564,7 @@
-
+
%n active connection(s) to Kevacoin network
%n active connection to Kevacoin network
@@ -615,17 +625,17 @@
Up to date
-
+
Show the %1 help message to get a list with possible Kevacoin command-line options
-
+
%1 client
-
+
Connecting to peers...
@@ -635,7 +645,7 @@
Catching up...
-
+
Date: %1
@@ -1149,6 +1159,290 @@
+
+ KevaAddKeyDialog
+
+
+ Key
+
+
+
+
+
+ New value
+
+
+
+
+ Value
+
+
+
+
+ KevaBookmarksDialog
+
+
+ Show
+
+
+
+
+ KevaBookmarksModel
+
+
+ Id
+
+
+
+
+ Name
+
+
+
+
+ KevaDetailDialog
+
+
+ This pane shows the value associated with a give key
+
+
+
+
+ Value for %1
+
+
+
+
+ KevaDialog
+
+
+ Show the selected request (does the same as double clicking an entry)
+
+
+
+
+
+ Show
+
+
+
+
+
+ The namespace ID with a prefix "N".
+
+
+
+
+ Use this form to perform Keva database operations.
+
+
+
+
+ Namespace:
+
+
+
+
+ Show content of the namespace.
+
+
+
+
+ Create a new namespace
+
+
+
+
+ &Create namespace
+
+
+
+
+ List my namespaces
+
+
+
+
+ &My Namespaces
+
+
+
+
+ Show bookmarks
+
+
+
+
+ &Bookmarks
+
+
+
+
+ Content of namespace
+
+
+
+
+ Remove the selected entries from the list
+
+
+
+
+ Remove
+
+
+
+
+ Add new key-value pair
+
+
+
+
+ Add key-value
+
+
+
+
+ Copy URI
+
+
+
+
+ Copy label
+
+
+
+
+ Copy message
+
+
+
+
+ Copy amount
+
+
+
+
+ Warning
+ Warning
+
+
+
+ Delete the key "%1"?
+
+
+
+
+ Invalid namespace "%1"
+
+
+
+
+ Key not found: "%1".
+
+
+
+
+
+
+ Unknown error.
+
+
+
+
+
+
+ Error
+ Error
+
+
+
+ Namespace too long "%1"
+
+
+
+
+ Cannot add key-value. Make sure you own this namespace.
+
+
+
+
+ Key too long.
+
+
+
+
+ Value too long.
+
+
+
+
+ KevaMyNamespacesDialog
+
+
+ Show
+
+
+
+
+ KevaNamespaceModel
+
+
+ Id
+
+
+
+
+ Name
+
+
+
+
+ KevaNewNamespaceDialog
+
+
+ The name of the namespace.
+
+
+
+
+ Name:
+
+
+
+
+ This pane allows the creation of a new Keva namespace
+
+
+
+
+ KevaTableModel
+
+
+ Date
+ Date
+
+
+
+ Key
+
+
+
+
+ Value
+
+
+
+
+ Block
+
+
+
+
+ Requested
+
+
+
ModalOverlay
@@ -1671,7 +1965,7 @@
PaymentServer
-
+
@@ -1950,7 +2244,7 @@
-
+
%1 didn't yet exit safely...
@@ -2623,7 +2917,7 @@
SendCoinsDialog
-
+
Send Coins
Send Coins
@@ -2754,7 +3048,7 @@
-
+
Send to multiple recipients at once
Send to multiple recipients at once
@@ -2769,7 +3063,7 @@
-
+
Dust:
@@ -2779,17 +3073,7 @@
-
- Enable Replace-By-Fee
-
-
-
-
- With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.
-
-
-
-
+
Clear &All
Clear &All
@@ -2809,7 +3093,7 @@
S&end
-
+
Copy quantity
@@ -2849,7 +3133,7 @@
-
+
@@ -2877,22 +3161,12 @@
-
- You can increase the fee later (signals Replace-By-Fee, BIP-125).
-
-
-
-
- Not signalling Replace-By-Fee, BIP-125.
-
-
-
-
+
Confirm send coins
-
+
The recipient address is not valid. Please recheck.
@@ -2942,7 +3216,7 @@
-
+
Estimated to begin confirmation within %n block(s).
Estimated to begin confirmation within %n block.
@@ -3329,11 +3603,6 @@
conflicted with a transaction with %1 confirmations
-
-
- %1/offline
-
-
0/unconfirmed, %1
@@ -3370,20 +3639,7 @@
-
- , has not been successfully broadcast yet
-
-
-
-
- , broadcast through %n node(s)
-
- , broadcast through %n node
- , broadcast through %n nodes
-
-
-
-
+
Date
Date
@@ -3593,11 +3849,6 @@
Open until %1
-
-
- Offline
-
-
Unconfirmed
@@ -3628,11 +3879,6 @@
Immature (%1 confirmations, will be available after %2)
-
-
- This block was not received by any other nodes and will probably not be accepted!
-
-
Generated but not accepted
@@ -3674,7 +3920,7 @@
-
+
(no label)
@@ -3927,12 +4173,12 @@
WalletModel
-
+
Send Coins
Send Coins
-
+
Fee bump error
@@ -3982,7 +4228,7 @@
WalletView
-
+
&Export
&Export
@@ -3992,7 +4238,7 @@
Export the data in the current tab to a file
-
+
Backup Wallet
@@ -4025,7 +4271,7 @@
bitcoin-core
-
+
Options:
Options:
@@ -4035,17 +4281,17 @@
Specify data directory
-
+
Connect to a node to retrieve peer addresses, and disconnect
Connect to a node to retrieve peer addresses, and disconnect
-
+
Specify your own public address
Specify your own public address
-
+
Accept command line and JSON-RPC commands
Accept command line and JSON-RPC commands
@@ -4085,7 +4331,7 @@
-
+
Pruning blockstore...
@@ -4100,7 +4346,7 @@
-
+
Kevacoin Core
Kevacoin Core
@@ -4200,12 +4446,7 @@
-
- Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >%u = automatically prune block files to stay under the specified target size in MiB)
-
-
-
-
+
Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)
@@ -4449,6 +4690,21 @@
Initialization sanity check failed. %s is shutting down.
+
+
+ Input tx is not a keva operation
+
+
+
+
+ Input tx is not mine
+
+
+
+
+ Input tx not found in wallet
+
+
Invalid amount for -%s=<amount>: '%s'
@@ -4625,7 +4881,7 @@
-
+
Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times
@@ -4740,7 +4996,7 @@
Information
-
+
Invalid -onion address or hostname: '%s'
@@ -4925,7 +5181,7 @@
Password for JSON-RPC connections
-
+
Execute command when the best block changes (%s in cmd is replaced by block hash)
Execute command when the best block changes (%s in cmd is replaced by block hash)
@@ -5000,7 +5256,12 @@
-
+
+ Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u = automatically prune block files to stay under the specified target size in MiB)
+
+
+
+
Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)
@@ -5115,7 +5376,7 @@
-
+
Keypool ran out, please call keypoolrefill first
@@ -5260,17 +5521,17 @@
Loading wallet...
-
+
Cannot downgrade wallet
Cannot downgrade wallet
-
+
Rescanning...
Rescanning...
-
+
Done loading
Done loading
@@ -5280,4 +5541,4 @@
Error
-
\ No newline at end of file
+
diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts
index 88e3c2079..8c5b70ce1 100644
--- a/src/qt/locale/bitcoin_zh_CN.ts
+++ b/src/qt/locale/bitcoin_zh_CN.ts
@@ -907,6 +907,229 @@
(需要%n GB空间)
+
+ KevaAddKeyDialog
+
+ Key
+ 键
+
+
+ New value
+ 新值
+
+
+ Value
+ 值
+
+
+
+ KevaBookmarksDialog
+
+ Show
+ 显示
+
+
+
+ KevaBookmarksModel
+
+ Id
+ ID
+
+
+ Name
+ 名称
+
+
+
+ KevaDetailDialog
+
+ This pane shows the value associated with a give key
+ 此窗格显示与给定键关联的值
+
+
+ Value for %1
+ %1 相应值
+
+
+
+ KevaDialog
+
+ Show
+ 显示
+
+
+ The namespace ID with a prefix "N".
+
+
+
+ Use this form to perform Keva database operations.
+ 使用此表单执行Keva数据库操作。
+
+
+ Namespace:
+ 命名空间:
+
+
+ Show content of the namespace.
+ 显示名称空间的内容。
+
+
+ Create a new namespace
+ 创建一个新的名称空间
+
+
+ &Create namespace
+ 创建名称空间
+
+
+ List my namespaces
+ 列出我的名称空间
+
+
+ &My Namespaces
+ 我的名称空间
+
+
+ Show bookmarks
+ 显示书签
+
+
+ &Bookmarks
+ 书签
+
+
+ Content of namespace
+ 命名空间的内容
+
+
+ Remove the selected entries from the list
+ 从列表中删除所选条目
+
+
+ Remove
+ 删除
+
+
+ Add new key-value pair
+ 添加新的键值对
+
+
+ Add key-value
+ 添加键值对
+
+
+ Copy URI
+
+
+
+ Copy label
+
+
+
+ Copy message
+
+
+
+ Copy amount
+
+
+
+ Warning
+ 警告
+
+
+ Delete the key "%1"?
+ 删除键 "%1"?
+
+
+ Invalid namespace "%1"
+ 无效的名称空间 "%1"
+
+
+ Key not found: "%1".
+ 找不到键: "%1"
+
+
+ Unknown error.
+ 未知错误。
+
+
+ Error
+ 错误
+
+
+ Namespace too long "%1"
+ 命名空间太长: "%1"
+
+
+ Cannot add key-value. Make sure you own this namespace.
+ 无法添加键值。确保您拥有此名称空间。
+
+
+ Key too long.
+ 键太长
+
+
+ Value too long.
+ 值太长。
+
+
+
+ KevaMyNamespacesDialog
+
+ Show
+ 显示
+
+
+
+ KevaNamespaceModel
+
+ Id
+ Id
+
+
+ Name
+ 名称
+
+
+
+ KevaNewNamespaceDialog
+
+ The name of the namespace.
+ 命名空间的名称。
+
+
+ Name:
+ 名称:
+
+
+ This pane allows the creation of a new Keva namespace
+ 此窗格允许创建新的Keva命名空间
+
+
+
+ KevaTableModel
+
+ Date
+ 日期
+
+
+ Key
+ 键
+
+
+ Value
+ 值
+
+
+ Block
+ 区块
+
+
+ Requested
+ 已要求
+
+
ModalOverlay
diff --git a/src/qt/res/icons/about.png b/src/qt/res/icons/about.png
index 473725b76..d034f477c 100644
Binary files a/src/qt/res/icons/about.png and b/src/qt/res/icons/about.png differ
diff --git a/src/qt/res/icons/keva.png b/src/qt/res/icons/keva.png
new file mode 100644
index 000000000..aa342e03c
Binary files /dev/null and b/src/qt/res/icons/keva.png differ
diff --git a/src/qt/res/icons/star.png b/src/qt/res/icons/star.png
new file mode 100644
index 000000000..79868e2cb
Binary files /dev/null and b/src/qt/res/icons/star.png differ
diff --git a/src/qt/res/icons/star_empty.png b/src/qt/res/icons/star_empty.png
new file mode 100644
index 000000000..87a5472b8
Binary files /dev/null and b/src/qt/res/icons/star_empty.png differ
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index 7a4ffea03..5d2abe771 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index c0b9d0426..ad84801fb 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -124,6 +124,13 @@ void WalletFrame::gotoHistoryPage()
i.value()->gotoHistoryPage();
}
+void WalletFrame::gotoKevaPage()
+{
+ QMap::const_iterator i;
+ for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
+ i.value()->gotoKevaPage();
+}
+
void WalletFrame::gotoReceiveCoinsPage()
{
QMap::const_iterator i;
diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h
index 42ce69fea..fbc648b2f 100644
--- a/src/qt/walletframe.h
+++ b/src/qt/walletframe.h
@@ -66,6 +66,8 @@ public Q_SLOTS:
void gotoOverviewPage();
/** Switch to history (transactions) page */
void gotoHistoryPage();
+ /** Switch to Keva page */
+ void gotoKevaPage();
/** Switch to receive coins page */
void gotoReceiveCoinsPage();
/** Switch to send coins page */
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index dbafd1613..ebfcc7b69 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -11,12 +11,17 @@
#include
#include
#include
+#include
+#include
+#include
#include
#include
#include
#include
#include
+#include
+#include
#include
#include // for g_connman
#include
@@ -36,11 +41,16 @@
#include
#include
+const int NAMESPACE_LENGTH = 21;
+const std::string DUMMY_NAMESPACE = "___DUMMY_NAMESPACE___";
WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *_wallet, OptionsModel *_optionsModel, QObject *parent) :
QObject(parent), wallet(_wallet), optionsModel(_optionsModel), addressTableModel(0),
transactionTableModel(0),
recentRequestsTableModel(0),
+ kevaTableModel(0),
+ kevaNamespaceModel(0),
+ kevaBookmarksModel(0),
cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
cachedEncryptionStatus(Unencrypted),
cachedNumBlocks(0)
@@ -51,6 +61,9 @@ WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *_wallet, O
addressTableModel = new AddressTableModel(wallet, this);
transactionTableModel = new TransactionTableModel(platformStyle, wallet, this);
recentRequestsTableModel = new RecentRequestsTableModel(wallet, this);
+ kevaTableModel = new KevaTableModel(wallet, this);
+ kevaNamespaceModel = new KevaNamespaceModel(wallet, this);
+ kevaBookmarksModel = new KevaBookmarksModel(wallet, this);
// This timer will be fired repeatedly to update the balance
pollTimer = new QTimer(this);
@@ -393,6 +406,21 @@ RecentRequestsTableModel *WalletModel::getRecentRequestsTableModel()
return recentRequestsTableModel;
}
+KevaTableModel *WalletModel::getKevaTableModel()
+{
+ return kevaTableModel;
+}
+
+KevaNamespaceModel *WalletModel::getKevaNamespaceModel()
+{
+ return kevaNamespaceModel;
+}
+
+KevaBookmarksModel *WalletModel::getKevaBookmarksModel()
+{
+ return kevaBookmarksModel;
+}
+
WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
{
if(!wallet->IsCrypted())
@@ -743,3 +771,261 @@ int WalletModel::getDefaultConfirmTarget() const
{
return nTxConfirmTarget;
}
+
+void WalletModel::getKevaEntries(std::vector& vKevaEntries, std::string nameSpace)
+{
+ valtype nameSpaceVal = ValtypeFromString(nameSpace);
+
+ {
+ // Get the unconfirmed namespaces and list them at the beginning.
+ LOCK (mempool.cs);
+
+ std::vector> unconfirmedKeyValueList;
+ mempool.getUnconfirmedKeyValueList(unconfirmedKeyValueList, nameSpaceVal);
+
+ for (auto e : unconfirmedKeyValueList) {
+ KevaEntry entry;
+ entry.key = ValtypeToString(std::get<1>(e));
+ entry.value = ValtypeToString(std::get<2>(e));
+ entry.block = -1; // Unconfirmed.
+ entry.date = QDateTime::currentDateTime();
+ vKevaEntries.push_back(std::move(entry));
+ }
+ }
+
+ LOCK(cs_main);
+
+ valtype key;
+ CKevaData data;
+ std::unique_ptr iter(pcoinsTip->IterateKeys(nameSpaceVal));
+ while (iter->next(key, data)) {
+ KevaEntry entry;
+ entry.key = ValtypeToString(key);
+ entry.value = ValtypeToString(data.getValue());
+ entry.block = data.getHeight();
+ CBlockIndex* pblockindex = chainActive[entry.block];
+ if (pblockindex) {
+ entry.date.setTime_t(pblockindex->nTime);
+ }
+ vKevaEntries.push_back(std::move(entry));
+ }
+
+}
+
+void WalletModel::getNamespaceEntries(std::vector& vNamespaceEntries)
+{
+ LOCK2(cs_main, wallet->cs_wallet);
+ std::map mapObjects;
+ for (const auto& item : wallet->mapWallet) {
+ const CWalletTx& tx = item.second;
+ if (!tx.tx->IsKevacoin()) {
+ continue;
+ }
+
+ CKevaScript kevaOp;
+ int nOut = -1;
+ for (unsigned i = 0; i < tx.tx->vout.size(); ++i) {
+ const CKevaScript cur(tx.tx->vout[i].scriptPubKey);
+ if (cur.isKevaOp()) {
+ if (nOut != -1) {
+ LogPrintf("ERROR: wallet contains tx with multiple name outputs");
+ } else {
+ kevaOp = cur;
+ nOut = i;
+ }
+ }
+ }
+
+ if (nOut == -1) {
+ continue;
+ }
+
+ if (!kevaOp.isNamespaceRegistration() && !kevaOp.isAnyUpdate()) {
+ continue;
+ }
+
+ const valtype nameSpace = kevaOp.getOpNamespace();
+ const std::string nameSpaceStr = EncodeBase58Check(nameSpace);
+ const CBlockIndex* pindex;
+ const int depth = tx.GetDepthInMainChain(pindex);
+ if (depth <= 0) {
+ continue;
+ }
+
+ const bool mine = IsMine(*wallet, kevaOp.getAddress());
+ CKevaData data;
+ if (mine && pcoinsTip->GetNamespace(nameSpace, data)) {
+ std::string displayName = ValtypeToString(data.getValue());
+ mapObjects[nameSpaceStr] = displayName;
+ }
+ }
+
+ {
+ // Also get the unconfirmed namespaces and list them at the beginning.
+ LOCK (mempool.cs);
+
+ std::vector> unconfirmedNamespaces;
+ mempool.getUnconfirmedNamespaceList(unconfirmedNamespaces);
+
+ for (auto ns: unconfirmedNamespaces) {
+ NamespaceEntry entry;
+ entry.id = EncodeBase58Check(std::get<0>(ns));
+ entry.name = ValtypeToString(std::get<1>(ns));
+ entry.confirmed = false;
+ vNamespaceEntries.push_back(std::move(entry));
+ }
+ }
+
+ // The confirmed namespaces.
+ std::map::iterator it = mapObjects.begin();
+ while (it != mapObjects.end()) {
+ NamespaceEntry entry;
+ entry.id = it->first;
+ entry.name = it->second;
+ vNamespaceEntries.push_back(std::move(entry));
+ it++;
+ }
+}
+
+int WalletModel::createNamespace(std::string displayNameStr, std::string& namespaceId)
+{
+ const valtype displayName = ValtypeFromString (displayNameStr);
+ if (displayName.size() > MAX_NAMESPACE_LENGTH) {
+ return NamespaceTooLong;
+ }
+
+ CReserveKey keyName(wallet);
+ CPubKey pubKey;
+ const bool ok = keyName.GetReservedKey(pubKey, true);
+ assert(ok);
+
+ CKeyID keyId = pubKey.GetID();
+
+ // The namespace name is: Hash160("first txin")
+ // For now we don't know the first txin, so use dummy name here.
+ // It will be replaced later in CreateTransaction.
+ valtype namespaceDummy = ToByteVector(std::string(DUMMY_NAMESPACE));
+ assert(namespaceDummy.size() == NAMESPACE_LENGTH);
+
+ CScript redeemScript = GetScriptForDestination(WitnessV0KeyHash(keyId));
+ CScriptID scriptHash = CScriptID(redeemScript);
+ CScript addrName = GetScriptForDestination(scriptHash);
+ const CScript newScript = CKevaScript::buildKevaNamespace(addrName, namespaceDummy, displayName);
+
+ CCoinControl coinControl;
+ CWalletTx wtx;
+ valtype kevaNamespace;
+ SendMoneyToScript(wallet, newScript, nullptr, kevaNamespace,
+ KEVA_LOCKED_AMOUNT, false, wtx, coinControl);
+ keyName.KeepKey();
+
+ namespaceId = EncodeBase58Check(kevaNamespace);
+ return 0;
+}
+
+
+int WalletModel::deleteKevaEntry(std::string namespaceStr, std::string keyStr)
+{
+ valtype nameSpace;
+ if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) {
+ return InvalidNamespace;
+ }
+
+ const valtype key = ValtypeFromString(keyStr);
+ if (key.size() > MAX_KEY_LENGTH) {
+ return KeyTooLong;
+ }
+
+ bool hasKey = false;
+ CKevaData data;
+ {
+ LOCK2(cs_main, mempool.cs);
+ std::vector> unconfirmedKeyValueList;
+ valtype val;
+ if (mempool.getUnconfirmedKeyValue(nameSpace, key, val)) {
+ if (val.size() > 0) {
+ hasKey = true;
+ }
+ } else if (pcoinsTip->GetName(nameSpace, key, data)) {
+ hasKey = true;
+ }
+ }
+
+ if (!hasKey) {
+ return KeyNotFound;
+ }
+
+ COutput output;
+ std::string kevaNamespce = namespaceStr;
+ if (!wallet->FindKevaCoin(output, kevaNamespce)) {
+ // TODO: This namespace can not be updated
+ return 0;
+ }
+ const COutPoint outp(output.tx->GetHash(), output.i);
+ const CTxIn txIn(outp);
+
+ CReserveKey keyName(wallet);
+ CPubKey pubKeyReserve;
+ const bool ok = keyName.GetReservedKey(pubKeyReserve, true);
+ assert(ok);
+
+ CScript redeemScript = GetScriptForDestination(WitnessV0KeyHash(pubKeyReserve.GetID()));
+ CScriptID scriptHash = CScriptID(redeemScript);
+ CScript addrName = GetScriptForDestination(scriptHash);
+
+ const CScript kevaScript = CKevaScript::buildKevaDelete(addrName, nameSpace, key);
+
+ CCoinControl coinControl;
+ CWalletTx wtx;
+ valtype empty;
+ SendMoneyToScript(wallet, kevaScript, &txIn, empty,
+ KEVA_LOCKED_AMOUNT, false, wtx, coinControl);
+
+ keyName.KeepKey();
+ return 0;
+}
+
+int WalletModel::addKeyValue(std::string& namespaceStr, std::string& keyStr, std::string& valueStr)
+{
+ valtype nameSpace;
+ if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) {
+ return InvalidNamespace;
+ }
+
+ const valtype key = ValtypeFromString(keyStr);
+ if (keyStr.size() > MAX_KEY_LENGTH) {
+ return KeyTooLong;
+ }
+
+ const valtype value = ValtypeFromString(valueStr);
+ if (value.size() > MAX_VALUE_LENGTH) {
+ return ValueTooLong;
+ }
+
+ COutput output;
+ if (!wallet->FindKevaCoin(output, namespaceStr)) {
+ return CannotUpdate;
+ }
+ const COutPoint outp(output.tx->GetHash(), output.i);
+ const CTxIn txIn(outp);
+
+ CReserveKey keyName(wallet);
+ CPubKey pubKeyReserve;
+ const bool ok = keyName.GetReservedKey(pubKeyReserve, true);
+ assert(ok);
+ CKeyID keyId = pubKeyReserve.GetID();
+ CScript redeemScript = GetScriptForDestination(WitnessV0KeyHash(keyId));
+ CScriptID scriptHash = CScriptID(redeemScript);
+ CScript addrName = GetScriptForDestination(scriptHash);
+
+ const CScript kevaScript = CKevaScript::buildKevaPut(addrName, nameSpace, key, value);
+
+ CCoinControl coinControl;
+ CWalletTx wtx;
+ valtype empty;
+ SendMoneyToScript(wallet, kevaScript, &txIn, empty,
+ KEVA_LOCKED_AMOUNT, false, wtx, coinControl);
+
+ keyName.KeepKey();
+ return 0;
+}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 9e13de79b..4140cb56d 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -21,6 +21,12 @@ class AddressTableModel;
class OptionsModel;
class PlatformStyle;
class RecentRequestsTableModel;
+class KevaTableModel;
+class KevaNamespaceModel;
+class KevaBookmarksModel;
+class KevaEntry;
+class NamespaceEntry;
+class BookmarkEntry;
class TransactionTableModel;
class WalletModelTransaction;
@@ -116,7 +122,15 @@ public:
TransactionCreationFailed, // Error returned when wallet is still locked
TransactionCommitFailed,
AbsurdFee,
- PaymentRequestExpired
+ PaymentRequestExpired,
+
+ // Keva status
+ InvalidNamespace,
+ KeyTooLong,
+ NamespaceTooLong,
+ KeyNotFound,
+ ValueTooLong,
+ CannotUpdate,
};
enum EncryptionStatus
@@ -130,6 +144,9 @@ public:
AddressTableModel *getAddressTableModel();
TransactionTableModel *getTransactionTableModel();
RecentRequestsTableModel *getRecentRequestsTableModel();
+ KevaTableModel *getKevaTableModel();
+ KevaNamespaceModel *getKevaNamespaceModel();
+ KevaBookmarksModel *getKevaBookmarksModel();
CAmount getBalance(const CCoinControl *coinControl = nullptr) const;
CAmount getUnconfirmedBalance() const;
@@ -220,6 +237,13 @@ public:
int getDefaultConfirmTarget() const;
+ // Keva
+ void getKevaEntries(std::vector& vKevaEntries, std::string nameSpace);
+ void getNamespaceEntries(std::vector& vNamespaceEntries);
+ int createNamespace(std::string displayName, std::string& namespaceId);
+ int deleteKevaEntry(std::string nameSpace, std::string key);
+ int addKeyValue(std::string& namespaceStr, std::string& keyStr, std::string& valueStr);
+
private:
CWallet *wallet;
bool fHaveWatchOnly;
@@ -232,6 +256,9 @@ private:
AddressTableModel *addressTableModel;
TransactionTableModel *transactionTableModel;
RecentRequestsTableModel *recentRequestsTableModel;
+ KevaTableModel *kevaTableModel;
+ KevaNamespaceModel *kevaNamespaceModel;
+ KevaBookmarksModel *kevaBookmarksModel;
// Cache some values to be able to detect changes
CAmount cachedBalance;
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 7eced9289..b0bb15935 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -53,6 +54,7 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent):
vbox->addLayout(hbox_buttons);
transactionsPage->setLayout(vbox);
+ kevaPage = new KevaDialog(platformStyle);
receiveCoinsPage = new ReceiveCoinsDialog(platformStyle);
sendCoinsPage = new SendCoinsDialog(platformStyle);
@@ -61,6 +63,7 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent):
addWidget(overviewPage);
addWidget(transactionsPage);
+ addWidget(kevaPage);
addWidget(receiveCoinsPage);
addWidget(sendCoinsPage);
@@ -100,7 +103,7 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui)
// Pass through transaction notifications
connect(this, SIGNAL(incomingTransaction(QString,int,CAmount,QString,QString,QString)), gui, SLOT(incomingTransaction(QString,int,CAmount,QString,QString,QString)));
- // Connect HD enabled state signal
+ // Connect HD enabled state signal
connect(this, SIGNAL(hdEnabledStatusChanged(int)), gui, SLOT(setHDStatus(int)));
}
}
@@ -119,6 +122,7 @@ void WalletView::setWalletModel(WalletModel *_walletModel)
// Put transaction list in tabs
transactionView->setModel(_walletModel);
+ kevaPage->setModel(_walletModel);
overviewPage->setWalletModel(_walletModel);
receiveCoinsPage->setModel(_walletModel);
sendCoinsPage->setModel(_walletModel);
@@ -179,6 +183,11 @@ void WalletView::gotoHistoryPage()
setCurrentWidget(transactionsPage);
}
+void WalletView::gotoKevaPage()
+{
+ setCurrentWidget(kevaPage);
+}
+
void WalletView::gotoReceiveCoinsPage()
{
setCurrentWidget(receiveCoinsPage);
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
index 30d68e4ef..d810a110a 100644
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -15,6 +15,7 @@ class OverviewPage;
class PlatformStyle;
class ReceiveCoinsDialog;
class SendCoinsDialog;
+class KevaDialog;
class SendCoinsRecipient;
class TransactionView;
class WalletModel;
@@ -62,6 +63,7 @@ private:
QWidget *transactionsPage;
ReceiveCoinsDialog *receiveCoinsPage;
SendCoinsDialog *sendCoinsPage;
+ KevaDialog *kevaPage;
AddressBookPage *usedSendingAddressesPage;
AddressBookPage *usedReceivingAddressesPage;
@@ -75,6 +77,8 @@ public Q_SLOTS:
void gotoOverviewPage();
/** Switch to history (transactions) page */
void gotoHistoryPage();
+ /** Switch to Keva page */
+ void gotoKevaPage();
/** Switch to receive coins page */
void gotoReceiveCoinsPage();
/** Switch to send coins page */