Merge branch 'master' into TextCompleter
This commit is contained in:
@@ -44,7 +44,8 @@ from electrum import WalletStorage
|
||||
# from electrum.synchronizer import Synchronizer
|
||||
# from electrum.verifier import SPV
|
||||
# from electrum.util import DebugMem
|
||||
from electrum.util import UserCancelled, print_error
|
||||
from electrum.util import (UserCancelled, print_error,
|
||||
WalletFileException, BitcoinException)
|
||||
# from electrum.wallet import Abstract_Wallet
|
||||
|
||||
from .installwizard import InstallWizard, GoBack
|
||||
@@ -185,42 +186,51 @@ class ElectrumGui:
|
||||
|
||||
def start_new_window(self, path, uri):
|
||||
'''Raises the window for the wallet if it is open. Otherwise
|
||||
opens the wallet and creates a new window for it.'''
|
||||
for w in self.windows:
|
||||
if w.wallet.storage.path == path:
|
||||
w.bring_to_top()
|
||||
break
|
||||
else:
|
||||
opens the wallet and creates a new window for it'''
|
||||
try:
|
||||
wallet = self.daemon.load_wallet(path, None)
|
||||
except BaseException as e:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
d = QMessageBox(QMessageBox.Warning, _('Error'),
|
||||
_('Cannot load wallet') + ' (1):\n' + str(e))
|
||||
d.exec_()
|
||||
return
|
||||
if not wallet:
|
||||
storage = WalletStorage(path, manual_upgrades=True)
|
||||
wizard = InstallWizard(self.config, self.app, self.plugins, storage)
|
||||
try:
|
||||
wallet = self.daemon.load_wallet(path, None)
|
||||
except BaseException as e:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
wallet = wizard.run_and_get_wallet(self.daemon.get_wallet)
|
||||
except UserCancelled:
|
||||
pass
|
||||
except GoBack as e:
|
||||
print_error('[start_new_window] Exception caught (GoBack)', e)
|
||||
except (WalletFileException, BitcoinException) as e:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
d = QMessageBox(QMessageBox.Warning, _('Error'),
|
||||
_('Cannot load wallet:') + '\n' + str(e))
|
||||
_('Cannot load wallet') + ' (2):\n' + str(e))
|
||||
d.exec_()
|
||||
return
|
||||
if not wallet:
|
||||
storage = WalletStorage(path, manual_upgrades=True)
|
||||
wizard = InstallWizard(self.config, self.app, self.plugins, storage)
|
||||
try:
|
||||
wallet = wizard.run_and_get_wallet()
|
||||
except UserCancelled:
|
||||
pass
|
||||
except GoBack as e:
|
||||
print_error('[start_new_window] Exception caught (GoBack)', e)
|
||||
finally:
|
||||
wizard.terminate()
|
||||
if not wallet:
|
||||
return
|
||||
if not wallet:
|
||||
return
|
||||
|
||||
if not self.daemon.get_wallet(wallet.storage.path):
|
||||
# wallet was not in memory
|
||||
wallet.start_threads(self.daemon.network)
|
||||
self.daemon.add_wallet(wallet)
|
||||
try:
|
||||
w = self.create_window_for_wallet(wallet)
|
||||
except BaseException as e:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
d = QMessageBox(QMessageBox.Warning, _('Error'),
|
||||
_('Cannot create window for wallet:') + '\n' + str(e))
|
||||
d.exec_()
|
||||
return
|
||||
try:
|
||||
for w in self.windows:
|
||||
if w.wallet.storage.path == wallet.storage.path:
|
||||
w.bring_to_top()
|
||||
return
|
||||
w = self.create_window_for_wallet(wallet)
|
||||
except BaseException as e:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
d = QMessageBox(QMessageBox.Warning, _('Error'),
|
||||
_('Cannot create window for wallet') + ':\n' + str(e))
|
||||
d.exec_()
|
||||
return
|
||||
if uri:
|
||||
w.pay_to_URI(uri)
|
||||
w.bring_to_top()
|
||||
|
||||
@@ -123,7 +123,7 @@ class AddressList(MyTreeWidget):
|
||||
address_item.setText(0, _('receiving'))
|
||||
address_item.setBackground(0, ColorScheme.GREEN.as_color(True))
|
||||
address_item.setFont(1, QFont(MONOSPACE_FONT))
|
||||
address_item.setData(1, Qt.UserRole, address)
|
||||
address_item.setData(0, Qt.UserRole, address) # column 0; independent from address column
|
||||
if self.wallet.is_frozen(address):
|
||||
address_item.setBackground(1, ColorScheme.BLUE.as_color(True))
|
||||
if self.wallet.is_beyond_limit(address):
|
||||
|
||||
@@ -223,7 +223,7 @@ class Console(QtWidgets.QPlainTextEdit):
|
||||
exec(command, self.namespace, self.namespace)
|
||||
except SystemExit:
|
||||
self.close()
|
||||
except Exception:
|
||||
except BaseException:
|
||||
traceback_lines = traceback.format_exc().split('\n')
|
||||
# Remove traceback mentioning this file, and a linebreak
|
||||
for i in (3,2,1,-1):
|
||||
|
||||
@@ -38,6 +38,8 @@ from PyQt5.QtWidgets import *
|
||||
from electrum.i18n import _
|
||||
from electrum import ELECTRUM_VERSION, bitcoin, constants
|
||||
|
||||
from .util import MessageBoxMixin
|
||||
|
||||
issue_template = """<h2>Traceback</h2>
|
||||
<pre>
|
||||
{traceback}
|
||||
@@ -54,7 +56,7 @@ issue_template = """<h2>Traceback</h2>
|
||||
report_server = "https://crashhub.electrum.org/crash"
|
||||
|
||||
|
||||
class Exception_Window(QWidget):
|
||||
class Exception_Window(QWidget, MessageBoxMixin):
|
||||
_active_window = None
|
||||
|
||||
def __init__(self, main_window, exctype, value, tb):
|
||||
@@ -75,7 +77,9 @@ class Exception_Window(QWidget):
|
||||
'information:')))
|
||||
|
||||
collapse_info = QPushButton(_("Show report contents"))
|
||||
collapse_info.clicked.connect(lambda: QMessageBox.about(self, "Report contents", self.get_report_string()))
|
||||
collapse_info.clicked.connect(
|
||||
lambda: self.msg_box(QMessageBox.NoIcon,
|
||||
self, "Report contents", self.get_report_string()))
|
||||
main_box.addWidget(collapse_info)
|
||||
|
||||
main_box.addWidget(QLabel(_("Please briefly describe what led to the error (optional):")))
|
||||
|
||||
@@ -161,6 +161,9 @@ class HistoryList(MyTreeWidget, AcceptFileDragDrop):
|
||||
|
||||
def show_summary(self):
|
||||
h = self.summary
|
||||
if not h:
|
||||
self.parent.show_message(_("Nothing to summarize."))
|
||||
return
|
||||
start_date = h.get('start_date')
|
||||
end_date = h.get('end_date')
|
||||
format_amount = lambda x: self.parent.format_amount(x.value) + ' ' + self.parent.base_unit()
|
||||
@@ -232,7 +235,7 @@ class HistoryList(MyTreeWidget, AcceptFileDragDrop):
|
||||
label = tx_item['label']
|
||||
status, status_str = self.wallet.get_tx_status(tx_hash, height, conf, timestamp)
|
||||
has_invoice = self.wallet.invoices.paid.get(tx_hash)
|
||||
icon = QIcon(":icons/" + TX_ICONS[status])
|
||||
icon = self.icon_cache.get(":icons/" + TX_ICONS[status])
|
||||
v_str = self.parent.format_amount(value, True, whitespaces=True)
|
||||
balance_str = self.parent.format_amount(balance, whitespaces=True)
|
||||
entry = ['', tx_hash, status_str, label, v_str, balance_str]
|
||||
@@ -250,10 +253,10 @@ class HistoryList(MyTreeWidget, AcceptFileDragDrop):
|
||||
item.setToolTip(0, str(conf) + " confirmation" + ("s" if conf != 1 else ""))
|
||||
item.setData(0, SortableTreeWidgetItem.DataRole, (status, conf))
|
||||
if has_invoice:
|
||||
item.setIcon(3, QIcon(":icons/seal"))
|
||||
item.setIcon(3, self.icon_cache.get(":icons/seal"))
|
||||
for i in range(len(entry)):
|
||||
if i>3:
|
||||
item.setTextAlignment(i, Qt.AlignRight)
|
||||
item.setTextAlignment(i, Qt.AlignRight | Qt.AlignVCenter)
|
||||
if i!=2:
|
||||
item.setFont(i, QFont(MONOSPACE_FONT))
|
||||
if value and value < 0:
|
||||
@@ -299,7 +302,7 @@ class HistoryList(MyTreeWidget, AcceptFileDragDrop):
|
||||
|
||||
def update_item(self, tx_hash, height, conf, timestamp):
|
||||
status, status_str = self.wallet.get_tx_status(tx_hash, height, conf, timestamp)
|
||||
icon = QIcon(":icons/" + TX_ICONS[status])
|
||||
icon = self.icon_cache.get(":icons/" + TX_ICONS[status])
|
||||
items = self.findItems(tx_hash, Qt.UserRole|Qt.MatchContains|Qt.MatchRecursive, column=1)
|
||||
if items:
|
||||
item = items[0]
|
||||
@@ -344,7 +347,7 @@ class HistoryList(MyTreeWidget, AcceptFileDragDrop):
|
||||
if child_tx:
|
||||
menu.addAction(_("Child pays for parent"), lambda: self.parent.cpfp(tx, child_tx))
|
||||
if pr_key:
|
||||
menu.addAction(QIcon(":icons/seal"), _("View invoice"), lambda: self.parent.show_invoice(pr_key))
|
||||
menu.addAction(self.icon_cache.get(":icons/seal"), _("View invoice"), lambda: self.parent.show_invoice(pr_key))
|
||||
if tx_URL:
|
||||
menu.addAction(_("View on block explorer"), lambda: webbrowser.open(tx_URL))
|
||||
menu.exec_(self.viewport().mapToGlobal(position))
|
||||
@@ -408,7 +411,7 @@ class HistoryList(MyTreeWidget, AcceptFileDragDrop):
|
||||
lines.append([item['txid'], item.get('label', ''), item['confirmations'], item['value'], item['date']])
|
||||
else:
|
||||
lines.append(item)
|
||||
with open(fileName, "w+") as f:
|
||||
with open(fileName, "w+", encoding='utf-8') as f:
|
||||
if is_csv:
|
||||
import csv
|
||||
transaction = csv.writer(f, lineterminator='\n')
|
||||
|
||||
@@ -148,7 +148,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
||||
self.raise_()
|
||||
self.refresh_gui() # Need for QT on MacOSX. Lame.
|
||||
|
||||
def run_and_get_wallet(self):
|
||||
def run_and_get_wallet(self, get_wallet_from_daemon):
|
||||
|
||||
vbox = QVBoxLayout()
|
||||
hbox = QHBoxLayout()
|
||||
@@ -181,10 +181,15 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
||||
|
||||
def on_filename(filename):
|
||||
path = os.path.join(wallet_folder, filename)
|
||||
wallet_from_memory = get_wallet_from_daemon(path)
|
||||
try:
|
||||
self.storage = WalletStorage(path, manual_upgrades=True)
|
||||
if wallet_from_memory:
|
||||
self.storage = wallet_from_memory.storage
|
||||
else:
|
||||
self.storage = WalletStorage(path, manual_upgrades=True)
|
||||
self.next_button.setEnabled(True)
|
||||
except IOError:
|
||||
except BaseException:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
self.storage = None
|
||||
self.next_button.setEnabled(False)
|
||||
if self.storage:
|
||||
@@ -192,7 +197,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
||||
msg =_("This file does not exist.") + '\n' \
|
||||
+ _("Press 'Next' to create this wallet, or choose another file.")
|
||||
pw = False
|
||||
else:
|
||||
elif not wallet_from_memory:
|
||||
if self.storage.is_encrypted_with_user_pw():
|
||||
msg = _("This file is encrypted with a password.") + '\n' \
|
||||
+ _('Enter your password or choose another file.')
|
||||
@@ -204,6 +209,10 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
||||
else:
|
||||
msg = _("Press 'Next' to open this wallet.")
|
||||
pw = False
|
||||
else:
|
||||
msg = _("This file is already open in memory.") + "\n" \
|
||||
+ _("Press 'Next' to create/focus window.")
|
||||
pw = False
|
||||
else:
|
||||
msg = _('Cannot read file')
|
||||
pw = False
|
||||
@@ -228,6 +237,9 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
||||
return
|
||||
if not self.storage.file_exists():
|
||||
break
|
||||
wallet_from_memory = get_wallet_from_daemon(self.storage.path)
|
||||
if wallet_from_memory:
|
||||
return wallet_from_memory
|
||||
if self.storage.file_exists() and self.storage.is_encrypted():
|
||||
if self.storage.is_encrypted_with_user_pw():
|
||||
password = self.pw_e.text()
|
||||
@@ -245,14 +257,12 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
||||
try:
|
||||
self.run('choose_hw_device', HWD_SETUP_DECRYPT_WALLET)
|
||||
except InvalidPassword as e:
|
||||
# FIXME if we get here because of mistyped passphrase
|
||||
# then that passphrase gets "cached"
|
||||
QMessageBox.information(
|
||||
None, _('Error'),
|
||||
_('Failed to decrypt using this hardware device.') + '\n' +
|
||||
_('If you use a passphrase, make sure it is correct.'))
|
||||
self.stack = []
|
||||
return self.run_and_get_wallet()
|
||||
return self.run_and_get_wallet(get_wallet_from_daemon)
|
||||
except BaseException as e:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
QMessageBox.information(None, _('Error'), str(e))
|
||||
@@ -302,8 +312,6 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
||||
self.wallet = Wallet(self.storage)
|
||||
return self.wallet
|
||||
|
||||
|
||||
|
||||
def finished(self):
|
||||
"""Called in hardware client wrapper, in order to close popups."""
|
||||
return
|
||||
@@ -340,7 +348,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
||||
if not result and raise_on_cancel:
|
||||
raise UserCancelled
|
||||
if result == 1:
|
||||
raise GoBack
|
||||
raise GoBack from None
|
||||
self.title.setVisible(False)
|
||||
self.back_button.setEnabled(False)
|
||||
self.next_button.setEnabled(False)
|
||||
|
||||
@@ -48,7 +48,7 @@ class InvoiceList(MyTreeWidget):
|
||||
exp = pr.get_expiration_date()
|
||||
date_str = format_time(exp) if exp else _('Never')
|
||||
item = QTreeWidgetItem([date_str, requestor, pr.memo, self.parent.format_amount(pr.get_amount(), whitespaces=True), pr_tooltips.get(status,'')])
|
||||
item.setIcon(4, QIcon(pr_icons.get(status)))
|
||||
item.setIcon(4, self.icon_cache.get(pr_icons.get(status)))
|
||||
item.setData(0, Qt.UserRole, key)
|
||||
item.setFont(1, QFont(MONOSPACE_FONT))
|
||||
item.setFont(3, QFont(MONOSPACE_FONT))
|
||||
|
||||
@@ -47,7 +47,7 @@ from electrum.i18n import _
|
||||
from electrum.util import (format_time, format_satoshis, PrintError,
|
||||
format_satoshis_plain, NotEnoughFunds,
|
||||
UserCancelled, NoDynamicFeeEstimates, profiler,
|
||||
export_meta, import_meta, bh2u, bfh)
|
||||
export_meta, import_meta, bh2u, bfh, InvalidPassword)
|
||||
from electrum import Transaction
|
||||
from electrum import util, bitcoin, commands, coinchooser
|
||||
from electrum import paymentrequest
|
||||
@@ -396,7 +396,11 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
self.show_warning(msg, title=_('Information'))
|
||||
|
||||
def open_wallet(self):
|
||||
wallet_folder = self.get_wallet_folder()
|
||||
try:
|
||||
wallet_folder = self.get_wallet_folder()
|
||||
except FileNotFoundError as e:
|
||||
self.show_error(str(e))
|
||||
return
|
||||
filename, __ = QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder)
|
||||
if not filename:
|
||||
return
|
||||
@@ -409,13 +413,12 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
filename, __ = QFileDialog.getSaveFileName(self, _('Enter a filename for the copy of your wallet'), wallet_folder)
|
||||
if not filename:
|
||||
return
|
||||
|
||||
new_path = os.path.join(wallet_folder, filename)
|
||||
if new_path != path:
|
||||
try:
|
||||
shutil.copy2(path, new_path)
|
||||
self.show_message(_("A copy of your wallet file was created in")+" '%s'" % str(new_path), title=_("Wallet backup created"))
|
||||
except (IOError, os.error) as reason:
|
||||
except BaseException as reason:
|
||||
self.show_critical(_("Electrum was unable to copy your wallet file to the specified location.") + "\n" + str(reason), title=_("Unable to create backup"))
|
||||
|
||||
def update_recently_visited(self, filename):
|
||||
@@ -441,7 +444,11 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
return os.path.dirname(os.path.abspath(self.config.get_wallet_path()))
|
||||
|
||||
def new_wallet(self):
|
||||
wallet_folder = self.get_wallet_folder()
|
||||
try:
|
||||
wallet_folder = self.get_wallet_folder()
|
||||
except FileNotFoundError as e:
|
||||
self.show_error(str(e))
|
||||
return
|
||||
i = 1
|
||||
while True:
|
||||
filename = "wallet_%d" % i
|
||||
@@ -531,7 +538,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
|
||||
help_menu = menubar.addMenu(_("&Help"))
|
||||
help_menu.addAction(_("&About"), self.show_about)
|
||||
help_menu.addAction(_("&Official website"), lambda: webbrowser.open("http://electrum.org"))
|
||||
help_menu.addAction(_("&Official website"), lambda: webbrowser.open("https://electrum.org"))
|
||||
help_menu.addSeparator()
|
||||
help_menu.addAction(_("&Documentation"), lambda: webbrowser.open("http://docs.electrum.org/")).setShortcut(QKeySequence.HelpContents)
|
||||
help_menu.addAction(_("&Report Bug"), self.show_report_bug)
|
||||
@@ -663,8 +670,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
edit.setStyleSheet(ColorScheme.DEFAULT.as_stylesheet())
|
||||
fiat_e.is_last_edited = (edit == fiat_e)
|
||||
amount = edit.get_amount()
|
||||
rate = self.fx.exchange_rate() if self.fx else None
|
||||
if rate is None or amount is None:
|
||||
rate = self.fx.exchange_rate() if self.fx else Decimal('NaN')
|
||||
if rate.is_nan() or amount is None:
|
||||
if edit is fiat_e:
|
||||
btc_e.setText("")
|
||||
if fee_e:
|
||||
@@ -1182,7 +1189,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
self.fee_adv_controls.setVisible(False)
|
||||
|
||||
self.preview_button = EnterButton(_("Preview"), self.do_preview)
|
||||
self.preview_button.setToolTip(_('Display the details of your transactions before signing it.'))
|
||||
self.preview_button.setToolTip(_('Display the details of your transaction before signing it.'))
|
||||
self.send_button = EnterButton(_("Send"), self.do_send)
|
||||
self.clear_button = EnterButton(_("Clear"), self.do_clear)
|
||||
buttons = QHBoxLayout()
|
||||
@@ -1329,8 +1336,13 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
# actual fees often differ somewhat.
|
||||
if freeze_feerate or self.fee_slider.is_active():
|
||||
displayed_feerate = self.feerate_e.get_amount()
|
||||
displayed_feerate = displayed_feerate // 1000 if displayed_feerate else 0
|
||||
displayed_fee = displayed_feerate * size
|
||||
if displayed_feerate:
|
||||
displayed_feerate = displayed_feerate // 1000
|
||||
else:
|
||||
# fallback to actual fee
|
||||
displayed_feerate = fee // size if fee is not None else None
|
||||
self.feerate_e.setAmount(displayed_feerate)
|
||||
displayed_fee = displayed_feerate * size if displayed_feerate is not None else None
|
||||
self.fee_e.setAmount(displayed_fee)
|
||||
else:
|
||||
if freeze_fee:
|
||||
@@ -1767,8 +1779,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
def remove_address(self, addr):
|
||||
if self.question(_("Do you want to remove")+" %s "%addr +_("from your wallet?")):
|
||||
self.wallet.delete_address(addr)
|
||||
self.address_list.update()
|
||||
self.history_list.update()
|
||||
self.need_update.set() # history, addresses, coins
|
||||
self.clear_receive_tab()
|
||||
|
||||
def get_coins(self):
|
||||
@@ -1827,6 +1838,9 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
|
||||
def show_invoice(self, key):
|
||||
pr = self.invoices.get(key)
|
||||
if pr is None:
|
||||
self.show_error('Cannot find payment request in wallet.')
|
||||
return
|
||||
pr.verify(self.contacts)
|
||||
self.show_pr_details(pr)
|
||||
|
||||
@@ -1968,10 +1982,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
return
|
||||
try:
|
||||
self.wallet.update_password(old_password, new_password, encrypt_file)
|
||||
except BaseException as e:
|
||||
except InvalidPassword as e:
|
||||
self.show_error(str(e))
|
||||
return
|
||||
except:
|
||||
except BaseException:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
self.show_error(_('Failed to update password'))
|
||||
return
|
||||
@@ -2304,7 +2318,11 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
self.pay_to_URI(data)
|
||||
return
|
||||
# else if the user scanned an offline signed tx
|
||||
data = bh2u(bitcoin.base_decode(data, length=None, base=43))
|
||||
try:
|
||||
data = bh2u(bitcoin.base_decode(data, length=None, base=43))
|
||||
except BaseException as e:
|
||||
self.show_error((_('Could not decode QR code')+':\n{}').format(e))
|
||||
return
|
||||
tx = self.tx_from_text(data)
|
||||
if not tx:
|
||||
return
|
||||
@@ -2621,13 +2639,13 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
|
||||
msg = '\n'.join([
|
||||
_('Time based: fee rate is based on average confirmation time estimates'),
|
||||
_('Mempool based: fee rate is targetting a depth in the memory pool')
|
||||
_('Mempool based: fee rate is targeting a depth in the memory pool')
|
||||
]
|
||||
)
|
||||
fee_type_label = HelpLabel(_('Fee estimation') + ':', msg)
|
||||
fee_type_combo = QComboBox()
|
||||
fee_type_combo.addItems([_('Static'), _('ETA'), _('Mempool')])
|
||||
fee_type_combo.setCurrentIndex(1 if self.config.use_mempool_fees() else 0)
|
||||
fee_type_combo.setCurrentIndex((2 if self.config.use_mempool_fees() else 1) if self.config.is_dynfee() else 0)
|
||||
def on_fee_type(x):
|
||||
self.config.set_key('mempool_fees', x==2)
|
||||
self.config.set_key('dynamic_fees', x>0)
|
||||
@@ -2648,7 +2666,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
use_rbf_cb.setChecked(self.config.get('use_rbf', True))
|
||||
use_rbf_cb.setToolTip(
|
||||
_('If you check this box, your transactions will be marked as non-final,') + '\n' + \
|
||||
_('and you will have the possiblity, while they are unconfirmed, to replace them with transactions that pay higher fees.') + '\n' + \
|
||||
_('and you will have the possibility, while they are unconfirmed, to replace them with transactions that pay higher fees.') + '\n' + \
|
||||
_('Note that some merchants do not accept non-final transactions until they are confirmed.'))
|
||||
def on_use_rbf(x):
|
||||
self.config.set_key('use_rbf', x == Qt.Checked)
|
||||
@@ -2658,7 +2676,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
msg = _('OpenAlias record, used to receive coins and to sign payment requests.') + '\n\n'\
|
||||
+ _('The following alias providers are available:') + '\n'\
|
||||
+ '\n'.join(['https://cryptoname.co/', 'http://xmr.link']) + '\n\n'\
|
||||
+ 'For more information, see http://openalias.org'
|
||||
+ 'For more information, see https://openalias.org'
|
||||
alias_label = HelpLabel(_('OpenAlias') + ':', msg)
|
||||
alias = self.config.get('alias','')
|
||||
alias_e = QLineEdit(alias)
|
||||
|
||||
@@ -28,6 +28,8 @@ import re
|
||||
from decimal import Decimal
|
||||
|
||||
from electrum import bitcoin
|
||||
from electrum.util import bfh
|
||||
|
||||
from .qrtextedit import ScanQRTextEdit
|
||||
from .completion_text_edit import CompletionTextEdit
|
||||
from . import util
|
||||
@@ -92,9 +94,12 @@ class PayToEdit(CompletionTextEdit, ScanQRTextEdit):
|
||||
for word in x.split():
|
||||
if word[0:3] == 'OP_':
|
||||
assert word in opcodes.lookup
|
||||
script += chr(opcodes.lookup[word])
|
||||
opcode_int = opcodes.lookup[word]
|
||||
assert opcode_int < 256 # opcode is single-byte
|
||||
script += bitcoin.int_to_hex(opcode_int)
|
||||
else:
|
||||
script += push_script(word).decode('hex')
|
||||
bfh(word) # to test it is hex data
|
||||
script += push_script(word)
|
||||
return script
|
||||
|
||||
def parse_amount(self, x):
|
||||
|
||||
@@ -46,9 +46,13 @@ class ScanQRTextEdit(ButtonsTextEdit, MessageBoxMixin):
|
||||
fileName, __ = QFileDialog.getOpenFileName(self, 'select file')
|
||||
if not fileName:
|
||||
return
|
||||
with open(fileName, "r") as f:
|
||||
data = f.read()
|
||||
self.setText(data)
|
||||
try:
|
||||
with open(fileName, "r") as f:
|
||||
data = f.read()
|
||||
except BaseException as e:
|
||||
self.show_error(_('Error opening file') + ':\n' + str(e))
|
||||
else:
|
||||
self.setText(data)
|
||||
|
||||
def qr_input(self):
|
||||
from electrum import qrscanner, get_config
|
||||
|
||||
@@ -98,10 +98,10 @@ class RequestList(MyTreeWidget):
|
||||
amount_str = self.parent.format_amount(amount) if amount else ""
|
||||
item = QTreeWidgetItem([date, address, '', message, amount_str, pr_tooltips.get(status,'')])
|
||||
if signature is not None:
|
||||
item.setIcon(2, QIcon(":icons/seal.png"))
|
||||
item.setIcon(2, self.icon_cache.get(":icons/seal.png"))
|
||||
item.setToolTip(2, 'signed by '+ requestor)
|
||||
if status is not PR_UNKNOWN:
|
||||
item.setIcon(6, QIcon(pr_icons.get(status)))
|
||||
item.setIcon(6, self.icon_cache.get(pr_icons.get(status)))
|
||||
self.addTopLevelItem(item)
|
||||
|
||||
|
||||
|
||||
@@ -179,11 +179,12 @@ class TxDialog(QDialog, MessageBoxMixin):
|
||||
|
||||
def sign(self):
|
||||
def sign_done(success):
|
||||
if success:
|
||||
# note: with segwit we could save partially signed tx, because they have a txid
|
||||
if self.tx.is_complete():
|
||||
self.prompt_if_unsaved = True
|
||||
self.saved = False
|
||||
self.save_button.setDisabled(False)
|
||||
self.save_button.setToolTip("")
|
||||
self.save_button.setDisabled(False)
|
||||
self.save_button.setToolTip("")
|
||||
self.update()
|
||||
self.main_window.pop_top_level_window(self)
|
||||
|
||||
@@ -289,7 +290,7 @@ class TxDialog(QDialog, MessageBoxMixin):
|
||||
cursor.insertText(prevout_hash[-8:] + ":%-4d " % prevout_n, ext)
|
||||
addr = x.get('address')
|
||||
if addr == "(pubkey)":
|
||||
_addr = self.wallet.find_pay_to_pubkey_address(prevout_hash, prevout_n)
|
||||
_addr = self.wallet.get_txin_address(x)
|
||||
if _addr:
|
||||
addr = _addr
|
||||
if addr is None:
|
||||
|
||||
@@ -393,6 +393,8 @@ class MyTreeWidget(QTreeWidget):
|
||||
self.addChild = self.addTopLevelItem
|
||||
self.insertChild = self.insertTopLevelItem
|
||||
|
||||
self.icon_cache = IconCache()
|
||||
|
||||
# Control which columns are editable
|
||||
self.editor = None
|
||||
self.pending_update = False
|
||||
@@ -779,6 +781,17 @@ class SortableTreeWidgetItem(QTreeWidgetItem):
|
||||
return self.text(column) < other.text(column)
|
||||
|
||||
|
||||
class IconCache:
|
||||
|
||||
def __init__(self):
|
||||
self.__cache = {}
|
||||
|
||||
def get(self, file_name):
|
||||
if file_name not in self.__cache:
|
||||
self.__cache[file_name] = QIcon(file_name)
|
||||
return self.__cache[file_name]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication([])
|
||||
t = WaitingDialog(None, 'testing ...', lambda: [time.sleep(1)], lambda x: QMessageBox.information(None, 'done', "done"))
|
||||
|
||||
Reference in New Issue
Block a user