forked from bitcoinafterlife/bal-electrum-plugin
Compare commits
1 Commits
d613438800
...
fix/balbui
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6b5738dfc |
476
qt.py
476
qt.py
@@ -1271,39 +1271,291 @@ class _LockTimeEditor:
|
|||||||
return cls.min_allowed_value <= x <= cls.max_allowed_value
|
return cls.min_allowed_value <= x <= cls.max_allowed_value
|
||||||
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
class HeirsLockTimeEdit(QWidget, _LockTimeEditor):
|
||||||
=======
|
valueEdited = pyqtSignal()
|
||||||
"""
|
locktime_threshold = 50000000
|
||||||
BalWizardDialog - A custom QDialog that implements a multi-step wizard interface.
|
|
||||||
|
|
||||||
This dialog provides a structured, step-by-step workflow for complex operations
|
def __init__(self, parent=None, default_index=1):
|
||||||
in the Bal Electrum plugin, guiding users through a sequence of pages with
|
QWidget.__init__(self, parent)
|
||||||
forward/backward navigation and validation.
|
|
||||||
|
|
||||||
Features:
|
hbox = QHBoxLayout()
|
||||||
- Multi-page navigation with Previous/Next buttons
|
self.setLayout(hbox)
|
||||||
- Automatic validation before proceeding to next page
|
hbox.setContentsMargins(0, 0, 0, 0)
|
||||||
- Progress tracking with visual indicators
|
hbox.setSpacing(0)
|
||||||
- Customizable page flow and validation rules
|
|
||||||
- Integration with BalDialog base class for consistent styling
|
|
||||||
|
|
||||||
Usage:
|
self.locktime_raw_e = LockTimeRawEdit(self, time_edit=self)
|
||||||
The wizard follows a standard pattern:
|
self.locktime_date_e = LockTimeDateEdit(self, time_edit=self)
|
||||||
1. Initialize with a list of page constructors
|
self.editors = [self.locktime_raw_e, self.locktime_date_e]
|
||||||
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:
|
self.combo = QComboBox()
|
||||||
pages (list): List of page constructors for the wizard
|
options = [_("Raw"), _("Date")]
|
||||||
current_page (int): Index of the currently displayed page
|
self.option_index_to_editor_map = {
|
||||||
page_widgets (list): List of instantiated page widgets
|
0: self.locktime_raw_e,
|
||||||
|
1: 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)
|
||||||
|
# spacer_widget = QWidget()
|
||||||
|
# spacer_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
# hbox.addWidget(spacer_widget)
|
||||||
|
|
||||||
|
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 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:
|
||||||
|
pass
|
||||||
|
return pos, s
|
||||||
|
|
||||||
|
def numbify(self):
|
||||||
|
text = self.text().strip()
|
||||||
|
# chars = '0123456789bdy' removed the option to choose locktime by block
|
||||||
|
chars = "0123456789dy"
|
||||||
|
pos = 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:
|
||||||
|
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:
|
||||||
|
self.setText("")
|
||||||
|
return
|
||||||
|
out = max(out, self.min_allowed_value)
|
||||||
|
out = min(out, self.max_allowed_value)
|
||||||
|
self.setText(str(out))
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
_NOT_GIVEN = object() # sentinel value
|
||||||
|
|
||||||
|
|
||||||
|
class PercAmountEdit(BTCAmountEdit):
|
||||||
|
def __init__(
|
||||||
|
self, decimal_point, is_int=False, parent=None, *, max_amount=_NOT_GIVEN
|
||||||
|
):
|
||||||
|
super().__init__(decimal_point, is_int, parent, max_amount=max_amount)
|
||||||
|
|
||||||
|
def numbify(self):
|
||||||
|
text = self.text().strip()
|
||||||
|
if text == "!":
|
||||||
|
self.shortcut.emit()
|
||||||
|
return
|
||||||
|
pos = self.cursorPosition()
|
||||||
|
chars = "0123456789%"
|
||||||
|
chars += DECIMAL_POINT
|
||||||
|
|
||||||
|
s = "".join([i for i in text if i in chars])
|
||||||
|
|
||||||
|
if "%" in s:
|
||||||
|
self.is_perc = True
|
||||||
|
s = s.replace("%", "")
|
||||||
|
else:
|
||||||
|
self.is_perc = False
|
||||||
|
|
||||||
|
if DECIMAL_POINT in s:
|
||||||
|
p = s.find(DECIMAL_POINT)
|
||||||
|
s = s.replace(DECIMAL_POINT, "")
|
||||||
|
s = s[:p] + DECIMAL_POINT + s[p : p + 8]
|
||||||
|
if self.is_perc:
|
||||||
|
s += "%"
|
||||||
|
|
||||||
|
self.setText(s)
|
||||||
|
self.setModified(self.hasFocus())
|
||||||
|
self.setCursorPosition(pos)
|
||||||
|
|
||||||
|
def _get_amount_from_text(self, text: str) -> Union[None, Decimal, int]:
|
||||||
|
try:
|
||||||
|
text = text.replace(DECIMAL_POINT, ".")
|
||||||
|
text = text.replace("%", "")
|
||||||
|
return (Decimal)(text)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_text_from_amount(self, amount):
|
||||||
|
out = super()._get_text_from_amount(amount)
|
||||||
|
if self.is_perc:
|
||||||
|
out += "%"
|
||||||
|
return out
|
||||||
|
|
||||||
|
def paintEvent(self, event):
|
||||||
|
QLineEdit.paintEvent(self, event)
|
||||||
|
if self.base_unit:
|
||||||
|
panel = QStyleOptionFrame()
|
||||||
|
self.initStyleOption(panel)
|
||||||
|
textRect = self.style().subElementRect(
|
||||||
|
QStyle.SubElement.SE_LineEditContents, panel, self
|
||||||
|
)
|
||||||
|
textRect.adjust(2, 0, -10, 0)
|
||||||
|
painter = QPainter(self)
|
||||||
|
painter.setPen(ColorScheme.GRAY.as_color())
|
||||||
|
if len(self.text()) == 0:
|
||||||
|
painter.drawText(
|
||||||
|
textRect,
|
||||||
|
int(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter),
|
||||||
|
self.base_unit() + " or perc value",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BalDialog(WindowModalDialog):
|
||||||
|
def __init__(self, parent, bal_plugin, title=None, icon="icons/bal32x32.png"):
|
||||||
|
self.parent = parent
|
||||||
|
WindowModalDialog.__init__(self, parent, title)
|
||||||
|
# WindowModalDialog.__init__(self,parent)
|
||||||
|
self.setWindowIcon(read_QIcon_from_bytes(bal_plugin.read_file(icon)))
|
||||||
|
|
||||||
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"):
|
||||||
@@ -1817,21 +2069,6 @@ 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"))
|
||||||
@@ -1839,7 +2076,6 @@ 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)
|
||||||
@@ -1849,46 +2085,15 @@ class BalBuildWillDialog(BalDialog):
|
|||||||
self.setMinimumWidth(600)
|
self.setMinimumWidth(600)
|
||||||
self.setMinimumHeight(100)
|
self.setMinimumHeight(100)
|
||||||
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
|
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
|
||||||
self.labels = []
|
|
||||||
=======
|
# Coda per i messaggi (thread-safe)
|
||||||
|
self._message_queue = []
|
||||||
# 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 = QTimer(self)
|
||||||
self._message_timer.setSingleShot(True)
|
self._message_timer.setSingleShot(True)
|
||||||
self._message_timer.setInterval(50) # Debounce interval: 50ms
|
self._message_timer.setInterval(50) # Debounce: 50ms
|
||||||
self._message_timer.timeout.connect(self._process_message_queue)
|
self._message_timer.timeout.connect(self._process_message_queue)
|
||||||
|
|
||||||
# Other initialization
|
self.labels = []
|
||||||
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
|
||||||
@@ -2338,87 +2543,41 @@ class BalBuildWillDialog(BalDialog):
|
|||||||
w.deleteLater()
|
w.deleteLater()
|
||||||
|
|
||||||
def msg_update(self):
|
def msg_update(self):
|
||||||
<<<<<<< HEAD
|
"""Aggiorna l'interfaccia con i messaggi in coda."""
|
||||||
self.clear_layout(self.labelsbox)
|
|
||||||
for label in self.labels:
|
|
||||||
label=label.replace("\n","<br>")
|
|
||||||
qlabel=QLabel(label)
|
|
||||||
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._message_queue.extend(self.labels)
|
||||||
self.labels = [] # Clear immediate labels after queuing
|
self.labels = []
|
||||||
if not self._message_timer.isActive():
|
if not self._message_timer.isActive():
|
||||||
self._message_timer.start()
|
self._message_timer.start()
|
||||||
|
|
||||||
def _process_message_queue(self):
|
def _process_message_queue(self):
|
||||||
"""Processes queued messages with debounce for efficient UI updates.
|
"""Processa i messaggi in coda con debounce."""
|
||||||
|
|
||||||
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:
|
if not self._message_queue:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Clear existing layout
|
# Pulisce il layout esistente
|
||||||
self.clear_layout(self.labelsbox)
|
self.clear_layout(self.labelsbox)
|
||||||
|
|
||||||
# Process all queued messages
|
# Aggiunge solo i messaggi nuovi
|
||||||
for text in self._message_queue:
|
for text in self._message_queue:
|
||||||
try:
|
formatted_text = text.replace("\n", "<br>")
|
||||||
# Format text for rich display
|
qlabel = QLabel(formatted_text)
|
||||||
formatted_text = text.replace("\n", "<br>")
|
qlabel.setWordWrap(True)
|
||||||
|
self.labelsbox.addWidget(qlabel)
|
||||||
# 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._message_queue = []
|
||||||
self.setMinimumHeight(min(30 * (len(self.labels) + 2), 400)) # Max height limit
|
self.setMinimumHeight(30*(len(self.labels)+2))
|
||||||
|
|
||||||
>>>>>>> origin/doc
|
|
||||||
|
|
||||||
def get_text(self):
|
def get_text(self):
|
||||||
return self.message_label.text()
|
return self.message_label.text()
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
"""Cleanup per evitare memory leak."""
|
||||||
|
if hasattr(self, '_message_timer') and self._message_timer:
|
||||||
|
self._message_timer.stop()
|
||||||
|
self._message_timer.deleteLater()
|
||||||
|
self.clear_layout(self.labelsbox)
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -3632,23 +3791,4 @@ 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