diff --git a/__init__.py b/__init__.py
index 8b13789..e69de29 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1 +0,0 @@
-
diff --git a/bal.py b/bal.py
index e516c00..0c07e41 100644
--- a/bal.py
+++ b/bal.py
@@ -107,6 +107,8 @@ class BalPlugin(BasePlugin):
self.ALLOW_REPUSH = BalConfig(config, "bal_allow_repush", True)
self.FIRST_EXECUTION = BalConfig(config, "bal_first_execution", True)
self.WELIST_SERVER = BalConfig(config,"bal_welist_server","https://welist.bitcoin-after.life/")
+ self.EVENT_DESCRIPTION = BalConfig(config,"bal_event_description", "Will execution for $wallet_name\n $heirs_complete\n")
+ self.EVENT_SUMMARY = BalConfig(config,"bal_event_summary", "Will execution of $wallet_name\n")
self.WILLEXECUTORS = BalConfig(
config,
"bal_willexecutors",
@@ -184,9 +186,62 @@ class BalPlugin(BasePlugin):
@staticmethod
def default_will_settings():
+ will_settings ={"baltx_fees":100}
+ will_settings.update(BalPlugin.default_will_settings_absolute())
+ return will_settings
+ @staticmethod
+ def default_will_settings_absolute():
+ relative_dates=BalPlugin.default_will_settings_relative()
today = date.today()
dt = datetime(today.year, today.month, today.day, 0, 0, 0)
- threshold =(dt + timedelta(days=180)).timestamp()
- locktime =(dt + timedelta(days=365)).timestamp()
+ threshold =(dt + timedelta(days=BalTimestamp(relative_dates["threshold"]).duration_to_days())).timestamp()
+ locktime =(dt + timedelta(days=BalTimestamp(relative_dates["locktime"]).duration_to_days())).timestamp()
+ return {"threshold": threshold, "locktime": locktime}
+ @staticmethod
+ def default_will_settings_relative():
+ return {"threshold" : "30d", "locktime": "1y"}
- return {"baltx_fees": 100, "threshold": threshold, "locktime": locktime}
+
+class BalTimestamp:
+ value = None
+ unit = None
+ def __init__(self,value):
+ str_value = str(value)
+ if str_value and str_value[-1].lower() in ("y","d"):
+ self.value = int(str_value[:-1])
+ self.unit = str_value[-1]
+ else:
+ try:
+ self.value = int(value)
+ except Exception as _e:
+ self.value=1
+ self.unit = None
+
+ def duration_to_days(self):
+ return self.value*365 if self.unit=='y' else self.value
+
+ def to_date(self,from_date=None,reverse=False):
+ if self.unit is None:
+ return datetime.fromtimestamp(self.value)
+ else:
+ if from_date is None:
+ from_date = datetime.now()
+ if isinstance(from_date, (int, float)):
+ from_date = datetime.fromtimestamp(from_date)
+ reverse = 1 if not reverse else -1
+ return (from_date + (reverse * timedelta(days = self.duration_to_days()))).replace(hour=0,minute=0,second=0,microsecond=0)
+
+ def to_timestamp(self,from_date=None,reverse=False):
+ return self.to_date(from_date,reverse).timestamp()
+
+ def __str__(self):
+ if self.unit is None:
+ return datetime.fromtimestamp(self.value).isoformat()
+ else:
+ return f"{self.value}{self.unit}"
+
+ def __repr__(self):
+ if self.unit is None:
+ return datetime.fromtimestamp(self.value).to_date().timestamp()
+ else:
+ return f"{self.value}{self.unit}"
diff --git a/qt.py b/qt.py
index 59faedf..77eb867 100644
--- a/qt.py
+++ b/qt.py
@@ -5,135 +5,67 @@ BAL
Bitcoin after life
"""
-import subprocess
-import os
+
import copy
import enum
-import sys
+import os
+import subprocess
+import tempfile
import time
import traceback
-from datetime import datetime,timedelta,timezone
+from datetime import datetime, timezone
from decimal import Decimal
from functools import partial
-from typing import TYPE_CHECKING, Any, Callable, Mapping, Optional, Union
+from typing import Any, Callable, Mapping, Optional, Union
-from electrum.gui.qt.util import getSaveFileName
-from electrum.util import FileExportFailed
-from typing import Any, Optional, Union
-from PyQt6.QtWidgets import QWidget, QHBoxLayout, QLabel, QComboBox, QLineEdit, QDateTimeEdit
-from PyQt6.QtCore import pyqtSignal, QDateTime, Qt
-from PyQt6.QtGui import QPainter
-#from PyQt6.QtStyle import QStyle, QStyleOptionFrame
-import tempfile
-
-#DELETEME
-
-from PyQt6.QtCore import (
- QDateTime,
- QModelIndex,
- QPersistentModelIndex,
- Qt,
- pyqtSignal,
-)
-from PyQt6.QtGui import (
- QColor,
- QPainter,
- QPalette,
- QStandardItem,
- QStandardItemModel,
-)
-from PyQt6.QtWidgets import (
- QAbstractItemView,
- QCheckBox,
- QComboBox,
- QDateTimeEdit,
- QGridLayout,
- QHBoxLayout,
- QLabel,
- QLineEdit,
- QMenu,
- QMenuBar,
- QPushButton,
- QScrollArea,
- QSizePolicy,
- QSpinBox,
- QStyle,
- QStyleOptionFrame,
- QVBoxLayout,
- QWidget,
-)
-
-from electrum.bitcoin import (
- NLOCKTIME_BLOCKHEIGHT_MAX,
- NLOCKTIME_MAX,
- NLOCKTIME_MIN,
-)
-from electrum.gui.qt.amountedit import (
- BTCAmountEdit,
-)
-
-if TYPE_CHECKING:
- from electrum.gui.qt.main_window import ElectrumWindow
-
-from electrum.gui.qt.main_window import StatusBarButton
+from electrum.bitcoin import (NLOCKTIME_BLOCKHEIGHT_MAX, NLOCKTIME_MAX,
+ NLOCKTIME_MIN)
+from electrum.gui.qt.amountedit import BTCAmountEdit
+from electrum.gui.qt.main_window import ElectrumWindow, StatusBarButton
from electrum.gui.qt.my_treeview import MyTreeView
from electrum.gui.qt.password_dialog import PasswordDialog
from electrum.gui.qt.transaction_dialog import TxDialog
-from electrum.gui.qt.util import (
- Buttons,
- CancelButton,
- ColorScheme,
- EnterButton,
- HelpButton,
- MessageBoxMixin,
- OkButton,
- TaskThread,
- WindowModalDialog,
- char_width_in_lineedit,
- import_meta_gui,
- read_QIcon_from_bytes,
- read_QPixmap_from_bytes,
-)
+from electrum.gui.qt.util import (Buttons, CancelButton, ColorScheme,
+ EnterButton, HelpButton, MessageBoxMixin,
+ OkButton, TaskThread, WindowModalDialog,
+ char_width_in_lineedit, getSaveFileName,
+ import_meta_gui, read_QIcon_from_bytes,
+ read_QPixmap_from_bytes)
from electrum.i18n import _
-from electrum.logging import Logger, get_logger
+from electrum.logging import get_logger
from electrum.network import BestEffortRequestFailed, Network, TxBroadcastError
from electrum.payment_identifier import PaymentIdentifier
-from electrum.plugin import hook, run_hook
+from electrum.plugin import hook
from electrum.transaction import SerializationError, Transaction, tx_from_any
-from electrum.util import (
- DECIMAL_POINT,
- FileImportFailed,
- UserCancelled,
- decimal_point_to_base_unit_name,
- read_json_file,
- write_json_file,
-)
+from electrum.util import (DECIMAL_POINT, FileExportFailed, UserCancelled,
+ decimal_point_to_base_unit_name, read_json_file,
+ write_json_file)
+from PyQt6.QtCore import (QDateTime, QModelIndex, QPersistentModelIndex, Qt,
+ QTimer, pyqtSignal)
+from PyQt6.QtGui import (QColor, QPainter, QPalette, QStandardItem,
+ QStandardItemModel)
+from PyQt6.QtWidgets import (QAbstractItemView, QCheckBox, QComboBox,
+ QDateTimeEdit, QGridLayout, QHBoxLayout, QLabel,
+ QLineEdit, QTextEdit, QMenu, QMenuBar, QPushButton,
+ QScrollArea, QSizePolicy, QSpinBox,
+ QStackedWidget, QStyle, QStyleOptionFrame,
+ QVBoxLayout, QWidget)
-from .bal import BalPlugin
+from .bal import BalPlugin,BalTimestamp
from .heirs import HEIR_DUST_AMOUNT, HEIR_REAL_AMOUNT, Heirs
-from .util import Util
-from .will import (
- AmountException,
- HeirChangeException,
- HeirNotFoundException,
- NoHeirsException,
- NotCompleteWillException,
- NoWillExecutorNotPresent,
- TxFeesChangedException,
- Will,
- WillexecutorChangeException,
- WillExecutorNotPresent,
- WillExpiredException,
- WillItem,
-)
+from .util import Util
+from .will import (AmountException, HeirChangeException, HeirNotFoundException,
+ NoHeirsException, NotCompleteWillException,
+ NoWillExecutorNotPresent, TxFeesChangedException, Will,
+ WillexecutorChangeException, WillExecutorNotPresent,
+ WillExpiredException, WillItem)
from .willexecutors import Willexecutors
_logger = get_logger(__name__)
-class Plugin(BalPlugin, Logger):
+class Plugin(BalPlugin):
def __init__(self, parent, config, name):
- Logger.__init__(self)
_logger.info("INIT BALPLUGIN")
BalPlugin.__init__(self, parent, config, name)
self.bal_windows = {}
@@ -151,8 +83,10 @@ class Plugin(BalPlugin, Logger):
title=_("Success"),
)
return
- w = BalWindow(self, window)
- self.bal_windows[window.winId] = w
+ Util.print_var(window)
+ top_level_window= window.top_level_window
+ w = BalWindow(self, top_level_window)
+ self.bal_windows[top_level_window.winId] = w
for child in window.children():
if isinstance(child, QMenuBar):
for menu_child in child.children():
@@ -220,8 +154,9 @@ class Plugin(BalPlugin, Logger):
def get_window(self, window):
w = self.bal_windows.get(window.winId, None)
if w is None:
- w = BalWindow(self, window)
- self.bal_windows[window.winId] = w
+ win=window.top_level_window()
+ w = BalWindow(self, win)
+ self.bal_windows[win.winId] = w
return w
def requires_settings(self):
@@ -262,24 +197,22 @@ class Plugin(BalPlugin, Logger):
lbl_logo = QLabel()
lbl_logo.setPixmap(qicon)
- # heir_ping_willexecutors = bal_checkbox(self.PING_WILLEXECUTORS)
- # heir_ask_ping_willexecutors = bal_checkbox(self.ASK_PING_WILLEXECUTORS)
- # heir_no_willexecutor = bal_checkbox(self.NO_WILLEXECUTOR)
+ # heir_ping_willexecutors = BalCheckBox(self.PING_WILLEXECUTORS)
+ # heir_ask_ping_willexecutors = BalCheckBox(self.ASK_PING_WILLEXECUTORS)
+ # heir_no_willexecutor = BalCheckBox(self.NO_WILLEXECUTOR)
def on_multiverse_change():
self.update_all()
- # heir_enable_multiverse = bal_checkbox(self.ENABLE_MULTIVERSE,on_multiverse_change)
+ # heir_enable_multiverse = BalCheckBox(self.ENABLE_MULTIVERSE,on_multiverse_change)
- heir_hide_replaced = bal_checkbox(self.HIDE_REPLACED, on_multiverse_change)
+ heir_hide_replaced = BalCheckBox(self.HIDE_REPLACED, on_multiverse_change)
- heir_hide_invalidated = bal_checkbox(
- self.HIDE_INVALIDATED, on_multiverse_change
- )
+ heir_hide_invalidated = BalCheckBox(self.HIDE_INVALIDATED, on_multiverse_change)
heir_repush = QPushButton("Rebroadcast transactions")
heir_repush.clicked.connect(partial(self.broadcast_transactions, True))
bal_mode = QComboBox()
- options =["Easy","Advanced","Experimental"]
+ options = ["Easy", "Advanced", "Experimental"]
bal_mode.addItems(options)
grid = QGridLayout(d)
@@ -287,7 +220,7 @@ class Plugin(BalPlugin, Logger):
grid,
"Hide Replaced",
heir_hide_replaced,
- 1,
+ 1,
"Hide replaced transactions from will detail and list",
)
add_widget(
@@ -297,9 +230,40 @@ class Plugin(BalPlugin, Logger):
2,
"Hide invalidated transactions from will detail and list",
)
- add_widget(grid,"Calendar App", QLineEdit(self.CALENDAR_APP.get()),3,"Default app used to open calendar",)
-
- add_widget(grid,"Bal Mode",bal_mode,4,"choose bal mode")
+ add_widget(
+ grid,
+ "Calendar App",
+ BalLineEdit(self.CALENDAR_APP),
+ 3,
+ "Default app used to open calendar",
+ )
+ add_widget(
+ grid,
+ "Event summary",
+ BalLineEdit(self.EVENT_SUMMARY),
+ 4,
+ (
+ "Default message to be used in event summary\n"
+ "Variables:\n"
+ " $wallet_name: name of wallet\n"
+ " $heirs_complete: list of heirs name,address,amount\n"
+ #" $will_details_complete: will details(id transaction, mining fees, willexecutor, willexecutor fees, locktime)\n"
+ )
+ )
+ add_widget(
+ grid,
+ "Event sescription",
+ BalTextEdit(self.EVENT_DESCRIPTION),
+ 5,
+ (
+ "Default message to be used in event description\n"
+ "Variables:\n"
+ " $wallet_name: name of wallet\n"
+ " $heirs_complete: list of heirs name,address,amount\n"
+ #" $will_details_complete: will details(id transaction, mining fees, willexecutor, willexecutor fees, locktime)\n"
+ )
+ )
+ #add_widget(grid, "Bal Mode", bal_mode, 4, "choose bal mode")
# add_widget(
# grid,
@@ -365,8 +329,7 @@ class shown_cv:
self.value = value
-class BalWindow():
-
+class BalWindow:
def __init__(self, bal_plugin: "BalPlugin", window: "ElectrumWindow"):
self.bal_plugin = bal_plugin
self.window = window
@@ -384,6 +347,7 @@ class BalWindow():
if not self.will_settings:
self.will_settings = self.bal_plugin.WILL_SETTINGS.get()
Util.fix_will_settings_tx_fees(self.will_settings)
+ self.heirs = Heirs(self.wallet)
self.heirs_tab = self.create_heirs_tab()
self.will_tab = self.create_will_tab()
@@ -433,8 +397,8 @@ class BalWindow():
for wid, w in self.will.items():
self.willitems[wid] = WillItem(w, wallet=self.wallet)
if self.willitems:
- self.will_list.will = self.willitems
- self.will_list.update_will(self.willitems)
+ self.will_list_widget.will = self.willitems
+ self.will_list_widget.update_will(self.willitems)
self.will_tab.update()
def save_willitems(self):
@@ -452,6 +416,7 @@ class BalWindow():
)
if not self.heirs:
self.heirs = Heirs._validate(Heirs(self.wallet))
+ self.heirs_tab.update()
if not self.will:
self.will = self.wallet.db.get_dict("will")
Util.fix_will_tx_fees(self.will)
@@ -468,7 +433,7 @@ class BalWindow():
self.close_wallet()
return
- #if not self.will_settings:
+ # if not self.will_settings:
# self.will_settings = self.wallet.db.get_dict("will_settings")
# Util.fix_will_settings_tx_fees(self.will_settings)
@@ -489,15 +454,16 @@ class BalWindow():
self.willexecutor_dialog.show()
def create_heirs_tab(self):
+ if not self.heirs:
+ self.heirs = Heirs(self.wallet)
self.heir_list_widget = HeirListWidget(self, self.window)
-
tab = self.window.create_list_tab(self.heir_list_widget)
tab.is_shown_cv = shown_cv(False)
return tab
def create_will_tab(self):
- self.will_list = PreviewList(self, self.window, None)
- tab = self.window.create_list_tab(self.will_list)
+ self.will_list_widget = PreviewList(self, self.window, None)
+ tab = self.window.create_list_tab(self.will_list_widget)
tab.is_shown_cv = shown_cv(True)
return tab
@@ -516,20 +482,17 @@ class BalWindow():
heir_name = QLineEdit()
heir_name.setFixedWidth(32 * char_width_in_lineedit())
- if heir:
- heir_name.setText(str(heir_key))
heir_address = QLineEdit()
heir_address.setFixedWidth(32 * char_width_in_lineedit())
- if heir:
- heir_address.setText(str(heir[0]))
heir_amount = PercAmountEdit(self.window.get_decimal_point)
+
if heir:
+ heir_name.setText(str(heir_key))
+ heir_address.setText(str(heir[0]))
heir_amount.setText(
str(Util.decode_amount(heir[1], self.window.get_decimal_point()))
)
- self.heir_locktime = LockTimeWidget(self.bal_window, self, heir[2])
- if heir:
- self.heir_locktime.set_value(heir[2])
+ self.heir_locktime = LockTimeWidget(self, self.window, heir[2])
# heir_is_xpub = QCheckBox()
@@ -573,7 +536,7 @@ class BalWindow():
heir_name.text(),
heir_address.text(),
Util.encode_amount(heir_amount.text(), self.window.get_decimal_point()),
- str(self.heir_locktime.get_value()),
+ str(self.will_settings["locktime"]),
]
try:
self.set_heir(heir)
@@ -606,7 +569,10 @@ class BalWindow():
def import_heirs(self):
import_meta_gui(
- self.window, _("heirs"), self.heirs.import_file, self.heir_list_widget.update
+ self.window,
+ _("heirs"),
+ self.heirs.import_file,
+ self.heir_list_widget.update,
)
def export_heirs(self):
@@ -632,7 +598,6 @@ class BalWindow():
# willtodelete = []
# willtoappend = {}
try:
- self.init_class_variables()
self.willexecutors = Willexecutors.get_willexecutors(
self.bal_plugin, update=False, bal_window=self
)
@@ -712,22 +677,48 @@ class BalWindow():
def show_critical(self, text):
self.window.show_critical(text)
- def update_setting_widgets(self,new_value,field,update_all=False,update_will_dialog=False,update_heirs_dialog=False,):
- new_value = self.will_settings[field] = new_value if new_value else BalPlugin.default_will_settings()[field]
- self.will_settings[field]=new_value
- self.bal_plugin.WILL_SETTINGS.set(self.will_settings)
- if update_all or update_will_dialog:
- try:
- self.will_list.will_settings_widget.widgets[field].set_value(new_value)
- except Exception as e:
- _logger.error(f"error setting will_settings_widgets[{field}].set_value({new_value})")
+ def update_combo_setting_widgets(
+ self,
+ new_value,
+ field,
+ update_all=False,
+ update_will_dialog=False,
+ update_heirs_dialog=False,
+ ):
+ if (update_all or update_will_dialog) and hasattr(self,'will_list_widget'):
+ self.update_widget_combo(self.will_list_widget,field,new_value)
+ if update_all or update_heirs_dialog and hasattr(self,'heir_list_widget'):
+ self.update_widget_combo(self.heir_list_widget,field,new_value)
+
+
+ def update_widget_combo(self,widget,field,value):
+ try:
+ widget.will_settings_widget.widgets[field].set_index(value)
+ except Exception as _e:
+ pass
+ def update_widget_value(self, widget, field, value):
+ try:
+ widget.will_settings_widget.widgets[field].set_value(value)
+ except Exception as _e:
+ pass
+
+ def update_setting_widgets(
+ self,
+ new_value,
+ field,
+ update_all=False,
+ update_will_dialog=False,
+ update_heirs_dialog=False,
+ ):
if update_all or update_heirs_dialog:
- try:
- self.heir_list_widget.will_settings_widget.widgets[field].set_value(new_value)
- except Exception as e:
- _logger.error(f"error updating settings widget {e}")
+ self.update_widget_value(self.heir_list_widget, field, new_value)
+ if update_all or update_will_dialog:
+ self.update_widget_value(self.will_list_widget, field, new_value)
+ self.will_settings[field] = new_value
+ self.bal_plugin.WILL_SETTINGS.set(self.will_settings)
def init_heirs_to_locktime(self, multiverse=False):
+ #pass
for heir in self.heirs:
h = self.heirs[heir]
if not multiverse:
@@ -737,24 +728,22 @@ class BalWindow():
if not self.heirs:
raise NoHeirsException(_("Heirs are not defined"))
try:
- self.date_to_check = Util.parse_locktime_string(
- self.will_settings["threshold"]
- )
+ self.date_to_check = BalTimestamp(self.will_settings['threshold']).to_timestamp()
# found = False
self.locktime_blocks = self.bal_plugin.LOCKTIME_BLOCKS.get()
self.current_block = Util.get_current_height(self.wallet.network)
- self.block_to_check=0
+ self.block_to_check = 0
self.no_willexecutor = self.bal_plugin.NO_WILLEXECUTOR.get()
self.willexecutors = Willexecutors.get_willexecutors(
self.bal_plugin, update=True, bal_window=self, task=False
)
if self.date_to_check < datetime.now().timestamp():
- raise CheckAliveException(self.date_to_check)
+ raise CheckAliveError(self.date_to_check)
self.init_heirs_to_locktime(self.bal_plugin.ENABLE_MULTIVERSE.get())
-
except Exception as e:
+ log_error(e, self)
_logger.error(f"init_class_variables: {e}")
raise e
@@ -782,8 +771,12 @@ class BalWindow():
f"In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts.{e}"
)
)
- except CheckAliveException:
- self.show_error(_("CheckAlive is in the past please update it to a date in the future but less than locktime"))
+ except CheckAliveError:
+ self.show_error(
+ _(
+ "CheckAlive is in the past please update it to a date in the future but less than locktime"
+ )
+ )
return
locktime = Util.parse_locktime_string(self.will_settings["locktime"])
if locktime < self.date_to_check:
@@ -902,7 +895,8 @@ class BalWindow():
self.show_message(_("No transactions to invalidate"))
def on_failure(exec_info):
- log_error(exec_info,self.bal_window)
+ log_error(exec_info, self.bal_window)
+
fee_per_byte = self.will_settings.get("baltx_fees", 1)
task = partial(Will.invalidate_will, self.willitems, self.wallet, fee_per_byte)
msg = _("Calculating Transactions")
@@ -995,7 +989,7 @@ class BalWindow():
self.willitems[txid].tx = copy.deepcopy(tx)
self.will[txid] = self.willitems[txid].to_dict()
try:
- self.will_list.update()
+ self.will_list_widget.update()
except Exception:
pass
if callback:
@@ -1005,7 +999,7 @@ class BalWindow():
raise e
def on_failure(exec_info):
- log_error(exec_info,self.bal_window)
+ log_error(exec_info, self.bal_window)
password = self.get_wallet_password()
task = partial(self.sign_transactions, password)
@@ -1017,7 +1011,7 @@ class BalWindow():
def broadcast_transactions(self, force=False):
def on_success(sulcess):
- self.will_list.update()
+ self.will_list_widget.update()
if sulcess:
_logger.info("error, some transaction was not sent")
self.show_warning(_("Some transaction was not broadcasted"))
@@ -1028,13 +1022,13 @@ class BalWindow():
)
def on_failure(exec_info):
- log_error(exec_info,self.bal_window)
- #a,b,c = err
- #_logger.error(f"fail to broadcast transactions:{err}")
- #_logger.error(f"error: {b}")
- #_logger.error("traceback ")
- #tb = c
- #while tb is not None:
+ log_error(exec_info, self.bal_window)
+ # a,b,c = err
+ # _logger.error(f"fail to broadcast transactions:{err}")
+ # _logger.error(f"error: {b}")
+ # _logger.error("traceback ")
+ # tb = c
+ # while tb is not None:
# frame = tb.tb_frame
# _logger.error("file:", frame.f_code.co_filename)
# _logger.error("name:", frame.f_code.co_name)
@@ -1085,10 +1079,7 @@ class BalWindow():
)
w = self.willitems[wid]
w.set_check_willexecutor(
- Willexecutors.check_transaction(
- wid,
- w.we["url"]
- )
+ Willexecutors.check_transaction(wid, w.we["url"])
)
self.waiting_dialog.update(
"checked {} - {} : {}".format(
@@ -1116,7 +1107,7 @@ class BalWindow():
def import_will(self):
def sulcess():
- self.will_list.update_will(self.willitems)
+ self.will_list_widget.update_will(self.willitems)
import_meta_gui(self.window, _("will"), self.import_json_file, sulcess)
@@ -1130,7 +1121,7 @@ class BalWindow():
self.update_will(willitems)
except Exception as e:
raise e
- raise FileImportFailed(_("Invalid will file"))
+ # raise FileImportFailed(_("Invalid will file"))
def check_transactions_task(self, will):
start = time.time()
@@ -1141,7 +1132,6 @@ class BalWindow():
w.set_check_willexecutor(Willexecutors.check_transaction(wid, w.we["url"]))
-
if time.time() - start < 3:
time.sleep(3 - (time.time() - start))
@@ -1152,9 +1142,9 @@ class BalWindow():
pass
def on_failure(exec_info):
- log_error(exec_info,self.bal_window)
- #_logger.error(f"error checking transactions {e}")
- #pass
+ log_error(exec_info, self)
+ # _logger.error(f"error checking transactions {e}")
+ # pass
task = partial(self.check_transactions_task, will)
msg = _("Check Transaction")
@@ -1163,7 +1153,7 @@ class BalWindow():
)
self.waiting_dialog.exe()
- def update_willexecutor_list_widget(self,parent,willexecutors):
+ def update_willexecutor_list_widget(self, parent, willexecutors):
try:
parent.willexecutors_list.update(willexecutors)
parent.will_executor_list_widget.update()
@@ -1171,23 +1161,25 @@ class BalWindow():
_logger.error(f"impossible to update will_executor_list_widget {e}")
self.will_executors.update()
- def download_list(self,willexecutors,fn_on_success,fn_on_failure=None):
+ def download_list(self, willexecutors, fn_on_success, fn_on_failure=None):
def on_success(result):
- #self.willexecutors.update(result)
+ # self.willexecutors.update(result)
fn_on_success(result)
+
def on_failure(exec_info):
fn_on_failure(exec_info)
if not fn_on_failure:
- fn_on_success=log_error
+ fn_on_success = log_error
welist_server = self.bal_plugin.WELIST_SERVER.get()
- task = partial(Willexecutors.download_list,willexecutors,welist_server)
+ task = partial(Willexecutors.download_list, willexecutors, welist_server)
msg = _(f"Downloadinf willexecutors list from {welist_server}")
self.waiting_dialog = BalWaitingDialog(
self, msg, task, on_success, on_failure, exe=False
)
self.waiting_dialog.exe()
+
def ping_willexecutors_task(self, wes):
_logger.info("ping willexecutots task")
pinged = []
@@ -1220,14 +1212,15 @@ class BalWindow():
else:
pinged.append(url)
- def ping_willexecutors(self, wes, fn_on_success,fn_on_failure=None):
+ def ping_willexecutors(self, wes, fn_on_success, fn_on_failure=None):
def on_success(result):
fn_on_success(result)
def on_failure(exec_info):
fn_on_failure(exec_info)
+
if not fn_on_failure:
- fn_on_failure=log_error
+ fn_on_failure = log_error
_logger.info("ping willexecutors")
task = partial(self.ping_willexecutors_task, wes)
msg = _("Ping Will-Executors")
@@ -1245,14 +1238,12 @@ class BalWindow():
Will.add_willtree(self.willitems)
all_utxos = self.wallet.get_utxos()
utxos_list = Will.utxos_strs(all_utxos)
- Will.check_invalidated(
- self.willitems, utxos_list, self.wallet
- )
+ Will.check_invalidated(self.willitems, utxos_list, self.wallet)
- self.will_list.update_will(self.willitems)
+ self.will_list_widget.update_will(self.willitems)
self.heirs_tab.update()
self.will_tab.update()
- self.will_list.update()
+ self.will_list_widget.update()
except Exception as e:
_logger.error(f"error while updating window: {e}")
@@ -1263,41 +1254,83 @@ def add_widget(grid, label, widget, row, help_):
grid.addWidget(HelpButton(help_), row, 2)
+class ClickableLabel(QLabel):
+ doubleClicked = pyqtSignal()
+
+ def mouseDoubleClickEvent(self, event):
+ self.doubleClicked.emit()
+ super().mouseDoubleClickEvent(event)
+
class BalTxFeesWidget(QWidget):
valueChanged = pyqtSignal()
- def __init__(self,bal_window,parent,value=None):
+ current_value = None
+
+ def __init__(self, bal_window, parent, value=None):
super().__init__(parent)
- self.bal_window=bal_window
+ self.bal_window = bal_window
layout = QHBoxLayout(self)
- self.txfee_widget=QSpinBox(self)
+ self.txfee_widget = QSpinBox(self)
self.txfee_widget.setMinimum(1)
self.txfee_widget.setMaximum(10000)
- value = value if value else self.bal_window.will_settings['baltx_fees']
- self.txfee_widget.setValue(value)
+ value = (
+ value
+ if value
+ else self.bal_window.bal_plugin.WILL_SETTINGS.get()["baltx_fees"]
+ )
+ self.set_value(value)
+ self.default_value = self.bal_window.bal_plugin.default_will_settings()[
+ "baltx_fees"
+ ]
self.txfee_widget.valueChanged.connect(self.on_heir_tx_fees)
- layout.addWidget(QLabel("Tx Fees:"))
+ label = ClickableLabel("Tx Fees:")
+ label.doubleClicked.connect(self.doubleclick)
+ layout.addWidget(label)
layout.addWidget(self.txfee_widget)
+ def doubleclick(self, event=None):
+ pass
def get_value(self):
return self.txfee_widget.value()
- def set_value(self,value):
- if not value:
- value=self.bal_window.bal_plugin.default_will_settings()['baltx_fees']
- return self.txfee_widget.setValue(value)
+ def set_value(self, value, emit=True):
+ value = int(value) if value is not None else 20
+ if getattr(self, "_updating", False):
+ return
- def on_heir_tx_fees(self,update_all=False):
+ self._updating = True
try:
- if update_all:
- self.bal_window.update_setting_widgets(self.get_value(),'baltx_fees',True)
- except Exception as e:
- _logger.error("error while trying to update txfees",e )
+ self.current_value = value
+ spin = self.txfee_widget
+ spin.blockSignals(True)
+ spin.setValue(value)
+ spin.blockSignals(False)
+
+ finally:
+ self._updating = False
+
+ if emit:
+ spin.valueChanged.emit(value)
+
+ def on_heir_tx_fees(self, value=None, update_all=True):
+ if value != self.current_value:
+ try:
+ self.set_value(value)
+ if update_all:
+ self.bal_window.update_setting_widgets(
+ self.get_value(), "baltx_fees", True
+ )
+ except Exception as e:
+ _logger.error(f"error while trying to update txfees{e}")
+ log_error(e)
+ else:
+ pass
class _LockTimeEditor:
min_allowed_value = NLOCKTIME_MIN
max_allowed_value = NLOCKTIME_MAX
+ alarm = None
def get_value(self) -> Optional[int]:
raise NotImplementedError()
@@ -1311,9 +1344,10 @@ class _LockTimeEditor:
return True
try:
x = int(x)
- except Exception:
+ except Exception as _e:
return False
return cls.min_allowed_value <= x <= cls.max_allowed_value
+
@staticmethod
def get_max_allowed_timestamp() -> int:
ts = NLOCKTIME_MAX
@@ -1326,29 +1360,34 @@ class _LockTimeEditor:
datetime.fromtimestamp(ts) # test if raises
return ts
+
class BalTimeEditWidget(QWidget, _LockTimeEditor):
valueEdited = pyqtSignal()
_setting_locktime = False
- _current_value = None
+ current_value = None
+ current_index = None
+ default_value = None
- help_text = "if you choose Raw, you can insert various options based on suffix:\n" \
- + " - d: number of days after current day(ex: 1d means tomorrow)\n" \
+ help_text = (
+ "if you choose Raw, you can insert various options based on suffix:\n"
+ + " - d: number of days after current day(ex: 1d means tomorrow)\n"
+ " - y: number of years after currrent day(ex: 1y means one year from today)\n"
- label_text ="locktime"
+ )
+ label_text = None
+ base_field = None
def __init__(self, bal_window, parent, default_locktime=None):
super().__init__(parent)
- self.bal_window=bal_window
+ self.bal_window = bal_window
hbox = QHBoxLayout()
self.setLayout(hbox)
hbox.setContentsMargins(0, 0, 0, 0)
hbox.setSpacing(0)
- self.setMinimumWidth(50*char_width_in_lineedit())
+ self.setMinimumWidth(40 * char_width_in_lineedit())
self.locktime_raw_e = TimeRawEditWidget(self, time_edit=self)
self.locktime_date_e = LockTimeDateEdit(self, time_edit=self)
self.editors = [self.locktime_raw_e, self.locktime_date_e]
-
self.combo = QComboBox()
options = [_("Raw"), _("Date")]
self.option_index_to_editor_map = {
@@ -1358,103 +1397,124 @@ class BalTimeEditWidget(QWidget, _LockTimeEditor):
self.combo.addItems(options)
default_index = 0
if not default_locktime:
- default_locktime = self.bal_window.will_settings[self.base_field]
+ default_locktime = self.bal_window.bal_plugin.WILL_SETTINGS.get()[self.base_field]
try:
int(default_locktime)
- default_index=1
- except Exception as e:
- default_index=0
+ default_index = 1
+ except Exception:
+ default_index = 0
hbox.addWidget(QLabel(self.label_text))
hbox.addWidget(HelpButton(self.help_text))
self.combo.currentIndexChanged.connect(self.on_current_index_changed)
- self.editor = self.option_index_to_editor_map[default_index]
- self.editor.set_value(default_locktime, force=False)
- self.combo.setCurrentIndex(default_index)
- self.on_current_index_changed(default_index)
+ for w in self.editors:
+ w.setVisible(False)
+ w.setEnabled(False)
+
+ self.editor = self.option_index_to_editor_map[default_index]
+ self.editor.setVisible(True)
+ self.editor.setEnabled(True)
+ self.set_index(default_index)
+ #self.on_current_index_changed(default_index)
+ self.set_value(default_locktime)
+ self.current_value=default_locktime
hbox.addWidget(self.combo)
for w in self.editors:
hbox.addWidget(w)
hbox.addStretch(1)
- # spacer_widget = QWidget()
+ # spssscer_widget = QWidget()
# spacer_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
# hbox.addWidget(spacer_widget)
self.valueEdited.connect(lambda: self.update_will_settings(True))
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)
+ #self.combo.currentIndexChanged.connect(self.valueEdited.emit)
+ def update_will_settings(
+ self,
+ update_all=False,
+ update_will_dialog=False,
+ update_heirs_dialog=False,
+ ):
+ self.bal_window.update_setting_widgets(
+ self.get_value(),
+ self.base_field,
+ update_all,
+ update_will_dialog,
+ update_heirs_dialog,
+ )
-
- def update_will_settings(self,update_all=False,update_will_dialog=False,update_heirs_dialog=False,):
- self.bal_window.update_setting_widgets(self.get_value(),self.base_field,update_all,update_will_dialog,update_heirs_dialog)
-
- def on_current_index_changed(self, i,force=False):
+ def on_current_index_changed(self, i):
+ self.current_index = i
for w in self.editors:
w.setVisible(False)
w.setEnabled(False)
- #prev_locktime = self.editor.get_value()
+ # prev_locktime = self.editor.get_value()
self.editor = self.option_index_to_editor_map[i]
- #if self.editor.is_acceptable_locktime(prev_locktime):
- # self.editor.set_value(prev_locktime, force=False)
+ if i==0:
+ self.editor.set_value(self.bal_window.bal_plugin.default_will_settings_relative()[self.base_field])
+ else:
+ self.editor.set_value(self.bal_window.bal_plugin.default_will_settings_absolute()[self.base_field])
+ self.valueEdited.emit()
+ # if self.editor.is_acceptable_locktime(prev_locktime):
+ # self.editor.set_value(prev_locktime, force=False)
self.editor.setVisible(True)
self.editor.setEnabled(True)
+ self.bal_window.update_combo_setting_widgets(i, self.base_field,True)
def get_value(self) -> Optional[str]:
val = self.editor.get_value()
+ #return self.current_value
return val
- def set_index(self, index,force = False):
- self.combo.setCurrentIndex(index)
- self.on_current_index_changed(index,force)
+ def set_index(self, index):
+ if self.current_index != index:
+ self.combo.setCurrentIndex(index)
+ #self.on_current_index_changed(index, force)
- def set_value(self, x: Any, force=None,update_all=False,update_will_dialog=False,update_heirs_dialog=False) -> None:
- current_val=self.get_value()
- if self._setting_locktime:
- return
- newtime=x
- current = self.get_value()
- if x==current:
- return
+ def set_value(
+ self,
+ x: Any,
+ force=None,
+ update_all=False,
+ update_will_dialog=False,
+ update_heirs_dialog=False,
+ ) -> None:
+ if not x:
+ if self.current_index == 0:
+ x = self.bal_window.bal_plugin.default_will_settings_relative()[self.base_field]
+ elif self.current_index == 1:
+ x = self.bal_window.bal_plugin.default_will_settings_absolute()[self.base_field]
+ if x != self.get_value():
+ self.editor.set_value(x)
+ self.current_value = x
+ self.bal_window.update_setting_widgets(x, self.base_field)
- self._setting_locktime = True
- try:
- if not newtime:
- newtime=self.bal_window.bal_plugin.WILL_SETTINGS.get()[self.base_field]
-
- try:
- int(x)
- if force is not None:
- self.set_index(1,True)
- except Exception:
- if isinstance(x,str):
- if force is not None:
- self.set_index(0,True)
- self.current_locktime = newtime
- self.editor.set_value(newtime, force=False)
- self.update_will_settings(update_all,update_will_dialog,update_heirs_dialog)
- finally:
- self._setting_locktime = False
class TimeRawEditWidget(QWidget):
editingFinished = pyqtSignal()
- def __init__(self,parent,time_edit=None):
+
+ def is_acceptable_locktime(self, value):
+ return True
+
+ def __init__(self, parent, time_edit=None):
super().__init__(parent)
- self.editor=LockTimeRawEdit(parent,time_edit)
- self.label=QLabel("")
- self.label.setFixedWidth(17 * char_width_in_lineedit())
- self.layout=QHBoxLayout(self)
+ self.editor = LockTimeRawEdit(parent, time_edit)
+ self.label = QLabel("")
+ self.label.setFixedWidth(10 * char_width_in_lineedit())
+ self.layout = QHBoxLayout(self)
self.layout.addWidget(self.editor)
self.layout.addWidget(self.label)
self.editor.editingFinished.connect(self.editingFinished.emit)
- self.get_value=self.editor.get_value
- self.set_value=self.editor.set_value
+ self.get_value = self.editor.get_value
+ self.set_value = self.editor.set_value
+
class LockTimeRawEdit(QLineEdit, _LockTimeEditor):
def __init__(self, parent=None, time_edit=None):
QLineEdit.__init__(self, parent)
- self.setFixedWidth(6 * char_width_in_lineedit())
+ self.setFixedWidth(12 * char_width_in_lineedit())
self.textChanged.connect(self.numbify)
self.isdays = False
self.isyears = False
@@ -1508,16 +1568,13 @@ class LockTimeRawEdit(QLineEdit, _LockTimeEditor):
self.blockSignals(True)
self.setText(s)
self.blockSignals(False)
- #self.set_value(s, force=False)
- self._current_value = s
+ # self.set_value(s, force=False)
+ self.current_value = s
# 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_absolute_value(self):
- return Util.locktime_to_str(Util.parse_locktime_string(self.get_value()))
-
def get_value(self) -> Optional[str]:
try:
return str(self.text())
@@ -1525,9 +1582,12 @@ class LockTimeRawEdit(QLineEdit, _LockTimeEditor):
return None
def set_value(self, x: Any, force=True) -> None:
- self.setText(str(x))
+ if x != self.get_value():
+ self.blockSignals(True)
+ self.setText(str(x))
+ self.blockSignals(False)
+ self.numbify()
- self.numbify()
class LockTimeDateEdit(QDateTimeEdit, _LockTimeEditor):
min_allowed_value = NLOCKTIME_BLOCKHEIGHT_MAX + 1
@@ -1537,13 +1597,21 @@ class LockTimeDateEdit(QDateTimeEdit, _LockTimeEditor):
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.setDateTime(QDateTime.currentDateTime())
self.time_edit = time_edit
def get_value(self) -> Optional[int]:
- dt = self.dateTime().toPyDateTime()
- locktime = int(time.mktime(dt.timetuple()))
- return locktime
+ #dt = self.dateTime().toPyDateTime()
+ #locktime = int(time.mktime(dt.timetuple()))
+ #p#
+ #dt = dt_edit.dateTime()
+ ## QDateTimets = dt.toSecsSinceEpoch()
+
+ dt = self.dateTime()
+ _ts = dt.toSecsSinceEpoch()
+
+ return _ts
+
def set_value(self, x: Any, force=False) -> None:
if not self.is_acceptable_locktime(x):
@@ -1551,161 +1619,178 @@ class LockTimeDateEdit(QDateTimeEdit, _LockTimeEditor):
return
try:
x = int(x)
- except Exception:
- self.setDateTime(QDateTime.currentDateTime())
- return
- dt = datetime.fromtimestamp(x)
- self.setDateTime(dt)
- self.alarm=dt
+ except Exception as e:
+ x = QDateTime.currentDateTime().timestamp()
+ finally:
+ _dt = datetime.fromtimestamp(x)
+ #if self.alarm != dt:
+ self.setDateTime(_dt)
+ self.alarm = _dt
+
class ThresholdTimeWidget(BalTimeEditWidget):
- help_text = ("Check to ask for invalidation.\n\n"
- "When less then this time is missing, ask to invalidate.\n"
- "If you fail to invalidate during this time, your transactions will be delivered to your heirs.\n\n"
- f"{BalTimeEditWidget.help_text}")
- label_text="Check Alive:"
+ help_text = (
+ "Check to ask for invalidation.\n\n"
+ "When less then this time is missing, ask to invalidate.\n"
+ "If you fail to invalidate during this time, your transactions will be delivered to your heirs.\n\n"
+ f"{BalTimeEditWidget.help_text}"
+ )
+ label_text = "Check Alive:"
base_field = "threshold"
+ def __init__(self, bal_window, parent, init_value=None):
+ if init_value is None:
+ init_value = bal_window.bal_plugin.WILL_SETTINGS.get()["threshold"]
+ super().__init__(bal_window, parent, init_value)
+ self.default_value = self.bal_window.bal_plugin.default_will_settings()[
+ "threshold"
+ ]
+
+
class LockTimeWidget(BalTimeEditWidget):
- help_text = ("Set Locktime for transactions.\n"
- "Any time is needed transaction will be anticipated by 1day\n"
- f"{BalTimeEditWidget.help_text}")
+ help_text = (
+ "Set Locktime for transactions.\n"
+ "Any time is needed transaction will be anticipated by 1day\n"
+ f"{BalTimeEditWidget.help_text}"
+ )
label_text = "Delivery Time:"
base_field = "locktime"
+ def __init__(self, bal_window, parent, init_value=None):
+ if init_value is None:
+ init_value = bal_window.bal_plugin.WILL_SETTINGS.get()["locktime"]
+ super().__init__(bal_window, parent, init_value)
+ self.default_value = self.bal_window.bal_plugin.default_will_settings()[
+ "locktime"
+ ]
+
+
class WillSettingsWidget(QWidget):
- widgets={}
- def __init__(self,bal_window,parent,layout_type='h'):
- super().__init__(parent)
- self.bal_window=bal_window
- box=QHBoxLayout(self) if layout_type=='h' else QVBoxLayout(self)
- self.calendar_button=QPushButton(_("Calendar"))
- self.calendar_button.setIcon(read_QIcon_from_bytes(self.bal_window.bal_plugin.read_file("icons/calendar.png")))
+ def __init__(self, bal_window: "BalWindow", parent, layout_type="h"):
+ self.widgets = {}
+ QWidget.__init__(self, parent)
+ self.bal_window = bal_window
+ box = QHBoxLayout(self) if layout_type == "h" else QVBoxLayout(self)
+
+ self.calendar_button = QPushButton()
+ self.calendar_button.setIcon(
+ read_QIcon_from_bytes(
+ self.bal_window.bal_plugin.read_file("icons/calendar.png")
+ )
+ )
self.calendar_button.clicked.connect(self.open_or_save_calendar)
- self.widgets['locktime']=LockTimeWidget(bal_window,self)
- self.widgets['threshold']= ThresholdTimeWidget(bal_window,self)
- self.widgets['baltx_fees'] =BalTxFeesWidget(bal_window,self)
- box.addWidget(self.widgets['locktime'])
- box.addWidget(self.widgets['threshold'])
- box.addWidget(self.calendar_button)
- box.addWidget(self.widgets['baltx_fees'])
- self.widgets['locktime'].valueEdited.connect(self.on_locktime_change)
- self.widgets['threshold'].valueEdited.connect(self.on_locktime_change)
+ self.widgets["locktime"] = LockTimeWidget(bal_window, self)
+ self.widgets["threshold"] = ThresholdTimeWidget(bal_window, self)
+ self.widgets["locktime"].valueEdited.connect(self.on_locktime_change)
+ self.widgets["threshold"].valueEdited.connect(self.on_locktime_change)
+ # self.widgets['baltx_fees'].valueChange.connect(self.bal_window.update_setting_widgets)
self.on_locktime_change()
-
- @staticmethod
- def write_temp_ics(content):
- fd, path = tempfile.mkstemp(prefix="event_", suffix=".ics")
- with os.fdopen(fd, "w", encoding="utf-8") as f:
- f.write(content)
- return path
+ self.widgets["baltx_fees"] = BalTxFeesWidget(bal_window, self)
+ if not hasattr(bal_window, "txfee_widgets"):
+ bal_window.txfee_widgets = []
- def open_with_default_app(self,path):
- try:
- subprocess.check_call([self.bal_window.bal_plugin.CALENDAR_APP.get(), path])
- return True
- except Exception as e:
- return False
- @staticmethod
- def save_to_cwd(path, filename="evento.ics"):
- target = os.path.abspath(filename)
- # se il file esiste, sovrascrive
- with open(path, "rb") as src, open(target, "wb") as dst:
- dst.write(src.read())
- return target
-
- @staticmethod
- def format_time(time):
- return time.astimezone(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
-
- @staticmethod
- def ical_escape(text: str) -> str:
- # escape per RFC5545: backslash, ; , newlines
- text = text.replace("\\", "\\\\").replace(";", r"\;").replace(",", r"\,").replace("\n", r"\n")
- return WillSettingsWidget.fold_ical_line(text)
-
- @staticmethod
- def fold_ical_line(line: str, limit: int = 75) -> str:
- # ritorna linee separate da CRLF e folding con spazio iniziale sulle righe successive
- encoded = line.encode("utf-8")
- parts = []
- while len(encoded) > limit:
- # taglia senza spezzare byte UTF-8
- cut = limit
- while (encoded[cut] & 0xC0) == 0x80: # byte di continuazione UTF-8
- cut -= 1
- parts.append(encoded[:cut].decode("utf-8"))
- encoded = encoded[cut:]
- parts.append(encoded.decode("utf-8"))
- return "\r\n ".join(parts)
+ w = self.widgets["baltx_fees"]
+ if w not in bal_window.txfee_widgets:
+ bal_window.txfee_widgets.append(w)
+ box.addWidget(self.widgets["locktime"])
+ box.addWidget(self.widgets["threshold"])
+ box.addWidget(self.calendar_button)
+ box.addWidget(self.widgets["baltx_fees"])
+ def create_alarms(self, alarm_start, alarm_end):
+ days = (alarm_end - alarm_start).days+1
+ lines = []
+ for i in range(1, days):
+ lines.extend(
+ [
+ "BEGIN:VALARM",
+ f"TRIGGER;RELATED=END:-P{i}D",
+ "ACTION:DISPLAY",
+ # f"DESCRIPTION:{self.bal_window.bal_plugin.ALARM_DESCRIPTION.get()}",
+ "END:VALARM",
+ ]
+ )
+ return lines
def open_or_save_calendar(self):
- now = self.format_time(datetime.now())
+ now = BalCalendar.format_time(datetime.now())
- alarm_start = self.format_time(self.widgets['threshold'].alarm)
- alarm_end = self.format_time(self.widgets['locktime'].alarm)
+ locktime = self.widgets["locktime"].alarm
+ threshold = self.widgets["threshold"].alarm
+ alarm_end = BalCalendar.format_time(locktime)
+ alarm_start = BalCalendar.format_time(threshold)
+ days_difference = (locktime - threshold).days
- heirs_details = "\n".join(f"{heir} - {self.bal_window.heirs[heir][1]}" for heir in self.bal_window.heirs)
- event_description = self.ical_escape(f"Your will for wallet {self.bal_window.wallet} is going to expire\n{heirs_details}")
- uid = f"{int(datetime.now().timestamp())}-{os.getpid()}@local" # UID univoco semplice
- summary = self.ical_escape(f"Bitcoin After Life {self.bal_window.wallet} expiry")
+ heirs_details = "\n".join(f"{heir} - {self.bal_window.heirs[heir][0]}, {self.bal_window.heirs[heir][1]}" for heir in self.bal_window.heirs)
+ event_description = BalCalendar.ical_escape(
+ f"{self.bal_window.bal_plugin.EVENT_DESCRIPTION.get()}".replace("$wallet_name",str(self.bal_window.wallet)).replace("$heirs_complete",heirs_details)
+ )
+ event_description =f"{event_description}{heirs_details}"
+ uid = f"bal-{str(self.bal_window.wallet)}"
+ summary = BalCalendar.ical_escape(
+ f"{self.bal_window.bal_plugin.EVENT_SUMMARY.get()}".replace("$wallet_name",str(self.bal_window.wallet))
+ )
lines = [
"BEGIN:VCALENDAR",
"VERSION:2.0",
- "PRODID:-//Example//EN",
+ f"PRODID:-//Bitcoin After Life//Electrum Plugin/{BalPlugin.version}",
"BEGIN:VEVENT",
f"UID:{uid}",
f"DTSTAMP:{now}",
- f"DTSTART:{alarm_start}",
+ f"DTSTART:{alarm_end}",
f"DTEND:{alarm_end}",
f"SUMMARY:{summary}",
f"DESCRIPTION:{event_description}",
+ ]
+ lines.extend(self.create_alarms(threshold, locktime))
+ lines.extend([
"END:VEVENT",
"END:VCALENDAR",
- ]
+ ])
ics_content = "\r\n".join(lines) + "\r\n"
- temp_path = self.write_temp_ics(ics_content)
- opened = self.open_with_default_app(temp_path)
+ temp_path = BalCalendar.write_temp_ics(ics_content)
+ opened = BalCalendar.open_with_default_app(
+ self.bal_window.bal_plugin.CALENDAR_APP.get(), temp_path
+ )
if opened:
_logger.info(f"File opened with default app: {temp_path}")
else:
- export_meta_gui(self.bal_window.window, f"{self.base_field}_event.csv", self.save_to_cwd)
+ export_meta_gui(
+ self.bal_window.window, f"{self.base_field}_event.csv", self.save_to_cwd
+ )
def on_locktime_change(self):
- threshold_value = str(self.widgets['threshold'].get_value())
- locktime_value = str(self.widgets['locktime'].get_value())
+ locktime = self.widgets["locktime"].get_value()
+ threshold = self.widgets["threshold"].get_value()
+ locktime = BalTimestamp(locktime)
+ threshold = BalTimestamp(threshold)
- dt=None
- if threshold_value[-1] in ['d','y']:
- ts=int(threshold_value[:-1])
- min_locktime = min(Will.get_min_locktime(self.bal_window.willitems,NLOCKTIME_MAX),Util.parse_locktime_string(locktime_value))
- threshold_value = ts*365 if threshold_value[-1] == 'y' else ts
- dt = datetime.fromtimestamp(min_locktime)
- dt = dt - timedelta(days = threshold_value)
- self.widgets['threshold'].editor.label.setText(dt.strftime("%Y-%m-%d"))
- self.widgets['threshold'].alarm = dt
- else:
- self.widgets['threshold'].alarm = datetime.fromtimestamp(Util.parse_locktime_string(self.widgets['threshold'].get_value()))
+ min_locktime = min(
+ Will.get_min_locktime(self.bal_window.willitems, NLOCKTIME_MAX),
+ locktime.to_timestamp(),
+ )
+ td = threshold.to_date(min_locktime, True)
+ self.widgets["threshold"].alarm=td
+ self.bal_window.will_settings["real_threshold"]=td.timestamp()
+ try:
+ self.widgets["threshold"].editor.label.setText(td.strftime("%Y-%m-%d"))
+ except Exception as _e:
+ pass
- if locktime_value[-1] in ['d','y']:
- lt = int(locktime_value[:-1])
- locktime_value = lt*365 if locktime_value[-1] == 'y' else lt
- dt =datetime.now()
- dt += timedelta(days= locktime_value)
- dt=dt.replace(hour=0,minute=0,second=0,microsecond=0)
- self.widgets['locktime'].editor.label.setText(dt.strftime("%Y-%m-%d"))
- self.widgets['locktime'].alarm = dt
- else:
- self.widgets['locktime'].alarm=datetime.fromtimestamp(Util.parse_locktime_string(self.widgets['locktime'].get_value()))
+ td = locktime.to_date()
+ alarm = BalTimestamp(min_locktime).to_date()
+ self.widgets["locktime"].alarm=alarm
+ self.bal_window.will_settings["real_locktime"]=td.timestamp()
+ try:
+ self.widgets["locktime"].editor.label.setText(td.strftime("%Y-%m-%d"))
+ except Exception as _e:
+ pass
class PercAmountEdit(BTCAmountEdit):
- def __init__(
- self, decimal_point, is_int=False, parent=None, *, max_amount=None
- ):
+ def __init__(self, decimal_point, is_int=False, parent=None, *, max_amount=None):
super().__init__(decimal_point, is_int, parent, max_amount=max_amount)
def numbify(self):
@@ -1776,12 +1861,14 @@ class BalDialog(WindowModalDialog):
WindowModalDialog.__init__(self, parent, title)
# WindowModalDialog.__init__(self,parent)
self.setWindowIcon(read_QIcon_from_bytes(bal_plugin.read_file(icon)))
- def closeEvent(self,event):
- self._stopping=True
+
+ def closeEvent(self, event):
+ self._stopping = True
if self.thread:
self.thread.stop()
- def hideEvent(self,event):
- self._stopping=True
+
+ def hideEvent(self, event):
+ self._stopping = True
if self.thread:
self.thread.stop()
@@ -1871,9 +1958,7 @@ class BalWizardDialog(BalDialog):
def closeEvent(self, event):
self._stopping = True
- self.thread.stop()
-
- #self.bal_window.heir_list_widget.will_settings_widget.update_will_settings()
+ # self.bal_window.heir_list_widget.will_settings_widget.update_will_settings()
pass
@@ -2010,7 +2095,7 @@ class BalWizardWEDownloadWidget(BalWizardWidget):
if index == 2:
- def doNothing():
+ def do_nothing():
self.bal_window.willexecutors.update(self.willexecutors)
Willexecutors.save(
self.bal_window.bal_plugin, self.bal_window.willexecutors
@@ -2021,7 +2106,7 @@ class BalWizardWEDownloadWidget(BalWizardWidget):
self.bal_window.window,
_("willexecutors"),
self.import_json_file,
- doNothing,
+ do_nothing,
)
if index < 2:
@@ -2029,8 +2114,10 @@ class BalWizardWEDownloadWidget(BalWizardWidget):
def on_success(willexecutors):
def ping_on_success(result):
ping_on_done()
+
def ping_on_failure(exec_info):
ping_on_done()
+
def ping_on_done():
if index < 1:
for we in self.bal_window.willexecutors:
@@ -2041,10 +2128,10 @@ class BalWizardWEDownloadWidget(BalWizardWidget):
)
self.bal_window.ping_willexecutors(
- self.bal_window.willexecutors,ping_on_success,ping_on_failure
+ self.bal_window.willexecutors, ping_on_success, ping_on_failure
)
- self.bal_window.download_list(self.bal_window.willexecutors,on_success)
+ self.bal_window.download_list(self.bal_window.willexecutors, on_success)
elif index == 3:
# TODO DO NOTHING
@@ -2087,10 +2174,7 @@ class BalWizardLocktimeAndFeeWidget(BalWizardWidget):
widget = QWidget()
layout = QVBoxLayout(widget)
- layout.addWidget(LockTimeWidget(self.bal_window,widget))
- layout.addWidget(ThresholdTimeWidget(self.bal_window,widget))
- layout.addWidget(BalTxFeesWidget(self.bal_window,widget))
-
+ layout.addWidget(WillSettingsWidget(self.bal_window, self, "v"))
spacer_widget = QWidget()
spacer_widget.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
@@ -2184,8 +2268,23 @@ class BalBlockingWaitingDialog(BalDialog):
# close popup
self.accept()
+class BalLineEdit(QLineEdit):
+ def __init__(self,variable):
+ QLineEdit.__init__(self)
+ self.setText(variable.get())
+ def on_edit():
+ variable.set(self.text())
+ self.editingFinished.connect(on_edit)
-class bal_checkbox(QCheckBox):
+class BalTextEdit(QTextEdit):
+ def __init__(self,variable):
+ QTextEdit.__init__(self)
+ self.setPlainText(variable.get())
+ def on_edit():
+ variable.set(self.toPlainText())
+ self.textChanged.connect(on_edit)
+
+class BalCheckBox(QCheckBox):
def __init__(self, variable, on_click=None):
QCheckBox.__init__(self)
self.setChecked(variable.get())
@@ -2193,7 +2292,7 @@ class bal_checkbox(QCheckBox):
def on_check(v):
variable.set(v == 2)
- variable.get()
+ #variable.get()
if self.on_click:
self.on_click()
@@ -2216,10 +2315,10 @@ class BalBuildWillDialog(BalDialog):
self.bal_plugin = bal_window.bal_plugin
self.message_label = QLabel(_("Building Will:"))
self.vbox = QVBoxLayout(self)
- self.vbox.addWidget(self.message_label,0)
+ self.vbox.addWidget(self.message_label, 0)
self.qwidget = QWidget(self)
- self.vbox.addWidget(self.qwidget,1)
- self.labelsbox=QVBoxLayout(self.qwidget)
+ self.vbox.addWidget(self.qwidget, 1)
+ self.labelsbox = QVBoxLayout(self.qwidget)
self.setMinimumWidth(600)
self.setMinimumHeight(100)
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
@@ -2249,24 +2348,29 @@ class BalBuildWillDialog(BalDialog):
self.exec()
def task_phase1(self):
- txs=None
+ txs = None
_logger.debug("close plugin phase 1 started")
varrow = self.msg_set_status("checking variables")
try:
self.bal_window.init_class_variables()
- except CheckAliveException as cae:
+ except CheckAliveError as cae:
fee_per_byte = self.bal_window.will_settings.get("baltx_fees", 1)
tx = Will.invalidate_will(
self.bal_window.willitems, self.bal_window.wallet, fee_per_byte
)
if tx:
- _logger.debug("during phase1 CAE: {}, Continue to invalidate".format(cae))
- self.msg_set_checking(self.msg_warning("Check Alive Threshold Passed: you have to Invalidate your old Will"))
+ _logger.debug(
+ "during phase1 CAE: {}, Continue to invalidate".format(cae)
+ )
+ self.msg_set_checking(
+ self.msg_warning(
+ "Check Alive Threshold Passed: you have to Invalidate your old Will"
+ )
+ )
else:
raise cae
return None, tx
-
except Exception as e:
raise e
try:
@@ -2336,7 +2440,7 @@ class BalBuildWillDialog(BalDialog):
_("Skipped"),
self.COLOR_ERROR,
)
- return False,None
+ return False, None
self.bal_window.check_will()
for wid in Will.only_valid(self.bal_window.willitems):
@@ -2446,7 +2550,9 @@ class BalBuildWillDialog(BalDialog):
self.bal_plugin = self.bal_window.bal_plugin
w = self.bal_window.willitems[wid]
- w.set_check_willexecutor(Willexecutors.check_transaction(wid, w.we["url"]))
+ w.set_check_willexecutor(
+ Willexecutors.check_transaction(wid, w.we["url"])
+ )
row = self.msg_edit_row(
"checked {} - {} : {}".format(
self.bal_window.willitems[wid].we["url"],
@@ -2466,7 +2572,8 @@ class BalBuildWillDialog(BalDialog):
self.msg_set_pushing(self.msg_error(e))
self.wait(10)
if not self._stopping:
- self.loop_push()
+ pass
+ # self.loop_push()
def invalidate_task(self, password, bal_window, tx):
_logger.debug(f"invalidate tx: {tx}")
@@ -2484,7 +2591,7 @@ class BalBuildWillDialog(BalDialog):
except Exception as e:
(f"exception:{e}")
self.msg_set_invalidating(f"Error: {e}")
- raise Exception("Impossible to sign")
+ raise Exception("Impossible to sign") from e
def on_success_invalidate(self, success):
self.thread.add(
@@ -2496,7 +2603,7 @@ class BalBuildWillDialog(BalDialog):
def on_success_phase1(self, result):
self.have_to_sign, tx = list(result)
- #if not tx:
+ # if not tx:
# self.msg_edit_row(self.msg_error("Error, no tx was built"))
# return
_logger.debug("have to sign {}".format(self.have_to_sign))
@@ -2574,7 +2681,7 @@ class BalBuildWillDialog(BalDialog):
self.msg_set_pushing(self.msg_ok())
except Exception as e:
- #td = traceback.format_exc()
+ # td = traceback.format_exc()
self.msg_set_pushing(self.msg_error(e))
self.msg_edit_row(self.msg_ok())
self.wait(5)
@@ -2585,13 +2692,13 @@ class BalBuildWillDialog(BalDialog):
def on_error_phase1(self, error):
self.bal_window.update_all()
- a,b,c = error
+ a, b, c = error
self.msg_edit_row(self.msg_error(f"Error: {b}"))
_logger.error(f"error phase1: {b}")
def on_error_phase2(self, error):
self.bal_window.upade_all()
- a,b,c = error
+ a, b, c = error
self.msg_edit_row(self.msg_error(f"Error: {b}"))
_logger.error(f"error phase2: {b}")
@@ -2649,7 +2756,6 @@ class BalBuildWillDialog(BalDialog):
self.labels.append(line)
row = len(self.labels) - 1
-
self.updatemessage.emit()
return row
@@ -2661,7 +2767,7 @@ class BalBuildWillDialog(BalDialog):
pass
self.updatemessage.emit()
- #def clear_layout(self,layout):
+ # def clear_layout(self,layout):
# while layout.count():
# item = layout.takeAt(0)
# w = item.widget()
@@ -2669,7 +2775,7 @@ class BalBuildWillDialog(BalDialog):
# w.setParent(None)
# w.deleteLater()
- #def msg_update(self):
+ # def msg_update(self):
# self.clear_layout(self.labelsbox)
# for label in self.labels:
# label=label.replace("\n","
")
@@ -2688,10 +2794,9 @@ class BalBuildWillDialog(BalDialog):
full_text = "
".join(self.labels).replace("\n", "
")
self.message_label.setText(full_text)
self.message_label.adjustSize()
- #self.setMinimumHeight(len(self.labels)*40)
+ # self.setMinimumHeight(len(self.labels)*40)
self.resize(self.sizeHint())
-
def get_text(self):
return self.message_label.text()
@@ -2718,8 +2823,10 @@ class HeirListWidget(MyTreeView, MessageBoxMixin):
def createEditor(self, parent, option, index):
return QLineEdit(parent)
+
def setEditorData(self, editor, index):
editor.setText(index.data())
+
def setModelData(self, editor, model, index):
model.setData(index, editor.text())
@@ -2737,7 +2844,6 @@ class HeirListWidget(MyTreeView, MessageBoxMixin):
self.decimal_point = bal_window.window.get_decimal_point()
self.bal_window = bal_window
-
try:
self.setModel(QStandardItemModel(self))
self.sortByColumn(self.Columns.NAME, Qt.SortOrder.AscendingOrder)
@@ -2857,10 +2963,13 @@ class HeirListWidget(MyTreeView, MessageBoxMixin):
if key == current_key:
idx = self.model().index(row_count, self.Columns.NAME)
set_current = QPersistentModelIndex(idx)
+ try:
+ self.will_settings_widget.on_locktime_change()
+ except Exception as e:
+ pass
self.set_current_idx(set_current)
# FIXME refresh loses sort order; so set "default" here:
self.filter()
- run_hook("update_heirs_tab", self)
def refresh_row(self, key, row):
# nothing to update here
@@ -2876,13 +2985,14 @@ class HeirListWidget(MyTreeView, MessageBoxMixin):
menu.addAction(_("Import"), self.bal_window.import_heirs)
menu.addAction(_("Export"), lambda: self.bal_window.export_heirs())
- widget = QWidget()
- layout = QHBoxLayout(widget)
- self.will_settings_widget=WillSettingsWidget(self.bal_window,widget)
-
- layout.addWidget(self.will_settings_widget)
newHeirButton = QPushButton(_("New Heir"))
newHeirButton.clicked.connect(self.bal_window.new_heir_dialog)
+
+ widget = QWidget(self)
+ layout = QHBoxLayout(widget)
+ self.will_settings_widget = WillSettingsWidget(self.bal_window, self)
+
+ layout.addWidget(self.will_settings_widget)
layout.addWidget(newHeirButton)
toolbar.insertWidget(2, widget)
@@ -2894,7 +3004,7 @@ class HeirListWidget(MyTreeView, MessageBoxMixin):
self.bal_window.prepare_will()
-class PreviewList(MyTreeView):
+class PreviewList(MyTreeView, MessageBoxMixin):
class Columns(MyTreeView.BaseColumnsEnum):
LOCKTIME = enum.auto()
TXID = enum.auto()
@@ -2911,29 +3021,39 @@ class PreviewList(MyTreeView):
ROLE_HEIR_KEY = Qt.ItemDataRole.UserRole + 2000
key_role = ROLE_HEIR_KEY
+ def createEditor(self, parent, option, index):
+ return QLineEdit(parent)
+
+ def setEditorData(self, editor, index):
+ editor.setText(index.data())
+
+ def setModelData(self, editor, model, index):
+ model.setData(index, editor.text())
+
def __init__(self, bal_window: "BalWindow", parent, will):
super().__init__(
parent=parent,
+ main_window=bal_window.window,
stretch_column=self.Columns.TXID,
)
- self.parent = parent
+ # self.parent = parent
self.bal_window = bal_window
self.decimal_point = bal_window.window.get_decimal_point
- self.setModel(QStandardItemModel(self))
- self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
if will is not None:
self.will = will
else:
self.will = bal_window.willitems
- self.wallet = bal_window.window.wallet
- self.setModel(QStandardItemModel(self))
- self.sortByColumn(self.Columns.LOCKTIME, Qt.SortOrder.AscendingOrder)
+ try:
+ self.setModel(QStandardItemModel(self))
+ self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
+ self.sortByColumn(self.Columns.NAME, Qt.SortOrder.AscendingOrder)
+ except Exception as e:
+ pass
+
self.setSortingEnabled(True)
self.std_model = self.model()
- self.config = bal_window.bal_plugin.config
- self.bal_plugin = self.bal_window.bal_plugin
self.update()
@@ -2968,7 +3088,7 @@ class PreviewList(MyTreeView):
_("check ").format(column_title),
lambda: self.check_transactions(selected_keys),
)
- if self.bal_plugin.ENABLE_MULTIVERSE.get():
+ if self.bal_window.bal_plugin.ENABLE_MULTIVERSE.get():
try:
self.importaction = self.menu.addAction(
_("Import"), self.import_will
@@ -3037,7 +3157,7 @@ class PreviewList(MyTreeView):
tx = bal_tx.tx
labels = [""] * len(self.Columns)
- labels[self.Columns.LOCKTIME] = Util.locktime_to_str(tx.locktime)
+ labels[self.Columns.LOCKTIME] = str(BalTimestamp(tx.locktime))
labels[self.Columns.TXID] = txid
we = "None"
if bal_tx.we:
@@ -3090,6 +3210,10 @@ class PreviewList(MyTreeView):
set_current = tmp
self.sortByColumn(self.Columns.LOCKTIME, Qt.SortOrder.AscendingOrder)
self.setSortingEnabled(True)
+ try:
+ self.will_settings_widget.on_locktime_change()
+ except Exception as _e:
+ pass
def create_toolbar(self, config):
toolbar, menu = self.create_toolbar_with_menu("")
@@ -3097,7 +3221,7 @@ class PreviewList(MyTreeView):
menu.addAction(_("Display"), self.bal_window.preview_modal_dialog)
menu.addAction(_("Sign"), self.ask_password_and_sign_transactions)
menu.addAction(_("Export"), self.export_will)
- if self.bal_plugin.ENABLE_MULTIVERSE.get():
+ if self.bal_window.bal_plugin.ENABLE_MULTIVERSE.get():
self.importaction = menu.addAction(_("Import"), self.import_will)
menu.addAction(_("Broadcast"), self.broadcast)
menu.addAction(_("Check"), self.check)
@@ -3105,16 +3229,15 @@ class PreviewList(MyTreeView):
wizard = QPushButton(_("Setup Wizard"))
wizard.clicked.connect(self.bal_window.init_wizard)
- #display = QPushButton(_("Display"))
- #display.clicked.connect(self.bal_window.preview_modal_dialog)
+ # display = QPushButton(_("Display"))
+ # display.clicked.connect(self.bal_window.preview_modal_dialog)
refresh = QPushButton(_("Refresh"))
refresh.clicked.connect(self.check)
- widget = QWidget()
+ widget = QWidget(self)
hlayout = QHBoxLayout(widget)
- self.will_settings_widget=WillSettingsWidget(self.bal_window,widget)
-
+ self.will_settings_widget = WillSettingsWidget(self.bal_window, self)
hlayout.addWidget(self.will_settings_widget)
hlayout.addWidget(wizard)
hlayout.addWidget(refresh)
@@ -3175,95 +3298,94 @@ class PreviewList(MyTreeView):
self.update()
-class PreviewDialog(BalDialog, MessageBoxMixin):
- def __init__(self, bal_window, will):
- self.parent = bal_window.window
- BalDialog.__init__(
- self, bal_window=bal_window, bal_plugin=bal_window.bal_plugin
- )
- self.bal_plugin = bal_window.bal_plugin
- self.gui_object = self.bal_plugin.gui_object
- self.config = self.bal_plugin.config
- self.bal_window = bal_window
- self.wallet = bal_window.window.wallet
- self.format_amount = bal_window.window.format_amount
- self.base_unit = bal_window.window.base_unit
- self.format_fiat_and_units = bal_window.window.format_fiat_and_units
- self.fx = bal_window.window.fx
- self.format_fee_rate = bal_window.window.format_fee_rate
- self.show_address = bal_window.window.show_address
- if not will:
- self.will = bal_window.willitems
- else:
- self.will = will
- self.setWindowTitle(_("Transactions Preview"))
- self.setMinimumSize(1000, 200)
- self.size_label = QLabel()
- self.transactions_list = PreviewList(self.bal_window, self.will)
-
- try:
- self.bal_window.init_class_variables()
- except Exception as e:
- _logger.error(f"PreviewDialog Exception: {e}")
- self.check_will()
-
- vbox = QVBoxLayout(self)
- vbox.addWidget(self.size_label)
- vbox.addWidget(self.transactions_list)
- buttonbox = QHBoxLayout()
-
- b = QPushButton(_("Sign"))
- b.clicked.connect(self.transactions_list.ask_password_and_sign_transactions)
- buttonbox.addWidget(b)
-
- b = QPushButton(_("Export Will"))
- b.clicked.connect(self.transactions_list.export_will)
- buttonbox.addWidget(b)
-
- b = QPushButton(_("Broadcast"))
- b.clicked.connect(self.transactions_list.broadcast)
- buttonbox.addWidget(b)
-
- b = QPushButton(_("Invalidate will"))
- b.clicked.connect(self.transactions_list.invalidate_will)
- buttonbox.addWidget(b)
-
- vbox.addLayout(buttonbox)
-
- self.update()
-
- def update_will(self, will):
- self.will.update(will)
- self.transactions_list.update_will(will)
- self.update()
-
- def update(self):
- self.transactions_list.update()
-
- def is_hidden(self):
- return self.isMinimized() or self.isHidden()
-
- def show_or_hide(self):
- if self.is_hidden():
- self.bring_to_top()
- else:
- self.hide()
-
- def bring_to_top(self):
- self.show()
- self.raise_()
-
- def closeEvent(self, event):
- event.accept()
+# class PreviewDialog(BalDialog, MessageBoxMixin):
+# def __init__(self, bal_window, will):
+# self.parent = bal_window.window
+# BalDialog.__init__(
+# self, bal_window=bal_window, bal_plugin=bal_window.bal_plugin
+# )
+# self.bal_plugin = bal_window.bal_plugin
+# self.gui_object = self.bal_plugin.gui_object
+# self.config = self.bal_plugin.config
+# self.bal_window = bal_window
+# self.wallet = bal_window.window.wallet
+# self.format_amount = bal_window.window.format_amount
+# self.base_unit = bal_window.window.base_unit
+# self.format_fiat_and_units = bal_window.window.format_fiat_and_units
+# self.fx = bal_window.window.fx
+# self.format_fee_rate = bal_window.window.format_fee_rate
+# self.show_address = bal_window.window.show_address
+# if not will:
+# self.will = bal_window.willitems
+# else:
+# self.will = will
+# self.setWindowTitle(_("Transactions Preview"))
+# self.setMinimumSize(1000, 200)
+# self.size_label = QLabel()
+# self.transactions_list = PreviewList(self.bal_window,self, self.will)
+#
+# try:
+# self.bal_window.init_class_variables()
+# except Exception as e:
+# _logger.error(f"PreviewDialog Exception: {e}")
+# self.check_will()
+#
+# vbox = QVBoxLayout(self)
+# vbox.addWidget(self.size_label)
+# vbox.addWidget(self.transactions_list)
+# buttonbox = QHBoxLayout()
+#
+# b = QPushButton(_("Sign"))
+# b.clicked.connect(self.transactions_list.ask_password_and_sign_transactions)
+# buttonbox.addWidget(b)
+#
+# b = QPushButton(_("Export Will"))
+# b.clicked.connect(self.transactions_list.export_will)
+# buttonbox.addWidget(b)
+#
+# b = QPushButton(_("Broadcast"))
+# b.clicked.connect(self.transactions_list.broadcast)
+# buttonbox.addWidget(b)
+#
+# b = QPushButton(_("Invalidate will"))
+# b.clicked.connect(self.transactions_list.invalidate_will)
+# buttonbox.addWidget(b)
+#
+# vbox.addLayout(buttonbox)
+#
+# self.update()
+#
+# def update_will(self, will):
+# self.will.update(will)
+# self.transactions_list.update_will(will)
+# self.update()
+#
+# def update(self):
+# self.transactions_list.update()
+#
+# def is_hidden(self):
+# return self.isMinimized() or self.isHidden()
+#
+# def show_or_hide(self):
+# if self.is_hidden():
+# self.bring_to_top()
+# else:
+# self.hide()
+#
+# def bring_to_top(self):
+# self.show()
+# self.raise_()
+#
+# def closeEvent(self, event):
+# event.accept()
class WillDetailDialog(BalDialog):
def __init__(self, bal_window):
self.will = bal_window.willitems
- self.threshold = Util.parse_locktime_string(
- bal_window.will_settings["threshold"]
- )
+ self.threshold = bal_window.will_settings["real_threshold"]
+
self.bal_window = bal_window
Will.add_willtree(self.will)
super().__init__(bal_window.window, bal_window.bal_plugin)
@@ -3300,7 +3422,7 @@ class WillDetailDialog(BalDialog):
self.paint_scroll_area()
self.vlayout.addWidget(
- QLabel(_("Expiration date: ") + Util.locktime_to_str(self.threshold))
+ QLabel(_("Expiration date: ") + str(BalTimestamp(self.threshold)))
)
self.vlayout.addWidget(self.scrollbox)
w = QWidget()
@@ -3393,8 +3515,8 @@ class WillWidget(QWidget):
partial(self.parent.bal_window.show_transaction, txid=w)
)
detaillayout.addWidget(willpushbutton)
- locktime = Util.locktime_to_str(self.will[w].tx.locktime)
- creation = Util.locktime_to_str(self.will[w].time)
+ locktime = str(BalTimestamp(self.will[w].tx.locktime))
+ creation = str(BalTimestamp(self.will[w].time))
def qlabel(title, value):
label = "" + _(str(title)) + f":\t{str(value)}"
@@ -3676,11 +3798,6 @@ class WillExecutorListWidget(MyTreeView):
set_current = QPersistentModelIndex(idx)
self.set_current_idx(set_current)
self.filter()
- #try:
- # self.parent.save_willexecutors()
- #except Exception as e:
- # print("exception saving willexecutors",e)
-
except Exception as e:
_logger.error(f"error updating willexcutor {e}")
raise e
@@ -3707,7 +3824,7 @@ class WillExecutorWidget(QWidget, MessageBoxMixin):
widget = QWidget()
hbox = QHBoxLayout(widget)
hbox.addWidget(QLabel(_("Add transactions without willexecutor")))
- heir_no_willexecutor = bal_checkbox(self.bal_plugin.NO_WILLEXECUTOR)
+ heir_no_willexecutor = BalCheckBox(self.bal_plugin.NO_WILLEXECUTOR)
hbox.addWidget(heir_no_willexecutor)
spacer_widget = QWidget()
spacer_widget.setSizePolicy(
@@ -3750,10 +3867,10 @@ class WillExecutorWidget(QWidget, MessageBoxMixin):
}
self.will_executor_list_widget.update()
- def download_list(self,wes=None):
+ def download_list(self, wes=None):
if not wes:
- wes=self.willexecutors_list
- self.bal_window.download_list(wes,self.save_willexecutors)
+ wes = self.willexecutors_list
+ self.bal_window.download_list(wes, self.save_willexecutors)
def export_file(self, path):
export_meta_gui(
@@ -3773,8 +3890,8 @@ class WillExecutorWidget(QWidget, MessageBoxMixin):
def update_willexecutors(self, wes=None):
if not wes:
- wes=self.willexecutors_list
- self.bal_window.ping_willexecutors(wes,self.save_willexecutors)
+ wes = self.willexecutors_list
+ self.bal_window.ping_willexecutors(wes, self.save_willexecutors)
def import_json_file(self, path):
data = read_json_file(path)
@@ -3786,9 +3903,9 @@ class WillExecutorWidget(QWidget, MessageBoxMixin):
def _validate(self, data):
return data
- def save_willexecutors(self,wes=None):
+ def save_willexecutors(self, wes=None):
if not wes:
- wes=self.willexecutors_list
+ wes = self.willexecutors_list
self.willexecutors_list.update(wes)
self.will_executor_list_widget.update()
Willexecutors.save(self.bal_window.bal_plugin, self.willexecutors_list)
@@ -3830,36 +3947,32 @@ class WillExecutorDialog(BalDialog, MessageBoxMixin):
event.accept()
-class CheckAliveException(Exception):
- def __init__(self,timestamp_to_check):
- self.timestamp_to_check = timestamp_to_check
- def __str__(self):
- return "Check alive expired please update it: {}".format(datetime.fromtimestamp(self.timestamp_to_check).isoformat())
+class CheckAliveError(Exception):
+ def __init__(self, timestamp_to_check):
+ self.timestamp_to_check = timestamp_to_check
-def log_error(exec_info,window=None):
+ def __str__(self):
+ return "Check alive expired please update it: {}".format(
+ datetime.fromtimestamp(self.timestamp_to_check).isoformat()
+ )
+
+
+def log_error(exec_info, window=None):
_logger.error(exec_info)
- tb=traceback.format_exc()
- while tb is not None:
- try:
- frame = tb.tb_frame
- _logger.error("file:", frame.f_code.co_filename)
- _logger.error("name:", frame.f_code.co_name)
- _logger.error("line:", tb.tb_lineno)
- _logger.error("lasti:", tb.tb_lasti)
- tb = tb.tb_next
- except Exception as e:
- _logger.error(tb,e)
- tb= None
- break
+ tb = traceback.format_exc()
+ _logger.error(tb)
if window is not None:
window.show_error(exec_info)
+
def export_meta_gui(electrum_window, title, exporter):
filter_ = "All files (*)"
filename = getSaveFileName(
parent=electrum_window,
title=_("Select file to save your {}".format(title)),
- filename="BALplugin_{}_{}_{}".format(BalPlugin.chainname,str(electrum_window.wallet),title),
+ filename="BALplugin_{}_{}_{}".format(
+ BalPlugin.chainname, str(electrum_window.wallet), title
+ ),
filter=filter_,
config=electrum_window.config,
)
@@ -3874,3 +3987,58 @@ def export_meta_gui(electrum_window, title, exporter):
_("Your {0} were exported to '{1}'".format(title, str(filename)))
)
+
+class BalCalendar:
+ @staticmethod
+ def write_temp_ics(content):
+ fd, path = tempfile.mkstemp(prefix="event_", suffix=".ics")
+ with os.fdopen(fd, "w", encoding="utf-8") as f:
+ f.write(content)
+ return path
+
+ @staticmethod
+ def open_with_default_app(calendar_app, path):
+ try:
+ subprocess.check_call([calendar_app, path])
+ return True
+ except Exception as _e:
+ return False
+
+ @staticmethod
+ def save_to_cwd(path, filename="evento.ics"):
+ target = os.path.abspath(filename)
+ # se il file esiste, sovrascrive
+ with open(path, "rb") as src, open(target, "wb") as dst:
+ dst.write(src.read())
+ return target
+
+ @staticmethod
+ def format_time(time):
+ return time.astimezone(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
+ #return time.astimezone(timezone.utc).strftime("%Y%m%d")
+
+ @staticmethod
+ def ical_escape(text: str) -> str:
+ # escape per RFC5545: backslash, ; , newlines
+ text = (
+ text.replace("\\", "\\\\")
+ .replace(";", r"\;")
+ .replace(",", r"\,")
+ .replace("\n", r"\n")
+ )
+ return BalCalendar.fold_ical_line(text)
+
+ @staticmethod
+ def fold_ical_line(line: str, limit: int = 75) -> str:
+ # ritorna linee separate da CRLF e folding con spazio iniziale sulle righe successive
+ encoded = line.encode("utf-8")
+ parts = []
+ while len(encoded) > limit:
+ # taglia senza spezzare byte UTF-8
+ cut = limit
+ while (encoded[cut] & 0xC0) == 0x80: # byte di continuazione UTF-8
+ cut -= 1
+ parts.append(encoded[:cut].decode("utf-8"))
+ encoded = encoded[cut:]
+ parts.append(encoded.decode("utf-8"))
+ return "\r\n ".join(parts)
diff --git a/will.py b/will.py
index eccd8f9..1bcc84a 100644
--- a/will.py
+++ b/will.py
@@ -526,7 +526,7 @@ class Will:
@staticmethod
def get_min_locktime(will,default_value=None):
- return min((v.tx.locktime for v in will.values() if v.get_status('VALID')), default=default_value)
+ return min((v.tx.locktime for v in will.values() if v.get_status('VALID')), default=default_value)