init
This commit is contained in:
255
balqt/locktimeedit.py
Normal file
255
balqt/locktimeedit.py
Normal file
@@ -0,0 +1,255 @@
|
||||
# Copyright (C) 2020 The Electrum developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENCE or http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
import time
|
||||
from datetime import datetime
|
||||
from typing import Optional, Any
|
||||
|
||||
from . import qt_resources
|
||||
if qt_resources.QT_VERSION == 5:
|
||||
from PyQt5.QtCore import Qt, QDateTime, pyqtSignal
|
||||
from PyQt5.QtGui import QPalette, QPainter
|
||||
from PyQt5.QtWidgets import (QWidget, QLineEdit, QStyle, QStyleOptionFrame, QComboBox, QHBoxLayout, QDateTimeEdit)
|
||||
else:
|
||||
from PyQt6.QtCore import Qt, QDateTime, pyqtSignal
|
||||
from PyQt6.QtGui import QPalette, QPainter
|
||||
from PyQt6.QtWidgets import (QWidget, QLineEdit, QStyle, QStyleOptionFrame, QComboBox, QHBoxLayout, QDateTimeEdit)
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.bitcoin import NLOCKTIME_MIN, NLOCKTIME_MAX, NLOCKTIME_BLOCKHEIGHT_MAX
|
||||
|
||||
from electrum.gui.qt.util import char_width_in_lineedit, ColorScheme
|
||||
|
||||
|
||||
class HeirsLockTimeEdit(QWidget):
|
||||
|
||||
valueEdited = pyqtSignal()
|
||||
locktime_threshold = 50000000
|
||||
def __init__(self, parent=None,default_index = 1):
|
||||
QWidget.__init__(self, parent)
|
||||
|
||||
hbox = QHBoxLayout()
|
||||
self.setLayout(hbox)
|
||||
hbox.setContentsMargins(0, 0, 0, 0)
|
||||
hbox.setSpacing(0)
|
||||
|
||||
self.locktime_raw_e = LockTimeRawEdit(self,time_edit = self)
|
||||
#self.locktime_height_e = LockTimeHeightEdit(self)
|
||||
self.locktime_date_e = LockTimeDateEdit(self,time_edit = self)
|
||||
#self.editors = [self.locktime_raw_e, self.locktime_height_e, self.locktime_date_e]
|
||||
self.editors = [self.locktime_raw_e, self.locktime_date_e]
|
||||
|
||||
self.combo = QComboBox()
|
||||
#options = [_("Raw"), _("Block height"), _("Date")]
|
||||
options = [_("Raw"),_("Date")]
|
||||
self.option_index_to_editor_map = {
|
||||
0: self.locktime_raw_e,
|
||||
#1: self.locktime_height_e,
|
||||
1: self.locktime_date_e,
|
||||
#2: self.locktime_date_e,
|
||||
}
|
||||
self.combo.addItems(options)
|
||||
|
||||
|
||||
self.editor = self.option_index_to_editor_map[default_index]
|
||||
self.combo.currentIndexChanged.connect(self.on_current_index_changed)
|
||||
self.combo.setCurrentIndex(default_index)
|
||||
self.on_current_index_changed(default_index)
|
||||
|
||||
hbox.addWidget(self.combo)
|
||||
for w in self.editors:
|
||||
hbox.addWidget(w)
|
||||
hbox.addStretch(1)
|
||||
|
||||
#self.locktime_height_e.textEdited.connect(self.valueEdited.emit)
|
||||
self.locktime_raw_e.editingFinished.connect(self.valueEdited.emit)
|
||||
self.locktime_date_e.dateTimeChanged.connect(self.valueEdited.emit)
|
||||
self.combo.currentIndexChanged.connect(self.valueEdited.emit)
|
||||
|
||||
def on_current_index_changed(self,i):
|
||||
for w in self.editors:
|
||||
w.setVisible(False)
|
||||
w.setEnabled(False)
|
||||
prev_locktime = self.editor.get_locktime()
|
||||
self.editor = self.option_index_to_editor_map[i]
|
||||
if self.editor.is_acceptable_locktime(prev_locktime):
|
||||
self.editor.set_locktime(prev_locktime,force=True)
|
||||
self.editor.setVisible(True)
|
||||
self.editor.setEnabled(True)
|
||||
|
||||
def get_locktime(self) -> Optional[str]:
|
||||
return self.editor.get_locktime()
|
||||
|
||||
def set_index(self,index):
|
||||
self.combo.setCurrentIndex(index)
|
||||
self.on_current_index_changed(index)
|
||||
|
||||
def set_locktime(self, x: Any,force=True) -> None:
|
||||
self.editor.set_locktime(x,force)
|
||||
|
||||
|
||||
class _LockTimeEditor:
|
||||
min_allowed_value = NLOCKTIME_MIN
|
||||
max_allowed_value = NLOCKTIME_MAX
|
||||
|
||||
def get_locktime(self) -> Optional[int]:
|
||||
raise NotImplementedError()
|
||||
|
||||
def set_locktime(self, x: Any,force=True) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
@classmethod
|
||||
def is_acceptable_locktime(cls, x: Any) -> bool:
|
||||
if not x: # e.g. empty string
|
||||
return True
|
||||
try:
|
||||
x = int(x)
|
||||
except Exception as e:
|
||||
return False
|
||||
return cls.min_allowed_value <= x <= cls.max_allowed_value
|
||||
|
||||
|
||||
class LockTimeRawEdit(QLineEdit, _LockTimeEditor):
|
||||
|
||||
def __init__(self, parent=None,time_edit=None):
|
||||
QLineEdit.__init__(self, parent)
|
||||
self.setFixedWidth(14 * char_width_in_lineedit())
|
||||
self.textChanged.connect(self.numbify)
|
||||
self.isdays = False
|
||||
self.isyears = False
|
||||
self.isblocks = False
|
||||
self.time_edit=time_edit
|
||||
|
||||
def replace_str(self,text):
|
||||
return str(text).replace('d','').replace('y','').replace('b','')
|
||||
|
||||
def checkbdy(self,s,pos,appendix):
|
||||
try:
|
||||
charpos = pos-1
|
||||
charpos = max(0,charpos)
|
||||
charpos = min(len(s)-1,charpos)
|
||||
if appendix == s[charpos]:
|
||||
s=self.replace_str(s)+appendix
|
||||
pos = charpos
|
||||
except Exception as e:
|
||||
pass
|
||||
return pos, s
|
||||
|
||||
def numbify(self):
|
||||
text = self.text().strip()
|
||||
#chars = '0123456789bdy' removed the option to choose locktime by block
|
||||
chars = '0123456789dy'
|
||||
pos = posx = self.cursorPosition()
|
||||
pos = len(''.join([i for i in text[:pos] if i in chars]))
|
||||
s = ''.join([i for i in text if i in chars])
|
||||
self.isdays = False
|
||||
self.isyears = False
|
||||
self.isblocks = False
|
||||
|
||||
pos,s = self.checkbdy(s,pos,'d')
|
||||
pos,s = self.checkbdy(s,pos,'y')
|
||||
pos,s = self.checkbdy(s,pos,'b')
|
||||
|
||||
if 'd' in s: self.isdays = True
|
||||
if 'y' in s: self.isyears = True
|
||||
if 'b' in s: self.isblocks = True
|
||||
|
||||
|
||||
if self.isdays: s= self.replace_str(s) + 'd'
|
||||
if self.isyears: s = self.replace_str(s) + 'y'
|
||||
if self.isblocks: s= self.replace_str(s) + 'b'
|
||||
|
||||
self.set_locktime(s,force=False)
|
||||
# setText sets Modified to False. Instead we want to remember
|
||||
# if updates were because of user modification.
|
||||
self.setModified(self.hasFocus())
|
||||
self.setCursorPosition(pos)
|
||||
|
||||
def get_locktime(self) -> Optional[str]:
|
||||
try:
|
||||
return str(self.text())
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
def set_locktime(self, x: Any,force=True) -> None:
|
||||
out = str(x)
|
||||
if 'd' in out:
|
||||
out = self.replace_str(x)+'d'
|
||||
elif 'y' in out:
|
||||
out = self.replace_str(x)+'y'
|
||||
elif 'b' in out:
|
||||
out = self.replace_str(x)+'b'
|
||||
else:
|
||||
try:
|
||||
out = int(x)
|
||||
except Exception as e:
|
||||
self.setText('')
|
||||
return
|
||||
out = max(out, self.min_allowed_value)
|
||||
out = min(out, self.max_allowed_value)
|
||||
self.setText(str(out))
|
||||
#try:
|
||||
# if self.time_edit and int(out)>self.time_edit.locktime_threshold and not force:
|
||||
# self.time_edit.set_index(1)
|
||||
#except:
|
||||
# pass
|
||||
|
||||
class LockTimeHeightEdit(LockTimeRawEdit):
|
||||
max_allowed_value = NLOCKTIME_BLOCKHEIGHT_MAX
|
||||
|
||||
def __init__(self, parent=None,time_edit=None):
|
||||
LockTimeRawEdit.__init__(self, parent)
|
||||
self.setFixedWidth(20 * char_width_in_lineedit())
|
||||
self.time_edit = time_edit
|
||||
|
||||
def paintEvent(self, event):
|
||||
super().paintEvent(event)
|
||||
panel = QStyleOptionFrame()
|
||||
self.initStyleOption(panel)
|
||||
textRect = self.style().subElementRect(QStyle.SE_LineEditContents, panel, self)
|
||||
textRect.adjust(2, 0, -10, 0)
|
||||
painter = QPainter(self)
|
||||
painter.setPen(ColorScheme.GRAY.as_color())
|
||||
painter.drawText(textRect, int(Qt.AlignRight | Qt.AlignVCenter), "height")
|
||||
|
||||
|
||||
def get_max_allowed_timestamp() -> int:
|
||||
ts = NLOCKTIME_MAX
|
||||
# Test if this value is within the valid timestamp limits (which is platform-dependent).
|
||||
# see #6170
|
||||
try:
|
||||
datetime.fromtimestamp(ts)
|
||||
except (OSError, OverflowError):
|
||||
ts = 2 ** 31 - 1 # INT32_MAX
|
||||
datetime.fromtimestamp(ts) # test if raises
|
||||
return ts
|
||||
|
||||
|
||||
class LockTimeDateEdit(QDateTimeEdit, _LockTimeEditor):
|
||||
min_allowed_value = NLOCKTIME_BLOCKHEIGHT_MAX + 1
|
||||
max_allowed_value = get_max_allowed_timestamp()
|
||||
|
||||
def __init__(self, parent=None,time_edit=None):
|
||||
QDateTimeEdit.__init__(self, parent)
|
||||
self.setMinimumDateTime(datetime.fromtimestamp(self.min_allowed_value))
|
||||
self.setMaximumDateTime(datetime.fromtimestamp(self.max_allowed_value))
|
||||
self.setDateTime(QDateTime.currentDateTime())
|
||||
self.time_edit = time_edit
|
||||
|
||||
def get_locktime(self) -> Optional[int]:
|
||||
dt = self.dateTime().toPyDateTime()
|
||||
locktime = int(time.mktime(dt.timetuple()))
|
||||
return locktime
|
||||
|
||||
def set_locktime(self, x: Any,force = False) -> None:
|
||||
if not self.is_acceptable_locktime(x):
|
||||
self.setDateTime(QDateTime.currentDateTime())
|
||||
return
|
||||
try:
|
||||
x = int(x)
|
||||
except Exception:
|
||||
self.setDateTime(QDateTime.currentDateTime())
|
||||
return
|
||||
dt = datetime.fromtimestamp(x)
|
||||
self.setDateTime(dt)
|
||||
Reference in New Issue
Block a user