diff --git a/alethzero/AllAccounts.cpp b/alethzero/AllAccounts.cpp new file mode 100644 index 000000000..71c96cc62 --- /dev/null +++ b/alethzero/AllAccounts.cpp @@ -0,0 +1,128 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file AllAccounts.h + * @author Gav Wood + * @date 2015 + */ + +#include "AllAccounts.h" +#include +#include +#include +#include +#include +#include +#include "ui_AllAccounts.h" +using namespace std; +using namespace dev; +using namespace az; +using namespace eth; + +AllAccounts::AllAccounts(MainFace* _m): + Plugin(_m, "AllAccounts"), + m_ui(new Ui::AllAccounts) +{ + dock(Qt::RightDockWidgetArea, "All Accounts")->setWidget(new QWidget()); + m_ui->setupUi(dock()->widget()); + installWatches(); + refresh(); + + connect(m_ui->accounts, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(on_accounts_currentItemChanged())); + connect(m_ui->accounts, SIGNAL(doubleClicked(QModelIndex)), SLOT(on_accounts_doubleClicked())); + connect(m_ui->refreshAccounts, SIGNAL(clicked()), SLOT(refresh())); + connect(m_ui->accountsFilter, SIGNAL(textChanged(QString)), SLOT(onAllChange())); + connect(m_ui->showBasic, SIGNAL(toggled(bool)), SLOT(onAllChange())); + connect(m_ui->showContracts, SIGNAL(toggled(bool)), SLOT(onAllChange())); + connect(m_ui->onlyNamed, SIGNAL(toggled(bool)), SLOT(onAllChange())); +} + +AllAccounts::~AllAccounts() +{ +} + +void AllAccounts::installWatches() +{ + main()->installWatch(ChainChangedFilter, [=](LocalisedLogEntries const&){ onAllChange(); }); + main()->installWatch(PendingChangedFilter, [=](LocalisedLogEntries const&){ onAllChange(); }); +} + +void AllAccounts::refresh() +{ + DEV_TIMED_FUNCTION; +#if ETH_FATDB || !ETH_TRUE + cwatch << "refreshAccounts()"; + m_ui->accounts->clear(); + bool showContract = m_ui->showContracts->isChecked(); + bool showBasic = m_ui->showBasic->isChecked(); + bool onlyNamed = m_ui->onlyNamed->isChecked(); + for (auto const& i: ethereum()->addresses()) + { + bool isContract = (ethereum()->codeHashAt(i) != EmptySHA3); + if (!((showContract && isContract) || (showBasic && !isContract))) + continue; + string r = static_cast(main())->render(i); + if (onlyNamed && !(r.find('"') != string::npos || r.substr(0, 2) == "XE")) + continue; + (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(QString::fromStdString(r)).arg((unsigned)ethereum()->countAt(i)), m_ui->accounts)) + ->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size)); + } +#endif + m_ui->refreshAccounts->setEnabled(false); +} + +void AllAccounts::onAllChange() +{ + m_ui->refreshAccounts->setEnabled(true); +} + +void AllAccounts::on_accounts_currentItemChanged() +{ + m_ui->accountInfo->clear(); + if (auto item = m_ui->accounts->currentItem()) + { + auto hba = item->data(Qt::UserRole).toByteArray(); + assert(hba.size() == 20); + auto address = h160((byte const*)hba.data(), h160::ConstructFromPointer); + + stringstream s; + try + { + auto storage = ethereum()->storageAt(address); + for (auto const& i: storage) + s << "@" << showbase << hex << main()->prettyU256(i.first) << "    " << showbase << hex << main()->prettyU256(i.second) << "
"; + s << "

Body Code (" << sha3(ethereum()->codeAt(address)).abridged() << ")

" << disassemble(ethereum()->codeAt(address)); + s << ETH_HTML_DIV(ETH_HTML_MONO) << toHex(ethereum()->codeAt(address)) << ""; + m_ui->accountInfo->appendHtml(QString::fromStdString(s.str())); + } + catch (dev::InvalidTrie) + { + m_ui->accountInfo->appendHtml("Corrupted trie."); + } + m_ui->accountInfo->moveCursor(QTextCursor::Start); + } +} + +void AllAccounts::on_accounts_doubleClicked() +{ + if (m_ui->accounts->count()) + { + auto hba = m_ui->accounts->currentItem()->data(Qt::UserRole).toByteArray(); + auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer); + qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray()))); + } +} + diff --git a/alethzero/AllAccounts.h b/alethzero/AllAccounts.h new file mode 100644 index 000000000..7104a6d70 --- /dev/null +++ b/alethzero/AllAccounts.h @@ -0,0 +1,59 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file AllAccounts.h + * @author Gav Wood + * @date 2015 + */ + +#pragma once + +#include +#include +#include "MainFace.h" + +namespace Ui +{ +class AllAccounts; +} + +namespace dev +{ +namespace az +{ + +class AllAccounts: public QObject, public Plugin +{ + Q_OBJECT + +public: + AllAccounts(MainFace* _m); + ~AllAccounts(); + +private slots: + void on_accounts_currentItemChanged(); + void on_accounts_doubleClicked(); + + void onAllChange(); + void refresh(); +private: + void installWatches(); + + Ui::AllAccounts* m_ui; +}; + +} +} diff --git a/alethzero/AllAccounts.ui b/alethzero/AllAccounts.ui new file mode 100644 index 000000000..ca0ad31bc --- /dev/null +++ b/alethzero/AllAccounts.ui @@ -0,0 +1,134 @@ + + + AllAccounts + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Filter... + + + + + + + Basic + + + true + + + + + + + Contracts + + + true + + + true + + + + + + + Only Named + + + true + + + false + + + + + + + Refresh + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + 0 + 0 + + + + Qt::NoFocus + + + QFrame::NoFrame + + + + + + 2 + 0 + + + + Qt::WheelFocus + + + QFrame::NoFrame + + + true + + + + + + + + + diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 1b1138eab..75576ecc1 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -31,6 +31,9 @@ qt5_wrap_ui(ui_ExportState.h ExportState.ui) qt5_wrap_ui(ui_GetPassword.h GetPassword.ui) qt5_wrap_ui(ui_GasPricing.h GasPricing.ui) +# Extensions +qt5_wrap_ui(ui_AllAccounts.h AllAccounts.ui) + file(GLOB HEADERS "*.h") if (APPLE) @@ -42,7 +45,7 @@ endif () # eth_add_executable is defined in cmake/EthExecutableHelper.cmake eth_add_executable(${EXECUTABLE} ICON alethzero - UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui GetPassword.ui GasPricing.ui + UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui GetPassword.ui GasPricing.ui AllAccounts.ui WIN_RESOURCES alethzero.rc ) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b1a93aaab..800c74d56 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -615,98 +615,6 @@ 0 - - - - - - Filter... - - - - - - - Basic - - - true - - - - - - - Contracts - - - true - - - true - - - - - - - Only Named - - - true - - - false - - - - - - - Refresh - - - - - - - - - Qt::Horizontal - - - - - 0 - 0 - - - - Qt::NoFocus - - - QFrame::NoFrame - - - - - - 2 - 0 - - - - Qt::WheelFocus - - - QFrame::NoFrame - - - true - - - - diff --git a/alethzero/MainFace.cpp b/alethzero/MainFace.cpp new file mode 100644 index 000000000..82c76563a --- /dev/null +++ b/alethzero/MainFace.cpp @@ -0,0 +1,71 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file MainFace.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "MainFace.h" +using namespace std; +using namespace dev; +using namespace az; + +Plugin::Plugin(MainFace* _f, std::string const& _name): + m_main(_f), + m_name(_name) +{ + _f->adoptPlugin(this); +} + +QDockWidget* Plugin::dock(Qt::DockWidgetArea _area, QString _title) +{ + if (_title.isEmpty()) + _title = QString::fromStdString(m_name); + if (!m_dock) + { + m_dock = new QDockWidget(_title, m_main); + m_main->addDockWidget(_area, m_dock); + m_dock->setFeatures(QDockWidget::AllDockWidgetFeatures | QDockWidget::DockWidgetVerticalTitleBar); + } + return m_dock; +} + +void Plugin::addToDock(Qt::DockWidgetArea _area, QDockWidget* _dockwidget, Qt::Orientation _orientation) +{ + m_main->addDockWidget(_area, _dockwidget, _orientation); +} + +void Plugin::addAction(QAction* _a) +{ + m_main->addAction(_a); +} + +void MainFace::adoptPlugin(Plugin* _p) +{ + m_plugins[_p->name()] = shared_ptr(_p); +} + +void MainFace::killPlugins() +{ + m_plugins.clear(); +} + +void MainFace::allChange() +{ + for (auto const& p: m_plugins) + p.second->onAllChange(); +} diff --git a/alethzero/MainFace.h b/alethzero/MainFace.h new file mode 100644 index 000000000..f6bf5b75a --- /dev/null +++ b/alethzero/MainFace.h @@ -0,0 +1,97 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file MainFace.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include "Context.h" + +namespace dev +{ + +class WebThreeDirect; +namespace eth { class Client; class LogFilter; } +namespace shh { class WhisperHost; } + +namespace az +{ + +class Plugin; + +using WatchHandler = std::function; + +class MainFace: public QMainWindow, public Context +{ +public: + explicit MainFace(QWidget* _parent = nullptr): QMainWindow(_parent) {} + + void adoptPlugin(Plugin* _p); + void killPlugins(); + + void allChange(); + + // TODO: tidy - all should be references that throw if module unavailable. + // TODO: provide a set of available web3 modules. + virtual dev::WebThreeDirect* web3() const = 0; + virtual dev::eth::Client* ethereum() const = 0; + virtual std::shared_ptr whisper() const = 0; + + virtual unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f) = 0; + virtual unsigned installWatch(dev::h256 const& _tf, WatchHandler const& _f) = 0; + +private: + std::unordered_map> m_plugins; +}; + +class Plugin +{ +public: + Plugin(MainFace* _f, std::string const& _name); + virtual ~Plugin() {} + + std::string const& name() const { return m_name; } + + dev::WebThreeDirect* web3() const { return m_main->web3(); } + dev::eth::Client* ethereum() const { return m_main->ethereum(); } + std::shared_ptr whisper() const { return m_main->whisper(); } + MainFace* main() { return m_main; } + QDockWidget* dock(Qt::DockWidgetArea _area = Qt::RightDockWidgetArea, QString _title = QString()); + void addToDock(Qt::DockWidgetArea _area, QDockWidget* _dockwidget, Qt::Orientation _orientation); + void addAction(QAction* _a); + + virtual void onAllChange() {} + +private: + MainFace* m_main = nullptr; + std::string m_name; + QDockWidget* m_dock = nullptr; +}; + +} + +} diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index dda627aa4..7c29bbb92 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -74,13 +74,15 @@ #include "DappHost.h" #include "WebPage.h" #include "ExportState.h" +#include "AllAccounts.h" #include "ui_Main.h" #include "ui_GetPassword.h" #include "ui_GasPricing.h" using namespace std; using namespace dev; -using namespace dev::p2p; -using namespace dev::eth; +using namespace az; +using namespace p2p; +using namespace eth; namespace js = json_spirit; string Main::fromRaw(h256 _n, unsigned* _inc) @@ -126,8 +128,8 @@ static QString filterOutTerminal(QString _s) return _s.replace(QRegExp("\x1b\\[(\\d;)?\\d+m"), ""); } -Main::Main(QWidget *parent) : - QMainWindow(parent), +Main::Main(QWidget* _parent): + MainFace(_parent), ui(new Ui::Main), m_transact(nullptr), m_dappLoader(nullptr), @@ -305,6 +307,8 @@ Main::Main(QWidget *parent) : s.setValue("splashMessage", false); } } + + new dev::az::AllAccounts(this); } Main::~Main() @@ -417,7 +421,7 @@ unsigned Main::installWatch(LogFilter const& _tf, WatchHandler const& _f) return ret; } -unsigned Main::installWatch(dev::h256 _tf, WatchHandler const& _f) +unsigned Main::installWatch(h256 const& _tf, WatchHandler const& _f) { auto ret = ethereum()->installWatch(_tf, Reaping::Manual); m_handlers[ret] = _f; @@ -525,7 +529,6 @@ void Main::onNewBlock() // update blockchain dependent views. refreshBlockCount(); refreshBlockChain(); - ui->refreshAccounts->setEnabled(true); // We must update balances since we can't filter updates to basic accounts. refreshBalances(); @@ -537,7 +540,6 @@ void Main::onNewPending() // update any pending-transaction dependent views. refreshPending(); - ui->refreshAccounts->setEnabled(true); } void Main::on_forceMining_triggered() @@ -1243,8 +1245,8 @@ void Main::refreshAll() refreshBlockChain(); refreshBlockCount(); refreshPending(); - ui->refreshAccounts->setEnabled(true); refreshBalances(); + allChange(); } void Main::refreshPending() @@ -1269,55 +1271,6 @@ void Main::refreshPending() } } -void Main::on_accountsFilter_textChanged() -{ - ui->refreshAccounts->setEnabled(true); -} - -void Main::on_showBasic_toggled() -{ - ui->refreshAccounts->setEnabled(true); -} - -void Main::on_showContracts_toggled() -{ - ui->refreshAccounts->setEnabled(true); -} - -void Main::on_onlyNamed_toggled() -{ - ui->refreshAccounts->setEnabled(true); -} - -void Main::on_refreshAccounts_clicked() -{ - refreshAccounts(); -} - -void Main::refreshAccounts() -{ - DEV_TIMED_FUNCTION; -#if ETH_FATDB || !ETH_TRUE - cwatch << "refreshAccounts()"; - ui->accounts->clear(); - bool showContract = ui->showContracts->isChecked(); - bool showBasic = ui->showBasic->isChecked(); - bool onlyNamed = ui->onlyNamed->isChecked(); - for (auto const& i: ethereum()->addresses()) - { - bool isContract = (ethereum()->codeHashAt(i) != EmptySHA3); - if (!((showContract && isContract) || (showBasic && !isContract))) - continue; - string r = render(i); - if (onlyNamed && !(r.find('"') != string::npos || r.substr(0, 2) == "XE")) - continue; - (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(QString::fromStdString(r)).arg((unsigned)ethereum()->countAt(i)), ui->accounts)) - ->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size)); - } -#endif - ui->refreshAccounts->setEnabled(false); -} - void Main::refreshBlockCount() { auto d = ethereum()->blockChain().details(); @@ -1925,33 +1878,6 @@ void Main::debugDumpState(int _add) } } -void Main::on_accounts_currentItemChanged() -{ - ui->accountInfo->clear(); - if (auto item = ui->accounts->currentItem()) - { - auto hba = item->data(Qt::UserRole).toByteArray(); - assert(hba.size() == 20); - auto address = h160((byte const*)hba.data(), h160::ConstructFromPointer); - - stringstream s; - try - { - auto storage = ethereum()->storageAt(address); - for (auto const& i: storage) - s << "@" << showbase << hex << prettyU256(i.first) << "    " << showbase << hex << prettyU256(i.second) << "
"; - s << "

Body Code (" << sha3(ethereum()->codeAt(address)).abridged() << ")

" << disassemble(ethereum()->codeAt(address)); - s << ETH_HTML_DIV(ETH_HTML_MONO) << toHex(ethereum()->codeAt(address)) << ""; - ui->accountInfo->appendHtml(QString::fromStdString(s.str())); - } - catch (dev::InvalidTrie) - { - ui->accountInfo->appendHtml("Corrupted trie."); - } - ui->accountInfo->moveCursor(QTextCursor::Start); - } -} - void Main::on_idealPeers_valueChanged(int) { m_webThree->setIdealPeerCount(ui->idealPeers->value()); @@ -1970,16 +1896,6 @@ void Main::on_ourAccounts_doubleClicked() m_logHistory.clear(); }*/ -void Main::on_accounts_doubleClicked() -{ - if (ui->accounts->count()) - { - auto hba = ui->accounts->currentItem()->data(Qt::UserRole).toByteArray(); - auto h = Address((byte const*)hba.data(), Address::ConstructFromPointer); - qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray()))); - } -} - static shh::Topics topicFromText(QString _s) { shh::BuildTopic ret; diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 307cc1533..918ff3ef4 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -26,7 +26,6 @@ #endif #include - #include #include #include @@ -42,6 +41,7 @@ #include "Transact.h" #include "NatspecHandler.h" #include "Connect.h" +#include "MainFace.h" class QListWidgetItem; class QActionGroup; @@ -65,11 +65,9 @@ class DappLoader; class DappHost; struct Dapp; -using WatchHandler = std::function; - QString contentsOfQResource(std::string const& res); -class Main: public QMainWindow, public Context +class Main: public dev::az::MainFace { Q_OBJECT @@ -77,9 +75,9 @@ public: explicit Main(QWidget *parent = 0); ~Main(); - dev::WebThreeDirect* web3() const { return m_webThree.get(); } - dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } - std::shared_ptr whisper() const { return m_webThree->whisper(); } + dev::WebThreeDirect* web3() const override { return m_webThree.get(); } + dev::eth::Client* ethereum() const override { return m_webThree->ethereum(); } + std::shared_ptr whisper() const override { return m_webThree->whisper(); } bool confirm() const; NatSpecFace* natSpec() { return &m_natSpecDB; } @@ -131,7 +129,6 @@ private slots: // View void on_refresh_triggered(); void on_showAll_triggered() { refreshBlockChain(); } - void on_showAllAccounts_triggered() { refreshAccounts(); } void on_preview_triggered(); // Account management @@ -144,13 +141,6 @@ private slots: void on_claimPresale_triggered(); void on_exportKey_triggered(); - // Account pane - void on_accountsFilter_textChanged(); - void on_showBasic_toggled(); - void on_showContracts_toggled(); - void on_onlyNamed_toggled(); - void on_refreshAccounts_clicked(); - // Tools void on_newTransaction_triggered(); void on_loadJS_triggered(); @@ -159,8 +149,6 @@ private slots: // Stuff concerning the blocks/transactions/accounts panels void on_ourAccounts_itemClicked(QListWidgetItem* _i); void on_ourAccounts_doubleClicked(); - void on_accounts_doubleClicked(); - void on_accounts_currentItemChanged(); void on_transactionQueue_currentItemChanged(); void on_blockChainFilter_textChanged(); void on_blocks_currentItemChanged(); @@ -229,8 +217,8 @@ private: void setPrivateChain(QString const& _private, bool _forceConfigure = false); - unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f); - unsigned installWatch(dev::h256 _tf, WatchHandler const& _f); + unsigned installWatch(dev::eth::LogFilter const& _tf, dev::az::WatchHandler const& _f) override; + unsigned installWatch(dev::h256 const& _tf, dev::az::WatchHandler const& _f) override; void uninstallWatch(unsigned _w); void keysChanged(); @@ -266,7 +254,7 @@ private: std::unique_ptr m_webThree; - std::map m_handlers; + std::map m_handlers; unsigned m_nameRegFilter = (unsigned)-1; unsigned m_currenciesFilter = (unsigned)-1; unsigned m_balancesFilter = (unsigned)-1;