forked from bitcoinafterlife/bal-electrum-plugin
Compare commits
6 Commits
fix/balbui
...
45d8173cf7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45d8173cf7 | ||
|
|
b739bdab40 | ||
|
|
d613438800 | ||
|
|
a27df11dfa | ||
|
|
686c11080f | ||
|
|
be38c9b589 |
228
qt.py
228
qt.py
@@ -1271,6 +1271,41 @@ class _LockTimeEditor:
|
|||||||
return cls.min_allowed_value <= x <= cls.max_allowed_value
|
return cls.min_allowed_value <= x <= cls.max_allowed_value
|
||||||
|
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
"""
|
||||||
|
HeirsLockTimeEdit - A custom QWidget for editing locktime values in the context of heirs distribution.
|
||||||
|
|
||||||
|
This widget combines raw locktime editing with date-based selection and provides
|
||||||
|
additional functionality for managing locktime values in a heir inheritance scenario.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
- Supports both raw locktime values and human-readable date formats
|
||||||
|
- Emits valueEdited signal when the locktime value is edited
|
||||||
|
- Provides threshold-based validation for locktime values
|
||||||
|
- Integrates with heir distribution workflows
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
The class handles three types of locktime values:
|
||||||
|
1. **Timestamps**: Raw integer values representing Unix timestamps
|
||||||
|
2. **Day intervals**: Values ending with 'd' (e.g., '3d' = 3 days from now)
|
||||||
|
3. **Year intervals**: Values ending with 'y' (e.g., '2y' = 2 years from now)
|
||||||
|
|
||||||
|
Only these formats are valid:
|
||||||
|
- Examples: '1609459200', '3d', '2y'
|
||||||
|
- Invalid: 'invalid', '5m', '10x'
|
||||||
|
|
||||||
|
The widget automatically converts day/year intervals to appropriate timestamps.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
valueEdited (pyqtSignal): Signal emitted when the locktime value is edited
|
||||||
|
locktime_threshold (int): Minimum threshold value for locktime (default: 50000000)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parent: Optional parent QWidget
|
||||||
|
default_index (int): Default index for the combo box (default: 1)
|
||||||
|
"""
|
||||||
|
|
||||||
class HeirsLockTimeEdit(QWidget, _LockTimeEditor):
|
class HeirsLockTimeEdit(QWidget, _LockTimeEditor):
|
||||||
valueEdited = pyqtSignal()
|
valueEdited = pyqtSignal()
|
||||||
locktime_threshold = 50000000
|
locktime_threshold = 50000000
|
||||||
@@ -1557,6 +1592,38 @@ class BalDialog(WindowModalDialog):
|
|||||||
self.setWindowIcon(read_QIcon_from_bytes(bal_plugin.read_file(icon)))
|
self.setWindowIcon(read_QIcon_from_bytes(bal_plugin.read_file(icon)))
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
BalWizardDialog - A custom QDialog that implements a multi-step wizard interface.
|
||||||
|
|
||||||
|
This dialog provides a structured, step-by-step workflow for complex operations
|
||||||
|
in the Bal Electrum plugin, guiding users through a sequence of pages with
|
||||||
|
forward/backward navigation and validation.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
- Multi-page navigation with Previous/Next buttons
|
||||||
|
- Automatic validation before proceeding to next page
|
||||||
|
- Progress tracking with visual indicators
|
||||||
|
- Customizable page flow and validation rules
|
||||||
|
- Integration with BalDialog base class for consistent styling
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
The wizard follows a standard pattern:
|
||||||
|
1. Initialize with a list of page constructors
|
||||||
|
2. Each page is responsible for its own setup and validation
|
||||||
|
3. The dialog manages navigation and state between pages
|
||||||
|
4. Finalize action is triggered when all pages are completed
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
pages (list): List of page constructors for the wizard
|
||||||
|
current_page (int): Index of the currently displayed page
|
||||||
|
page_widgets (list): List of instantiated page widgets
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parent: Optional parent QWidget
|
||||||
|
title (str): Title to display in the dialog header
|
||||||
|
pages (list): List of page constructors (callables) for each step
|
||||||
|
"""
|
||||||
|
|
||||||
class BalWizardDialog(BalDialog):
|
class BalWizardDialog(BalDialog):
|
||||||
def __init__(self, bal_window: "BalWindow"):
|
def __init__(self, bal_window: "BalWindow"):
|
||||||
assert bal_window
|
assert bal_window
|
||||||
@@ -2069,6 +2136,21 @@ class BalBuildWillDialog(BalDialog):
|
|||||||
COLOR_OK = "#05ad05"
|
COLOR_OK = "#05ad05"
|
||||||
|
|
||||||
def __init__(self, bal_window, parent=None):
|
def __init__(self, bal_window, parent=None):
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
"""Initialize the Build Will dialog.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bal_window (BalWindow): The main application window
|
||||||
|
parent (QWidget, optional): Parent widget. Defaults to None.
|
||||||
|
|
||||||
|
Initializes:
|
||||||
|
- Main UI components (message label, container widget)
|
||||||
|
- Message queue system with debounce timer
|
||||||
|
- Layout management
|
||||||
|
- Network connection
|
||||||
|
"""
|
||||||
|
>>>>>>> origin/doc
|
||||||
if not parent:
|
if not parent:
|
||||||
parent = bal_window.window
|
parent = bal_window.window
|
||||||
BalDialog.__init__(self, parent, bal_window.bal_plugin, _("Building Will"))
|
BalDialog.__init__(self, parent, bal_window.bal_plugin, _("Building Will"))
|
||||||
@@ -2076,6 +2158,7 @@ class BalBuildWillDialog(BalDialog):
|
|||||||
self.updatemessage.connect(self.msg_update)
|
self.updatemessage.connect(self.msg_update)
|
||||||
self.bal_window = bal_window
|
self.bal_window = bal_window
|
||||||
self.bal_plugin = bal_window.bal_plugin
|
self.bal_plugin = bal_window.bal_plugin
|
||||||
|
<<<<<<< HEAD
|
||||||
self.message_label = QLabel(_("Building Will:"))
|
self.message_label = QLabel(_("Building Will:"))
|
||||||
self.vbox = QVBoxLayout(self)
|
self.vbox = QVBoxLayout(self)
|
||||||
self.vbox.addWidget(self.message_label,0)
|
self.vbox.addWidget(self.message_label,0)
|
||||||
@@ -2086,6 +2169,45 @@ class BalBuildWillDialog(BalDialog):
|
|||||||
self.setMinimumHeight(100)
|
self.setMinimumHeight(100)
|
||||||
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
|
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
|
||||||
self.labels = []
|
self.labels = []
|
||||||
|
=======
|
||||||
|
|
||||||
|
# Main message label
|
||||||
|
self.message_label = QLabel(_("Building Will:"))
|
||||||
|
self.vbox = QVBoxLayout(self)
|
||||||
|
self.vbox.addWidget(self.message_label, 0)
|
||||||
|
|
||||||
|
# Container for dynamic messages
|
||||||
|
self.qwidget = QWidget(self)
|
||||||
|
self.vbox.addWidget(self.qwidget, 1)
|
||||||
|
|
||||||
|
# Layout for messages with reduced spacing
|
||||||
|
self.labelsbox = QVBoxLayout(self.qwidget)
|
||||||
|
self.labelsbox.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.labelsbox.setSpacing(4) # Reduced spacing between messages
|
||||||
|
|
||||||
|
# Set minimum dimensions
|
||||||
|
self.setMinimumWidth(600)
|
||||||
|
self.setMinimumHeight(100)
|
||||||
|
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
|
||||||
|
|
||||||
|
# Message queue implementation for efficient updates
|
||||||
|
self._message_queue = [] # Thread-safe message queue
|
||||||
|
self._message_timer = QTimer(self)
|
||||||
|
self._message_timer.setSingleShot(True)
|
||||||
|
self._message_timer.setInterval(50) # Debounce interval: 50ms
|
||||||
|
self._message_timer.timeout.connect(self._process_message_queue)
|
||||||
|
|
||||||
|
# Other initialization
|
||||||
|
self.labels = [] # Immediate message storage
|
||||||
|
self.check_row = None
|
||||||
|
self.inval_row = None
|
||||||
|
self.build_row = None
|
||||||
|
self.sign_row = None
|
||||||
|
self.push_row = None
|
||||||
|
self.network = Network.get_instance()
|
||||||
|
self._stopping = False
|
||||||
|
|
||||||
|
>>>>>>> origin/doc
|
||||||
self.check_row = None
|
self.check_row = None
|
||||||
self.inval_row = None
|
self.inval_row = None
|
||||||
self.build_row = None
|
self.build_row = None
|
||||||
@@ -2535,22 +2657,83 @@ class BalBuildWillDialog(BalDialog):
|
|||||||
w.deleteLater()
|
w.deleteLater()
|
||||||
|
|
||||||
def msg_update(self):
|
def msg_update(self):
|
||||||
|
<<<<<<< HEAD
|
||||||
self.clear_layout(self.labelsbox)
|
self.clear_layout(self.labelsbox)
|
||||||
for text in self.labels:
|
for label in self.labels:
|
||||||
text = text.replace("\n","<br>")
|
label=label.replace("\n","<br>")
|
||||||
qlabel = QLabel(text)
|
qlabel=QLabel(label)
|
||||||
qlabel.setWordWrap(True)
|
self.labelsbox.addWidget(QLabel(label),1)
|
||||||
self.labelsbox.addWidget(qlabel)
|
|
||||||
self.setMinimumHeight(30*(len(self.labels)+2))
|
self.setMinimumHeight(30*(len(self.labels)+2))
|
||||||
|
|
||||||
def clear_layout(self, layout):
|
=======
|
||||||
while layout.count():
|
"""Updates the UI with new messages using a debounced queue system.
|
||||||
item = layout.takeAt(0)
|
|
||||||
widget = item.widget()
|
This method implements the following logic:
|
||||||
if widget is not None:
|
1. Adds all pending messages to the queue
|
||||||
widget.deleteLater()
|
2. Clears the immediate message storage
|
||||||
else:
|
3. Starts the debounce timer if not already active
|
||||||
self.clear_layout(item.layout())
|
|
||||||
|
The actual UI update happens in _process_message_queue after the
|
||||||
|
debounce interval to prevent excessive UI updates.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Thread-safe operation - can be called from any thread
|
||||||
|
"""
|
||||||
|
self._message_queue.extend(self.labels)
|
||||||
|
self.labels = [] # Clear immediate labels after queuing
|
||||||
|
if not self._message_timer.isActive():
|
||||||
|
self._message_timer.start()
|
||||||
|
|
||||||
|
def _process_message_queue(self):
|
||||||
|
"""Processes queued messages with debounce for efficient UI updates.
|
||||||
|
|
||||||
|
This method:
|
||||||
|
1. Clears the existing layout
|
||||||
|
2. Processes all queued messages
|
||||||
|
3. Updates the UI once with all new messages
|
||||||
|
4. Resets the queue
|
||||||
|
5. Adjusts dialog height based on content
|
||||||
|
|
||||||
|
The debounce interval (50ms) ensures rapid message bursts are
|
||||||
|
processed in a single batch, reducing UI flicker.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Called automatically by QTimer after debounce interval
|
||||||
|
"""
|
||||||
|
if not self._message_queue:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Clear existing layout
|
||||||
|
self.clear_layout(self.labelsbox)
|
||||||
|
|
||||||
|
# Process all queued messages
|
||||||
|
for text in self._message_queue:
|
||||||
|
try:
|
||||||
|
# Format text for rich display
|
||||||
|
formatted_text = text.replace("\n", "<br>")
|
||||||
|
|
||||||
|
# Create label with proper settings
|
||||||
|
label = QLabel(formatted_text)
|
||||||
|
label.setWordWrap(True)
|
||||||
|
label.setTextFormat(Qt.TextFormat.RichText)
|
||||||
|
label.setOpenExternalLinks(False) # Security
|
||||||
|
|
||||||
|
# Set size policy
|
||||||
|
label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||||
|
|
||||||
|
# Add to layout
|
||||||
|
self.labelsbox.addWidget(label)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# Log errors without interrupting processing
|
||||||
|
import logging
|
||||||
|
logging.error(f"Error creating label in BalBuildWillDialog: {e}")
|
||||||
|
|
||||||
|
# Reset queue and update dimensions
|
||||||
|
self._message_queue = []
|
||||||
|
self.setMinimumHeight(min(30 * (len(self.labels) + 2), 400)) # Max height limit
|
||||||
|
|
||||||
|
>>>>>>> origin/doc
|
||||||
|
|
||||||
def get_text(self):
|
def get_text(self):
|
||||||
return self.message_label.text()
|
return self.message_label.text()
|
||||||
@@ -3768,4 +3951,23 @@ class CheckAliveException(Exception):
|
|||||||
def __init__(self,timestamp_to_check):
|
def __init__(self,timestamp_to_check):
|
||||||
self.timestamp_to_check = timestamp_to_check
|
self.timestamp_to_check = timestamp_to_check
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
"""Explicit cleanup to prevent memory leaks.
|
||||||
|
|
||||||
|
This destructor ensures proper cleanup of:
|
||||||
|
- Message queue timer
|
||||||
|
- All widgets in the layout
|
||||||
|
- Network connections
|
||||||
|
|
||||||
|
Called automatically when the dialog is destroyed.
|
||||||
|
"""
|
||||||
|
if hasattr(self, '_message_timer') and self._message_timer:
|
||||||
|
self._message_timer.stop()
|
||||||
|
self._message_timer.deleteLater()
|
||||||
|
self.clear_layout(self.labelsbox)
|
||||||
|
|
||||||
|
>>>>>>> origin/doc
|
||||||
return "Check alive expired please update it: {}".format(datetime.fromtimestamp(self.timestamp_to_check).isoformat())
|
return "Check alive expired please update it: {}".format(datetime.fromtimestamp(self.timestamp_to_check).isoformat())
|
||||||
|
|||||||
Reference in New Issue
Block a user