Merge pull request #1019 from laanwj/2012_03_uirefactor
Streamline UI ↔ Core interface
This commit is contained in:
@@ -94,8 +94,6 @@ void AddressBookPage::setModel(AddressTableModel *model)
|
||||
this->model = model;
|
||||
if(!model)
|
||||
return;
|
||||
// Refresh list from core
|
||||
model->updateList();
|
||||
|
||||
proxyModel = new QSortFilterProxyModel(this);
|
||||
proxyModel->setSourceModel(model);
|
||||
|
||||
@@ -231,7 +231,7 @@ QModelIndex AddressTableModel::index(int row, int column, const QModelIndex & pa
|
||||
}
|
||||
}
|
||||
|
||||
void AddressTableModel::updateList()
|
||||
void AddressTableModel::update()
|
||||
{
|
||||
// Update address book model from Bitcoin core
|
||||
beginResetModel();
|
||||
@@ -285,10 +285,9 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
// Add entry and update list
|
||||
// Add entry
|
||||
CRITICAL_BLOCK(wallet->cs_wallet)
|
||||
wallet->SetAddressBookName(strAddress, strLabel);
|
||||
updateList();
|
||||
return QString::fromStdString(strAddress);
|
||||
}
|
||||
|
||||
@@ -306,15 +305,9 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex & paren
|
||||
{
|
||||
wallet->DelAddressBookName(rec->address.toStdString());
|
||||
}
|
||||
updateList();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddressTableModel::update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* Look up label for address in address book, if not found return empty string.
|
||||
*/
|
||||
QString AddressTableModel::labelForAddress(const QString &address) const
|
||||
|
||||
@@ -56,10 +56,6 @@ public:
|
||||
*/
|
||||
QString addRow(const QString &type, const QString &label, const QString &address);
|
||||
|
||||
/* Update address list from core. Invalidates any indices.
|
||||
*/
|
||||
void updateList();
|
||||
|
||||
/* Look up label for address in address book, if not found return empty string.
|
||||
*/
|
||||
QString labelForAddress(const QString &address) const;
|
||||
@@ -82,6 +78,8 @@ signals:
|
||||
void defaultAddressChanged(const QString &address);
|
||||
|
||||
public slots:
|
||||
/* Update address list from core. Invalidates any indices.
|
||||
*/
|
||||
void update();
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "clientmodel.h"
|
||||
#include "walletmodel.h"
|
||||
#include "optionsmodel.h"
|
||||
#include "guiutil.h"
|
||||
|
||||
#include "headers.h"
|
||||
#include "init.h"
|
||||
@@ -12,7 +13,6 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMessageBox>
|
||||
#include <QThread>
|
||||
#include <QTextCodec>
|
||||
#include <QLocale>
|
||||
#include <QTranslator>
|
||||
@@ -21,27 +21,35 @@
|
||||
|
||||
#include <boost/interprocess/ipc/message_queue.hpp>
|
||||
|
||||
#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
|
||||
#define _BITCOIN_QT_PLUGINS_INCLUDED
|
||||
#define __INSURE__
|
||||
#include <QtPlugin>
|
||||
Q_IMPORT_PLUGIN(qcncodecs)
|
||||
Q_IMPORT_PLUGIN(qjpcodecs)
|
||||
Q_IMPORT_PLUGIN(qtwcodecs)
|
||||
Q_IMPORT_PLUGIN(qkrcodecs)
|
||||
Q_IMPORT_PLUGIN(qtaccessiblewidgets)
|
||||
#endif
|
||||
|
||||
// Need a global reference for the notifications to find the GUI
|
||||
BitcoinGUI *guiref;
|
||||
QSplashScreen *splashref;
|
||||
static BitcoinGUI *guiref;
|
||||
static QSplashScreen *splashref;
|
||||
static WalletModel *walletmodel;
|
||||
static ClientModel *clientmodel;
|
||||
|
||||
int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
|
||||
{
|
||||
// Message from AppInit2(), always in main thread before main window is constructed
|
||||
QMessageBox::critical(0, QString::fromStdString(caption),
|
||||
QString::fromStdString(message),
|
||||
QMessageBox::Ok, QMessageBox::Ok);
|
||||
return 4;
|
||||
}
|
||||
|
||||
int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
|
||||
int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
|
||||
{
|
||||
// Message from network thread
|
||||
if(guiref)
|
||||
{
|
||||
QMetaObject::invokeMethod(guiref, "error", Qt::QueuedConnection,
|
||||
bool modal = (style & wxMODAL);
|
||||
// in case of modal message, use blocking connection to wait for user to click OK
|
||||
QMetaObject::invokeMethod(guiref, "error",
|
||||
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
|
||||
Q_ARG(QString, QString::fromStdString(caption)),
|
||||
Q_ARG(QString, QString::fromStdString(message)));
|
||||
Q_ARG(QString, QString::fromStdString(message)),
|
||||
Q_ARG(bool, modal));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -51,7 +59,7 @@ int ThreadSafeMessageBox(const std::string& message, const std::string& caption,
|
||||
return 4;
|
||||
}
|
||||
|
||||
bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent)
|
||||
bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
|
||||
{
|
||||
if(!guiref)
|
||||
return false;
|
||||
@@ -59,15 +67,7 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindo
|
||||
return true;
|
||||
bool payFee = false;
|
||||
|
||||
// Call slot on GUI thread.
|
||||
// If called from another thread, use a blocking QueuedConnection.
|
||||
Qt::ConnectionType connectionType = Qt::DirectConnection;
|
||||
if(QThread::currentThread() != QCoreApplication::instance()->thread())
|
||||
{
|
||||
connectionType = Qt::BlockingQueuedConnection;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(guiref, "askFee", connectionType,
|
||||
QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(),
|
||||
Q_ARG(qint64, nFeeRequired),
|
||||
Q_ARG(bool*, &payFee));
|
||||
|
||||
@@ -79,31 +79,22 @@ void ThreadSafeHandleURL(const std::string& strURL)
|
||||
if(!guiref)
|
||||
return;
|
||||
|
||||
// Call slot on GUI thread.
|
||||
// If called from another thread, use a blocking QueuedConnection.
|
||||
Qt::ConnectionType connectionType = Qt::DirectConnection;
|
||||
if(QThread::currentThread() != QCoreApplication::instance()->thread())
|
||||
{
|
||||
connectionType = Qt::BlockingQueuedConnection;
|
||||
}
|
||||
QMetaObject::invokeMethod(guiref, "handleURL", connectionType,
|
||||
QMetaObject::invokeMethod(guiref, "handleURL", GUIUtil::blockingGUIThreadConnection(),
|
||||
Q_ARG(QString, QString::fromStdString(strURL)));
|
||||
}
|
||||
|
||||
void CalledSetStatusBar(const std::string& strText, int nField)
|
||||
{
|
||||
// Only used for built-in mining, which is disabled, simple ignore
|
||||
}
|
||||
|
||||
void UIThreadCall(boost::function0<void> fn)
|
||||
{
|
||||
// Only used for built-in mining, which is disabled, simple ignore
|
||||
}
|
||||
|
||||
void MainFrameRepaint()
|
||||
{
|
||||
if(guiref)
|
||||
QMetaObject::invokeMethod(guiref, "refreshStatusBar", Qt::QueuedConnection);
|
||||
if(clientmodel)
|
||||
QMetaObject::invokeMethod(clientmodel, "update", Qt::QueuedConnection);
|
||||
if(walletmodel)
|
||||
QMetaObject::invokeMethod(walletmodel, "update", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void AddressBookRepaint()
|
||||
{
|
||||
if(walletmodel)
|
||||
QMetaObject::invokeMethod(walletmodel, "updateAddressList", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void InitMessage(const std::string &message)
|
||||
@@ -115,6 +106,11 @@ void InitMessage(const std::string &message)
|
||||
}
|
||||
}
|
||||
|
||||
void QueueShutdown()
|
||||
{
|
||||
QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
/*
|
||||
Translate string to current locale using Qt.
|
||||
*/
|
||||
@@ -221,22 +217,24 @@ int main(int argc, char *argv[])
|
||||
|
||||
try
|
||||
{
|
||||
BitcoinGUI window;
|
||||
guiref = &window;
|
||||
if(AppInit2(argc, argv))
|
||||
{
|
||||
{
|
||||
// Put this in a block, so that BitcoinGUI is cleaned up properly before
|
||||
// calling Shutdown() in case of exceptions.
|
||||
// Put this in a block, so that the Model objects are cleaned up before
|
||||
// calling Shutdown().
|
||||
|
||||
optionsModel.Upgrade(); // Must be done after AppInit2
|
||||
|
||||
BitcoinGUI window;
|
||||
if (splashref)
|
||||
splash.finish(&window);
|
||||
|
||||
ClientModel clientModel(&optionsModel);
|
||||
clientmodel = &clientModel;
|
||||
WalletModel walletModel(pwalletMain, &optionsModel);
|
||||
walletmodel = &walletModel;
|
||||
|
||||
guiref = &window;
|
||||
window.setClientModel(&clientModel);
|
||||
window.setWalletModel(&walletModel);
|
||||
|
||||
@@ -273,7 +271,11 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
app.exec();
|
||||
|
||||
window.setClientModel(0);
|
||||
window.setWalletModel(0);
|
||||
guiref = 0;
|
||||
clientmodel = 0;
|
||||
walletmodel = 0;
|
||||
}
|
||||
Shutdown(NULL);
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
|
||||
connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
|
||||
|
||||
// Report errors from network/worker thread
|
||||
connect(clientModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
|
||||
connect(clientModel, SIGNAL(error(QString,QString, bool)), this, SLOT(error(QString,QString,bool)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel)
|
||||
if(walletModel)
|
||||
{
|
||||
// Report errors from wallet thread
|
||||
connect(walletModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
|
||||
connect(walletModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
|
||||
|
||||
// Put transaction list in tabs
|
||||
transactionView->setModel(walletModel);
|
||||
@@ -552,23 +552,15 @@ void BitcoinGUI::setNumBlocks(int count)
|
||||
progressBar->setToolTip(tooltip);
|
||||
}
|
||||
|
||||
void BitcoinGUI::refreshStatusBar()
|
||||
{
|
||||
/* Might display multiple times in the case of multiple alerts
|
||||
static QString prevStatusBar;
|
||||
QString newStatusBar = clientModel->getStatusBarWarnings();
|
||||
if (prevStatusBar != newStatusBar)
|
||||
{
|
||||
prevStatusBar = newStatusBar;
|
||||
error(tr("Network Alert"), newStatusBar);
|
||||
}*/
|
||||
setNumBlocks(clientModel->getNumBlocks());
|
||||
}
|
||||
|
||||
void BitcoinGUI::error(const QString &title, const QString &message)
|
||||
void BitcoinGUI::error(const QString &title, const QString &message, bool modal)
|
||||
{
|
||||
// Report errors from network/worker thread
|
||||
notificator->notify(Notificator::Critical, title, message);
|
||||
if(modal)
|
||||
{
|
||||
QMessageBox::critical(this, title, message, QMessageBox::Ok, QMessageBox::Ok);
|
||||
} else {
|
||||
notificator->notify(Notificator::Critical, title, message);
|
||||
}
|
||||
}
|
||||
|
||||
void BitcoinGUI::changeEvent(QEvent *e)
|
||||
|
||||
@@ -113,11 +113,9 @@ public slots:
|
||||
@see WalletModel::EncryptionStatus
|
||||
*/
|
||||
void setEncryptionStatus(int status);
|
||||
/** Set the status bar text if there are any warnings (removes sync progress bar if applicable) */
|
||||
void refreshStatusBar();
|
||||
|
||||
/** Notify the user of an error in the network or transaction handling code. */
|
||||
void error(const QString &title, const QString &message);
|
||||
void error(const QString &title, const QString &message, bool modal);
|
||||
/** Asks the user whether to pay the transaction fee or to cancel the transaction.
|
||||
It is currently not possible to pass a return value to another thread through
|
||||
BlockingQueuedConnection, so an indirected pointer is used.
|
||||
|
||||
@@ -6,19 +6,12 @@
|
||||
|
||||
#include "headers.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
|
||||
ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
|
||||
QObject(parent), optionsModel(optionsModel),
|
||||
cachedNumConnections(0), cachedNumBlocks(0)
|
||||
{
|
||||
// Until signal notifications is built into the bitcoin core,
|
||||
// simply update everything after polling using a timer.
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
|
||||
timer->start(MODEL_UPDATE_DELAY);
|
||||
|
||||
numBlocksAtStartup = -1;
|
||||
}
|
||||
|
||||
@@ -47,14 +40,23 @@ void ClientModel::update()
|
||||
{
|
||||
int newNumConnections = getNumConnections();
|
||||
int newNumBlocks = getNumBlocks();
|
||||
QString newStatusBar = getStatusBarWarnings();
|
||||
|
||||
if(cachedNumConnections != newNumConnections)
|
||||
emit numConnectionsChanged(newNumConnections);
|
||||
if(cachedNumBlocks != newNumBlocks)
|
||||
if(cachedNumBlocks != newNumBlocks || cachedStatusBar != newStatusBar)
|
||||
{
|
||||
// Simply emit a numBlocksChanged for now in case the status message changes,
|
||||
// so that the view updates the status bar.
|
||||
// TODO: It should send a notification.
|
||||
// (However, this might generate looped notifications and needs to be thought through and tested carefully)
|
||||
// error(tr("Network Alert"), newStatusBar);
|
||||
emit numBlocksChanged(newNumBlocks);
|
||||
}
|
||||
|
||||
cachedNumConnections = newNumConnections;
|
||||
cachedNumBlocks = newNumBlocks;
|
||||
cachedStatusBar = newStatusBar;
|
||||
}
|
||||
|
||||
bool ClientModel::isTestNet() const
|
||||
|
||||
@@ -43,6 +43,7 @@ private:
|
||||
|
||||
int cachedNumConnections;
|
||||
int cachedNumBlocks;
|
||||
QString cachedStatusBar;
|
||||
|
||||
int numBlocksAtStartup;
|
||||
|
||||
@@ -51,7 +52,7 @@ signals:
|
||||
void numBlocksChanged(int count);
|
||||
|
||||
//! Asynchronous error notification
|
||||
void error(const QString &title, const QString &message);
|
||||
void error(const QString &title, const QString &message, bool modal);
|
||||
|
||||
public slots:
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <QClipboard>
|
||||
#include <QFileDialog>
|
||||
#include <QDesktopServices>
|
||||
#include <QThread>
|
||||
|
||||
QString GUIUtil::dateTimeStr(qint64 nTime)
|
||||
{
|
||||
@@ -184,3 +185,14 @@ QString GUIUtil::getSaveFileName(QWidget *parent, const QString &caption,
|
||||
return result;
|
||||
}
|
||||
|
||||
Qt::ConnectionType GUIUtil::blockingGUIThreadConnection()
|
||||
{
|
||||
if(QThread::currentThread() != QCoreApplication::instance()->thread())
|
||||
{
|
||||
return Qt::BlockingQueuedConnection;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Qt::DirectConnection;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,14 @@ public:
|
||||
const QString &dir=QString(), const QString &filter=QString(),
|
||||
QString *selectedSuffixOut=0);
|
||||
|
||||
|
||||
/** Get connection type to call object slot in GUI thread with invokeMethod. The call will be blocking.
|
||||
|
||||
@returns If called from the GUI thread, return a Qt::DirectConnection.
|
||||
If called from another thread, return a Qt::BlockingQueuedConnection.
|
||||
*/
|
||||
static Qt::ConnectionType blockingGUIThreadConnection();
|
||||
|
||||
};
|
||||
|
||||
#endif // GUIUTIL_H
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "bitcoinunits.h"
|
||||
|
||||
#include "headers.h"
|
||||
#include "qtui.h"
|
||||
#include "ui_interface.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "headers.h"
|
||||
#include "db.h" // for BackupWallet
|
||||
|
||||
#include <QTimer>
|
||||
#include <QSet>
|
||||
|
||||
WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
|
||||
@@ -16,12 +15,6 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p
|
||||
cachedBalance(0), cachedUnconfirmedBalance(0), cachedNumTransactions(0),
|
||||
cachedEncryptionStatus(Unencrypted)
|
||||
{
|
||||
// Until signal notifications is built into the bitcoin core,
|
||||
// simply update everything after polling using a timer.
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
|
||||
timer->start(MODEL_UPDATE_DELAY);
|
||||
|
||||
addressTableModel = new AddressTableModel(wallet, this);
|
||||
transactionTableModel = new TransactionTableModel(wallet, this);
|
||||
}
|
||||
@@ -69,6 +62,11 @@ void WalletModel::update()
|
||||
addressTableModel->update();
|
||||
}
|
||||
|
||||
void WalletModel::updateAddressList()
|
||||
{
|
||||
addressTableModel->update();
|
||||
}
|
||||
|
||||
bool WalletModel::validateAddress(const QString &address)
|
||||
{
|
||||
CBitcoinAddress addressParsed(address.toStdString());
|
||||
@@ -142,7 +140,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
|
||||
}
|
||||
return TransactionCreationFailed;
|
||||
}
|
||||
if(!ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString(), NULL))
|
||||
if(!ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
|
||||
{
|
||||
return Aborted;
|
||||
}
|
||||
@@ -164,9 +162,6 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
|
||||
}
|
||||
}
|
||||
|
||||
// Update our model of the address table
|
||||
addressTableModel->updateList();
|
||||
|
||||
return SendCoinsReturn(OK, 0, hex);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "util.h"
|
||||
#include "allocators.h" /* for SecureString */
|
||||
|
||||
class OptionsModel;
|
||||
class AddressTableModel;
|
||||
@@ -135,12 +135,11 @@ signals:
|
||||
void requireUnlock();
|
||||
|
||||
// Asynchronous error notification
|
||||
void error(const QString &title, const QString &message);
|
||||
void error(const QString &title, const QString &message, bool modal);
|
||||
|
||||
public slots:
|
||||
|
||||
private slots:
|
||||
void update();
|
||||
void updateAddressList();
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user