pylupdate4 kalam.pro
[bitcoin:spesmilo.git] / send.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 decimal import Decimal
18 import re
19 from PySide.QtCore import *
20 from PySide.QtGui import *
21 from PySide.QtWebKit import *
22 from settings import humanAmount, humanToAmount, SpesmiloSettings
23
24 class SendDialog(QDialog):
25     def __init__(self, core, parent, uri = None):
26         super(SendDialog, self).__init__(parent)
27         self.core = core
28         
29         formlay = QFormLayout()
30         self.destaddy = QLineEdit()
31         self.amount = QLineEdit()
32         self.amount.setAlignment(Qt.AlignRight|Qt.AlignVCenter)
33         amount_max_width = self.fontMetrics().averageCharWidth() * 10
34         self.amount.setMaximumWidth(amount_max_width)
35         dv = QDoubleValidator(self.amount)
36         dv.setDecimals(2)
37         dv.setNotation(QDoubleValidator.StandardNotation)
38         self.dv = dv
39         tv = QRegExpValidator(QRegExp('-?(?:[\d\\xe9d9-\\xe9df]+\.?|[\d\\xe9d9-\\xe9df]*\.[\d\\xe9d9-\\xe9df]{1,4})'), self.amount)
40         self.tv = tv
41         self.amount_unit = QComboBox(self)
42         self.amount_unit.addItem(self.tr("BTC"), "BTC")
43         self.amount_unit.addItem(self.tr("TBC"), "TBC")
44         self.amount_unit.currentIndexChanged.connect(self.update_validator)
45         prefunit = 'TBC' if SpesmiloSettings.getNumberSystem() == 'Tonal' else 'BTC'
46         self.amount_unit.setCurrentIndex(self.amount_unit.findData(prefunit))
47         formlay.addRow(self.tr('Pay to:'), self.destaddy)
48         amountlay = QHBoxLayout()
49         amountlay.addWidget(self.amount)
50         amountlay.addWidget(self.amount_unit)
51         amountlay.addStretch()
52         formlay.addRow(self.tr('Amount:'), amountlay)
53
54         actionlay = QHBoxLayout()
55         sendbtn = QPushButton(self.tr('&Send'))
56         sendbtn.clicked.connect(self.do_payment)
57         sendbtn.setAutoDefault(True)
58         cancelbtn = QPushButton(self.tr('&Cancel'))
59         cancelbtn.clicked.connect(self.reject)
60         actionlay.addStretch()
61         actionlay.addWidget(sendbtn)
62         actionlay.addWidget(cancelbtn)
63
64         # layout includes form + instructions
65         instructions = QLabel(self.tr('<i>Enter a bitcoin address (e.g. 1A9Pv2PYuZYvfqku7sJxovw99Az72mZ4YH)</i>'))
66         mainlay = QVBoxLayout(self)
67         mainlay.addWidget(instructions)
68         mainlay.addLayout(formlay)
69         mainlay.addLayout(actionlay)
70
71         if parent is not None:
72             self.setWindowIcon(parent.bitcoin_icon)
73         self.setWindowTitle(self.tr('Send bitcoins'))
74
75         if not uri is None:
76             self.load_uri(uri)
77
78         self.show()
79         self.destaddy.setFocus()
80
81     def load_uri(self, uri):
82         m = re.match(r'^bitcoin\:([1-9A-HJ-NP-Za-km-z]+)(?:\?(.*))?$', uri)
83         if m is None:
84             raise RuntimeError('Invalid bitcoin URI')
85         addr = m.group(1)
86         query = m.group(2)
87         param = {}
88         if not query is None:
89             query = re.split(r'[&?;]', query)
90             for q in query:
91                 k, v = q.split('=', 1)
92                 param[k] = v
93         self.destaddy.setText(addr)
94         if 'amount' in param:
95             amount = param['amount']
96             m = re.match(r'^(([\d.]+)(X(\d+))?|x([\da-f]*)(\.([\da-f]*))?(X([\da-f]+))?)$', amount, re.IGNORECASE)
97             if m.group(5):
98                 # TBC
99                 amount = float(int(m.group(5), 16))
100                 if m.group(7):
101                     amount += float(int(m.group(7), 16)) * pow(16, -(len(m.group(7))))
102                 if m.group(9):
103                     amount *= pow(16, int(m.group(9), 16))
104                 else:
105                     amount *= 0x10000
106                 NU = 'Tonal'
107             else:
108                 amount = Decimal(m.group(2))
109                 if m.group(4):
110                     amount *= 10 ** int(m.group(4))
111                 else:
112                     amount *= 100000000
113                 NU = 'Decimal'
114             amount = int(amount)
115             NU = SpesmiloSettings.ChooseUnits(amount, NU)
116             if NU == 'Tonal':
117                 self.amount_unit.setCurrentIndex(self.amount_unit.findData('TBC'))
118                 amount = SpesmiloSettings._toTBC(amount, addSign=False, wantTLA=False)
119             else:
120                 self.amount_unit.setCurrentIndex(self.amount_unit.findData('BTC'))
121                 amount = SpesmiloSettings._toBTC(amount, addSign=False, wantTLA=False)
122             self.amount.setText(amount)
123
124     def update_validator(self):
125         u = self.amount_unit.itemData(self.amount_unit.currentIndex())
126         if u == 'BTC':
127             self.amount.setValidator(self.dv)
128         elif u == 'TBC':
129             self.amount.setValidator(self.tv)
130         else:
131             self.amount.setValidator(None)
132
133     def do_payment(self):
134         if not self.amount.text():
135             self.amount.setFocus(Qt.OtherFocusReason)
136             return
137         self.hide()
138
139         addy = self.destaddy.text()
140         if not self.core.validate_address(addy):
141             error = QMessageBox(QMessageBox.Critical, 
142                                 self.tr('Invalid address'),
143                                 self.tr('Invalid address: %s')%addy)
144             error.exec_()
145             self.reject()
146             return
147
148         amount = self.amount.text()
149         amount += ' ' + self.amount_unit.itemData(self.amount_unit.currentIndex())
150         amount = humanToAmount(amount)
151
152         balance = self.core.balance()
153         if amount > balance:
154             error = QMessageBox(QMessageBox.Critical, 
155                                 self.tr('Insufficient balance'),
156                             self.tr('Balance of %g is too small.') % (humanAmount(balance),))
157             error.exec_()
158             self.reject()
159             return
160
161         try:
162             self.core.send(addy, amount)
163         except Exception, e:
164             error = QMessageBox(QMessageBox.Critical, 
165                                 self.tr('Error sending'),
166                             self.tr('Your send failed: %s') % (e,))
167             error.exec_()
168             self.reject()
169             return
170         self.accept()
171
172 if __name__ == '__main__':
173     import os
174     import sys
175     import core_interface
176     from settings import SpesmiloSettings
177     os.system('bitcoind')
178     app = QApplication(sys.argv)
179     SpesmiloSettings.loadTranslator()
180     uri = SpesmiloSettings.getEffectiveURI()
181     core = core_interface.CoreInterface(uri)
182     send = SendDialog(core, None, sys.argv[1] if len(sys.argv) > 1 else None)
183     sys.exit(app.exec_())