forked from bitcoinafterlife/bal-electrum-plugin
Compare commits
6 Commits
fix/balbui
...
45d8173cf7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45d8173cf7 | ||
|
|
b739bdab40 | ||
|
|
d613438800 | ||
|
|
a27df11dfa | ||
|
|
686c11080f | ||
|
|
be38c9b589 |
211
qt.py
211
qt.py
@@ -1271,6 +1271,41 @@ class _LockTimeEditor:
|
||||
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):
|
||||
valueEdited = pyqtSignal()
|
||||
locktime_threshold = 50000000
|
||||
@@ -1557,6 +1592,38 @@ class BalDialog(WindowModalDialog):
|
||||
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):
|
||||
def __init__(self, bal_window: "BalWindow"):
|
||||
assert bal_window
|
||||
@@ -2069,6 +2136,21 @@ class BalBuildWillDialog(BalDialog):
|
||||
COLOR_OK = "#05ad05"
|
||||
|
||||
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:
|
||||
parent = bal_window.window
|
||||
BalDialog.__init__(self, parent, bal_window.bal_plugin, _("Building Will"))
|
||||
@@ -2076,6 +2158,7 @@ class BalBuildWillDialog(BalDialog):
|
||||
self.updatemessage.connect(self.msg_update)
|
||||
self.bal_window = bal_window
|
||||
self.bal_plugin = bal_window.bal_plugin
|
||||
<<<<<<< HEAD
|
||||
self.message_label = QLabel(_("Building Will:"))
|
||||
self.vbox = QVBoxLayout(self)
|
||||
self.vbox.addWidget(self.message_label,0)
|
||||
@@ -2086,6 +2169,45 @@ class BalBuildWillDialog(BalDialog):
|
||||
self.setMinimumHeight(100)
|
||||
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
|
||||
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.inval_row = None
|
||||
self.build_row = None
|
||||
@@ -2535,6 +2657,7 @@ class BalBuildWillDialog(BalDialog):
|
||||
w.deleteLater()
|
||||
|
||||
def msg_update(self):
|
||||
<<<<<<< HEAD
|
||||
self.clear_layout(self.labelsbox)
|
||||
for label in self.labels:
|
||||
label=label.replace("\n","<br>")
|
||||
@@ -2542,6 +2665,75 @@ class BalBuildWillDialog(BalDialog):
|
||||
self.labelsbox.addWidget(QLabel(label),1)
|
||||
self.setMinimumHeight(30*(len(self.labels)+2))
|
||||
|
||||
=======
|
||||
"""Updates the UI with new messages using a debounced queue system.
|
||||
|
||||
This method implements the following logic:
|
||||
1. Adds all pending messages to the queue
|
||||
2. Clears the immediate message storage
|
||||
3. Starts the debounce timer if not already active
|
||||
|
||||
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):
|
||||
return self.message_label.text()
|
||||
@@ -3759,4 +3951,23 @@ class CheckAliveException(Exception):
|
||||
def __init__(self,timestamp_to_check):
|
||||
self.timestamp_to_check = timestamp_to_check
|
||||
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())
|
||||
|
||||
Reference in New Issue
Block a user