pylupdate4 kalam.pro
[bitcoin:spesmilo.git] / main.py
1 # -*- coding: utf-8 -*-
2 # Spesmilo -- Python Bitcoin user interface
3 # Copyright © 2011 Luke Dashjr
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, version 3 only.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 from PySide.QtCore import *
18 from PySide.QtGui import *
19 from PySide.QtWebKit import *
20 import core_interface
21 import cashier
22 import send
23 from settings import SpesmiloSettings, SettingsDialog
24
25 class ConnectingDialog(QDialog):
26     def __init__(self, parent):
27         super(ConnectingDialog, self).__init__(parent)
28         main_layout = QVBoxLayout(self)
29         main_layout.addWidget(QLabel(self.tr('Connecting...')))
30         progressbar = QProgressBar()
31         progressbar.setMinimum(0)
32         progressbar.setMaximum(0)
33         main_layout.addWidget(progressbar)
34         
35         button_layout = QHBoxLayout()
36         button_layout.addStretch()
37         abortbtn = QPushButton('&Abort')
38         abortbtn.clicked.connect(self.stop)
39         button_layout.addWidget(abortbtn)
40         main_layout.addLayout(button_layout)
41
42         if parent is not None:
43             self.setWindowIcon(parent.bitcoin_icon)
44         self.setWindowTitle(self.tr('Connecting...'))
45         self.setAttribute(Qt.WA_DeleteOnClose, False)
46         self.show()
47
48     def stop(self):
49         self.hide()
50         self.parent().stop()
51
52     def closeEvent(self, event):
53         self.hide()
54         event.ignore()
55
56 class TrayIcon(QSystemTrayIcon):
57     def __init__(self, core, parent):
58         super(TrayIcon, self).__init__(parent)
59         self.core = core
60         self.current_window = None
61         self.create_menu()
62         self.setIcon(self.parent().bitcoin_icon)
63         self.activated.connect(self.toggle_window)
64         self.show()
65     
66     def create_menu(self):
67         tray_menu = QMenu()
68         self.cash_act = QAction(self.tr('&Cashier'), self)
69         self.cash_act.triggered.connect(self.show_cashier)
70         self.cash_act.setDisabled(True)
71         tray_menu.addAction(self.cash_act)
72         self.send_act = QAction(self.tr('&Send funds'), self)
73         self.send_act.triggered.connect(self.show_send)
74         self.send_act.setDisabled(True)
75         tray_menu.addAction(self.send_act)
76         tray_menu.addSeparator()
77         quit_act = QAction(self.tr('&Quit'), self)
78         quit_act.triggered.connect(self.quit)
79         tray_menu.addAction(quit_act)
80         self.setContextMenu(tray_menu)
81
82     def delete_window(self):
83         if self.current_window is not None:
84             self.current_window.deleteLater()
85
86     def create_connecting(self):
87         self.delete_window()
88         self.current_window = ConnectingDialog(self.parent())
89
90     def create_cashier(self):
91         self.cash_act.setDisabled(False)
92         self.send_act.setDisabled(False)
93         self.delete_window()
94         self.current_window = cashier.Cashier(self.core, qApp.clipboard(),
95                                               self.parent())
96         self.show_cashier()
97
98     def show_cashier(self):
99         self.current_window.show()
100
101     def toggle_window(self, reason):
102         if reason == self.Trigger:
103             if self.current_window is not None:
104                 if self.current_window.isVisible():
105                     self.current_window.hide()
106                 else:
107                     self.current_window.show()
108
109     def show_send(self):
110         send.SendDialog(self.core, self.parent())
111
112     def quit(self):
113         self.parent().stop()
114
115 class RootWindow(QMainWindow):
116     CLIENT_NONE = 0
117     CLIENT_CONNECTING = 1
118     CLIENT_DOWNLOADING = 2
119     CLIENT_RUNNING = 3
120
121     def __init__(self):
122         super(RootWindow, self).__init__()
123         
124         icon = lambda s: QIcon('./icons/' + s)
125         self.bitcoin_icon = icon('bitcoin32.xpm')
126         
127         self.state = self.CLIENT_NONE
128     
129     def start(self):
130         self.uri = SpesmiloSettings.getEffectiveURI()
131         self.core = core_interface.CoreInterface(self.uri)
132         self.tray = TrayIcon(self.core, self)
133
134         refresh_state_timer = QTimer(self)
135         refresh_state_timer.timeout.connect(self.refresh_state)
136         refresh_state_timer.start(1000)
137         self.refresh_state()
138
139     def refresh_state(self):
140         is_init = False
141         if self.state == self.CLIENT_NONE:
142             self.state = self.CLIENT_CONNECTING
143             try:
144                 is_init = self.core.is_initialised()
145             except:
146                 pass
147             # show initialising dialog
148             self.tray.create_connecting()
149         elif self.state == self.CLIENT_CONNECTING:
150             try:
151                 is_init = self.core.is_initialised()
152             except IOError:
153                 error = QErrorMessage()
154                 error.showMessage('Internal error: failed to find bitcoin core')
155                 error.exec_()
156                 qApp.quit()
157                 raise
158         if is_init:
159             # some voodoo here checking whether we have blocks
160             self.state = self.CLIENT_RUNNING
161             self.tray.create_cashier()
162
163     def closeEvent(self, event):
164         super(RootWindow, self).closeEvent(event)
165         self.stop()
166
167     def stop(self):
168         try:
169             if SpesmiloSettings.useInternalCore():
170                 # Keep looping until connected so we can issue the stop command
171                 while True:
172                     try:
173                         self.core.stop()
174                     except core_interface.JSONRPCException:
175                         pass
176                     except:
177                         raise
178                     else:
179                         break
180         # Re-proprogate exception & trigger app exit so we can break out
181         except:
182             raise
183         finally:
184             qApp.quit()
185
186 def _startup(rootwindow):
187     if SpesmiloSettings.useInternalCore():
188         import os
189         os.system('bitcoind')
190     rootwindow.start()
191
192 if __name__ == '__main__':
193     import sys
194     app = QApplication(sys.argv)
195     SpesmiloSettings.loadTranslator()
196     app.setQuitOnLastWindowClosed(False)
197     rootwindow = RootWindow()
198     if SpesmiloSettings.isConfigured():
199         _startup(rootwindow)
200     else:
201         sd = SettingsDialog(rootwindow)
202         sd.accepted.connect(lambda: _startup(rootwindow))
203         sd.rejected.connect(lambda: qApp.quit())
204     sys.exit(app.exec_())