use QPlainTextEdit instead of QTextEdit
[electrum-nvc.git] / gui / qt / paytoedit.py
index 3357a2c..f306373 100644 (file)
 
 from PyQt4.QtCore import *
 from PyQt4.QtGui import *
+from qrtextedit import QRTextEdit
 
+import re
+from decimal import Decimal
+from electrum import bitcoin
 
-class PayToEdit(QTextEdit):
+RE_ADDRESS = '[1-9A-HJ-NP-Za-km-z]{26,}'
+RE_ALIAS = '(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>'
 
-    def __init__(self, *args, **kwargs):
-        QTextEdit.__init__(self, *args, **kwargs)
+frozen_style = "QWidget { background-color:none; border:none;}"
+normal_style = "QPlainTextEdit { }"
+
+class PayToEdit(QRTextEdit):
+
+    def __init__(self, win):
+        QRTextEdit.__init__(self)
+        self.win = win
+        self.amount_edit = win.amount_e
         self.document().contentsChanged.connect(self.update_size)
         self.heightMin = 0
         self.heightMax = 150
-        self.setMinimumHeight(27)
-        self.setMaximumHeight(27)
-        #self.setStyleSheet("QTextEdit { border-style:solid; border-width: 1px;}")
         self.c = None
+        self.textChanged.connect(self.check_text)
+        self.outputs = []
+        self.is_pr = False
+        self.scan_f = self.win.pay_from_URI
+        self.update_size()
+        self.payto_address = None
+
+    def lock_amount(self):
+        self.amount_edit.setFrozen(True)
+
+    def unlock_amount(self):
+        self.amount_edit.setFrozen(False)
+
+    def setFrozen(self, b):
+        self.setReadOnly(b)
+        self.setStyleSheet(frozen_style if b else normal_style)
+        self.button.setHidden(b)
+
+    def setGreen(self):
+        self.is_pr = True
+        self.setStyleSheet("QWidget { background-color:#80ff80;}")
+
+    def setExpired(self):
+        self.is_pr = True
+        self.setStyleSheet("QWidget { background-color:#ffcccc;}")
+
+    def parse_address_and_amount(self, line):
+        m = re.match('^OP_RETURN\s+"(.+)"$', line.strip())
+        if m:
+            address = 'OP_RETURN:' + m.group(1)
+            amount = 0
+        else:
+            x, y = line.split(',')
+            address = self.parse_address(x)
+            amount = self.parse_amount(y)
+        return address, amount
+
+
+    def parse_amount(self, x):
+        p = pow(10, self.amount_edit.decimal_point())
+        return int( p * Decimal(x.strip()))
+
+
+    def parse_address(self, line):
+        r = line.strip()
+        m = re.match('^'+RE_ALIAS+'$', r)
+        address = m.group(2) if m else r
+        assert bitcoin.is_address(address)
+        return address
+
+
+    def check_text(self):
+        if self.is_pr:
+            return
+
+        # filter out empty lines
+        lines = filter( lambda x: x, self.lines())
+        outputs = []
+        total = 0
+
+        self.payto_address = None
+
+        if len(lines) == 1:
+            try:
+                self.payto_address = self.parse_address(lines[0])
+            except:
+                pass
+
+            if self.payto_address:
+                self.unlock_amount()
+                return
+
+        for line in lines:
+            try:
+                to_address, amount = self.parse_address_and_amount(line)
+            except:
+                continue
+                
+            outputs.append((to_address, amount))
+            total += amount
+
+        self.outputs = outputs
+        self.payto_address = None
+
+        if outputs:
+            self.amount_edit.setAmount(total)
+        else:
+            self.amount_edit.setText("")
+
+        self.amount_edit.textEdited.emit("")
+
+        if total or len(lines)>1:
+            self.lock_amount()
+        else:
+            self.unlock_amount()
+
+
+    def get_outputs(self):
+        if self.payto_address:
+            try:
+                amount = self.amount_edit.get_amount()
+            except:
+                amount = None
+
+            self.outputs = [(self.payto_address, amount)]
+
+        return self.outputs[:]
+
+
+    def lines(self):
+        return str(self.toPlainText()).split('\n')
+
+
+    def is_multiline(self):
+        return len(self.lines()) > 1
 
 
     def update_size(self):
         docHeight = self.document().size().height()
-        if self.heightMin <= docHeight <= self.heightMax:
-            self.setMinimumHeight(docHeight + 2)
-            self.setMaximumHeight(docHeight + 2)
+        h = docHeight*17 + 11
+        if self.heightMin <= h <= self.heightMax:
+            self.setMinimumHeight(h)
+            self.setMaximumHeight(h)
+        self.verticalScrollBar().hide()
 
 
     def setCompleter(self, completer):
@@ -65,15 +191,23 @@ class PayToEdit(QTextEdit):
 
 
     def keyPressEvent(self, e):
+        if self.isReadOnly():
+            return
+
         if self.c.popup().isVisible():
             if e.key() in [Qt.Key_Enter, Qt.Key_Return]:
                 e.ignore()
                 return
 
-        isShortcut = (e.modifiers() and Qt.ControlModifier) and e.key() == Qt.Key_E
+        if e.key() in [Qt.Key_Tab]:
+            e.ignore()
+            return
+
+        if e.key() in [Qt.Key_Down, Qt.Key_Up] and not self.is_multiline():
+            e.ignore()
+            return
 
-        if not self.c or not isShortcut:
-            QTextEdit.keyPressEvent(self, e)
+        QPlainTextEdit.keyPressEvent(self, e)
 
         ctrlOrShift = e.modifiers() and (Qt.ControlModifier or Qt.ShiftModifier)
         if self.c is None or (ctrlOrShift and e.text().isEmpty()):
@@ -83,7 +217,7 @@ class PayToEdit(QTextEdit):
         hasModifier = (e.modifiers() != Qt.NoModifier) and not ctrlOrShift;
         completionPrefix = self.textUnderCursor()
 
-        if not isShortcut and (hasModifier or e.text().isEmpty() or completionPrefix.length() < 1 or eow.contains(e.text().right(1)) ):
+        if hasModifier or e.text().isEmpty() or completionPrefix.length() < 1 or eow.contains(e.text().right(1)):
             self.c.popup().hide()
             return
 
@@ -95,4 +229,3 @@ class PayToEdit(QTextEdit):
         cr.setWidth(self.c.popup().sizeHintForColumn(0) + self.c.popup().verticalScrollBar().sizeHint().width())
         self.c.complete(cr)
 
-