You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bitcoingui.cpp 41KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  1. // Copyright (c) 2011-2015 The Bitcoin Core developers
  2. // Distributed under the MIT software license, see the accompanying
  3. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4. #if defined(HAVE_CONFIG_H)
  5. #include "config/bitcoin-config.h"
  6. #endif
  7. #include "bitcoingui.h"
  8. #include "bitcoinunits.h"
  9. #include "clientmodel.h"
  10. #include "guiconstants.h"
  11. #include "guiutil.h"
  12. #include "networkstyle.h"
  13. #include "notificator.h"
  14. #include "openuridialog.h"
  15. #include "optionsdialog.h"
  16. #include "optionsmodel.h"
  17. #include "platformstyle.h"
  18. #include "rpcconsole.h"
  19. #include "utilitydialog.h"
  20. #ifdef ENABLE_WALLET
  21. #include "walletframe.h"
  22. #include "walletmodel.h"
  23. #endif // ENABLE_WALLET
  24. #ifdef Q_OS_MAC
  25. #include "macdockiconhandler.h"
  26. #endif
  27. #include "init.h"
  28. #include "ui_interface.h"
  29. #include "util.h"
  30. #include <iostream>
  31. #include <QAction>
  32. #include <QApplication>
  33. #include <QDateTime>
  34. #include <QDesktopWidget>
  35. #include <QDragEnterEvent>
  36. #include <QListWidget>
  37. #include <QMenuBar>
  38. #include <QMessageBox>
  39. #include <QMimeData>
  40. #include <QProgressBar>
  41. #include <QProgressDialog>
  42. #include <QSettings>
  43. #include <QShortcut>
  44. #include <QStackedWidget>
  45. #include <QStatusBar>
  46. #include <QStyle>
  47. #include <QTimer>
  48. #include <QToolBar>
  49. #include <QVBoxLayout>
  50. #if QT_VERSION < 0x050000
  51. #include <QTextDocument>
  52. #include <QUrl>
  53. #else
  54. #include <QUrlQuery>
  55. #endif
  56. const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
  57. #if defined(Q_OS_MAC)
  58. "macosx"
  59. #elif defined(Q_OS_WIN)
  60. "windows"
  61. #else
  62. "other"
  63. #endif
  64. ;
  65. const QString BitcoinGUI::DEFAULT_WALLET = "~Default";
  66. BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
  67. QMainWindow(parent),
  68. clientModel(0),
  69. walletFrame(0),
  70. unitDisplayControl(0),
  71. labelWalletEncryptionIcon(0),
  72. labelWalletHDStatusIcon(0),
  73. labelConnectionsIcon(0),
  74. labelBlocksIcon(0),
  75. progressBarLabel(0),
  76. progressBar(0),
  77. progressDialog(0),
  78. appMenuBar(0),
  79. overviewAction(0),
  80. historyAction(0),
  81. quitAction(0),
  82. sendCoinsAction(0),
  83. sendCoinsMenuAction(0),
  84. usedSendingAddressesAction(0),
  85. usedReceivingAddressesAction(0),
  86. signMessageAction(0),
  87. verifyMessageAction(0),
  88. aboutAction(0),
  89. receiveCoinsAction(0),
  90. receiveCoinsMenuAction(0),
  91. optionsAction(0),
  92. toggleHideAction(0),
  93. encryptWalletAction(0),
  94. backupWalletAction(0),
  95. changePassphraseAction(0),
  96. aboutQtAction(0),
  97. openRPCConsoleAction(0),
  98. openAction(0),
  99. showHelpMessageAction(0),
  100. trayIcon(0),
  101. trayIconMenu(0),
  102. notificator(0),
  103. rpcConsole(0),
  104. helpMessageDialog(0),
  105. prevBlocks(0),
  106. spinnerFrame(0),
  107. platformStyle(platformStyle)
  108. {
  109. GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
  110. QString windowTitle = tr(PACKAGE_NAME) + " - ";
  111. #ifdef ENABLE_WALLET
  112. /* if compiled with wallet support, -disablewallet can still disable the wallet */
  113. enableWallet = !GetBoolArg("-disablewallet", false);
  114. #else
  115. enableWallet = false;
  116. #endif // ENABLE_WALLET
  117. if(enableWallet)
  118. {
  119. windowTitle += tr("Wallet");
  120. } else {
  121. windowTitle += tr("Node");
  122. }
  123. windowTitle += " " + networkStyle->getTitleAddText();
  124. #ifndef Q_OS_MAC
  125. QApplication::setWindowIcon(networkStyle->getTrayAndWindowIcon());
  126. setWindowIcon(networkStyle->getTrayAndWindowIcon());
  127. #else
  128. MacDockIconHandler::instance()->setIcon(networkStyle->getAppIcon());
  129. #endif
  130. setWindowTitle(windowTitle);
  131. #if defined(Q_OS_MAC) && QT_VERSION < 0x050000
  132. // This property is not implemented in Qt 5. Setting it has no effect.
  133. // A replacement API (QtMacUnifiedToolBar) is available in QtMacExtras.
  134. setUnifiedTitleAndToolBarOnMac(true);
  135. #endif
  136. rpcConsole = new RPCConsole(platformStyle, 0);
  137. helpMessageDialog = new HelpMessageDialog(this, false);
  138. #ifdef ENABLE_WALLET
  139. if(enableWallet)
  140. {
  141. /** Create wallet frame and make it the central widget */
  142. walletFrame = new WalletFrame(platformStyle, this);
  143. setCentralWidget(walletFrame);
  144. } else
  145. #endif // ENABLE_WALLET
  146. {
  147. /* When compiled without wallet or -disablewallet is provided,
  148. * the central widget is the rpc console.
  149. */
  150. setCentralWidget(rpcConsole);
  151. }
  152. // Accept D&D of URIs
  153. setAcceptDrops(true);
  154. // Create actions for the toolbar, menu bar and tray/dock icon
  155. // Needs walletFrame to be initialized
  156. createActions();
  157. // Create application menu bar
  158. createMenuBar();
  159. // Create the toolbars
  160. createToolBars();
  161. // Create system tray icon and notification
  162. createTrayIcon(networkStyle);
  163. // Create status bar
  164. statusBar();
  165. // Disable size grip because it looks ugly and nobody needs it
  166. statusBar()->setSizeGripEnabled(false);
  167. // Status bar notification icons
  168. QFrame *frameBlocks = new QFrame();
  169. frameBlocks->setContentsMargins(0,0,0,0);
  170. frameBlocks->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
  171. QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
  172. frameBlocksLayout->setContentsMargins(3,0,3,0);
  173. frameBlocksLayout->setSpacing(3);
  174. unitDisplayControl = new UnitDisplayStatusBarControl(platformStyle);
  175. labelWalletEncryptionIcon = new QLabel();
  176. labelWalletHDStatusIcon = new QLabel();
  177. labelConnectionsIcon = new QLabel();
  178. labelBlocksIcon = new QLabel();
  179. if(enableWallet)
  180. {
  181. frameBlocksLayout->addStretch();
  182. frameBlocksLayout->addWidget(unitDisplayControl);
  183. frameBlocksLayout->addStretch();
  184. frameBlocksLayout->addWidget(labelWalletEncryptionIcon);
  185. frameBlocksLayout->addWidget(labelWalletHDStatusIcon);
  186. }
  187. frameBlocksLayout->addStretch();
  188. frameBlocksLayout->addWidget(labelConnectionsIcon);
  189. frameBlocksLayout->addStretch();
  190. frameBlocksLayout->addWidget(labelBlocksIcon);
  191. frameBlocksLayout->addStretch();
  192. // Progress bar and label for blocks download
  193. progressBarLabel = new QLabel();
  194. progressBarLabel->setVisible(false);
  195. progressBar = new GUIUtil::ProgressBar();
  196. progressBar->setAlignment(Qt::AlignCenter);
  197. progressBar->setVisible(false);
  198. // Override style sheet for progress bar for styles that have a segmented progress bar,
  199. // as they make the text unreadable (workaround for issue #1071)
  200. // See https://qt-project.org/doc/qt-4.8/gallery.html
  201. QString curStyle = QApplication::style()->metaObject()->className();
  202. if(curStyle == "QWindowsStyle" || curStyle == "QWindowsXPStyle")
  203. {
  204. progressBar->setStyleSheet("QProgressBar { background-color: #e8e8e8; border: 1px solid grey; border-radius: 7px; padding: 1px; text-align: center; } QProgressBar::chunk { background: QLinearGradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #FF8000, stop: 1 orange); border-radius: 7px; margin: 0px; }");
  205. }
  206. statusBar()->addWidget(progressBarLabel);
  207. statusBar()->addWidget(progressBar);
  208. statusBar()->addPermanentWidget(frameBlocks);
  209. // Install event filter to be able to catch status tip events (QEvent::StatusTip)
  210. this->installEventFilter(this);
  211. // Initially wallet actions should be disabled
  212. setWalletActionsEnabled(false);
  213. // Subscribe to notifications from core
  214. subscribeToCoreSignals();
  215. }
  216. BitcoinGUI::~BitcoinGUI()
  217. {
  218. // Unsubscribe from notifications from core
  219. unsubscribeFromCoreSignals();
  220. GUIUtil::saveWindowGeometry("nWindow", this);
  221. if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
  222. trayIcon->hide();
  223. #ifdef Q_OS_MAC
  224. delete appMenuBar;
  225. MacDockIconHandler::cleanup();
  226. #endif
  227. delete rpcConsole;
  228. }
  229. void BitcoinGUI::createActions()
  230. {
  231. QActionGroup *tabGroup = new QActionGroup(this);
  232. overviewAction = new QAction(platformStyle->SingleColorIcon(":/icons/overview"), tr("&Overview"), this);
  233. overviewAction->setStatusTip(tr("Show general overview of wallet"));
  234. overviewAction->setToolTip(overviewAction->statusTip());
  235. overviewAction->setCheckable(true);
  236. overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1));
  237. tabGroup->addAction(overviewAction);
  238. sendCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/send"), tr("&Send"), this);
  239. sendCoinsAction->setStatusTip(tr("Send coins to a Bitcoin address"));
  240. sendCoinsAction->setToolTip(sendCoinsAction->statusTip());
  241. sendCoinsAction->setCheckable(true);
  242. sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
  243. tabGroup->addAction(sendCoinsAction);
  244. sendCoinsMenuAction = new QAction(platformStyle->TextColorIcon(":/icons/send"), sendCoinsAction->text(), this);
  245. sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip());
  246. sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip());
  247. receiveCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
  248. receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)"));
  249. receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
  250. receiveCoinsAction->setCheckable(true);
  251. receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
  252. tabGroup->addAction(receiveCoinsAction);
  253. receiveCoinsMenuAction = new QAction(platformStyle->TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction->text(), this);
  254. receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip());
  255. receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip());
  256. historyAction = new QAction(platformStyle->SingleColorIcon(":/icons/history"), tr("&Transactions"), this);
  257. historyAction->setStatusTip(tr("Browse transaction history"));
  258. historyAction->setToolTip(historyAction->statusTip());
  259. historyAction->setCheckable(true);
  260. historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4));
  261. tabGroup->addAction(historyAction);
  262. #ifdef ENABLE_WALLET
  263. // These showNormalIfMinimized are needed because Send Coins and Receive Coins
  264. // can be triggered from the tray menu, and need to show the GUI to be useful.
  265. connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
  266. connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
  267. connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
  268. connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
  269. connect(sendCoinsMenuAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
  270. connect(sendCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
  271. connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
  272. connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
  273. connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
  274. connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
  275. connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
  276. connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
  277. #endif // ENABLE_WALLET
  278. quitAction = new QAction(platformStyle->TextColorIcon(":/icons/quit"), tr("E&xit"), this);
  279. quitAction->setStatusTip(tr("Quit application"));
  280. quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
  281. quitAction->setMenuRole(QAction::QuitRole);
  282. aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About %1").arg(tr(PACKAGE_NAME)), this);
  283. aboutAction->setStatusTip(tr("Show information about %1").arg(tr(PACKAGE_NAME)));
  284. aboutAction->setMenuRole(QAction::AboutRole);
  285. aboutAction->setEnabled(false);
  286. aboutQtAction = new QAction(platformStyle->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
  287. aboutQtAction->setStatusTip(tr("Show information about Qt"));
  288. aboutQtAction->setMenuRole(QAction::AboutQtRole);
  289. optionsAction = new QAction(platformStyle->TextColorIcon(":/icons/options"), tr("&Options..."), this);
  290. optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(tr(PACKAGE_NAME)));
  291. optionsAction->setMenuRole(QAction::PreferencesRole);
  292. optionsAction->setEnabled(false);
  293. toggleHideAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
  294. toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
  295. encryptWalletAction = new QAction(platformStyle->TextColorIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
  296. encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
  297. encryptWalletAction->setCheckable(true);
  298. backupWalletAction = new QAction(platformStyle->TextColorIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
  299. backupWalletAction->setStatusTip(tr("Backup wallet to another location"));
  300. changePassphraseAction = new QAction(platformStyle->TextColorIcon(":/icons/key"), tr("&Change Passphrase..."), this);
  301. changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption"));
  302. signMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/edit"), tr("Sign &message..."), this);
  303. signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
  304. verifyMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/verify"), tr("&Verify message..."), this);
  305. verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
  306. openRPCConsoleAction = new QAction(platformStyle->TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this);
  307. openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
  308. // initially disable the debug window menu item
  309. openRPCConsoleAction->setEnabled(false);
  310. usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
  311. usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
  312. usedReceivingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Receiving addresses..."), this);
  313. usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels"));
  314. openAction = new QAction(platformStyle->TextColorIcon(":/icons/open"), tr("Open &URI..."), this);
  315. openAction->setStatusTip(tr("Open a bitcoin: URI or payment request"));
  316. showHelpMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/info"), tr("&Command-line options"), this);
  317. showHelpMessageAction->setMenuRole(QAction::NoRole);
  318. showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(tr(PACKAGE_NAME)));
  319. connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
  320. connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
  321. connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
  322. connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
  323. connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden()));
  324. connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked()));
  325. connect(openRPCConsoleAction, SIGNAL(triggered()), this, SLOT(showDebugWindow()));
  326. // prevents an open debug window from becoming stuck/unusable on client shutdown
  327. connect(quitAction, SIGNAL(triggered()), rpcConsole, SLOT(hide()));
  328. #ifdef ENABLE_WALLET
  329. if(walletFrame)
  330. {
  331. connect(encryptWalletAction, SIGNAL(triggered(bool)), walletFrame, SLOT(encryptWallet(bool)));
  332. connect(backupWalletAction, SIGNAL(triggered()), walletFrame, SLOT(backupWallet()));
  333. connect(changePassphraseAction, SIGNAL(triggered()), walletFrame, SLOT(changePassphrase()));
  334. connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
  335. connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab()));
  336. connect(usedSendingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedSendingAddresses()));
  337. connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses()));
  338. connect(openAction, SIGNAL(triggered()), this, SLOT(openClicked()));
  339. }
  340. #endif // ENABLE_WALLET
  341. new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C), this, SLOT(showDebugWindowActivateConsole()));
  342. new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D), this, SLOT(showDebugWindow()));
  343. }
  344. void BitcoinGUI::createMenuBar()
  345. {
  346. #ifdef Q_OS_MAC
  347. // Create a decoupled menu bar on Mac which stays even if the window is closed
  348. appMenuBar = new QMenuBar();
  349. #else
  350. // Get the main window's menu bar on other platforms
  351. appMenuBar = menuBar();
  352. #endif
  353. // Configure the menus
  354. QMenu *file = appMenuBar->addMenu(tr("&File"));
  355. if(walletFrame)
  356. {
  357. file->addAction(openAction);
  358. file->addAction(backupWalletAction);
  359. file->addAction(signMessageAction);
  360. file->addAction(verifyMessageAction);
  361. file->addSeparator();
  362. file->addAction(usedSendingAddressesAction);
  363. file->addAction(usedReceivingAddressesAction);
  364. file->addSeparator();
  365. }
  366. file->addAction(quitAction);
  367. QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
  368. if(walletFrame)
  369. {
  370. settings->addAction(encryptWalletAction);
  371. settings->addAction(changePassphraseAction);
  372. settings->addSeparator();
  373. }
  374. settings->addAction(optionsAction);
  375. QMenu *help = appMenuBar->addMenu(tr("&Help"));
  376. if(walletFrame)
  377. {
  378. help->addAction(openRPCConsoleAction);
  379. }
  380. help->addAction(showHelpMessageAction);
  381. help->addSeparator();
  382. help->addAction(aboutAction);
  383. help->addAction(aboutQtAction);
  384. }
  385. void BitcoinGUI::createToolBars()
  386. {
  387. if(walletFrame)
  388. {
  389. QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
  390. toolbar->setMovable(false);
  391. toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  392. toolbar->addAction(overviewAction);
  393. toolbar->addAction(sendCoinsAction);
  394. toolbar->addAction(receiveCoinsAction);
  395. toolbar->addAction(historyAction);
  396. overviewAction->setChecked(true);
  397. }
  398. }
  399. void BitcoinGUI::setClientModel(ClientModel *clientModel)
  400. {
  401. this->clientModel = clientModel;
  402. if(clientModel)
  403. {
  404. // Create system tray menu (or setup the dock menu) that late to prevent users from calling actions,
  405. // while the client has not yet fully loaded
  406. createTrayIconMenu();
  407. // Keep up to date with client
  408. setNumConnections(clientModel->getNumConnections());
  409. connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
  410. setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate(), clientModel->getVerificationProgress(NULL), false);
  411. connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
  412. // Receive and report messages from client model
  413. connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
  414. // Show progress dialog
  415. connect(clientModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int)));
  416. rpcConsole->setClientModel(clientModel);
  417. #ifdef ENABLE_WALLET
  418. if(walletFrame)
  419. {
  420. walletFrame->setClientModel(clientModel);
  421. }
  422. #endif // ENABLE_WALLET
  423. unitDisplayControl->setOptionsModel(clientModel->getOptionsModel());
  424. OptionsModel* optionsModel = clientModel->getOptionsModel();
  425. if(optionsModel)
  426. {
  427. // be aware of the tray icon disable state change reported by the OptionsModel object.
  428. connect(optionsModel,SIGNAL(hideTrayIconChanged(bool)),this,SLOT(setTrayIconVisible(bool)));
  429. // initialize the disable state of the tray icon with the current value in the model.
  430. setTrayIconVisible(optionsModel->getHideTrayIcon());
  431. }
  432. } else {
  433. // Disable possibility to show main window via action
  434. toggleHideAction->setEnabled(false);
  435. if(trayIconMenu)
  436. {
  437. // Disable context menu on tray icon
  438. trayIconMenu->clear();
  439. }
  440. }
  441. }
  442. #ifdef ENABLE_WALLET
  443. bool BitcoinGUI::addWallet(const QString& name, WalletModel *walletModel)
  444. {
  445. if(!walletFrame)
  446. return false;
  447. setWalletActionsEnabled(true);
  448. return walletFrame->addWallet(name, walletModel);
  449. }
  450. bool BitcoinGUI::setCurrentWallet(const QString& name)
  451. {
  452. if(!walletFrame)
  453. return false;
  454. return walletFrame->setCurrentWallet(name);
  455. }
  456. void BitcoinGUI::removeAllWallets()
  457. {
  458. if(!walletFrame)
  459. return;
  460. setWalletActionsEnabled(false);
  461. walletFrame->removeAllWallets();
  462. }
  463. #endif // ENABLE_WALLET
  464. void BitcoinGUI::setWalletActionsEnabled(bool enabled)
  465. {
  466. overviewAction->setEnabled(enabled);
  467. sendCoinsAction->setEnabled(enabled);
  468. sendCoinsMenuAction->setEnabled(enabled);
  469. receiveCoinsAction->setEnabled(enabled);
  470. receiveCoinsMenuAction->setEnabled(enabled);
  471. historyAction->setEnabled(enabled);
  472. encryptWalletAction->setEnabled(enabled);
  473. backupWalletAction->setEnabled(enabled);
  474. changePassphraseAction->setEnabled(enabled);
  475. signMessageAction->setEnabled(enabled);
  476. verifyMessageAction->setEnabled(enabled);
  477. usedSendingAddressesAction->setEnabled(enabled);
  478. usedReceivingAddressesAction->setEnabled(enabled);
  479. openAction->setEnabled(enabled);
  480. }
  481. void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
  482. {
  483. #ifndef Q_OS_MAC
  484. trayIcon = new QSystemTrayIcon(this);
  485. QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText();
  486. trayIcon->setToolTip(toolTip);
  487. trayIcon->setIcon(networkStyle->getTrayAndWindowIcon());
  488. trayIcon->hide();
  489. #endif
  490. notificator = new Notificator(QApplication::applicationName(), trayIcon, this);
  491. }
  492. void BitcoinGUI::createTrayIconMenu()
  493. {
  494. #ifndef Q_OS_MAC
  495. // return if trayIcon is unset (only on non-Mac OSes)
  496. if (!trayIcon)
  497. return;
  498. trayIconMenu = new QMenu(this);
  499. trayIcon->setContextMenu(trayIconMenu);
  500. connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
  501. this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
  502. #else
  503. // Note: On Mac, the dock icon is used to provide the tray's functionality.
  504. MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
  505. dockIconHandler->setMainWindow((QMainWindow *)this);
  506. trayIconMenu = dockIconHandler->dockMenu();
  507. #endif
  508. // Configuration of the tray icon (or dock icon) icon menu
  509. trayIconMenu->addAction(toggleHideAction);
  510. trayIconMenu->addSeparator();
  511. trayIconMenu->addAction(sendCoinsMenuAction);
  512. trayIconMenu->addAction(receiveCoinsMenuAction);
  513. trayIconMenu->addSeparator();
  514. trayIconMenu->addAction(signMessageAction);
  515. trayIconMenu->addAction(verifyMessageAction);
  516. trayIconMenu->addSeparator();
  517. trayIconMenu->addAction(optionsAction);
  518. trayIconMenu->addAction(openRPCConsoleAction);
  519. #ifndef Q_OS_MAC // This is built-in on Mac
  520. trayIconMenu->addSeparator();
  521. trayIconMenu->addAction(quitAction);
  522. #endif
  523. }
  524. #ifndef Q_OS_MAC
  525. void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
  526. {
  527. if(reason == QSystemTrayIcon::Trigger)
  528. {
  529. // Click on system tray icon triggers show/hide of the main window
  530. toggleHidden();
  531. }
  532. }
  533. #endif
  534. void BitcoinGUI::optionsClicked()
  535. {
  536. if(!clientModel || !clientModel->getOptionsModel())
  537. return;
  538. OptionsDialog dlg(this, enableWallet);
  539. dlg.setModel(clientModel->getOptionsModel());
  540. dlg.exec();
  541. }
  542. void BitcoinGUI::aboutClicked()
  543. {
  544. if(!clientModel)
  545. return;
  546. HelpMessageDialog dlg(this, true);
  547. dlg.exec();
  548. }
  549. void BitcoinGUI::showDebugWindow()
  550. {
  551. rpcConsole->showNormal();
  552. rpcConsole->show();
  553. rpcConsole->raise();
  554. rpcConsole->activateWindow();
  555. }
  556. void BitcoinGUI::showDebugWindowActivateConsole()
  557. {
  558. rpcConsole->setTabFocus(RPCConsole::TAB_CONSOLE);
  559. showDebugWindow();
  560. }
  561. void BitcoinGUI::showHelpMessageClicked()
  562. {
  563. helpMessageDialog->show();
  564. }
  565. #ifdef ENABLE_WALLET
  566. void BitcoinGUI::openClicked()
  567. {
  568. OpenURIDialog dlg(this);
  569. if(dlg.exec())
  570. {
  571. Q_EMIT receivedURI(dlg.getURI());
  572. }
  573. }
  574. void BitcoinGUI::gotoOverviewPage()
  575. {
  576. overviewAction->setChecked(true);
  577. if (walletFrame) walletFrame->gotoOverviewPage();
  578. }
  579. void BitcoinGUI::gotoHistoryPage()
  580. {
  581. historyAction->setChecked(true);
  582. if (walletFrame) walletFrame->gotoHistoryPage();
  583. }
  584. void BitcoinGUI::gotoReceiveCoinsPage()
  585. {
  586. receiveCoinsAction->setChecked(true);
  587. if (walletFrame) walletFrame->gotoReceiveCoinsPage();
  588. }
  589. void BitcoinGUI::gotoSendCoinsPage(QString addr)
  590. {
  591. sendCoinsAction->setChecked(true);
  592. if (walletFrame) walletFrame->gotoSendCoinsPage(addr);
  593. }
  594. void BitcoinGUI::gotoSignMessageTab(QString addr)
  595. {
  596. if (walletFrame) walletFrame->gotoSignMessageTab(addr);
  597. }
  598. void BitcoinGUI::gotoVerifyMessageTab(QString addr)
  599. {
  600. if (walletFrame) walletFrame->gotoVerifyMessageTab(addr);
  601. }
  602. #endif // ENABLE_WALLET
  603. void BitcoinGUI::setNumConnections(int count)
  604. {
  605. QString icon;
  606. switch(count)
  607. {
  608. case 0: icon = ":/icons/connect_0"; break;
  609. case 1: case 2: case 3: icon = ":/icons/connect_1"; break;
  610. case 4: case 5: case 6: icon = ":/icons/connect_2"; break;
  611. case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
  612. default: icon = ":/icons/connect_4"; break;
  613. }
  614. labelConnectionsIcon->setPixmap(platformStyle->SingleColorIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
  615. labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
  616. }
  617. void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header)
  618. {
  619. if(!clientModel)
  620. return;
  621. // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbelled text)
  622. statusBar()->clearMessage();
  623. // Acquire current block source
  624. enum BlockSource blockSource = clientModel->getBlockSource();
  625. switch (blockSource) {
  626. case BLOCK_SOURCE_NETWORK:
  627. if (header) {
  628. return;
  629. }
  630. progressBarLabel->setText(tr("Synchronizing with network..."));
  631. break;
  632. case BLOCK_SOURCE_DISK:
  633. if (header) {
  634. progressBarLabel->setText(tr("Indexing blocks on disk..."));
  635. } else {
  636. progressBarLabel->setText(tr("Processing blocks on disk..."));
  637. }
  638. break;
  639. case BLOCK_SOURCE_REINDEX:
  640. progressBarLabel->setText(tr("Reindexing blocks on disk..."));
  641. break;
  642. case BLOCK_SOURCE_NONE:
  643. if (header) {
  644. return;
  645. }
  646. // Case: not Importing, not Reindexing and no network connection
  647. progressBarLabel->setText(tr("No block source available..."));
  648. break;
  649. }
  650. QString tooltip;
  651. QDateTime currentDate = QDateTime::currentDateTime();
  652. qint64 secs = blockDate.secsTo(currentDate);
  653. tooltip = tr("Processed %n block(s) of transaction history.", "", count);
  654. // Set icon state: spinning if catching up, tick otherwise
  655. if(secs < 90*60)
  656. {
  657. tooltip = tr("Up to date") + QString(".<br>") + tooltip;
  658. labelBlocksIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
  659. #ifdef ENABLE_WALLET
  660. if(walletFrame)
  661. walletFrame->showOutOfSyncWarning(false);
  662. #endif // ENABLE_WALLET
  663. progressBarLabel->setVisible(false);
  664. progressBar->setVisible(false);
  665. }
  666. else
  667. {
  668. QString timeBehindText = GUIUtil::formateNiceTimeOffset(secs);
  669. progressBarLabel->setVisible(true);
  670. progressBar->setFormat(tr("%1 behind").arg(timeBehindText));
  671. progressBar->setMaximum(1000000000);
  672. progressBar->setValue(nVerificationProgress * 1000000000.0 + 0.5);
  673. progressBar->setVisible(true);
  674. tooltip = tr("Catching up...") + QString("<br>") + tooltip;
  675. if(count != prevBlocks)
  676. {
  677. labelBlocksIcon->setPixmap(platformStyle->SingleColorIcon(QString(
  678. ":/movies/spinner-%1").arg(spinnerFrame, 3, 10, QChar('0')))
  679. .pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
  680. spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES;
  681. }
  682. prevBlocks = count;
  683. #ifdef ENABLE_WALLET
  684. if(walletFrame)
  685. walletFrame->showOutOfSyncWarning(true);
  686. #endif // ENABLE_WALLET
  687. tooltip += QString("<br>");
  688. tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText);
  689. tooltip += QString("<br>");
  690. tooltip += tr("Transactions after this will not yet be visible.");
  691. }
  692. // Don't word-wrap this (fixed-width) tooltip
  693. tooltip = QString("<nobr>") + tooltip + QString("</nobr>");
  694. labelBlocksIcon->setToolTip(tooltip);
  695. progressBarLabel->setToolTip(tooltip);
  696. progressBar->setToolTip(tooltip);
  697. }
  698. void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style, bool *ret)
  699. {
  700. QString strTitle = tr("Bitcoin"); // default title
  701. // Default to information icon
  702. int nMBoxIcon = QMessageBox::Information;
  703. int nNotifyIcon = Notificator::Information;
  704. QString msgType;
  705. // Prefer supplied title over style based title
  706. if (!title.isEmpty()) {
  707. msgType = title;
  708. }
  709. else {
  710. switch (style) {
  711. case CClientUIInterface::MSG_ERROR:
  712. msgType = tr("Error");
  713. break;
  714. case CClientUIInterface::MSG_WARNING:
  715. msgType = tr("Warning");
  716. break;
  717. case CClientUIInterface::MSG_INFORMATION:
  718. msgType = tr("Information");
  719. break;
  720. default:
  721. break;
  722. }
  723. }
  724. // Append title to "Bitcoin - "
  725. if (!msgType.isEmpty())
  726. strTitle += " - " + msgType;
  727. // Check for error/warning icon
  728. if (style & CClientUIInterface::ICON_ERROR) {
  729. nMBoxIcon = QMessageBox::Critical;
  730. nNotifyIcon = Notificator::Critical;
  731. }
  732. else if (style & CClientUIInterface::ICON_WARNING) {
  733. nMBoxIcon = QMessageBox::Warning;
  734. nNotifyIcon = Notificator::Warning;
  735. }
  736. // Display message
  737. if (style & CClientUIInterface::MODAL) {
  738. // Check for buttons, use OK as default, if none was supplied
  739. QMessageBox::StandardButton buttons;
  740. if (!(buttons = (QMessageBox::StandardButton)(style & CClientUIInterface::BTN_MASK)))
  741. buttons = QMessageBox::Ok;
  742. showNormalIfMinimized();
  743. QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons, this);
  744. int r = mBox.exec();
  745. if (ret != NULL)
  746. *ret = r == QMessageBox::Ok;
  747. }
  748. else
  749. notificator->notify((Notificator::Class)nNotifyIcon, strTitle, message);
  750. }
  751. void BitcoinGUI::changeEvent(QEvent *e)
  752. {
  753. QMainWindow::changeEvent(e);
  754. #ifndef Q_OS_MAC // Ignored on Mac
  755. if(e->type() == QEvent::WindowStateChange)
  756. {
  757. if(clientModel && clientModel->getOptionsModel() && clientModel->getOptionsModel()->getMinimizeToTray())
  758. {
  759. QWindowStateChangeEvent *wsevt = static_cast<QWindowStateChangeEvent*>(e);
  760. if(!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized())
  761. {
  762. QTimer::singleShot(0, this, SLOT(hide()));
  763. e->ignore();
  764. }
  765. }
  766. }
  767. #endif
  768. }
  769. void BitcoinGUI::closeEvent(QCloseEvent *event)
  770. {
  771. #ifndef Q_OS_MAC // Ignored on Mac
  772. if(clientModel && clientModel->getOptionsModel())
  773. {
  774. if(!clientModel->getOptionsModel()->getMinimizeOnClose())
  775. {
  776. // close rpcConsole in case it was open to make some space for the shutdown window
  777. rpcConsole->close();
  778. QApplication::quit();
  779. }
  780. else
  781. {
  782. QMainWindow::showMinimized();
  783. event->ignore();
  784. }
  785. }
  786. #else
  787. QMainWindow::closeEvent(event);
  788. #endif
  789. }
  790. void BitcoinGUI::showEvent(QShowEvent *event)
  791. {
  792. // enable the debug window when the main window shows up
  793. openRPCConsoleAction->setEnabled(true);
  794. aboutAction->setEnabled(true);
  795. optionsAction->setEnabled(true);
  796. }
  797. #ifdef ENABLE_WALLET
  798. void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label)
  799. {
  800. // On new transaction, make an info balloon
  801. QString msg = tr("Date: %1\n").arg(date) +
  802. tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(unit, amount, true)) +
  803. tr("Type: %1\n").arg(type);
  804. if (!label.isEmpty())
  805. msg += tr("Label: %1\n").arg(label);
  806. else if (!address.isEmpty())
  807. msg += tr("Address: %1\n").arg(address);
  808. message((amount)<0 ? tr("Sent transaction") : tr("Incoming transaction"),
  809. msg, CClientUIInterface::MSG_INFORMATION);
  810. }
  811. #endif // ENABLE_WALLET
  812. void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
  813. {
  814. // Accept only URIs
  815. if(event->mimeData()->hasUrls())
  816. event->acceptProposedAction();
  817. }
  818. void BitcoinGUI::dropEvent(QDropEvent *event)
  819. {
  820. if(event->mimeData()->hasUrls())
  821. {
  822. Q_FOREACH(const QUrl &uri, event->mimeData()->urls())
  823. {
  824. Q_EMIT receivedURI(uri.toString());
  825. }
  826. }
  827. event->acceptProposedAction();
  828. }
  829. bool BitcoinGUI::eventFilter(QObject *object, QEvent *event)
  830. {
  831. // Catch status tip events
  832. if (event->type() == QEvent::StatusTip)
  833. {
  834. // Prevent adding text from setStatusTip(), if we currently use the status bar for displaying other stuff
  835. if (progressBarLabel->isVisible() || progressBar->isVisible())
  836. return true;
  837. }
  838. return QMainWindow::eventFilter(object, event);
  839. }
  840. #ifdef ENABLE_WALLET
  841. bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient)
  842. {
  843. // URI has to be valid
  844. if (walletFrame && walletFrame->handlePaymentRequest(recipient))
  845. {
  846. showNormalIfMinimized();
  847. gotoSendCoinsPage();
  848. return true;
  849. }
  850. return false;
  851. }
  852. void BitcoinGUI::setHDStatus(int hdEnabled)
  853. {
  854. labelWalletHDStatusIcon->setPixmap(platformStyle->SingleColorIcon(hdEnabled ? ":/icons/hd_enabled" : ":/icons/hd_disabled").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
  855. labelWalletHDStatusIcon->setToolTip(hdEnabled ? tr("HD key generation is <b>enabled</b>") : tr("HD key generation is <b>disabled</b>"));
  856. // eventually disable the QLabel to set its opacity to 50%
  857. labelWalletHDStatusIcon->setEnabled(hdEnabled);
  858. }
  859. void BitcoinGUI::setEncryptionStatus(int status)
  860. {
  861. switch(status)
  862. {
  863. case WalletModel::Unencrypted:
  864. labelWalletEncryptionIcon->hide();
  865. encryptWalletAction->setChecked(false);
  866. changePassphraseAction->setEnabled(false);
  867. encryptWalletAction->setEnabled(true);
  868. break;
  869. case WalletModel::Unlocked:
  870. labelWalletEncryptionIcon->show();
  871. labelWalletEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
  872. labelWalletEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
  873. encryptWalletAction->setChecked(true);
  874. changePassphraseAction->setEnabled(true);
  875. encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
  876. break;
  877. case WalletModel::Locked:
  878. labelWalletEncryptionIcon->show();
  879. labelWalletEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
  880. labelWalletEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
  881. encryptWalletAction->setChecked(true);
  882. changePassphraseAction->setEnabled(true);
  883. encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
  884. break;
  885. }
  886. }
  887. #endif // ENABLE_WALLET
  888. void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
  889. {
  890. if(!clientModel)
  891. return;
  892. // activateWindow() (sometimes) helps with keyboard focus on Windows
  893. if (isHidden())
  894. {
  895. show();
  896. activateWindow();
  897. }
  898. else if (isMinimized())
  899. {
  900. showNormal();
  901. activateWindow();
  902. }
  903. else if (GUIUtil::isObscured(this))
  904. {
  905. raise();
  906. activateWindow();
  907. }
  908. else if(fToggleHidden)
  909. hide();
  910. }
  911. void BitcoinGUI::toggleHidden()
  912. {
  913. showNormalIfMinimized(true);
  914. }
  915. void BitcoinGUI::detectShutdown()
  916. {
  917. if (ShutdownRequested())
  918. {
  919. if(rpcConsole)
  920. rpcConsole->hide();
  921. qApp->quit();
  922. }
  923. }
  924. void BitcoinGUI::showProgress(const QString &title, int nProgress)
  925. {
  926. if (nProgress == 0)
  927. {
  928. progressDialog = new QProgressDialog(title, "", 0, 100);
  929. progressDialog->setWindowModality(Qt::ApplicationModal);
  930. progressDialog->setMinimumDuration(0);
  931. progressDialog->setCancelButton(0);
  932. progressDialog->setAutoClose(false);
  933. progressDialog->setValue(0);
  934. }
  935. else if (nProgress == 100)
  936. {
  937. if (progressDialog)
  938. {
  939. progressDialog->close();
  940. progressDialog->deleteLater();
  941. }
  942. }
  943. else if (progressDialog)
  944. progressDialog->setValue(nProgress);
  945. }
  946. void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon)
  947. {
  948. if (trayIcon)
  949. {
  950. trayIcon->setVisible(!fHideTrayIcon);
  951. }
  952. }
  953. static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style)
  954. {
  955. bool modal = (style & CClientUIInterface::MODAL);
  956. // The SECURE flag has no effect in the Qt GUI.
  957. // bool secure = (style & CClientUIInterface::SECURE);
  958. style &= ~CClientUIInterface::SECURE;
  959. bool ret = false;
  960. // In case of modal message, use blocking connection to wait for user to click a button
  961. QMetaObject::invokeMethod(gui, "message",
  962. modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
  963. Q_ARG(QString, QString::fromStdString(caption)),
  964. Q_ARG(QString, QString::fromStdString(message)),
  965. Q_ARG(unsigned int, style),
  966. Q_ARG(bool*, &ret));
  967. return ret;
  968. }
  969. void BitcoinGUI::subscribeToCoreSignals()
  970. {
  971. // Connect signals to client
  972. uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
  973. uiInterface.ThreadSafeQuestion.connect(boost::bind(ThreadSafeMessageBox, this, _1, _3, _4));
  974. }
  975. void BitcoinGUI::unsubscribeFromCoreSignals()
  976. {
  977. // Disconnect signals from client
  978. uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
  979. uiInterface.ThreadSafeQuestion.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _3, _4));
  980. }
  981. UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *platformStyle) :
  982. optionsModel(0),
  983. menu(0)
  984. {
  985. createContextMenu();
  986. setToolTip(tr("Unit to show amounts in. Click to select another unit."));
  987. QList<BitcoinUnits::Unit> units = BitcoinUnits::availableUnits();
  988. int max_width = 0;
  989. const QFontMetrics fm(font());
  990. Q_FOREACH (const BitcoinUnits::Unit unit, units)
  991. {
  992. max_width = qMax(max_width, fm.width(BitcoinUnits::name(unit)));
  993. }
  994. setMinimumSize(max_width, 0);
  995. setAlignment(Qt::AlignRight | Qt::AlignVCenter);
  996. setStyleSheet(QString("QLabel { color : %1 }").arg(platformStyle->SingleColor().name()));
  997. }
  998. /** So that it responds to button clicks */
  999. void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event)
  1000. {
  1001. onDisplayUnitsClicked(event->pos());
  1002. }
  1003. /** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
  1004. void UnitDisplayStatusBarControl::createContextMenu()
  1005. {
  1006. menu = new QMenu();
  1007. Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
  1008. {
  1009. QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this);
  1010. menuAction->setData(QVariant(u));
  1011. menu->addAction(menuAction);
  1012. }
  1013. connect(menu,SIGNAL(triggered(QAction*)),this,SLOT(onMenuSelection(QAction*)));
  1014. }
  1015. /** Lets the control know about the Options Model (and its signals) */
  1016. void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *optionsModel)
  1017. {
  1018. if (optionsModel)
  1019. {
  1020. this->optionsModel = optionsModel;
  1021. // be aware of a display unit change reported by the OptionsModel object.
  1022. connect(optionsModel,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int)));
  1023. // initialize the display units label with the current value in the model.
  1024. updateDisplayUnit(optionsModel->getDisplayUnit());
  1025. }
  1026. }
  1027. /** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
  1028. void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits)
  1029. {
  1030. setText(BitcoinUnits::name(newUnits));
  1031. }
  1032. /** Shows context menu with Display Unit options by the mouse coordinates */
  1033. void UnitDisplayStatusBarControl::onDisplayUnitsClicked(const QPoint& point)
  1034. {
  1035. QPoint globalPos = mapToGlobal(point);
  1036. menu->exec(globalPos);
  1037. }
  1038. /** Tells underlying optionsModel to update its current display unit. */
  1039. void UnitDisplayStatusBarControl::onMenuSelection(QAction* action)
  1040. {
  1041. if (action)
  1042. {
  1043. optionsModel->setDisplayUnit(action->data());
  1044. }
  1045. }