Пример #1
0
    def on_update(self) -> None:
        if self._send_view._account_id is None:
            return

        self._stop_timer()

        current_id = None
        if self._send_view._payment_request is not None:
            current_id = self._send_view._payment_request.get_id()
        if current_id is None:
            current_item = self.currentItem()
            current_id = current_item.data(
                COL_RECEIVED, Qt.UserRole) if current_item else None

        self.clear()

        current_item = None
        current_time = time.time()
        nearest_expiry_time = float("inf")

        for row in self._send_view._account.invoices.get_invoices():
            flags = row.flags & PaymentFlag.STATE_MASK
            if flags & PaymentFlag.UNPAID and row.date_expires:
                if row.date_expires <= current_time + 5:
                    flags = (row.flags
                             & ~PaymentFlag.UNPAID) | PaymentFlag.EXPIRED
                else:
                    nearest_expiry_time = min(nearest_expiry_time,
                                              row.date_expires)

            requestor_uri = urllib.parse.urlparse(row.payment_uri)
            requestor_text = requestor_uri.netloc
            received_text = format_time(row.date_created, _("Unknown"))
            expires_text = format_time(
                row.date_expires,
                _("Unknown") if row.date_expires else _('Never'))
            item = QTreeWidgetItem([
                received_text,
                expires_text,
                requestor_text,
                row.description,
                app_state.format_amount(row.value, whitespaces=True),
                # The tooltip text should be None to ensure the icon does not have extra RHS space.
                pr_tooltips.get(flags, None)
            ])
            icon_entry = pr_icons.get(flags)
            if icon_entry:
                item.setIcon(COL_STATUS, read_QIcon(icon_entry))
            if row.invoice_id == current_id:
                current_item = item
            item.setData(COL_RECEIVED, Qt.UserRole, row.invoice_id)
            item.setFont(COL_DESCRIPTION, self._monospace_font)
            item.setFont(COL_AMOUNT, self._monospace_font)
            self.addTopLevelItem(item)

        if current_item is not None:
            self.setCurrentItem(current_item)

        if nearest_expiry_time != float("inf"):
            self._start_timer(nearest_expiry_time)
Пример #2
0
    def on_update(self) -> None:
        if self._account_id is None:
            return

        invoices = self._account.invoices
        inv_list = invoices.unpaid_invoices()
        self.clear()
        for pr in inv_list:
            request_id = pr.get_id()
            status = invoices.get_status(request_id)
            requestor = pr.get_requestor()
            exp = pr.get_expiration_date()
            date_str = format_time(exp, _("Unknown")) if exp else _('Never')
            item = QTreeWidgetItem([
                date_str, requestor, pr.memo,
                self._main_window.format_amount(pr.get_amount(),
                                                whitespaces=True),
                pr_tooltips.get(status, '')
            ])
            item.setIcon(4, read_QIcon(pr_icons.get(status)))
            item.setData(0, Qt.UserRole, (self._account_id, request_id))
            item.setFont(1, self.monospace_font)
            item.setFont(3, self.monospace_font)
            self.addTopLevelItem(item)
        self.setCurrentItem(self.topLevelItem(0))
        self.setVisible(len(inv_list))
        self._main_window.invoices_label.setVisible(len(inv_list))
Пример #3
0
 def test_get_tx_desc(self) -> None:
     from electrumsv.gui.qt.history_list import TxStatus, TX_STATUS, get_tx_desc
     # Values with a text description should return that text description.
     for status_kind in [ TxStatus.UNCONFIRMED, TxStatus.MISSING ]:
         self.assertEqual(TX_STATUS[status_kind], get_tx_desc(status_kind, 1))
     # Otherwise the timestamp should be used.
     time_string = format_time(1, "...")
     self.assertNotEqual("...", time_string)
     self.assertEqual(time_string, get_tx_desc(TxStatus.FINAL, 1))
     self.assertEqual(_("unknown"), get_tx_desc(TxStatus.FINAL, False))
Пример #4
0
    def on_update(self):
        self.wallet = self.parent.wallet
        # hide receive tab if no receive requests available
        b = len(self.wallet.receive_requests) > 0
        self.setVisible(b)
        self.parent.receive_requests_label.setVisible(b)
        if not b:
            self.parent.expires_label.hide()
            self.parent.expires_combo.show()

        # update the receive address if necessary
        current_address_string = self.parent.receive_address_e.text().strip()
        current_address = (Address.from_string(current_address_string)
                           if len(current_address_string) else None)
        domain = self.wallet.get_receiving_addresses()
        addr = self.wallet.get_unused_address()
        if not current_address in domain and addr:
            self.parent.set_receive_address(addr)
        self.parent.new_request_button.setEnabled(addr != current_address)

        # clear the list and fill it again
        self.clear()
        for req in self.wallet.get_sorted_requests(self.config):
            address = req['address']
            if address not in domain:
                continue
            timestamp = req.get('time', 0)
            amount = req.get('amount')
            expiration = req.get('exp', None)
            message = req.get('memo', '')
            date = format_time(timestamp)
            status = req.get('status')
            signature = req.get('sig')
            requestor = req.get('name', '')
            amount_str = self.parent.format_amount(amount) if amount else ""
            item = QTreeWidgetItem([
                date,
                address.to_ui_string(), '', message, amount_str,
                pr_tooltips.get(status, '')
            ])
            item.setData(0, Qt.UserRole, address)
            if signature is not None:
                item.setIcon(2, QIcon(":icons/seal.png"))
                item.setToolTip(2, 'signed by ' + requestor)
            if status is not PR_UNKNOWN:
                item.setIcon(6, QIcon(pr_icons.get(status)))
            self.addTopLevelItem(item)
Пример #5
0
    def on_update(self) -> None:
        if self._account_id is None:
            return

        # hide receive tab if no receive requests available
        b = len(self._account._payment_requests) > 0
        self.setVisible(b)
        self._main_window.receive_requests_label.setVisible(b)
        if not b:
            self._main_window.expires_label.hide()
            self._main_window.expires_combo.show()

        # update the receive address if necessary
        current_key_id = self._main_window.get_receive_key_id()
        if current_key_id is None:
            return

        keyinstance = None
        if self._account.is_deterministic():
            keyinstance = self._account.get_fresh_keys(RECEIVING_SUBPATH, 1)[0]
        if keyinstance is not None:
            self._main_window.set_receive_key(keyinstance)
        self._main_window.new_request_button.setEnabled(
            current_key_id != keyinstance.keyinstance_id)

        account_id = self._account.get_id()

        # clear the list and fill it again
        self.clear()
        for req in self._account.get_sorted_requests():
            date = format_time(req.date_created, _("Unknown"))
            amount_str = self._main_window.format_amount(
                req.value) if req.value else ""

            script_template = self._account.get_script_template_for_id(
                req.keyinstance_id)
            address_text = script_template_to_string(script_template)

            item = QTreeWidgetItem([
                date, address_text, '', req.description or "", amount_str,
                pr_tooltips.get(req.state, '')
            ])
            item.setData(0, Qt.UserRole, req.paymentrequest_id)
            if req.state != PaymentState.UNKNOWN:
                item.setIcon(6, read_QIcon(pr_icons.get(req.state)))
            self.addTopLevelItem(item)
Пример #6
0
 def get_tx_status(self, tx_hash, height, conf, timestamp):
     if conf == 0:
         tx = self.wallet.get_transaction(tx_hash)
         if not tx:
             return 3, _('unknown')
         if height < 0:
             status = 0
         elif height == 0:
             status = 1
         else:
             status = 2
     else:
         status = 3 + min(conf, 6)
     if status < len(TX_STATUS):
         status_str = TX_STATUS[status]
     else:
         status_str = format_time(timestamp, _("unknown")) if timestamp else _("unknown")
     return status, status_str
Пример #7
0
    def add_main_content(self, parent_layout: QHBoxLayout) -> None:
        layout = QVBoxLayout()
        parent_layout.addLayout(layout)

        layout.addStretch(1)
        if self._row.event_type == WalletEventType.SEED_BACKUP_REMINDER:
            title_label = QLabel(_("Backup your wallet"))
            title_label.setObjectName("NotificationCardTitle")

            description_label = QLabel(
                _("You should make sure you back up your wallet. If you "
                  "lose access to it, you may not have any way to access or recover your funds and "
                  "any other information it may contain. In the worst case, you may be able to "
                  "write down and use your "
                  "<a href=\"action:view-secured-data\">account's secured data</a>. More information "
                  "is <a href=\"help:view-secured-data\">available here</a>."))
            description_label.setObjectName("NotificationCardDescription")
            description_label.setWordWrap(True)
            description_label.setTextInteractionFlags(
                Qt.TextBrowserInteraction)
            description_label.linkActivated.connect(self.on_link_activated)

            date_context_label = QLabel(
                format_time(self._row.date_created, _("Unknown")))
            date_context_label.setAlignment(Qt.AlignRight)
            date_context_label.setObjectName("NotificationCardContext")

            account_name = self._context.wallet_api.get_account_name(
                self._row.account_id)
            account_context_label = QLabel(
                _("Account: {}").format(account_name))
            account_context_label.setObjectName("NotificationCardContext")

            bottom_layout = QHBoxLayout()
            bottom_layout.addWidget(account_context_label, 1, Qt.AlignLeft)
            bottom_layout.addWidget(date_context_label, 1, Qt.AlignRight)

            layout.addWidget(title_label)
            layout.addWidget(description_label)
            layout.addLayout(bottom_layout)
        else:
            layout.addWidget(QLabel("Not yet implemented"))
        layout.addStretch(1)
Пример #8
0
    def on_update(self) -> None:
        if self._account_id is None:
            return

        wallet = self._account._wallet
        with wallet.get_payment_request_table() as table:
            rows = table.read(self._account_id, flags=PaymentFlag.NONE,
                mask=PaymentFlag.ARCHIVED)

        # update the receive address if necessary
        current_key_id = self._receive_view.get_receive_key_id()
        if current_key_id is None:
            return

        keyinstance = None
        if self._account.is_deterministic():
            keyinstance = self._account.get_fresh_keys(RECEIVING_SUBPATH, 1)[0]
        if keyinstance is not None:
            self._receive_view.set_receive_key(keyinstance)
            self._receive_view.set_new_button_enabled(current_key_id != keyinstance.keyinstance_id)

        # clear the list and fill it again
        self.clear()
        for row in rows:
            date = format_time(row.date_created, _("Unknown"))
            amount_str = app_state.format_amount(row.value, whitespaces=True) if row.value else ""

            script_template = self._account.get_script_template_for_id(row.keyinstance_id)
            address_text = script_template_to_string(script_template)

            state = row.state & sum(pr_icons.keys())
            item = QTreeWidgetItem([date, address_text, '', row.description or "",
                amount_str, pr_tooltips.get(state,'')])
            item.setData(0, Qt.UserRole, row.paymentrequest_id)
            if state != PaymentFlag.UNKNOWN:
                icon_name = pr_icons.get(state)
                if icon_name is not None:
                    item.setIcon(6, read_QIcon(icon_name))
            item.setFont(4, self._monospace_font)
            self.addTopLevelItem(item)
Пример #9
0
 def on_update(self):
     inv_list = self.parent.invoices.unpaid_invoices()
     self.clear()
     for pr in inv_list:
         key = pr.get_id()
         status = self.parent.invoices.get_status(key)
         requestor = pr.get_requestor()
         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.setData(0, Qt.UserRole, key)
         item.setFont(1, QFont(MONOSPACE_FONT))
         item.setFont(3, QFont(MONOSPACE_FONT))
         self.addTopLevelItem(item)
     self.setCurrentItem(self.topLevelItem(0))
     self.setVisible(len(inv_list))
     self.parent.invoices_label.setVisible(len(inv_list))
Пример #10
0
def get_tx_desc(status: TxStatus, timestamp: Union[bool, int]) -> str:
    if status in [TxStatus.UNCONFIRMED, TxStatus.MISSING]:
        return TX_STATUS[status]
    return format_time(timestamp, _("unknown")) if timestamp else _("unknown")
Пример #11
0
    def data(self, model_index: QModelIndex, role: int) -> QVariant:
        row = model_index.row()
        column = model_index.column()
        if row >= len(self._data):
            return None
        if column >= len(self._column_names):
            return None

        if model_index.isValid():
            line = self._data[row]

            # First check the custom sort role.
            if role == QT_SORT_ROLE:
                if column == DATE_ADDED_COLUMN:
                    return line.date_added
                elif column == DATE_UPDATED_COLUMN:
                    return line.date_updated
                elif column == STATE_COLUMN:
                    if line.flags & TxFlags.StateDispatched:
                        return 0
                    elif line.flags & TxFlags.StateReceived:
                        return 2
                    elif line.flags & TxFlags.StateSigned:
                        return 1
                    else:
                        return 3
                elif column == LABEL_COLUMN:
                    return self._view._wallet.get_transaction_label(line.hash)
                elif column in (VALUE_COLUMN, FIAT_VALUE_COLUMN):
                    return line.value

            elif role == Qt.DecorationRole:
                if column == LABEL_COLUMN and line.flags & TxFlags.PaysInvoice:
                    return self._view._invoice_icon

            elif role == Qt.DisplayRole:
                if column == DATE_ADDED_COLUMN:
                    return (format_time(line.date_added, _("unknown"))
                        if line.date_added else _("unknown"))
                elif column == DATE_UPDATED_COLUMN:
                    return (format_time(line.date_updated, _("unknown"))
                        if line.date_updated else _("unknown"))

                elif column == STATE_COLUMN:
                    if line.flags & TxFlags.StateDispatched:
                        return _("Dispatched")
                    elif line.flags & TxFlags.StateReceived:
                        return _("Received")
                    elif line.flags & TxFlags.StateSigned:
                        return _("Signed")
                    return line.flags
                elif column == LABEL_COLUMN:
                    return self._view._wallet.get_transaction_label(line.hash)
                elif column == VALUE_COLUMN:
                    return app_state.format_amount(line.value, whitespaces=True)
                elif column == FIAT_VALUE_COLUMN:
                    fx = app_state.fx
                    rate = fx.exchange_rate()
                    return fx.value_str(line.value, rate)

            elif role == Qt.FontRole:
                if column in (VALUE_COLUMN, FIAT_VALUE_COLUMN):
                    return self._monospace_font

            elif role == Qt.TextAlignmentRole:
                if column in (VALUE_COLUMN, FIAT_VALUE_COLUMN):
                    return Qt.AlignRight | Qt.AlignVCenter
                return Qt.AlignVCenter

            elif role == Qt.ToolTipRole:
                if column == LABEL_COLUMN:
                    if line.flags & TxFlags.PaysInvoice:
                        return _("This transaction is associated with an invoice.")
                elif column == STATE_COLUMN:
                    if line.flags & TxFlags.StateDispatched:
                        return _("This transaction has been sent to the network, but has not "
                            "cleared yet.")
                    elif line.flags & TxFlags.StateReceived:
                        return _("This transaction has been received from another party, but "
                            "has not been broadcast yet.")
                    elif line.flags & TxFlags.StateSigned:
                        return _("This transaction has been signed, but has not been broadcast "
                            "yet.")

            elif role == Qt.EditRole:
                if column == LABEL_COLUMN:
                    return self._view._wallet.get_transaction_label(line.hash)
Пример #12
0
 def _format_tx_status(self, status: int, timestamp: int) -> str:
     if status < len(TX_STATUS):
         return TX_STATUS[status]
     return format_time(timestamp,
                        _("Unknown")) if timestamp else _("Unknown")
Пример #13
0
    def __init__(self, main_window: 'ElectrumWindow', row: InvoiceRow) -> None:
        super().__init__(main_window, _("Invoice"))

        self.setMinimumWidth(400)

        self._main_window = weakref.proxy(main_window)

        self._pr = pr = PaymentRequest.from_json(row.invoice_data)

        state = row.flags & PaymentFlag.STATE_MASK
        if state & PaymentFlag.UNPAID and has_expired(row.date_expires):
            state = PaymentFlag.EXPIRED

        total_amount = 0
        for output in pr.outputs:
            total_amount += output.amount

        vbox = QVBoxLayout(self)
        form = FormSectionWidget(minimum_label_width=120)
        form.add_row(_('Type'), QLabel(_("BIP270")))
        form.add_row(_("State"), QLabel(pr_tooltips.get(state, _("Unknown"))))
        form.add_row(
            _('Amount'),
            QLabel(
                app_state.format_amount(output.amount) + " " +
                app_state.base_unit()))
        form.add_row(_('Memo'), QLabel(row.description))
        form.add_row(_('Date Created'),
                     QLabel(format_time(pr.creation_timestamp, _("Unknown"))))
        form.add_row(_('Date Received'),
                     QLabel(format_time(row.date_created, _("Unknown"))))
        if row.date_expires:
            form.add_row(_('Date Expires'),
                         QLabel(format_time(row.date_expires, _("Unknown"))))
        vbox.addWidget(form)

        self._table = table = ButtonsTableWidget()
        table.setSelectionBehavior(QAbstractItemView.SelectRows)
        table.setSelectionMode(QAbstractItemView.SingleSelection)

        vh = table.verticalHeader()
        vh.setSectionResizeMode(QHeaderView.ResizeToContents)
        vh.hide()

        table.setColumnCount(3)
        table.setContextMenuPolicy(Qt.CustomContextMenu)
        table.customContextMenuRequested.connect(self._on_table_menu)
        table.setHorizontalHeaderLabels(self._table_column_names)
        table.setRowCount(len(pr.outputs))
        # table.addButton("icons8-copy-to-clipboard-32.png", f,
        #     _("Copy all listed destinations to the clipboard"))
        # table.addButton("icons8-save-as-32-windows.png", f,
        #     _("Save the listed destinations to a file"))
        hh = table.horizontalHeader()
        hh.setStretchLastSection(True)

        for row, output in enumerate(pr.outputs):
            label = QLabel(
                app_state.format_amount(output.amount) + " " +
                app_state.base_unit())
            table.setCellWidget(row, 0, label)

            table.setCellWidget(row, 1, QLabel(output.description))

            kind = classify_output_script(output.script, Net.COIN)
            text = script_to_display_text(output.script, kind)
            table.setCellWidget(row, 2, QLabel(text))

            vbox.addWidget(table, 1)

        def do_export():
            fn = self._main_window.getSaveFileName(_("Export invoice to file"),
                                                   "*.bip270.json")
            if not fn:
                return
            with open(fn, 'w') as f:
                data = f.write(row.invoice_data)
            self._main_window.show_message(_('Invoice saved as' + ' ' + fn))

        exportButton = EnterButton(_('Export'), do_export)

        def do_delete():
            if self.question(
                    _('Are you sure you want to delete this invoice?'),
                    title=_("Delete invoice"),
                    icon=QMessageBox.Warning):
                self._main_window._send_view._invoice_list._delete_invoice(
                    row.invoice_id)
                self.close()

        deleteButton = EnterButton(_('Delete'), do_delete)

        vbox.addLayout(Buttons(exportButton, deleteButton, CloseButton(self)))