From 8f1631b797f35b377764eaa94b8cdc6489dc292e Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 30 Sep 2011 17:36:39 +0200 Subject: [PATCH 1/7] make USE_SSL actually work (thanks @prusnak for noticing) --- bitcoin-qt.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 2d9cdc7e..8c494dd9 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -32,7 +32,7 @@ contains(USE_DBUS, 1) { } # use: qmake "USE_SSL=1" -contains(USE_DBUS, 1) { +contains(USE_SSL, 1) { message(Building with SSL support for RPC) DEFINES += USE_SSL } From 608dacf6895223159bff6a342fdbe581187c8b4b Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 1 Oct 2011 13:23:00 +0200 Subject: [PATCH 2/7] only install translator when not empty --- src/qt/bitcoin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 60a90742..91881c34 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -121,7 +121,8 @@ int main(int argc, char *argv[]) QString locale = QLocale::system().name(); QTranslator translator; translator.load(":/translations/"+locale); - app.installTranslator(&translator); + if (!translator.isEmpty()) + app.installTranslator(&translator); QSplashScreen splash(QPixmap(":/images/splash"), 0); splash.show(); From 5d3083c3fbd3ab4999bb01e4987920d91e78fb7c Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 29 Sep 2011 15:02:12 -0400 Subject: [PATCH 3/7] Bugfix: Restore old behaviour of USE_UPNP as close as possible (built & enabled by default, can be disabled or unsupported by option) --- bitcoin-qt.pro | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 8c494dd9..a6035497 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -16,10 +16,17 @@ OBJECTS_DIR = build MOC_DIR = build UI_DIR = build -# use: qmake "USE_UPNP=0" (disable by default) or "USE_UPNP=1" (enable by default) -# miniupnpc (http://miniupnp.free.fr/files/) must be installed -count(USE_UPNP, 1) { +# use: qmake "USE_UPNP=1" ( enabled by default; default) +# or: qmake "USE_UPNP=0" (disabled by default) +# or: qmake "USE_UPNP=-" (not supported) +# miniupnpc (http://miniupnp.free.fr/files/) must be installed for support +contains(USE_UPNP, -) { + message(Building without UPNP support) +} else { message(Building with UPNP support) + count(USE_UPNP, 0) { + USE_UPNP=1 + } DEFINES += USE_UPNP=$$USE_UPNP LIBS += -lminiupnpc } From ba2db7262bec34d45c75c6842c3a1c0cfaba893e Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sun, 2 Oct 2011 10:47:23 +0300 Subject: [PATCH 4/7] Edited doc/readme-qt.rst via GitHub --- doc/readme-qt.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/readme-qt.rst b/doc/readme-qt.rst index b12aa309..b7f0d2c1 100644 --- a/doc/readme-qt.rst +++ b/doc/readme-qt.rst @@ -119,13 +119,13 @@ http://miniupnp.tuxfamily.org/files/. UPnP support is not compiled in by defaul Set USE_UPNP to a different value to control this: -+------------+--------------------------------------------------------------+ -| USE_UPNP= | (the default) no UPnP support, miniupnpc not required; | -+------------+--------------------------------------------------------------+ -| USE_UPNP=0 | UPnP support turned off by default at runtime; | -+------------+--------------------------------------------------------------+ -| USE_UPNP=1 | UPnP support turned on by default at runtime. | -+------------+--------------------------------------------------------------+ ++------------+--------------------------------------------------------------------------+ +| USE_UPNP=- | no UPnP support, miniupnpc not required; | ++------------+--------------------------------------------------------------------------+ +| USE_UPNP=0 | (the default) built with UPnP, support turned off by default at runtime; | ++------------+--------------------------------------------------------------------------+ +| USE_UPNP=1 | build with UPnP support turned on by default at runtime. | ++------------+--------------------------------------------------------------------------+ Mac OS X users: miniupnpc is currently outdated on MacPorts. An updated Portfile is provided in contrib/miniupnpc within this project. You can execute the following commands in a terminal to install it: From d934e7e3ddd7d919e58f76705439cdb15c745951 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sun, 9 Oct 2011 21:06:28 +0200 Subject: [PATCH 5/7] Make "Quit" menu saner - Use 'x' for Exit shortcut - Set Ctrl-Q as global quit key sequence --- src/qt/bitcoingui.cpp | 6 ++---- src/qt/locale/bitcoin_de.ts | 2 +- src/qt/locale/bitcoin_nl.ts | 2 +- src/qt/locale/bitcoin_ru.ts | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index be10b97c..25261c78 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -65,9 +65,6 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): // Menus QMenu *file = menuBar()->addMenu(tr("&File")); - file->addAction(sendCoinsAction); - file->addAction(receiveCoinsAction); - file->addSeparator(); file->addAction(quitAction); QMenu *settings = menuBar()->addMenu(tr("&Settings")); @@ -197,8 +194,9 @@ void BitcoinGUI::createActions() connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); - quitAction = new QAction(QIcon(":/icons/quit"), tr("&Exit"), this); + quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this); quitAction->setToolTip(tr("Quit application")); + quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About"), this); aboutAction->setToolTip(tr("Show information about Bitcoin")); optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this); diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index ba2e25d6..c674eb43 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -351,7 +351,7 @@ Are you sure you wish to encrypt your wallet? - &Exit + E&xit Beenden diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index 9940e90e..a7ea7e66 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -372,7 +372,7 @@ Are you sure you wish to encrypt your wallet? - &Exit + E&xit A&fsluiten diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts index ea32d956..b6127959 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -343,7 +343,7 @@ Are you sure you wish to encrypt your wallet? - &Exit + E&xit Вы&ход From 527137e3ee542da5ecd4d04364fac0eb0067a2a4 Mon Sep 17 00:00:00 2001 From: p2k Date: Fri, 7 Oct 2011 13:21:45 +0200 Subject: [PATCH 6/7] Improved Mac experience; QDoubleSpinBox for BitcoinAmountField Now it can't be told if this is was a Windows App before. All Mac design principles are fulfilled and some cosmetics have been applied to suit the native look and feel. The biggest change there is the proper use of the Dock icon which takes the role of the Tray icon on Mac. The QDoubleSpinBox improves entering of Bitcoin amounts, no two separate fields are required anymore. All functionality and validation effects have been retained; pressing the comma key will be internally translated to a period to keep it consistent throughout the application and eases entering in countries which use the comma as decimal separator. Additionally, Notificator now supports Growl, Mac's native notification system. This is provided via Apple Script in order to avoid linking to Growl on compile time. Other changes involve encapsulation of Toolbar and Menubar creation, loading of Qt's own translation and some clean up. --- bitcoin-qt.pro | 3 + src/qt/addressbookpage.cpp | 7 ++ src/qt/bitcoin.cpp | 7 ++ src/qt/bitcoinamountfield.cpp | 91 ++++++++++----------- src/qt/bitcoinamountfield.h | 9 +-- src/qt/bitcoingui.cpp | 136 ++++++++++++++++++++++++-------- src/qt/bitcoingui.h | 7 ++ src/qt/forms/sendcoinsdialog.ui | 3 - src/qt/forms/sendcoinsentry.ui | 17 +--- src/qt/macdockiconhandler.h | 37 +++++++++ src/qt/macdockiconhandler.mm | 99 +++++++++++++++++++++++ src/qt/notificator.cpp | 73 +++++++++++++++++ src/qt/notificator.h | 4 + src/qt/optionsdialog.cpp | 12 +++ src/qt/overviewpage.cpp | 1 + src/qt/sendcoinsdialog.cpp | 6 ++ src/qt/sendcoinsentry.cpp | 4 + src/qt/transactionview.cpp | 31 ++++++-- 18 files changed, 435 insertions(+), 112 deletions(-) create mode 100644 src/qt/macdockiconhandler.h create mode 100644 src/qt/macdockiconhandler.mm diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 1f65d057..5b9d748e 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -221,6 +221,9 @@ windows:LIBS += -lws2_32 -lgdi32 windows:DEFINES += WIN32 windows:RC_FILE = src/qt/res/bitcoin-qt.rc +macx:HEADERS += src/qt/macdockiconhandler.h +macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm +macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit macx:DEFINES += MAC_OSX MSG_NOSIGNAL=0 BOOST_FILESYSTEM_VERSION=3 macx:ICON = src/qt/res/icons/bitcoin.icns macx:TARGET = "Bitcoin Qt" diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index ee64cc2c..6be59a08 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -18,6 +18,13 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : tab(tab) { ui->setupUi(this); + +#ifdef Q_WS_MAC // Icons on push buttons are very uncommon on Mac + ui->newAddressButton->setIcon(QIcon()); + ui->copyToClipboard->setIcon(QIcon()); + ui->deleteButton->setIcon(QIcon()); +#endif + switch(mode) { case ForSending: diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 91881c34..c8e33241 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -16,6 +16,7 @@ #include #include #include +#include // Need a global reference for the notifications to find the GUI BitcoinGUI *guiref; @@ -119,11 +120,17 @@ int main(int argc, char *argv[]) // Load language file for system locale QString locale = QLocale::system().name(); + QTranslator qtTranslator; + qtTranslator.load(QLibraryInfo::location(QLibraryInfo::TranslationsPath) + "/qt_" + locale); + if (!qtTranslator.isEmpty()) + app.installTranslator(&qtTranslator); QTranslator translator; translator.load(":/translations/"+locale); if (!translator.isEmpty()) app.installTranslator(&translator); + app.setApplicationName(QApplication::translate("main", "Bitcoin Qt")); + QSplashScreen splash(QPixmap(":/images/splash"), 0); splash.show(); splash.setAutoFillBackground(true); diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index f1edc62b..19cd5655 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -1,33 +1,30 @@ #include "bitcoinamountfield.h" -#include "qvalidatedlineedit.h" #include "qvaluecombobox.h" #include "bitcoinunits.h" +#include "guiconstants.h" + #include #include #include #include #include +#include #include +#include +#include BitcoinAmountField::BitcoinAmountField(QWidget *parent): - QWidget(parent), amount(0), decimals(0), currentUnit(-1) + QWidget(parent), amount(0), currentUnit(-1) { - amount = new QValidatedLineEdit(this); - amount->setValidator(new QRegExpValidator(QRegExp("[0-9]*"), this)); - amount->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + amount = new QDoubleSpinBox(this); + amount->setLocale(QLocale::c()); + amount->setDecimals(8); amount->installEventFilter(this); - amount->setMaximumWidth(75); - decimals = new QValidatedLineEdit(this); - decimals->setValidator(new QRegExpValidator(QRegExp("[0-9]+"), this)); - decimals->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); - decimals->setMaximumWidth(75); + amount->setMaximumWidth(170); QHBoxLayout *layout = new QHBoxLayout(this); - layout->setSpacing(0); layout->addWidget(amount); - layout->addWidget(new QLabel(QString("."))); - layout->addWidget(decimals); unit = new QValueComboBox(this); unit->setModel(new BitcoinUnits(this)); layout->addWidget(unit); @@ -40,8 +37,7 @@ BitcoinAmountField::BitcoinAmountField(QWidget *parent): setFocusProxy(amount); // If one if the widgets changes, the combined content changes as well - connect(amount, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged())); - connect(decimals, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged())); + connect(amount, SIGNAL(valueChanged(QString)), this, SIGNAL(textChanged())); connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int))); // Set default based on configuration @@ -50,79 +46,72 @@ BitcoinAmountField::BitcoinAmountField(QWidget *parent): void BitcoinAmountField::setText(const QString &text) { - const QStringList parts = text.split(QString(".")); - if(parts.size() == 2) - { - amount->setText(parts[0]); - decimals->setText(parts[1]); - } + if (text.isEmpty()) + amount->clear(); else - { - amount->setText(QString()); - decimals->setText(QString()); - } + amount->setValue(text.toDouble()); } void BitcoinAmountField::clear() { amount->clear(); - decimals->clear(); unit->setCurrentIndex(0); } bool BitcoinAmountField::validate() { bool valid = true; - if(decimals->text().isEmpty()) - { - decimals->setValid(false); + if (amount->value() == 0.0) valid = false; - } - if(!BitcoinUnits::parse(currentUnit, text(), 0)) - { - setValid(false); + if (valid && !BitcoinUnits::parse(currentUnit, text(), 0)) valid = false; - } + + setValid(valid); return valid; } void BitcoinAmountField::setValid(bool valid) { - amount->setValid(valid); - decimals->setValid(valid); + if (valid) + amount->setStyleSheet(""); + else + amount->setStyleSheet(STYLE_INVALID); } QString BitcoinAmountField::text() const { - if(decimals->text().isEmpty() && amount->text().isEmpty()) - { + if (amount->text().isEmpty()) return QString(); - } - return amount->text() + QString(".") + decimals->text(); + else + return amount->text(); } -// Intercept '.' and ',' keys, if pressed focus a specified widget bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event) { - Q_UNUSED(object); - if(event->type() == QEvent::KeyPress) + if (event->type() == QEvent::FocusIn) + { + // Clear invalid flag on focus + setValid(true); + } + else if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { QKeyEvent *keyEvent = static_cast(event); - if(keyEvent->key() == Qt::Key_Period || keyEvent->key() == Qt::Key_Comma) + if (keyEvent->key() == Qt::Key_Comma) { - decimals->setFocus(); - decimals->selectAll(); + // Translate a comma into a period + QKeyEvent periodKeyEvent(event->type(), Qt::Key_Period, keyEvent->modifiers(), ".", keyEvent->isAutoRepeat(), keyEvent->count()); + qApp->sendEvent(object, &periodKeyEvent); + return true; } } - return false; + return QWidget::eventFilter(object, event); } QWidget *BitcoinAmountField::setupTabChain(QWidget *prev) { QWidget::setTabOrder(prev, amount); - QWidget::setTabOrder(amount, decimals); - return decimals; + return amount; } qint64 BitcoinAmountField::value(bool *valid_out) const @@ -156,8 +145,8 @@ void BitcoinAmountField::unitChanged(int idx) currentUnit = newUnit; // Set max length after retrieving the value, to prevent truncation - amount->setMaxLength(BitcoinUnits::amountDigits(currentUnit)); - decimals->setMaxLength(BitcoinUnits::decimals(currentUnit)); + amount->setDecimals(BitcoinUnits::decimals(currentUnit)); + amount->setMaximum(qPow(10, BitcoinUnits::amountDigits(currentUnit)) - qPow(10, -amount->decimals())); if(valid) { diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index cc92159f..8457a418 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -4,7 +4,7 @@ #include QT_BEGIN_NAMESPACE -class QValidatedLineEdit; +class QDoubleSpinBox; class QValueComboBox; QT_END_NAMESPACE @@ -13,7 +13,7 @@ QT_END_NAMESPACE class BitcoinAmountField: public QWidget { Q_OBJECT - Q_PROPERTY(qint64 value READ value WRITE setValue NOTIFY textChanged USER true); + Q_PROPERTY(qint64 value READ value WRITE setValue NOTIFY textChanged USER true) public: explicit BitcoinAmountField(QWidget *parent = 0); @@ -38,12 +38,11 @@ signals: void textChanged(); protected: - // Intercept '.' and ',' keys, if pressed focus a specified widget + // Intercept focus-in event and ',' keypresses bool eventFilter(QObject *object, QEvent *event); private: - QValidatedLineEdit *amount; - QValidatedLineEdit *decimals; + QDoubleSpinBox *amount; QValueComboBox *unit; int currentUnit; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 25261c78..beffa85c 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -22,6 +22,10 @@ #include "askpassphrasedialog.h" #include "notificator.h" +#ifdef Q_WS_MAC +#include "macdockiconhandler.h" +#endif + #include #include #include @@ -57,37 +61,26 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): { resize(850, 550); setWindowTitle(tr("Bitcoin Wallet")); +#ifndef Q_WS_MAC setWindowIcon(QIcon(":icons/bitcoin")); +#else + setUnifiedTitleAndToolBarOnMac(true); + QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); +#endif // Accept D&D of URIs setAcceptDrops(true); + // Create actions for the toolbar, menu bar and tray/dock icon createActions(); - // Menus - QMenu *file = menuBar()->addMenu(tr("&File")); - file->addAction(quitAction); - - QMenu *settings = menuBar()->addMenu(tr("&Settings")); - settings->addAction(encryptWalletAction); - settings->addAction(changePassphraseAction); - settings->addSeparator(); - settings->addAction(optionsAction); + // Create application menu bar + createMenuBar(); - QMenu *help = menuBar()->addMenu(tr("&Help")); - help->addAction(aboutAction); - - // Toolbars - QToolBar *toolbar = addToolBar(tr("Tabs toolbar")); - toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - toolbar->addAction(overviewAction); - toolbar->addAction(sendCoinsAction); - toolbar->addAction(receiveCoinsAction); - toolbar->addAction(historyAction); - toolbar->addAction(addressBookAction); + // Create the toolbars + createToolBars(); - QToolBar *toolbar2 = addToolBar(tr("Actions toolbar")); - toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - toolbar2->addAction(exportAction); + // Create the tray icon (or setup the dock icon) + createTrayIcon(); // Create tabs overviewPage = new OverviewPage(); @@ -146,8 +139,6 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): statusBar()->addWidget(progressBar); statusBar()->addPermanentWidget(frameBlocks); - createTrayIcon(); - syncIconMovie = new QMovie(":/movies/update_spinner", "mng", this); // Clicking on a transaction on the overview page simply sends you to transaction history page @@ -159,6 +150,13 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): gotoOverviewPage(); } +BitcoinGUI::~BitcoinGUI() +{ +#ifdef Q_WS_MAC + delete appMenuBar; +#endif +} + void BitcoinGUI::createActions() { QActionGroup *tabGroup = new QActionGroup(this); @@ -197,10 +195,13 @@ void BitcoinGUI::createActions() quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this); quitAction->setToolTip(tr("Quit application")); quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); - aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About"), this); + quitAction->setMenuRole(QAction::QuitRole); + aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About %1").arg(qApp->applicationName()), this); aboutAction->setToolTip(tr("Show information about Bitcoin")); + aboutAction->setMenuRole(QAction::AboutQtRole); optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this); optionsAction->setToolTip(tr("Modify configuration options for bitcoin")); + optionsAction->setMenuRole(QAction::PreferencesRole); openBitcoinAction = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this); openBitcoinAction->setToolTip(tr("Show the Bitcoin window")); exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this); @@ -219,6 +220,45 @@ void BitcoinGUI::createActions() connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase())); } +void BitcoinGUI::createMenuBar() +{ +#ifdef Q_WS_MAC + // Create a decoupled menu bar on Mac which stays even if the window is closed + appMenuBar = new QMenuBar(); +#else + // Get the main window's menu bar on other platforms + appMenuBar = menuBar(); +#endif + + // Configure the menus + QMenu *file = appMenuBar->addMenu(tr("&File")); + file->addAction(quitAction); + + QMenu *settings = appMenuBar->addMenu(tr("&Settings")); + settings->addAction(encryptWalletAction); + settings->addAction(changePassphraseAction); + settings->addSeparator(); + settings->addAction(optionsAction); + + QMenu *help = appMenuBar->addMenu(tr("&Help")); + help->addAction(aboutAction); +} + +void BitcoinGUI::createToolBars() +{ + QToolBar *toolbar = addToolBar(tr("Tabs toolbar")); + toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + toolbar->addAction(overviewAction); + toolbar->addAction(sendCoinsAction); + toolbar->addAction(receiveCoinsAction); + toolbar->addAction(historyAction); + toolbar->addAction(addressBookAction); + + QToolBar *toolbar2 = addToolBar(tr("Actions toolbar")); + toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + toolbar2->addAction(exportAction); +} + void BitcoinGUI::setClientModel(ClientModel *clientModel) { this->clientModel = clientModel; @@ -227,7 +267,11 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) { QString title_testnet = windowTitle() + QString(" ") + tr("[testnet]"); setWindowTitle(title_testnet); +#ifndef Q_WS_MAC setWindowIcon(QIcon(":icons/bitcoin_testnet")); +#else + MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); +#endif if(trayIcon) { trayIcon->setToolTip(title_testnet); @@ -274,23 +318,39 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel) void BitcoinGUI::createTrayIcon() { - QMenu *trayIconMenu = new QMenu(this); - trayIconMenu->addAction(openBitcoinAction); - trayIconMenu->addAction(optionsAction); - trayIconMenu->addSeparator(); - trayIconMenu->addAction(quitAction); - + QMenu *trayIconMenu; +#ifndef Q_WS_MAC trayIcon = new QSystemTrayIcon(this); + trayIconMenu = new QMenu(this); trayIcon->setContextMenu(trayIconMenu); trayIcon->setToolTip("Bitcoin client"); trayIcon->setIcon(QIcon(":/icons/toolbar")); connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); trayIcon->show(); +#else + // Note: On Mac, the dock icon is used to provide the tray's functionality. + MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); + connect(dockIconHandler, SIGNAL(dockIconClicked()), openBitcoinAction, SLOT(trigger())); + trayIconMenu = dockIconHandler->dockMenu(); +#endif + + // Configuration of the tray icon (or dock icon) icon menu + trayIconMenu->addAction(openBitcoinAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(receiveCoinsAction); + trayIconMenu->addAction(sendCoinsAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(optionsAction); +#ifndef Q_WS_MAC // This is built-in on Mac + trayIconMenu->addSeparator(); + trayIconMenu->addAction(quitAction); +#endif notificator = new Notificator(tr("bitcoin-qt"), trayIcon); } +#ifndef Q_WS_MAC void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) { if(reason == QSystemTrayIcon::Trigger) @@ -300,6 +360,7 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) } } +#endif void BitcoinGUI::optionsClicked() { @@ -403,9 +464,10 @@ void BitcoinGUI::error(const QString &title, const QString &message) void BitcoinGUI::changeEvent(QEvent *e) { +#ifndef Q_WS_MAC // Ignored on Mac if (e->type() == QEvent::WindowStateChange) { - if(clientModel->getOptionsModel()->getMinimizeToTray()) + if (clientModel->getOptionsModel()->getMinimizeToTray()) { if (isMinimized()) { @@ -419,16 +481,19 @@ void BitcoinGUI::changeEvent(QEvent *e) } } } +#endif QMainWindow::changeEvent(e); } void BitcoinGUI::closeEvent(QCloseEvent *event) { +#ifndef Q_WS_MAC // Ignored on Mac if(!clientModel->getOptionsModel()->getMinimizeToTray() && !clientModel->getOptionsModel()->getMinimizeOnClose()) { qApp->quit(); } +#endif QMainWindow::closeEvent(event); } @@ -480,6 +545,7 @@ void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int void BitcoinGUI::gotoOverviewPage() { + show(); overviewAction->setChecked(true); centralWidget->setCurrentWidget(overviewPage); @@ -489,6 +555,7 @@ void BitcoinGUI::gotoOverviewPage() void BitcoinGUI::gotoHistoryPage() { + show(); historyAction->setChecked(true); centralWidget->setCurrentWidget(transactionsPage); @@ -499,6 +566,7 @@ void BitcoinGUI::gotoHistoryPage() void BitcoinGUI::gotoAddressBookPage() { + show(); addressBookAction->setChecked(true); centralWidget->setCurrentWidget(addressBookPage); @@ -509,6 +577,7 @@ void BitcoinGUI::gotoAddressBookPage() void BitcoinGUI::gotoReceiveCoinsPage() { + show(); receiveCoinsAction->setChecked(true); centralWidget->setCurrentWidget(receiveCoinsPage); @@ -519,6 +588,7 @@ void BitcoinGUI::gotoReceiveCoinsPage() void BitcoinGUI::gotoSendCoinsPage() { + show(); sendCoinsAction->setChecked(true); centralWidget->setCurrentWidget(sendCoinsPage); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 59661350..a9121921 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -29,6 +29,8 @@ class BitcoinGUI : public QMainWindow Q_OBJECT public: explicit BitcoinGUI(QWidget *parent = 0); + ~BitcoinGUI(); + void setClientModel(ClientModel *clientModel); void setWalletModel(WalletModel *walletModel); @@ -64,6 +66,7 @@ private: QLabel *progressBarLabel; QProgressBar *progressBar; + QMenuBar *appMenuBar; QAction *overviewAction; QAction *historyAction; QAction *quitAction; @@ -84,6 +87,8 @@ private: QMovie *syncIconMovie; void createActions(); + void createMenuBar(); + void createToolBars(); QWidget *createTabs(); void createTrayIcon(); @@ -110,7 +115,9 @@ private slots: // Misc actions void optionsClicked(); void aboutClicked(); +#ifndef Q_WS_MAC void trayIconActivated(QSystemTrayIcon::ActivationReason reason); +#endif void incomingTransaction(const QModelIndex & parent, int start, int end); void encryptWallet(bool status); void changePassphrase(); diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index f9dd02fe..e5e19e10 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -58,9 +58,6 @@ - - 6 - diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui index 13593c2c..0297d17f 100644 --- a/src/qt/forms/sendcoinsentry.ui +++ b/src/qt/forms/sendcoinsentry.ui @@ -83,7 +83,7 @@ - + 0 @@ -98,7 +98,7 @@ - + Choose adress from address book @@ -112,16 +112,10 @@ Alt+A - - false - - - false - - + Paste address from clipboard @@ -135,13 +129,10 @@ Alt+P - - false - - + Remove this recipient diff --git a/src/qt/macdockiconhandler.h b/src/qt/macdockiconhandler.h new file mode 100644 index 00000000..cc78c7a7 --- /dev/null +++ b/src/qt/macdockiconhandler.h @@ -0,0 +1,37 @@ +#ifndef MACDOCKICONHANDLER_H +#define MACDOCKICONHANDLER_H + +#include + +class QMenu; +class QIcon; +class QWidget; +class objc_object; + +class MacDockIconHandler : public QObject +{ + Q_OBJECT +public: + ~MacDockIconHandler(); + + QMenu *dockMenu(); + void setIcon(const QIcon &icon); + + static MacDockIconHandler *instance(); + + void handleDockIconClickEvent(); + +signals: + void dockIconClicked(); + +public slots: + +private: + MacDockIconHandler(); + + objc_object *m_dockIconClickEventHandler; + QWidget *m_dummyWidget; + QMenu *m_dockMenu; +}; + +#endif // MACDOCKICONCLICKHANDLER_H diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm new file mode 100644 index 00000000..df56e694 --- /dev/null +++ b/src/qt/macdockiconhandler.mm @@ -0,0 +1,99 @@ + +#include "macdockiconhandler.h" + +#include +#include + +extern void qt_mac_set_dock_menu(QMenu*); + +#undef slots +#include + +@interface DockIconClickEventHandler : NSObject +{ + MacDockIconHandler* dockIconHandler; +} + +@end + +@implementation DockIconClickEventHandler + +- (id)initWithDockIconHandler:(MacDockIconHandler *)aDockIconHandler +{ + self = [super init]; + if (self) { + dockIconHandler = aDockIconHandler; + + [[NSAppleEventManager sharedAppleEventManager] + setEventHandler:self + andSelector:@selector(handleDockClickEvent:withReplyEvent:) + forEventClass:kCoreEventClass + andEventID:kAEReopenApplication]; + } + return self; +} + +- (void)handleDockClickEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent +{ + Q_UNUSED(event) + Q_UNUSED(replyEvent) + + if (dockIconHandler) + dockIconHandler->handleDockIconClickEvent(); +} + +@end + +MacDockIconHandler::MacDockIconHandler() : QObject() +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this]; + + this->m_dummyWidget = new QWidget(); + this->m_dockMenu = new QMenu(this->m_dummyWidget); + qt_mac_set_dock_menu(this->m_dockMenu); + [pool release]; +} + +MacDockIconHandler::~MacDockIconHandler() +{ + [this->m_dockIconClickEventHandler release]; + delete this->m_dummyWidget; +} + +QMenu *MacDockIconHandler::dockMenu() +{ + return this->m_dockMenu; +} + +void MacDockIconHandler::setIcon(const QIcon &icon) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSImage *image; + if (icon.isNull()) + image = [[NSImage imageNamed:@"NSApplicationIcon"] retain]; + else { + QSize size = icon.actualSize(QSize(128, 128)); + QPixmap pixmap = icon.pixmap(size); + CGImageRef cgImage = pixmap.toMacCGImageRef(); + image = [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize]; + CFRelease(cgImage); + } + + [NSApp setApplicationIconImage:image]; + [image release]; + [pool release]; +} + +MacDockIconHandler *MacDockIconHandler::instance() +{ + static MacDockIconHandler *s_instance = NULL; + if (!s_instance) + s_instance = new MacDockIconHandler(); + return s_instance; +} + +void MacDockIconHandler::handleDockIconClickEvent() +{ + emit this->dockIconClicked(); +} diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index cf0c0a39..a2314caa 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -8,12 +8,19 @@ #include #include #include +#include +#include #ifdef USE_DBUS #include #include #endif +#ifdef Q_WS_MAC +#include +extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret); +#endif + // https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128 const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128; @@ -39,6 +46,19 @@ Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, mode = Freedesktop; } #endif +#ifdef Q_WS_MAC + // Check if Growl is installed (based on Qt's tray icon implementation) + CFURLRef cfurl; + OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl); + if (status != kLSApplicationNotFoundErr) { + CFBundleRef bundle = CFBundleCreate(0, cfurl); + CFRelease(cfurl); + if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) { + mode = Growl; + } + CFRelease(bundle); + } +#endif } Notificator::~Notificator() @@ -201,6 +221,54 @@ void Notificator::notifySystray(Class cls, const QString &title, const QString & trayIcon->showMessage(title, text, sicon, millisTimeout); } +// Based on Qt's tray icon implementation +#ifdef Q_WS_MAC +void Notificator::notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon) +{ + const QString script( + "tell application \"GrowlHelperApp\"\n" + " set the allNotificationsList to {\"Notification\"}\n" // -- Make a list of all the notification types (all) + " set the enabledNotificationsList to {\"Notification\"}\n" // -- Make a list of the notifications (enabled) + " register as application \"%1\" all notifications allNotificationsList default notifications enabledNotificationsList\n" // -- Register our script with Growl + " notify with name \"Notification\" title \"%2\" description \"%3\" application name \"%1\"%4\n" // -- Send a Notification + "end tell" + ); + + QString notificationApp(QApplication::applicationName()); + if (notificationApp.isEmpty()) + notificationApp = "Application"; + + QPixmap notificationIconPixmap; + if (icon.isNull()) { // If no icon specified, set icon based on class + QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion; + switch (cls) + { + case Information: sicon = QStyle::SP_MessageBoxInformation; break; + case Warning: sicon = QStyle::SP_MessageBoxWarning; break; + case Critical: sicon = QStyle::SP_MessageBoxCritical; break; + } + notificationIconPixmap = QApplication::style()->standardPixmap(sicon); + } + else { + QSize size = icon.actualSize(QSize(48, 48)); + notificationIconPixmap = icon.pixmap(size); + } + + QString notificationIcon; + QTemporaryFile notificationIconFile; + if (!notificationIconPixmap.isNull() && notificationIconFile.open()) { + QImageWriter writer(¬ificationIconFile, "PNG"); + if (writer.write(notificationIconPixmap.toImage())) + notificationIcon = QString(" image from location \"file://%1\"").arg(notificationIconFile.fileName()); + } + + QString quotedTitle(title), quotedText(text); + quotedTitle.replace("\\", "\\\\").replace("\"", "\\"); + quotedText.replace("\\", "\\\\").replace("\"", "\\"); + qt_mac_execute_apple_script(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon), 0); +} +#endif + void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) { switch(mode) @@ -213,6 +281,11 @@ void Notificator::notify(Class cls, const QString &title, const QString &text, c case QSystemTray: notifySystray(cls, title, text, icon, millisTimeout); break; +#ifdef Q_WS_MAC + case Growl: + notifyGrowl(cls, title, text, icon); + break; +#endif default: if(cls == Critical) { diff --git a/src/qt/notificator.h b/src/qt/notificator.h index 4217f7e0..ed69ae5c 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -48,6 +48,7 @@ private: None, Freedesktop, // Use DBus org.freedesktop.Notifications QSystemTray, // Use QSystemTray::showMessage + Growl // Use the Growl notification system (Mac only) }; QString programName; Mode mode; @@ -58,6 +59,9 @@ private: void notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); #endif void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); +#ifdef Q_WS_MAC + void notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon); +#endif }; #endif // NOTIFICATOR_H diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 7267e3d1..ea3164e3 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -30,9 +30,13 @@ public: void setMapper(MonitoredDataMapper *mapper); private: QCheckBox *bitcoin_at_startup; +#ifndef Q_WS_MAC QCheckBox *minimize_to_tray; +#endif QCheckBox *map_port_upnp; +#ifndef Q_WS_MAC QCheckBox *minimize_on_close; +#endif QCheckBox *connect_socks4; QLineEdit *proxy_ip; QLineEdit *proxy_port; @@ -167,17 +171,21 @@ MainOptionsPage::MainOptionsPage(QWidget *parent): bitcoin_at_startup->setToolTip(tr("Automatically start Bitcoin after the computer is turned on")); layout->addWidget(bitcoin_at_startup); +#ifndef Q_WS_MAC minimize_to_tray = new QCheckBox(tr("&Minimize to the tray instead of the taskbar")); minimize_to_tray->setToolTip(tr("Show only a tray icon after minimizing the window")); layout->addWidget(minimize_to_tray); +#endif map_port_upnp = new QCheckBox(tr("Map port using &UPnP")); map_port_upnp->setToolTip(tr("Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.")); layout->addWidget(map_port_upnp); +#ifndef Q_WS_MAC minimize_on_close = new QCheckBox(tr("M&inimize on close")); minimize_on_close->setToolTip(tr("Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu.")); layout->addWidget(minimize_on_close); +#endif connect_socks4 = new QCheckBox(tr("&Connect through SOCKS4 proxy:")); connect_socks4->setToolTip(tr("Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor)")); @@ -239,9 +247,13 @@ void MainOptionsPage::setMapper(MonitoredDataMapper *mapper) { // Map model to widgets mapper->addMapping(bitcoin_at_startup, OptionsModel::StartAtStartup); +#ifndef Q_WS_MAC mapper->addMapping(minimize_to_tray, OptionsModel::MinimizeToTray); +#endif mapper->addMapping(map_port_upnp, OptionsModel::MapPortUPnP); +#ifndef Q_WS_MAC mapper->addMapping(minimize_on_close, OptionsModel::MinimizeOnClose); +#endif mapper->addMapping(connect_socks4, OptionsModel::ConnectSOCKS4); mapper->addMapping(proxy_ip, OptionsModel::ProxyIP); mapper->addMapping(proxy_port, OptionsModel::ProxyPort); diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index f84a79fe..6dedde02 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -116,6 +116,7 @@ OverviewPage::OverviewPage(QWidget *parent) : ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE)); ui->listTransactions->setSelectionMode(QAbstractItemView::NoSelection); ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2)); + ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false); connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SIGNAL(transactionClicked(QModelIndex))); } diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 58eb5c21..719cc518 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -19,6 +19,12 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) : { ui->setupUi(this); +#ifdef Q_WS_MAC // Icons on push buttons are very uncommon on Mac + ui->addButton->setIcon(QIcon()); + ui->clearButton->setIcon(QIcon()); + ui->sendButton->setIcon(QIcon()); +#endif + addEntry(); connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry())); diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index fccef232..1802095b 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -17,6 +17,10 @@ SendCoinsEntry::SendCoinsEntry(QWidget *parent) : { ui->setupUi(this); +#ifdef Q_WS_MAC + ui->payToLayout->setSpacing(4); +#endif + #if QT_VERSION >= 0x040700 ui->payTo->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)")); ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book")); diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index b2777b7b..92dda578 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -38,13 +38,20 @@ TransactionView::TransactionView(QWidget *parent) : QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->setContentsMargins(0,0,0,0); +#ifdef Q_WS_MAC + hlayout->setSpacing(5); + hlayout->addSpacing(26); +#else hlayout->setSpacing(0); - hlayout->addSpacing(23); +#endif dateWidget = new QComboBox(this); - dateWidget->setMaximumWidth(120); - dateWidget->setMinimumWidth(120); +#ifdef Q_WS_MAC + dateWidget->setFixedWidth(121); +#else + dateWidget->setFixedWidth(120); +#endif dateWidget->addItem(tr("All"), All); dateWidget->addItem(tr("Today"), Today); dateWidget->addItem(tr("This week"), ThisWeek); @@ -55,8 +62,11 @@ TransactionView::TransactionView(QWidget *parent) : hlayout->addWidget(dateWidget); typeWidget = new QComboBox(this); - typeWidget->setMaximumWidth(120); - typeWidget->setMinimumWidth(120); +#ifdef Q_WS_MAC + typeWidget->setFixedWidth(121); +#else + typeWidget->setFixedWidth(120); +#endif typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES); typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) | @@ -79,8 +89,11 @@ TransactionView::TransactionView(QWidget *parent) : #if QT_VERSION >= 0x040700 amountWidget->setPlaceholderText(tr("Min amount")); #endif - amountWidget->setMaximumWidth(100); - amountWidget->setMinimumWidth(100); +#ifdef Q_WS_MAC + amountWidget->setFixedWidth(97); +#else + amountWidget->setFixedWidth(100); +#endif amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this)); hlayout->addWidget(amountWidget); @@ -96,7 +109,11 @@ TransactionView::TransactionView(QWidget *parent) : vlayout->setSpacing(0); int width = view->verticalScrollBar()->sizeHint().width(); // Cover scroll bar width with spacing +#ifdef Q_WS_MAC + hlayout->addSpacing(width+2); +#else hlayout->addSpacing(width); +#endif // Always show scroll bar view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); view->setTabKeyNavigation(false); From d85f2458007ba8f7558220a99fe1dd03abd74307 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sun, 9 Oct 2011 21:40:03 +0200 Subject: [PATCH 7/7] Add alt-1..alt-5 shortcut to switch between tabs --- src/qt/bitcoingui.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index beffa85c..b9995fdd 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -164,26 +164,31 @@ void BitcoinGUI::createActions() overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this); overviewAction->setToolTip(tr("Show general overview of wallet")); overviewAction->setCheckable(true); + overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1)); tabGroup->addAction(overviewAction); historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this); historyAction->setToolTip(tr("Browse transaction history")); historyAction->setCheckable(true); + historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4)); tabGroup->addAction(historyAction); addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this); addressBookAction->setToolTip(tr("Edit the list of stored addresses and labels")); addressBookAction->setCheckable(true); + addressBookAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5)); tabGroup->addAction(addressBookAction); receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this); receiveCoinsAction->setToolTip(tr("Show the list of addresses for receiving payments")); receiveCoinsAction->setCheckable(true); + receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3)); tabGroup->addAction(receiveCoinsAction); sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this); sendCoinsAction->setToolTip(tr("Send coins to a bitcoin address")); sendCoinsAction->setCheckable(true); + sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2)); tabGroup->addAction(sendCoinsAction); connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));