Ejemplo n.º 1
0
 def __init__(self, config, daemon, plugins):
     try:
         default_language = locale.getdefaultlocale()[0]
     except:
         default_language = ''
     set_language(config.get('language', default_language))
     # Uncomment this call to verify objects are being properly
     # GC-ed when windows are closed
     #network.add_jobs([DebugMem([Abstract_Wallet, SPV, Synchronizer,
     #                            ElectrumWindow], interval=5)])
     QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads)
     if hasattr(QtCore.Qt, "AA_ShareOpenGLContexts"):
         QtCore.QCoreApplication.setAttribute(
             QtCore.Qt.AA_ShareOpenGLContexts)
     if hasattr(QGuiApplication, 'setDesktopFileName'):
         QGuiApplication.setDesktopFileName('qtum-electrum.desktop')
     self.config = config
     self.daemon = daemon
     self.plugins = plugins
     self.windows = []
     self.efilter = OpenFileEventFilter(self.windows)
     self.app = QElectrumApplication(sys.argv)
     self.app.installEventFilter(self.efilter)
     self.timer = Timer()
     self.nd = None
     self.network_updated_signal_obj = QNetworkUpdatedSignalObject()
     # init tray
     self.dark_icon = self.config.get("dark_icon", False)
     self.tray = QSystemTrayIcon(self.tray_icon(), None)
     self.tray.setToolTip('Qtum Electrum')
     self.tray.activated.connect(self.tray_activated)
     self.build_tray_menu()
     self.tray.show()
     self.app.new_window_signal.connect(self.start_new_window)
     run_hook('init_qt', self)
Ejemplo n.º 2
0
    def on_update(self):
        wallet = self.parent.wallet
        item = self.currentItem()
        current_key = item.data(0, Qt.UserRole) if item else None
        self.clear()
        for hist in wallet.get_token_history():
            _from, to, amount, token, txid, height, conf, timestamp, call_index, log_index = hist
            payout = False
            if _from == to:
                amount = 0
            if hash160_to_p2pkh(binascii.a2b_hex(to)) == token.bind_addr:
                balance_str = '+'
            else:
                balance_str = '-'
                payout = True
            balance_str += '{}'.format(amount / 10**token.decimals)
            tx_mined_status = TxMinedStatus(height, conf, timestamp, None)
            status, status_str = wallet.get_tx_status(txid, tx_mined_status)
            icon = self.icon_cache.get(":icons/" + TX_ICONS[status])

            item = QTreeWidgetItem(
                ['', status_str, token.bind_addr, token.symbol, balance_str])
            item.setIcon(0, icon)
            item.setToolTip(
                0,
                str(conf) + " confirmation" + ("s" if conf != 1 else ""))
            item.setData(0, Qt.UserRole, txid)
            item.setTextAlignment(0, Qt.AlignLeft | Qt.AlignVCenter)
            self.addTopLevelItem(item)
            if txid == current_key:
                self.setCurrentItem(item)
            if payout:
                item.setForeground(3, QBrush(QColor("#BC1E1E")))
                item.setForeground(4, QBrush(QColor("#BC1E1E")))
        run_hook('update_token_hist_tab', self)
Ejemplo n.º 3
0
 def create_window_for_wallet(self, wallet):
     w = ElectrumWindow(self, wallet)
     self.windows.append(w)
     self.build_tray_menu()
     # FIXME: Remove in favour of the load_wallet hook
     run_hook('on_new_window', w)
     return w
Ejemplo n.º 4
0
 def close_window(self, window):
     self.windows.remove(window)
     self.build_tray_menu()
     # save wallet path of last open window
     if not self.windows:
         self.config.save_last_wallet(window.wallet)
     run_hook('on_close_window', window)
Ejemplo n.º 5
0
 def create_menu(self, position):
     menu = QMenu()
     selected = self.selectedItems()
     multi_select = len(selected) > 1
     if not selected:
         menu.addAction(_("Add Token"),
                        lambda: self.parent.token_add_dialog())
     elif not multi_select:
         item = selected[0]
         name = item.text(0)
         bind_addr = item.text(1)
         contract_addr = item.data(0, Qt.UserRole)
         key = '{}_{}'.format(contract_addr, bind_addr)
         token = self.parent.tokens.get(key, None)
         column = self.currentColumn()
         column_title = self.headerItem().text(column)
         column_data = '\n'.join([item.text(column) for item in selected])
         menu.addAction(
             _("Copy %s") % column_title,
             lambda: self.parent.app.clipboard().setText(column_data))
         menu.addAction(_("View Info"),
                        lambda: self.parent.token_view_dialog(token))
         menu.addAction(_("Send"),
                        lambda: self.parent.token_send_dialog(token))
         menu.addAction(_("Delete"), lambda: self.parent.delete_token(key))
         URL = block_explorer_URL(self.config, {
             'addr': bind_addr,
             'token': contract_addr
         })
         if URL:
             menu.addAction(_("View on block explorer"),
                            lambda: open_browser(URL))
     run_hook('create_tokens_menu', menu, selected)
     menu.exec_(self.viewport().mapToGlobal(position))
Ejemplo n.º 6
0
 def create_menu(self, position):
     menu = QMenu()
     selected = self.selectedItems()
     multi_select = len(selected) > 1
     if not selected:
         menu.addAction(_("Add contract"),
                        lambda: self.parent.contract_add_dialog())
         menu.addAction(_("Create contract"),
                        lambda: self.parent.contract_create_dialog())
     elif not multi_select:
         item = selected[0]
         name = item.text(0)
         address = item.text(1)
         column = self.currentColumn()
         column_title = self.headerItem().text(column)
         column_data = '\n'.join([item.text(column) for item in selected])
         menu.addAction(
             _("Copy %s") % column_title,
             lambda: self.parent.app.clipboard().setText(column_data))
         menu.addAction(_("Edit"),
                        lambda: self.parent.contract_edit_dialog(address))
         menu.addAction(_("Function"),
                        lambda: self.parent.contract_func_dialog(address))
         menu.addAction(_("Delete"),
                        lambda: self.parent.delete_samart_contact(address))
         URL = block_explorer_URL(self.config, {'contract': address})
         if URL:
             menu.addAction(_("View on block explorer"),
                            lambda: open_browser(URL))
     run_hook('create_smart_contract_menu', menu, selected)
     menu.exec_(self.viewport().mapToGlobal(position))
Ejemplo n.º 7
0
 def __init__(self, text="", allow_multi=False):
     ButtonsTextEdit.__init__(self, text)
     self.allow_multi = allow_multi
     self.setReadOnly(0)
     self.addButton("file.png", self.file_input, _("Read file"))
     icon = "qrcode.png"
     self.addButton(icon, self.qr_input, _("Read QR code"))
     run_hook('scan_text_edit', self)
Ejemplo n.º 8
0
 def __init__(self, parent, contract=None):
     QDialog.__init__(self, parent=parent)
     self.setWindowTitle(_('Smart Contract'))
     self.setMinimumSize(700, 400)
     self.main_window = parent
     run_hook('contract_edit_dialog', self)
     layout = ContractInfoLayout(self, contract, callback=self.save)
     self.setLayout(layout)
Ejemplo n.º 9
0
 def __init__(self, parent, contract):
     QDialog.__init__(self, parent=parent)
     self.contract = contract
     self.setWindowTitle(contract['name'])
     self.setMinimumSize(700, 200)
     self.main_window = parent
     run_hook('contract_func_dialog', self)
     layout = ContractFuncLayout(self, contract)
     self.setLayout(layout)
Ejemplo n.º 10
0
 def __init__(self, parent):
     QDialog.__init__(self, parent=parent)
     self.setWindowTitle(_('Create Smart Contract'))
     self.setMinimumSize(700, 400)
     self.setMaximumSize(780, 500)
     self.main_window = parent
     run_hook('contract_create_dialog', self)
     layout = ContractCreateLayout(self)
     self.setLayout(layout)
Ejemplo n.º 11
0
 def load_wallet(self, wallet):
     self.wallet = wallet
     self.update_wallet()
     # Once GUI has been initialized check if we want to announce something
     # since the callback has been called before the GUI was initialized
     if self.receive_screen:
         self.receive_screen.clear()
     self.update_tabs()
     run_hook('load_wallet', wallet, self)
Ejemplo n.º 12
0
 def on_update(self):
     item = self.currentItem()
     current_key = item.data(0, Qt.UserRole) if item else None
     self.clear()
     for address in sorted(self.parent.smart_contracts.keys()):
         name, abi = self.parent.smart_contracts[address]
         item = QTreeWidgetItem([name, address])
         item.setData(0, Qt.UserRole, address)
         self.addTopLevelItem(item)
         if address == current_key:
             self.setCurrentItem(item)
     run_hook('update_smart_contract_tab', self)
 def on_update(self):
     item = self.currentItem()
     current_key = item.data(0, Qt.UserRole) if item else None
     self.clear()
     for key in sorted(self.parent.contacts.keys()):
         _type, name = self.parent.contacts[key]
         item = QTreeWidgetItem([name, key])
         item.setData(0, Qt.UserRole, key)
         self.addTopLevelItem(item)
         if key == current_key:
             self.setCurrentItem(item)
     run_hook('update_contacts_tab', self)
Ejemplo n.º 14
0
    def update(self):
        desc = self.desc
        base_unit = self.main_window.base_unit()
        format_amount = self.main_window.format_amount
        tx_hash, status, label, can_broadcast, can_rbf, amount, fee, height, conf, timestamp, exp_n = self.wallet.get_tx_info(
            self.tx)
        size = self.tx.estimated_size()
        self.broadcast_button.setEnabled(can_broadcast)
        can_sign = not self.tx.is_complete() and \
                   (self.wallet.can_sign(self.tx) or bool(self.main_window.tx_external_keypairs))
        self.sign_button.setEnabled(can_sign)
        self.tx_hash_e.setText(tx_hash or _('Unknown'))
        if desc is None:
            self.tx_desc.hide()
        else:
            self.tx_desc.setText(_("Description") + ': ' + desc)
            self.tx_desc.show()
        self.status_label.setText(_('Status:') + ' ' + status)

        if timestamp:
            time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(
                ' ')[:-3]
            self.date_label.setText(_("Date: %s") % time_str)
            self.date_label.show()
        elif exp_n:
            text = '%d blocks' % (exp_n) if exp_n > 0 else _(
                'unknown (low fee)')
            self.date_label.setText(
                _('Expected confirmation time') + ': ' + text)
            self.date_label.show()
        else:
            self.date_label.hide()
        if amount is None:
            amount_str = _("Transaction unrelated to your wallet")
        elif amount > 0:
            amount_str = _("Amount received:"
                           ) + ' %s' % format_amount(amount) + ' ' + base_unit
        else:
            amount_str = _("Amount sent:"
                           ) + ' %s' % format_amount(-amount) + ' ' + base_unit
        size_str = _("Size:") + ' %d bytes' % size
        fee_str = _("Fee") + ': %s' % (format_amount(fee) + ' ' + base_unit
                                       if fee is not None else _('unknown'))
        if fee is not None:
            fee_str += '  ( %s )' % (format_amount(fee * 1000 / size) + ' ' +
                                     base_unit + '/kB')
        self.amount_label.setText(amount_str)
        self.fee_label.setText(fee_str)
        self.size_label.setText(size_str)
        run_hook('transaction_dialog_update', self)
Ejemplo n.º 15
0
 def __init__(self, parent=None, msg=None):
     msg = msg or _('Please enter your password')
     WindowModalDialog.__init__(self, parent, _("Enter Password"))
     self.pw = pw = QLineEdit()
     pw.setEchoMode(2)
     vbox = QVBoxLayout()
     vbox.addWidget(QLabel(msg))
     grid = QGridLayout()
     grid.setSpacing(8)
     grid.addWidget(QLabel(_('Password')), 1, 0)
     grid.addWidget(pw, 1, 1)
     vbox.addLayout(grid)
     vbox.addLayout(Buttons(CancelButton(self), OkButton(self)))
     self.setLayout(vbox)
     run_hook('password_dialog', pw, grid, 1)
Ejemplo n.º 16
0
 def on_update(self):
     item = self.currentItem()
     current_key = item.data(0, Qt.UserRole) if item else None
     self.clear()
     for key in sorted(self.parent.tokens.keys()):
         token = self.parent.tokens[key]
         balance_str = '{}'.format(token.balance / 10**token.decimals)
         # balance_str = format_satoshis(token.balance, is_diff=False, num_zeros=0,
         #                               decimal_point=token.decimals, whitespaces=True)
         item = QTreeWidgetItem([token.name, token.bind_addr, balance_str])
         item.setData(0, Qt.UserRole, token.contract_addr)
         item.setTextAlignment(0, Qt.AlignLeft | Qt.AlignVCenter)
         item.setTextAlignment(2, Qt.AlignRight | Qt.AlignVCenter)
         item.setFont(2, QFont(MONOSPACE_FONT))
         self.addTopLevelItem(item)
         if key == current_key:
             self.setCurrentItem(item)
     run_hook('update_tokens_tab', self)
Ejemplo n.º 17
0
 def on_start(self):
     ''' This is the start point of the kivy ui
     '''
     import time
     Logger.info('Time to on_start: {} <<<<<<<<'.format(time.clock()))
     win = Window
     win.bind(size=self.on_size, on_keyboard=self.on_keyboard)
     win.bind(on_key_down=self.on_key_down)
     #win.softinput_mode = 'below_target'
     self.on_size(win, win.size)
     self.init_ui()
     self.load_wallet_by_name(self.electrum_config.get_wallet_path())
     # init plugins
     run_hook('init_kivy', self)
     # fiat currency
     self.fiat_unit = self.fx.ccy if self.fx.is_enabled() else ''
     # default tab
     self.switch_to('history')
     # bind intent for bitcoin: URI scheme
     if platform == 'android':
         from android import activity
         from jnius import autoclass
         PythonActivity = autoclass('org.kivy.android.PythonActivity')
         mactivity = PythonActivity.mActivity
         self.on_new_intent(mactivity.getIntent())
         activity.bind(on_new_intent=self.on_new_intent)
     # connect callbacks
     if self.network:
         interests = [
             'updated', 'status', 'new_transaction', 'verified',
             'interfaces'
         ]
         self.network.register_callback(self.on_network_event, interests)
         self.network.register_callback(self.on_quotes, ['on_quotes'])
         self.network.register_callback(self.on_history, ['on_history'])
     # URI passed in config
     uri = self.electrum_config.get('url')
     if uri:
         self.set_URI(uri)
Ejemplo n.º 18
0
 def create_menu(self, position):
     item = self.itemAt(position)
     if not item:
         return
     addr = str(item.text(1))
     req = self.wallet.receive_requests[addr]
     column = self.currentColumn()
     column_title = self.headerItem().text(column)
     column_data = item.text(column)
     menu = QMenu(self)
     menu.addAction(
         _("Copy %s") % column_title,
         lambda: self.parent.app.clipboard().setText(column_data))
     menu.addAction(
         _("Copy URI"), lambda: self.parent.view_and_paste(
             'URI', '', self.parent.get_request_URI(addr)))
     menu.addAction(_("Save as BIP70 file"),
                    lambda: self.parent.export_payment_request(addr))
     menu.addAction(_("Delete"),
                    lambda: self.parent.delete_payment_request(addr))
     run_hook('receive_list_menu', menu, addr)
     menu.exec_(self.viewport().mapToGlobal(position))
Ejemplo n.º 19
0
 def create_menu(self, position):
     menu = QMenu()
     selected = self.selectedItems()
     multi_select = len(selected) > 1
     if not selected:
         pass
     elif not multi_select:
         item = selected[0]
         txid = item.data(0, Qt.UserRole)
         column = self.currentColumn()
         column_title = self.headerItem().text(column)
         column_data = '\n'.join([item.text(column) for item in selected])
         menu.addAction(
             _("Copy %s") % column_title,
             lambda: self.parent.app.clipboard().setText(column_data))
         menu.addAction(_("Copy Transaction ID"),
                        lambda: self.parent.app.clipboard().setText(txid))
         URL = block_explorer_URL(self.config, {'tx': txid})
         if URL:
             menu.addAction(_("View on block explorer"),
                            lambda: open_browser(URL))
     run_hook('create_token_hist_menu', menu, selected)
     menu.exec_(self.viewport().mapToGlobal(position))
    def create_menu(self, position):
        menu = QMenu()
        selected = self.selectedItems()
        if not selected:
            menu.addAction(_("New contact"),
                           lambda: self.parent.new_contact_dialog())
            menu.addAction(_("Import file"), lambda: self.import_contacts())
            menu.addAction(_("Export file"), lambda: self.export_contacts())
        else:
            names = [item.text(0) for item in selected]
            keys = [item.text(1) for item in selected]
            column = self.currentColumn()
            column_title = self.headerItem().text(column)
            column_data = '\n'.join([item.text(column) for item in selected])
            menu.addAction(
                _("Copy %s") % column_title,
                lambda: self.parent.app.clipboard().setText(column_data))
            if column in self.editable_columns:
                item = self.currentItem()
                menu.addAction(
                    _("Edit %s") % column_title,
                    lambda: self.editItem(item, column))
            menu.addAction(_("Pay to"),
                           lambda: self.parent.payto_contacts(keys))
            menu.addAction(_("Delete"),
                           lambda: self.parent.delete_contacts(keys))
            URLs = [
                block_explorer_URL(self.config, {'addr': key})
                for key in filter(is_address, keys)
            ]
            if URLs:
                menu.addAction(_("View on block explorer"),
                               lambda: map(open_browser, URLs))

        run_hook('create_contact_menu', menu, selected)
        menu.exec_(self.viewport().mapToGlobal(position))
Ejemplo n.º 21
0
    def __init__(self, tx, parent, desc, prompt_if_unsaved):
        '''Transactions in the wallet will show their description.
        Pass desc to give a description for txs not yet in the wallet.
        '''
        # We want to be a top-level window
        QDialog.__init__(self, parent=None)
        # Take a copy; it might get updated in the main window by
        # e.g. the FX plugin.  If this happens during or after a long
        # sign operation the signatures are lost.
        self.tx = tx = copy.deepcopy(tx)
        try:
            self.tx.deserialize()
        except BaseException as e:
            raise SerializationError(e)
        self.main_window = parent
        self.wallet = parent.wallet
        self.prompt_if_unsaved = prompt_if_unsaved
        self.saved = False
        self.desc = desc

        # if the wallet can populate the inputs with more info, do it now.
        # as a result, e.g. we might learn an imported address tx is segwit,
        # in which case it's ok to display txid
        self.wallet.add_input_info_to_all_inputs(tx)

        self.setMinimumWidth(880)
        self.setWindowTitle(_("Transaction"))

        vbox = QVBoxLayout()
        self.setLayout(vbox)

        vbox.addWidget(QLabel(_("Transaction ID:")))
        self.tx_hash_e  = ButtonsLineEdit()
        qr_show = lambda: parent.show_qrcode(str(self.tx_hash_e.text()), 'Transaction ID', parent=self)
        self.tx_hash_e.addButton(":icons/qrcode.png", qr_show, _("Show as QR code"))
        self.tx_hash_e.setReadOnly(True)
        vbox.addWidget(self.tx_hash_e)
        self.tx_desc = QLabel()
        vbox.addWidget(self.tx_desc)
        self.status_label = QLabel()
        vbox.addWidget(self.status_label)
        self.date_label = QLabel()
        vbox.addWidget(self.date_label)
        self.amount_label = QLabel()
        vbox.addWidget(self.amount_label)
        self.size_label = QLabel()
        vbox.addWidget(self.size_label)
        self.fee_label = QLabel()
        vbox.addWidget(self.fee_label)

        self.add_io(vbox)

        self.sign_button = b = QPushButton(_("Sign"))
        b.clicked.connect(self.sign)

        self.broadcast_button = b = QPushButton(_("Broadcast"))
        b.clicked.connect(self.do_broadcast)

        self.save_button = b = QPushButton(_("Save"))
        save_button_disabled = not tx.is_complete()
        b.setDisabled(save_button_disabled)
        if save_button_disabled:
            b.setToolTip(SAVE_BUTTON_DISABLED_TOOLTIP)
        else:
            b.setToolTip(SAVE_BUTTON_ENABLED_TOOLTIP)
        b.clicked.connect(self.save)

        self.export_button = b = QPushButton(_("Export"))
        b.clicked.connect(self.export)

        self.cancel_button = b = QPushButton(_("Close"))
        b.clicked.connect(self.close)
        b.setDefault(True)

        self.qr_button = b = QPushButton()
        b.setIcon(QIcon(":icons/qrcode.png"))
        b.clicked.connect(self.show_qr)

        self.copy_button = CopyButton(lambda: str(self.tx), parent.app)

        # Action buttons
        self.buttons = [self.sign_button, self.broadcast_button, self.cancel_button]
        # Transaction sharing buttons
        self.sharing_buttons = [self.copy_button, self.qr_button, self.export_button, self.save_button]

        run_hook('transaction_dialog', self)

        hbox = QHBoxLayout()
        share_btn_layout = Buttons(*self.sharing_buttons)
        hbox.addLayout(share_btn_layout)
        run_hook('send_tx_layout', self, share_btn_layout, tx)
        hbox.addStretch(1)
        hbox.addLayout(Buttons(*self.buttons))
        vbox.addLayout(hbox)
        self.update()
Ejemplo n.º 22
0
    def update(self):
        desc = self.desc
        base_unit = self.main_window.base_unit()
        format_amount = self.main_window.format_amount
        tx_details = self.wallet.get_tx_info(self.tx)
        tx_mined_info = tx_details.tx_mined_info
        exp_n = tx_details.mempool_depth_bytes
        amount, fee = tx_details.amount, tx_details.fee
        size = self.tx.estimated_size()
        self.broadcast_button.setEnabled(tx_details.can_broadcast)
        can_sign = not self.tx.is_complete() and \
                   (self.wallet.can_sign(self.tx) or bool(self.main_window.tx_external_keypairs))
        self.sign_button.setEnabled(can_sign)
        self.tx_hash_e.setText(tx_details.txid or _('Unknown'))

        if desc is None:
            self.tx_desc.hide()
        else:
            self.tx_desc.setText(_("Description") + ': ' + desc)
            self.tx_desc.show()
        self.status_label.setText(_('Status:') + ' ' + tx_details.status)

        if tx_mined_info.timestamp:
            time_str = datetime.datetime.fromtimestamp(
                tx_mined_info.timestamp).isoformat(' ')[:-3]
            self.date_label.setText(_("Date: %s") % time_str)
            self.date_label.show()
        elif exp_n:
            text = '%d blocks' % (exp_n) if exp_n > 0 else _(
                'unknown (low fee)')
            self.date_label.setText(
                _('Expected confirmation time') + ': ' + text)
            self.date_label.show()
        else:
            self.date_label.hide()
        self.locktime_label.setText(f"LockTime: {self.tx.locktime}")
        self.rbf_label.setText(f"RBF: {not self.tx.is_final()}")
        if tx_mined_info.header_hash:
            self.block_hash_label.setText(
                _("Included in block: {}").format(tx_mined_info.header_hash))
            self.block_height_label.setText(
                _("At block height: {}").format(tx_mined_info.height))
        else:
            self.block_hash_label.hide()
            self.block_height_label.hide()

        if amount is None:
            amount_str = _("Transaction unrelated to your wallet")
        elif amount > 0:
            amount_str = _("Amount received:"
                           ) + ' %s' % format_amount(amount) + ' ' + base_unit
        else:
            amount_str = _("Amount sent:"
                           ) + ' %s' % format_amount(-amount) + ' ' + base_unit
        size_str = _("Size:") + ' %d bytes' % size
        fee_str = _("Fee") + ': %s' % (format_amount(fee) + ' ' + base_unit
                                       if fee is not None else _('unknown'))
        if fee is not None:
            fee_str += '  ( %s )' % (format_amount(fee * 1000 / size) + ' ' +
                                     base_unit + '/kB')
        self.amount_label.setText(amount_str)
        self.fee_label.setText(fee_str)
        self.size_label.setText(size_str)
        run_hook('transaction_dialog_update', self)
Ejemplo n.º 23
0
 def __init__(self, text=""):
     ButtonsTextEdit.__init__(self, text)
     self.setReadOnly(0)
     self.addButton("file.png", self.file_input, _("Read file"))
     self.addButton("qrcode.png", self.qr_input, _("Read QR code"))
     run_hook('scan_text_edit', self)
Ejemplo n.º 24
0
    def __init__(self, text=None):
        ButtonsTextEdit.__init__(self, text)
        self.setReadOnly(1)
        self.addButton("qrcode.png", self.qr_show, _("Show as QR code"))

        run_hook('show_text_edit', self)
Ejemplo n.º 25
0
    def create_menu(self, position):
        from qtum_electrum.wallet import Multisig_Wallet
        is_multisig = isinstance(self.wallet, Multisig_Wallet)
        can_delete = self.wallet.can_delete_address()
        selected = self.selectedItems()
        multi_select = len(selected) > 1
        addrs = [item.text(0) for item in selected]
        if not addrs:
            return
        if not multi_select:
            item = self.itemAt(position)
            col = self.currentColumn()
            if not item:
                return
            addr = addrs[0]
            if not is_address(addr):
                item.setExpanded(not item.isExpanded())
                return

        menu = QMenu()
        if not multi_select:
            column_title = self.headerItem().text(col)
            menu.addAction(
                _("Copy %s") % column_title,
                lambda: self.parent.app.clipboard().setText(item.text(col)))
            menu.addAction(_('Details'),
                           lambda: self.parent.show_address(addr))
            if col in self.editable_columns:
                menu.addAction(
                    _("Edit %s") % column_title,
                    lambda: self.editItem(item, col))
            menu.addAction(_("Request payment"),
                           lambda: self.parent.receive_at(addr))
            if self.wallet.can_export():
                menu.addAction(_("Private key"),
                               lambda: self.parent.show_private_key(addr))
            if not is_multisig and not self.wallet.is_watching_only():
                menu.addAction(_("Sign/verify message"),
                               lambda: self.parent.sign_verify_message(addr))
                menu.addAction(_("Encrypt/decrypt message"),
                               lambda: self.parent.encrypt_message(addr))
            if can_delete:
                menu.addAction(_("Remove from wallet"),
                               lambda: self.parent.remove_address(addr))
            addr_URL = block_explorer_URL(self.config, {'addr': addr})
            if addr_URL:
                menu.addAction(_("View on block explorer"),
                               lambda: open_browser(addr_URL))

            if not self.wallet.is_frozen(addr):
                menu.addAction(
                    _("Freeze"),
                    lambda: self.parent.set_frozen_state([addr], True))
            else:
                menu.addAction(
                    _("Unfreeze"),
                    lambda: self.parent.set_frozen_state([addr], False))

        coins = self.wallet.get_utxos(addrs)
        if coins:
            menu.addAction(_("Spend from"),
                           lambda: self.parent.spend_coins(coins))

        run_hook('receive_menu', menu, addrs, self.wallet)
        menu.exec_(self.viewport().mapToGlobal(position))