Browse Source

Implemented GUI for Keva operations.

keva-gui
Just Wonder 5 years ago
parent
commit
0628dfa08f
  1. 3
      contrib/bitcoin-qt.pro
  2. 34
      src/Makefile.qt.include
  3. 1
      src/qt/bitcoin.qrc
  4. 16
      src/qt/bitcoingui.cpp
  5. 3
      src/qt/bitcoingui.h
  6. 7
      src/qt/bitcoinstrings.cpp
  7. 71
      src/qt/forms/kevaaddkeydialog.ui
  8. 43
      src/qt/forms/kevabookmarksdialog.ui
  9. 74
      src/qt/forms/kevadetaildialog.ui
  10. 329
      src/qt/forms/kevadialog.ui
  11. 77
      src/qt/forms/kevamynamespacesdialog.ui
  12. 60
      src/qt/forms/kevanewnamespacedialog.ui
  13. 60
      src/qt/kevaaddkeydialog.cpp
  14. 41
      src/qt/kevaaddkeydialog.h
  15. 78
      src/qt/kevabookmarksdialog.cpp
  16. 51
      src/qt/kevabookmarksdialog.h
  17. 242
      src/qt/kevabookmarksmodel.cpp
  18. 90
      src/qt/kevabookmarksmodel.h
  19. 56
      src/qt/kevadetaildialog.cpp
  20. 40
      src/qt/kevadetaildialog.h
  21. 425
      src/qt/kevadialog.cpp
  22. 88
      src/qt/kevadialog.h
  23. 80
      src/qt/kevamynamespacesdialog.cpp
  24. 51
      src/qt/kevamynamespacesdialog.h
  25. 156
      src/qt/kevanamespacemodel.cpp
  26. 80
      src/qt/kevanamespacemodel.h
  27. 53
      src/qt/kevanewnamespacedialog.cpp
  28. 36
      src/qt/kevanewnamespacedialog.h
  29. 177
      src/qt/kevatablemodel.cpp
  30. 89
      src/qt/kevatablemodel.h
  31. 467
      src/qt/locale/bitcoin_en.ts
  32. 223
      src/qt/locale/bitcoin_zh_CN.ts
  33. BIN
      src/qt/res/icons/about.png
  34. BIN
      src/qt/res/icons/keva.png
  35. BIN
      src/qt/res/icons/star.png
  36. BIN
      src/qt/res/icons/star_empty.png
  37. 1
      src/qt/test/wallettests.cpp
  38. 7
      src/qt/walletframe.cpp
  39. 2
      src/qt/walletframe.h
  40. 286
      src/qt/walletmodel.cpp
  41. 29
      src/qt/walletmodel.h
  42. 9
      src/qt/walletview.cpp
  43. 4
      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 \

34
src/Makefile.qt.include

@ -135,6 +135,12 @@ QT_FORMS_UI = \ @@ -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 = \ @@ -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 = \ @@ -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 = \ @@ -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 = \ @@ -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 = \ @@ -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 \

1
src/qt/bitcoin.qrc

@ -39,6 +39,7 @@ @@ -39,6 +39,7 @@
<file alias="lock_closed">res/icons/lock_closed.png</file>
<file alias="lock_open">res/icons/lock_open.png</file>
<file alias="key">res/icons/key.png</file>
<file alias="keva">res/icons/keva.png</file>
<file alias="filesave">res/icons/filesave.png</file>
<file alias="debugwindow">res/icons/debugwindow.png</file>
<file alias="open">res/icons/open.png</file>

16
src/qt/bitcoingui.cpp

@ -313,6 +313,13 @@ void BitcoinGUI::createActions() @@ -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() @@ -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() @@ -462,6 +471,7 @@ void BitcoinGUI::createToolBars()
toolbar->addAction(sendCoinsAction);
toolbar->addAction(receiveCoinsAction);
toolbar->addAction(historyAction);
toolbar->addAction(kevaAction);
overviewAction->setChecked(true);
}
}
@ -691,6 +701,12 @@ void BitcoinGUI::gotoHistoryPage() @@ -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);

3
src/qt/bitcoingui.h

@ -91,6 +91,7 @@ private: @@ -91,6 +91,7 @@ private:
QMenuBar *appMenuBar;
QAction *overviewAction;
QAction *kevaAction;
QAction *historyAction;
QAction *quitAction;
QAction *sendCoinsAction;
@ -195,6 +196,8 @@ private Q_SLOTS: @@ -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 */

7
src/qt/bitcoinstrings.cpp

@ -9,7 +9,7 @@ @@ -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", "" @@ -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 @@ -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'"),

71
src/qt/forms/kevaaddkeydialog.ui

@ -0,0 +1,71 @@ @@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KevaAddKeyDialog</class>
<widget class="QDialog" name="KevaAddKeyDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Add New Key-Value Pair</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_1">
<property name="text">
<string>Key</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="keyText">
<property name="toolTip">
<string>New value</string>
</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>15</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Value</string>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="valueText">
<property name="toolTip">
<string>New value</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
</ui>

43
src/qt/forms/kevabookmarksdialog.ui

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KevaBookmarksDialog</class>
<widget class="QDialog" name="KevaBookmarksDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Namespace Bookmarks</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTableView" name="namespaceView">
<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>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
</ui>

74
src/qt/forms/kevadetaildialog.ui

@ -0,0 +1,74 @@ @@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KevaDetailDialog</class>
<widget class="QDialog" name="KevaDetailDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Value</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTextEdit" name="detailText">
<property name="toolTip">
<string>This pane shows the value associated with a give key</string>
</property>
<property name="readOnly">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>KevaDetailDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>KevaDetailDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
</connections>
</ui>

329
src/qt/forms/kevadialog.ui

@ -0,0 +1,329 @@ @@ -0,0 +1,329 @@
<?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="4" column="2">
<widget class="QLineEdit" name="nameSpace">
<property name="toolTip">
<string>The namespace ID with a prefix "N".</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Use this form to perform Keva database operations.</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="toolTip">
<string>The namespace ID with a prefix "N".</string>
</property>
<property name="text">
<string>Namespace:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>namespace</cstring>
</property>
</widget>
</item>
<item row="7" column="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="showContent">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Show content of the namespace.</string>
</property>
<property name="text">
<string>Show</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/eye</normaloff>:/icons/eye</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="createNamespace">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Create a new namespace</string>
</property>
<property name="text">
<string>&amp;Create namespace</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/add</normaloff>:/icons/add</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="listNamespaces">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>List my namespaces</string>
</property>
<property name="text">
<string>&amp;My Namespaces</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/editpaste</normaloff>:/icons/editpaste</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="bookmarksButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Show bookmarks</string>
</property>
<property name="text">
<string>&amp;Bookmarks</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/address-book</normaloff>:/icons/address-book</iconset>
</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>
</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>Content of namespace</string>
</property>
</widget>
</item>
<item>
<widget class="QTableView" name="kevaView">
<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="showValueButton">
<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="removeButton">
<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>
<widget class="QPushButton" name="addKVButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Add new key-value pair</string>
</property>
<property name="text">
<string>Add key-value</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/add</normaloff>:/icons/add</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>reqMessage</tabstop>
<tabstop>receiveButton</tabstop>
<tabstop>clearButton</tabstop>
<tabstop>recentRequestsView</tabstop>
<tabstop>showValueButton</tabstop>
<tabstop>removeButton</tabstop>
</tabstops>
<resources>
<include location="../bitcoin.qrc"/>
</resources>
<connections/>
</ui>

77
src/qt/forms/kevamynamespacesdialog.ui

@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KevaMyNamespacesDialog</class>
<widget class="QDialog" name="KevaMyNamespacesDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">My Namespaces</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTableView" name="namespaceView">
<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>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>KevaMyNamespacesDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>KevaMyNamespacesDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
</connections>
</ui>

60
src/qt/forms/kevanewnamespacedialog.ui

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KevaNewNamespaceDialog</class>
<widget class="QDialog" name="KevaNewNamespaceDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>100</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Create New Namespace</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="toolTip">
<string>The name of the namespace.</string>
</property>
<property name="text">
<string>Name:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>namespaceText</cstring>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="namespaceText">
<property name="toolTip">
<string>This pane allows the creation of a new Keva namespace</string>
</property>
<property name="readOnly">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
</ui>

60
src/qt/kevaaddkeydialog.cpp

@ -0,0 +1,60 @@ @@ -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 <qt/kevaaddkeydialog.h>
#include <qt/forms/ui_kevaaddkeydialog.h>
#include <qt/kevatablemodel.h>
#include <qt/kevadialog.h>
#include <QPushButton>
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);
}

41
src/qt/kevaaddkeydialog.h

@ -0,0 +1,41 @@ @@ -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 <QObject>
#include <QString>
#include <QDialog>
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

78
src/qt/kevabookmarksdialog.cpp

@ -0,0 +1,78 @@ @@ -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 <qt/kevabookmarksdialog.h>
#include <qt/forms/ui_kevabookmarksdialog.h>
#include <qt/kevabookmarksmodel.h>
#include <qt/kevadialog.h>
#include <QPushButton>
#include <QModelIndex>
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;
}

51
src/qt/kevabookmarksdialog.h

@ -0,0 +1,51 @@ @@ -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 <QObject>
#include <QString>
#include <QDialog>
#include <QItemSelection>
#include <QAbstractItemView>
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

242
src/qt/kevabookmarksmodel.cpp

@ -0,0 +1,242 @@ @@ -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 <qt/kevabookmarksmodel.h>
#include <qt/bitcoinunits.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <util.h>
#include <clientversion.h>
#include <streams.h>
#include <QFile>
#include <QJsonDocument>
#include <QJsonArray>
#include <QDir>
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<BookmarkEntry> 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<BookmarkEntry> 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;
}
}

90
src/qt/kevabookmarksmodel.h

@ -0,0 +1,90 @@ @@ -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 <qt/walletmodel.h>
#include <QAbstractTableModel>
#include <QStringList>
#include <QDateTime>
#include <QJsonObject>
#include <QJsonArray>
#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<BookmarkEntry> 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<BookmarkEntry> list;
int64_t nReceiveRequestsMaxId;
QString getBookmarkFile();
};
#endif // BITCOIN_QT_KEVABOOKMARKSMODEL_H

56
src/qt/kevadetaildialog.cpp

@ -0,0 +1,56 @@ @@ -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 <qt/kevadetaildialog.h>
#include <qt/forms/ui_kevadetaildialog.h>
#include <qt/kevatablemodel.h>
#include <qt/kevadialog.h>
#include <QModelIndex>
#include <QPushButton>
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();
}

40
src/qt/kevadetaildialog.h

@ -0,0 +1,40 @@ @@ -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 <QObject>
#include <QString>
#include <QDialog>
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

425
src/qt/kevadialog.cpp

@ -0,0 +1,425 @@ @@ -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 <wallet/wallet.h>
#include <keva/common.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/kevatablemodel.h>
#include <qt/kevanamespacemodel.h>
#include <qt/kevabookmarksmodel.h>
#include <qt/kevadetaildialog.h>
#include <qt/kevaaddkeydialog.h>
#include <qt/kevabookmarksdialog.h>
#include <qt/kevanewnamespacedialog.h>
#include <qt/kevamynamespacesdialog.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->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<NamespaceEntry> 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<KevaEntry> 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;
}

88
src/qt/kevadialog.h

@ -0,0 +1,88 @@ @@ -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 <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,
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

80
src/qt/kevamynamespacesdialog.cpp

@ -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.
#include <qt/kevamynamespacesdialog.h>
#include <qt/forms/ui_kevamynamespacesdialog.h>
#include <qt/kevanamespacemodel.h>
#include <qt/kevadialog.h>
#include <QPushButton>
#include <QModelIndex>
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;
}

51
src/qt/kevamynamespacesdialog.h

@ -0,0 +1,51 @@ @@ -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 <QObject>
#include <QString>
#include <QDialog>
#include <QItemSelection>
#include <QAbstractItemView>
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

156
src/qt/kevanamespacemodel.cpp

@ -0,0 +1,156 @@ @@ -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 <qt/kevanamespacemodel.h>
#include <qt/bitcoinunits.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <clientversion.h>
#include <streams.h>
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<NamespaceEntry> 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;
}
}

80
src/qt/kevanamespacemodel.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_KEVANAMESPACEMODEL_H
#define BITCOIN_QT_KEVANAMESPACEMODEL_H
#include <qt/walletmodel.h>
#include <QAbstractTableModel>
#include <QStringList>
#include <QDateTime>
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<NamespaceEntry> vNamespaceEntries);
public Q_SLOTS:
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
private:
WalletModel *walletModel;
QStringList columns;
QList<NamespaceEntry> list;
int64_t nReceiveRequestsMaxId;
};
#endif // BITCOIN_QT_KEVANAMESPACEMODEL_H

53
src/qt/kevanewnamespacedialog.cpp

@ -0,0 +1,53 @@ @@ -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 <qt/kevanewnamespacedialog.h>
#include <qt/forms/ui_kevanewnamespacedialog.h>
#include <qt/kevatablemodel.h>
#include <qt/kevadialog.h>
#include <QPushButton>
#include <QModelIndex>
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;
}

36
src/qt/kevanewnamespacedialog.h

@ -0,0 +1,36 @@ @@ -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 <QObject>
#include <QString>
#include <QDialog>
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

177
src/qt/kevatablemodel.cpp

@ -0,0 +1,177 @@ @@ -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 <qt/kevatablemodel.h>
#include <qt/bitcoinunits.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <clientversion.h>
#include <streams.h>
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<KevaEntry> 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;
}
}

89
src/qt/kevatablemodel.h

@ -0,0 +1,89 @@ @@ -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 <qt/walletmodel.h>
#include <QAbstractTableModel>
#include <QStringList>
#include <QDateTime>
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<KevaEntry> vKevaEntries);
public Q_SLOTS:
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
void updateDisplayUnit();
private:
WalletModel *walletModel;
QStringList columns;
QList<KevaEntry> 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

467
src/qt/locale/bitcoin_en.ts

@ -85,7 +85,7 @@ @@ -85,7 +85,7 @@
</message>
<message>
<location line="+4"/>
<source>These are your Kevacoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
<source>These are your Kevaoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
@ -304,17 +304,17 @@ @@ -304,17 +304,17 @@
<context>
<name>BitcoinGUI</name>
<message>
<location filename="../bitcoingui.cpp" line="+358"/>
<location filename="../bitcoingui.cpp" line="+367"/>
<source>Sign &amp;message...</source>
<translation>Sign &amp;message...</translation>
</message>
<message>
<location line="+430"/>
<location line="+437"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
<location line="-508"/>
<location line="-524"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
@ -339,7 +339,17 @@ @@ -339,7 +339,17 @@
<translation>Browse transaction history</translation>
</message>
<message>
<location line="+23"/>
<location line="+6"/>
<source>&amp;Keva</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Keva related operations</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+25"/>
<source>E&amp;xit</source>
<translation>E&amp;xit</translation>
</message>
@ -409,7 +419,7 @@ @@ -409,7 +419,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+360"/>
<location line="+367"/>
<source>Click to disable network activity.</source>
<translation type="unfinished"></translation>
</message>
@ -434,12 +444,12 @@ @@ -434,12 +444,12 @@
<translation>Reindexing blocks on disk...</translation>
</message>
<message>
<location line="-511"/>
<location line="-527"/>
<source>Send coins to a Kevacoin address</source>
<translation>Send coins to a Kevacoin address</translation>
</message>
<message>
<location line="+67"/>
<location line="+76"/>
<source>Backup wallet to another location</source>
<translation>Backup wallet to another location</translation>
</message>
@ -464,12 +474,12 @@ @@ -464,12 +474,12 @@
<translation>&amp;Verify message...</translation>
</message>
<message>
<location line="+517"/>
<location line="+524"/>
<source>Kevacoin</source>
<translation>Kevacoin</translation>
</message>
<message>
<location line="-743"/>
<location line="-759"/>
<source>Wallet</source>
<translation>Wallet</translation>
</message>
@ -484,7 +494,7 @@ @@ -484,7 +494,7 @@
<translation>&amp;Receive</translation>
</message>
<message>
<location line="+50"/>
<location line="+59"/>
<source>&amp;Show / Hide</source>
<translation>&amp;Show / Hide</translation>
</message>
@ -529,12 +539,12 @@ @@ -529,12 +539,12 @@
<translation>Tabs toolbar</translation>
</message>
<message>
<location line="-158"/>
<location line="-167"/>
<source>Request payments (generates QR codes and kevacoin: URIs)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+70"/>
<location line="+79"/>
<source>Show the list of used sending addresses and labels</source>
<translation type="unfinished"></translation>
</message>
@ -554,7 +564,7 @@ @@ -554,7 +564,7 @@
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location line="+357"/>
<location line="+364"/>
<source>%n active connection(s) to Kevacoin network</source>
<translation>
<numerusform>%n active connection to Kevacoin network</numerusform>
@ -615,17 +625,17 @@ @@ -615,17 +625,17 @@
<translation>Up to date</translation>
</message>
<message>
<location line="-441"/>
<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>
<message>
<location line="+200"/>
<location line="+201"/>
<source>%1 client</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+227"/>
<location line="+233"/>
<source>Connecting to peers...</source>
<translation type="unfinished"></translation>
</message>
@ -635,7 +645,7 @@ @@ -635,7 +645,7 @@
<translation>Catching up...</translation>
</message>
<message>
<location line="+150"/>
<location line="+151"/>
<source>Date: %1
</source>
<translation type="unfinished"></translation>
@ -1149,6 +1159,290 @@ @@ -1149,6 +1159,290 @@
</translation>
</message>
</context>
<context>
<name>KevaAddKeyDialog</name>
<message>
<location filename="../forms/kevaaddkeydialog.ui" line="+20"/>
<source>Key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<location line="+27"/>
<source>New value</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-7"/>
<source>Value</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>KevaBookmarksDialog</name>
<message>
<location filename="../kevabookmarksdialog.cpp" line="+20"/>
<source>Show</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>KevaBookmarksModel</name>
<message>
<location filename="../kevabookmarksmodel.cpp" line="+28"/>
<source>Id</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Name</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>KevaDetailDialog</name>
<message>
<location filename="../forms/kevadetaildialog.ui" line="+20"/>
<source>This pane shows the value associated with a give key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../kevadetaildialog.cpp" line="+24"/>
<source>Value for %1</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>KevaDialog</name>
<message>
<location filename="../forms/kevadialog.ui" line="+235"/>
<source>Show the selected request (does the same as double clicking an entry)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-160"/>
<location line="+163"/>
<source>Show</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-204"/>
<location line="+14"/>
<source>The namespace ID with a prefix &quot;N&quot;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-7"/>
<source>Use this form to perform Keva database operations.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
<source>Namespace:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+21"/>
<source>Show content of the namespace.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
<source>Create a new namespace</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>&amp;Create namespace</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+17"/>
<source>List my namespaces</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>&amp;My Namespaces</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+17"/>
<source>Show bookmarks</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>&amp;Bookmarks</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+72"/>
<source>Content of namespace</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+45"/>
<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 line="+17"/>
<source>Add new key-value pair</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Add key-value</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../kevadialog.cpp" line="+53"/>
<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>
<message>
<location line="+192"/>
<source>Warning</source>
<translation type="unfinished">Warning</translation>
</message>
<message>
<location line="+0"/>
<source>Delete the key &quot;%1&quot;?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+15"/>
<source>Invalid namespace &quot;%1&quot;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Key not found: &quot;%1&quot;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<location line="+122"/>
<location line="+28"/>
<source>Unknown error.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="-148"/>
<location line="+122"/>
<location line="+28"/>
<source>Error</source>
<translation type="unfinished">Error</translation>
</message>
<message>
<location line="-33"/>
<source>Namespace too long &quot;%1&quot;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+22"/>
<source>Cannot add key-value. Make sure you own this namespace.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Key too long.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Value too long.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>KevaMyNamespacesDialog</name>
<message>
<location filename="../kevamynamespacesdialog.cpp" line="+20"/>
<source>Show</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>KevaNamespaceModel</name>
<message>
<location filename="../kevanamespacemodel.cpp" line="+21"/>
<source>Id</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Name</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>KevaNewNamespaceDialog</name>
<message>
<location filename="../forms/kevanewnamespacedialog.ui" line="+22"/>
<source>The name of the namespace.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Name:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+13"/>
<source>This pane allows the creation of a new Keva namespace</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>KevaTableModel</name>
<message>
<location filename="../kevatablemodel.cpp" line="+21"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
<message>
<location line="+0"/>
<source>Key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Value</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Block</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+81"/>
<source>Requested</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ModalOverlay</name>
<message>
@ -1671,7 +1965,7 @@ @@ -1671,7 +1965,7 @@
<context>
<name>PaymentServer</name>
<message>
<location filename="../paymentserver.cpp" line="+326"/>
<location filename="../paymentserver.cpp" line="+327"/>
<location line="+214"/>
<location line="+42"/>
<location line="+111"/>
@ -1950,7 +2244,7 @@ @@ -1950,7 +2244,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../bitcoin.cpp" line="+178"/>
<location filename="../bitcoin.cpp" line="+171"/>
<source>%1 didn&apos;t yet exit safely...</source>
<translation type="unfinished"></translation>
</message>
@ -2623,7 +2917,7 @@ @@ -2623,7 +2917,7 @@
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
<location filename="../sendcoinsdialog.cpp" line="+578"/>
<location filename="../sendcoinsdialog.cpp" line="+588"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
@ -2754,7 +3048,7 @@ @@ -2754,7 +3048,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+185"/>
<location line="+175"/>
<source>Send to multiple recipients at once</source>
<translation>Send to multiple recipients at once</translation>
</message>
@ -2769,7 +3063,7 @@ @@ -2769,7 +3063,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="-833"/>
<location line="-823"/>
<source>Dust:</source>
<translation type="unfinished"></translation>
</message>
@ -2779,17 +3073,7 @@ @@ -2779,17 +3073,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+74"/>
<source>Enable Replace-By-Fee</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>With Replace-By-Fee (BIP-125) you can increase a transaction&apos;s fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+65"/>
<location line="+132"/>
<source>Clear &amp;All</source>
<translation>Clear &amp;All</translation>
</message>
@ -2809,7 +3093,7 @@ @@ -2809,7 +3093,7 @@
<translation>S&amp;end</translation>
</message>
<message>
<location filename="../sendcoinsdialog.cpp" line="-494"/>
<location filename="../sendcoinsdialog.cpp" line="-504"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
@ -2849,7 +3133,7 @@ @@ -2849,7 +3133,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+127"/>
<location line="+129"/>
<location line="+5"/>
<location line="+5"/>
<location line="+4"/>
@ -2877,22 +3161,12 @@ @@ -2877,22 +3161,12 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Not signalling Replace-By-Fee, BIP-125.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<location line="+13"/>
<source>Confirm send coins</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+192"/>
<location line="+198"/>
<source>The recipient address is not valid. Please recheck.</source>
<translation type="unfinished"></translation>
</message>
@ -2942,7 +3216,7 @@ @@ -2942,7 +3216,7 @@
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location line="+42"/>
<location line="+43"/>
<source>Estimated to begin confirmation within %n block(s).</source>
<translation>
<numerusform>Estimated to begin confirmation within %n block.</numerusform>
@ -3329,11 +3603,6 @@ @@ -3329,11 +3603,6 @@
<source>conflicted with a transaction with %1 confirmations</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>%1/offline</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>0/unconfirmed, %1</source>
@ -3370,20 +3639,7 @@ @@ -3370,20 +3639,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>, has not been successfully broadcast yet</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location line="+2"/>
<source>, broadcast through %n node(s)</source>
<translation>
<numerusform>, broadcast through %n node</numerusform>
<numerusform>, broadcast through %n nodes</numerusform>
</translation>
</message>
<message>
<location line="+4"/>
<location line="+3"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@ -3593,11 +3849,6 @@ @@ -3593,11 +3849,6 @@
<source>Open until %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Offline</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Unconfirmed</source>
@ -3628,11 +3879,6 @@ @@ -3628,11 +3879,6 @@
<source>Immature (%1 confirmations, will be available after %2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>This block was not received by any other nodes and will probably not be accepted!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Generated but not accepted</source>
@ -3674,7 +3920,7 @@ @@ -3674,7 +3920,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+213"/>
<location line="+210"/>
<source>(no label)</source>
<translation type="unfinished"></translation>
</message>
@ -3927,12 +4173,12 @@ @@ -3927,12 +4173,12 @@
<context>
<name>WalletModel</name>
<message>
<location filename="../walletmodel.cpp" line="+290"/>
<location filename="../walletmodel.cpp" line="+304"/>
<source>Send Coins</source>
<translation type="unfinished">Send Coins</translation>
</message>
<message>
<location line="+384"/>
<location line="+399"/>
<location line="+39"/>
<location line="+6"/>
<source>Fee bump error</source>
@ -3982,7 +4228,7 @@ @@ -3982,7 +4228,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>
@ -3992,7 +4238,7 @@ @@ -3992,7 +4238,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>
@ -4025,7 +4271,7 @@ @@ -4025,7 +4271,7 @@
<context>
<name>bitcoin-core</name>
<message>
<location filename="../bitcoinstrings.cpp" line="+349"/>
<location filename="../bitcoinstrings.cpp" line="+352"/>
<source>Options:</source>
<translation>Options:</translation>
</message>
@ -4035,17 +4281,17 @@ @@ -4035,17 +4281,17 @@
<translation>Specify data directory</translation>
</message>
<message>
<location line="-99"/>
<location line="-102"/>
<source>Connect to a node to retrieve peer addresses, and disconnect</source>
<translation>Connect to a node to retrieve peer addresses, and disconnect</translation>
</message>
<message>
<location line="+102"/>
<location line="+105"/>
<source>Specify your own public address</source>
<translation>Specify your own public address</translation>
</message>
<message>
<location line="-116"/>
<location line="-119"/>
<source>Accept command line and JSON-RPC commands</source>
<translation>Accept command line and JSON-RPC commands</translation>
</message>
@ -4085,7 +4331,7 @@ @@ -4085,7 +4331,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+41"/>
<location line="+44"/>
<source>Pruning blockstore...</source>
<translation type="unfinished"></translation>
</message>
@ -4100,7 +4346,7 @@ @@ -4100,7 +4346,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="-395"/>
<location line="-398"/>
<source>Kevacoin Core</source>
<translation type="unfinished">Kevacoin Core</translation>
</message>
@ -4200,12 +4446,7 @@ @@ -4200,12 +4446,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+6"/>
<source>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, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+12"/>
<location line="+18"/>
<source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
<translation type="unfinished"></translation>
</message>
@ -4449,6 +4690,21 @@ @@ -4449,6 +4690,21 @@
<source>Initialization sanity check failed. %s is shutting down.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Input tx is not a keva operation</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Input tx is not mine</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Input tx not found in wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
<source>Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
@ -4625,7 +4881,7 @@ @@ -4625,7 +4881,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="-395"/>
<location line="-398"/>
<source>Allow JSON-RPC connections from specified source. Valid for &lt;ip&gt; 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</source>
<translation type="unfinished"></translation>
</message>
@ -4740,7 +4996,7 @@ @@ -4740,7 +4996,7 @@
<translation>Information</translation>
</message>
<message>
<location line="+3"/>
<location line="+6"/>
<source>Invalid -onion address or hostname: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
@ -4925,7 +5181,7 @@ @@ -4925,7 +5181,7 @@
<translation>Password for JSON-RPC connections</translation>
</message>
<message>
<location line="-261"/>
<location line="-264"/>
<source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
<translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation>
</message>
@ -5000,7 +5256,12 @@ @@ -5000,7 +5256,12 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+37"/>
<location line="+19"/>
<source>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, &gt;=%u = automatically prune block files to stay under the specified target size in MiB)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+18"/>
<source>Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)</source>
<translation type="unfinished"></translation>
</message>
@ -5115,7 +5376,7 @@ @@ -5115,7 +5376,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location line="+14"/>
<location line="+17"/>
<source>Keypool ran out, please call keypoolrefill first</source>
<translation type="unfinished"></translation>
</message>
@ -5260,17 +5521,17 @@ @@ -5260,17 +5521,17 @@
<translation>Loading wallet...</translation>
</message>
<message>
<location line="-61"/>
<location line="-64"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
<message>
<location line="+87"/>
<location line="+90"/>
<source>Rescanning...</source>
<translation>Rescanning...</translation>
</message>
<message>
<location line="-75"/>
<location line="-78"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>

223
src/qt/locale/bitcoin_zh_CN.ts

@ -907,6 +907,229 @@ @@ -907,6 +907,229 @@
<translation><numerusform>(%n GB空间)</numerusform></translation>
</message>
</context>
<context>
<name>KevaAddKeyDialog</name>
<message>
<source>Key</source>
<translation></translation>
</message>
<message>
<source>New value</source>
<translation></translation>
</message>
<message>
<source>Value</source>
<translation></translation>
</message>
</context>
<context>
<name>KevaBookmarksDialog</name>
<message>
<source>Show</source>
<translation></translation>
</message>
</context>
<context>
<name>KevaBookmarksModel</name>
<message>
<source>Id</source>
<translation>ID</translation>
</message>
<message>
<source>Name</source>
<translation></translation>
</message>
</context>
<context>
<name>KevaDetailDialog</name>
<message>
<source>This pane shows the value associated with a give key</source>
<translation></translation>
</message>
<message numerus="yes">
<source>Value for %1</source>
<translation><numerusform>%1 </numerusform></translation>
</message>
</context>
<context>
<name>KevaDialog</name>
<message>
<source>Show</source>
<translation></translation>
</message>
<message>
<source>The namespace ID with a prefix &quot;N&quot;.</source>
<translation></translation>
</message>
<message>
<source>Use this form to perform Keva database operations.</source>
<translation>使Keva数据库操作</translation>
</message>
<message>
<source>Namespace:</source>
<translation></translation>
</message>
<message>
<source>Show content of the namespace.</source>
<translation></translation>
</message>
<message>
<source>Create a new namespace</source>
<translation></translation>
</message>
<message>
<source>&amp;Create namespace</source>
<translation></translation>
</message>
<message>
<source>List my namespaces</source>
<translation></translation>
</message>
<message>
<source>&amp;My Namespaces</source>
<translation></translation>
</message>
<message>
<source>Show bookmarks</source>
<translation></translation>
</message>
<message>
<source>&amp;Bookmarks</source>
<translation></translation>
</message>
<message>
<source>Content of namespace</source>
<translation></translation>
</message>
<message>
<source>Remove the selected entries from the list</source>
<translation></translation>
</message>
<message>
<source>Remove</source>
<translation></translation>
</message>
<message>
<source>Add new key-value pair</source>
<translation></translation>
</message>
<message>
<source>Add key-value</source>
<translation></translation>
</message>
<message>
<source>Copy URI</source>
<translation></translation>
</message>
<message>
<source>Copy label</source>
<translation></translation>
</message>
<message>
<source>Copy message</source>
<translation></translation>
</message>
<message>
<source>Copy amount</source>
<translation></translation>
</message>
<message>
<source>Warning</source>
<translation></translation>
</message>
<message numerus="yes">
<source>Delete the key &quot;%1&quot;?</source>
<translation><numerusform> &quot;%1&quot;?</numerusform></translation>
</message>
<message numerus="yes">
<source>Invalid namespace &quot;%1&quot;</source>
<translation><numerusform> &quot;%1&quot;</numerusform></translation>
</message>
<message numerus="yes">
<source>Key not found: &quot;%1&quot;.</source>
<translation><numerusform>: &quot;%1&quot;</numerusform></translation>
</message>
<message>
<source>Unknown error.</source>
<translation></translation>
</message>
<message>
<source>Error</source>
<translation></translation>
</message>
<message numerus="yes">
<source>Namespace too long &quot;%1&quot;</source>
<translation><numerusform>: &quot;%1&quot;</numerusform></translation>
</message>
<message>
<source>Cannot add key-value. Make sure you own this namespace.</source>
<translation></translation>
</message>
<message>
<source>Key too long.</source>
<translation></translation>
</message>
<message>
<source>Value too long.</source>
<translation></translation>
</message>
</context>
<context>
<name>KevaMyNamespacesDialog</name>
<message>
<source>Show</source>
<translation></translation>
</message>
</context>
<context>
<name>KevaNamespaceModel</name>
<message>
<source>Id</source>
<translation>Id</translation>
</message>
<message>
<source>Name</source>
<translation></translation>
</message>
</context>
<context>
<name>KevaNewNamespaceDialog</name>
<message>
<source>The name of the namespace.</source>
<translation></translation>
</message>
<message>
<source>Name:</source>
<translation>:</translation>
</message>
<message>
<source>This pane allows the creation of a new Keva namespace</source>
<translation>Keva命名空间</translation>
</message>
</context>
<context>
<name>KevaTableModel</name>
<message>
<source>Date</source>
<translation></translation>
</message>
<message>
<source>Key</source>
<translation></translation>
</message>
<message>
<source>Value</source>
<translation></translation>
</message>
<message>
<source>Block</source>
<translation></translation>
</message>
<message>
<source>Requested</source>
<translation></translation>
</message>
</context>
<context>
<name>ModalOverlay</name>
<message>

BIN
src/qt/res/icons/about.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
src/qt/res/icons/keva.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
src/qt/res/icons/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
src/qt/res/icons/star_empty.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

1
src/qt/test/wallettests.cpp

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

7
src/qt/walletframe.cpp

@ -124,6 +124,13 @@ void WalletFrame::gotoHistoryPage() @@ -124,6 +124,13 @@ void WalletFrame::gotoHistoryPage()
i.value()->gotoHistoryPage();
}
void WalletFrame::gotoKevaPage()
{
QMap<QString, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
i.value()->gotoKevaPage();
}
void WalletFrame::gotoReceiveCoinsPage()
{
QMap<QString, WalletView*>::const_iterator i;

2
src/qt/walletframe.h

@ -66,6 +66,8 @@ public Q_SLOTS: @@ -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 */

286
src/qt/walletmodel.cpp

@ -11,12 +11,17 @@ @@ -11,12 +11,17 @@
#include <qt/optionsmodel.h>
#include <qt/paymentserver.h>
#include <qt/recentrequeststablemodel.h>
#include <qt/kevatablemodel.h>
#include <qt/kevanamespacemodel.h>
#include <qt/kevabookmarksmodel.h>
#include <qt/sendcoinsdialog.h>
#include <qt/transactiontablemodel.h>
#include <base58.h>
#include <chain.h>
#include <keystore.h>
#include <keva/common.h>
#include <keva/main.h>
#include <validation.h>
#include <net.h> // for g_connman
#include <policy/fees.h>
@ -36,11 +41,16 @@ @@ -36,11 +41,16 @@
#include <QSet>
#include <QTimer>
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 @@ -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() @@ -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 @@ -743,3 +771,261 @@ int WalletModel::getDefaultConfirmTarget() const
{
return nTxConfirmTarget;
}
void WalletModel::getKevaEntries(std::vector<KevaEntry>& vKevaEntries, std::string nameSpace)
{
valtype nameSpaceVal = ValtypeFromString(nameSpace);
{
// Get the unconfirmed namespaces and list them at the beginning.
LOCK (mempool.cs);
std::vector<std::tuple<valtype, valtype, valtype, uint256>> 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<CKevaIterator> 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<NamespaceEntry>& vNamespaceEntries)
{
LOCK2(cs_main, wallet->cs_wallet);
std::map<std::string, std::string> 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<std::tuple<valtype, valtype, uint256>> 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<std::string, std::string>::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<std::tuple<valtype, valtype, valtype, uint256>> 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;
}

29
src/qt/walletmodel.h

@ -21,6 +21,12 @@ class AddressTableModel; @@ -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: @@ -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: @@ -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: @@ -220,6 +237,13 @@ public:
int getDefaultConfirmTarget() const;
// Keva
void getKevaEntries(std::vector<KevaEntry>& vKevaEntries, std::string nameSpace);
void getNamespaceEntries(std::vector<NamespaceEntry>& 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: @@ -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;

9
src/qt/walletview.cpp

@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
#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>
@ -53,6 +54,7 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent): @@ -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): @@ -61,6 +63,7 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent):
addWidget(overviewPage);
addWidget(transactionsPage);
addWidget(kevaPage);
addWidget(receiveCoinsPage);
addWidget(sendCoinsPage);
@ -119,6 +122,7 @@ void WalletView::setWalletModel(WalletModel *_walletModel) @@ -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() @@ -179,6 +183,11 @@ void WalletView::gotoHistoryPage()
setCurrentWidget(transactionsPage);
}
void WalletView::gotoKevaPage()
{
setCurrentWidget(kevaPage);
}
void WalletView::gotoReceiveCoinsPage()
{
setCurrentWidget(receiveCoinsPage);

4
src/qt/walletview.h

@ -15,6 +15,7 @@ class OverviewPage; @@ -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: @@ -62,6 +63,7 @@ private:
QWidget *transactionsPage;
ReceiveCoinsDialog *receiveCoinsPage;
SendCoinsDialog *sendCoinsPage;
KevaDialog *kevaPage;
AddressBookPage *usedSendingAddressesPage;
AddressBookPage *usedReceivingAddressesPage;
@ -75,6 +77,8 @@ public Q_SLOTS: @@ -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 */

Loading…
Cancel
Save