forked from bitcoinafterlife/bal-electrum-plugin
add bal/gui
This commit is contained in:
173
bal/gui/qt/common.py
Normal file
173
bal/gui/qt/common.py
Normal file
@@ -0,0 +1,173 @@
|
||||
"""
|
||||
bal.gui.qt.common
|
||||
=================
|
||||
|
||||
Shared imports and tiny helper utilities for the Qt GUI layer.
|
||||
|
||||
Every other ``bal.gui.qt`` module does ``from .common import *`` so that the
|
||||
long list of Electrum / PyQt6 imports lives in a single place. This file also
|
||||
hosts a few GUI helpers that do not deserve a module of their own:
|
||||
|
||||
* :class:`shown_cv` - trivial mutable "is this tab shown?" holder.
|
||||
* :func:`add_widget` - add a labelled widget (plus optional help) to a grid.
|
||||
* :func:`log_error` - format an exception traceback for a dialog.
|
||||
* :func:`export_meta_gui` - export plugin metadata to a JSON file.
|
||||
* :class:`CheckAliveError`- raised when the "check alive" date is in the past.
|
||||
"""
|
||||
|
||||
import copy
|
||||
import enum
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
import traceback
|
||||
from datetime import datetime, timezone
|
||||
from decimal import Decimal
|
||||
from functools import partial
|
||||
from typing import Any, Callable, Mapping, Optional, Union
|
||||
|
||||
from electrum.bitcoin import (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, getSaveFileName,
|
||||
import_meta_gui, read_QIcon_from_bytes,
|
||||
read_QPixmap_from_bytes)
|
||||
from electrum.i18n import _
|
||||
from electrum.logging import get_logger
|
||||
from electrum.network import BestEffortRequestFailed, Network, TxBroadcastError
|
||||
from electrum.payment_identifier import PaymentIdentifier
|
||||
from electrum.plugin import hook
|
||||
from electrum.transaction import SerializationError, Transaction, tx_from_any
|
||||
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, QSize,
|
||||
Qt, QTimer, pyqtSignal)
|
||||
from PyQt6.QtGui import (QColor, QPainter, QPalette, QStandardItem,
|
||||
QStandardItemModel)
|
||||
from PyQt6.QtWidgets import (QAbstractItemView, QAbstractSpinBox, QCheckBox,
|
||||
QComboBox, QDateTimeEdit, QGridLayout, QHBoxLayout,
|
||||
QLabel, QLineEdit, QTextEdit, QMenu, QMenuBar,
|
||||
QPushButton, QScrollArea, QSizePolicy, QSpinBox,
|
||||
QStackedWidget, QStyle, QStyleOptionFrame,
|
||||
QVBoxLayout, QWidget, QDialog)
|
||||
|
||||
# --- Core (GUI-free) logic layer ---
|
||||
from ...core.plugin_base import BalPlugin, BalTimestamp
|
||||
from ...core.heirs import HEIR_DUST_AMOUNT, HEIR_REAL_AMOUNT, Heirs
|
||||
from ...core.util import Util
|
||||
from ...core.will import (AmountException, HeirChangeException,
|
||||
HeirNotFoundException, NoHeirsException,
|
||||
NotCompleteWillException, NoWillExecutorNotPresent,
|
||||
TxFeesChangedException, Will,
|
||||
WillexecutorChangeException, WillExecutorNotPresent,
|
||||
WillExpiredException, WillItem, WillPostponedException)
|
||||
from ...core.willexecutors import Willexecutors
|
||||
|
||||
# --- Presentation helpers ---
|
||||
from .theme import server_status_text, server_status_tooltip, status_color
|
||||
from .window_utils import (bring_to_front, show_modal, show_on_top,
|
||||
stop_thread, top_level_of)
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
|
||||
class shown_cv:
|
||||
_type = bool
|
||||
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def get(self):
|
||||
return self.value
|
||||
|
||||
def set(self, value):
|
||||
self.value = value
|
||||
|
||||
|
||||
|
||||
|
||||
def add_widget(grid, label, widget, row, help_):
|
||||
grid.addWidget(QLabel(_(label)), row, 0)
|
||||
grid.addWidget(widget, row, 1)
|
||||
grid.addWidget(HelpButton(help_), row, 2)
|
||||
|
||||
|
||||
|
||||
|
||||
class CheckAliveError(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()
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
def log_error(exec_info, window=None):
|
||||
"""Log an error and optionally show it.
|
||||
|
||||
``exec_info`` may be either a ``sys.exc_info()`` triple
|
||||
``(type, value, traceback)`` or a single exception instance (callers use
|
||||
both forms), so we handle both and always try to log a full traceback.
|
||||
"""
|
||||
_logger.error(f"LOG_ERROR: {exec_info}")
|
||||
exc = None
|
||||
if isinstance(exec_info, BaseException):
|
||||
exc = exec_info
|
||||
elif isinstance(exec_info, (tuple, list)) and len(exec_info) >= 2:
|
||||
# sys.exc_info() form: the exception instance is the 2nd element.
|
||||
exc = exec_info[1]
|
||||
try:
|
||||
if exc is not None:
|
||||
_logger.error(
|
||||
"".join(
|
||||
traceback.format_exception(type(exc), exc, exc.__traceback__)
|
||||
)
|
||||
)
|
||||
else:
|
||||
_logger.error(traceback.format_exc())
|
||||
except Exception:
|
||||
_logger.error(traceback.format_exc())
|
||||
|
||||
if window is not None:
|
||||
# show_error expects a human-readable message, not a triple.
|
||||
window.show_error(str(exc) if exc is not None else str(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
|
||||
),
|
||||
filter=filter_,
|
||||
config=electrum_window.config,
|
||||
)
|
||||
if not filename:
|
||||
return
|
||||
try:
|
||||
exporter(filename)
|
||||
except FileExportFailed as e:
|
||||
electrum_window.show_critical(str(e))
|
||||
else:
|
||||
electrum_window.show_message(
|
||||
_("Your {0} were exported to '{1}'".format(title, str(filename)))
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user