Skip to content
Snippets Groups Projects
currency_tab.py 13.24 KiB
'''
Created on 2 févr. 2014

@author: inso
'''

import time
import logging
from PyQt5.QtWidgets import QWidget, QMenu, QAction, QApplication, \
                            QMessageBox, QDialog, QAbstractItemView, QHeaderView
from PyQt5.QtCore import QModelIndex, Qt, pyqtSlot, \
                        QThread, QDateTime
from PyQt5.QtGui import QIcon, QCursor
from ..gen_resources.currency_tab_uic import Ui_CurrencyTabWidget
from .community_tab import CommunityTabWidget
from .transfer import TransferMoneyDialog
from .wallets_tab import WalletsTabWidget
from .network_tab import NetworkTabWidget
from ..models.txhistory import HistoryTableModel, TxFilterProxyModel
from .informations_tab import InformationsTabWidget
from ..tools.exceptions import MembershipNotFoundError
from ..core.wallet import Wallet
from ..core.person import Person
from ..core.transfer import Transfer
from ..core.watchers.blockchain import BlockchainWatcher
from ..core.watchers.persons import PersonsWatcher


class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget):

    '''
    classdocs
    '''

    def __init__(self, app, community, password_asker, status_label):
        '''
        Constructor
        '''
        super().__init__()
        self.setupUi(self)
        self.app = app
        self.community = community
        self.password_asker = password_asker
        self.status_label = status_label
        self.tab_community = CommunityTabWidget(self.app.current_account,
                                                    self.community,
                                                    self.password_asker)
        self.tab_wallets = WalletsTabWidget(self.app,
                                            self.app.current_account,
                                            self.community,
                                            self.password_asker)

        self.tab_network = NetworkTabWidget(self.community)

        self.bc_watcher = BlockchainWatcher(self.app.current_account,
                                                community)
        self.bc_watcher.new_block_mined.connect(self.refresh_block)
        self.bc_watcher.connection_error.connect(self.display_error)

        self.watcher_thread = QThread()
        self.bc_watcher.moveToThread(self.watcher_thread)
        self.watcher_thread.started.connect(self.bc_watcher.watch)

        self.watcher_thread.start()

        self.persons_watcher = PersonsWatcher(self.community)
        self.persons_watcher.person_changed.connect(self.tab_community.refresh_person)
        self.persons_watcher_thread = QThread()
        self.persons_watcher.moveToThread(self.persons_watcher_thread)
        self.persons_watcher_thread.started.connect(self.persons_watcher.watch)
        self.persons_watcher.end_watching.connect(self.persons_watcher_thread.finished)
        self.persons_watcher_thread.start()

        person = Person.lookup(self.app.current_account.pubkey, self.community)
        try:
            join_block = person.membership(self.community)['blockNumber']
            join_date = self.community.get_block(join_block).mediantime
            parameters = self.community.parameters
            expiration_date = join_date + parameters['sigValidity']
            current_time = time.time()
            sig_validity = self.community.parameters['sigValidity']
            warning_expiration_time = int(sig_validity / 3)
            will_expire_soon = (current_time > expiration_date - warning_expiration_time)

            if will_expire_soon:
                days = QDateTime().currentDateTime().daysTo(QDateTime.fromTime_t(expiration_date))
                if days > 0:
                    QMessageBox.warning(
                        self,
                        "Membership expiration",
                        "Warning : Membership expiration in {0} days".format(days),
                        QMessageBox.Ok
                    )
        except MembershipNotFoundError as e:
            pass

    def refresh(self):
        if self.app.current_account is None:
            self.tabs_account.setEnabled(False)
        else:
            self.tabs_account.setEnabled(True)
            self.refresh_wallets()
            blockchain_init = QDateTime()
            blockchain_init.setTime_t(self.community.get_block(1).mediantime)

            self.date_from.setMinimumDateTime(blockchain_init)
            self.date_from.setDateTime(blockchain_init)
            self.date_from.setMaximumDateTime(QDateTime().currentDateTime())

            self.date_to.setMinimumDateTime(blockchain_init)
            tomorrow_datetime = QDateTime().currentDateTime().addDays(1)
            self.date_to.setDateTime(tomorrow_datetime)
            self.date_to.setMaximumDateTime(tomorrow_datetime)

            ts_from = self.date_from.dateTime().toTime_t()
            ts_to = self.date_to.dateTime().toTime_t()

            model = HistoryTableModel(self.app.current_account, self.community)
            proxy = TxFilterProxyModel(ts_from, ts_to)
            proxy.setSourceModel(model)
            proxy.setDynamicSortFilter(True)
            proxy.setSortRole(Qt.DisplayRole)

            self.table_history.setModel(proxy)
            self.table_history.setSelectionBehavior(QAbstractItemView.SelectRows)
            self.table_history.setSortingEnabled(True)
            self.table_history.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
            self.tab_community = CommunityTabWidget(self.app.current_account,
                                                    self.community,
                                                    self.password_asker)
            self.tabs_account.addTab(self.tab_community,
                                     QIcon(':/icons/community_icon'),
                                    "Community")

            self.tab_wallets = WalletsTabWidget(self.app,
                                                self.app.current_account,
                                                self.community,
                                                self.password_asker)
            self.tabs_account.addTab(self.tab_wallets,
                                     QIcon(':/icons/wallet_icon'),
                                    "Wallets")

            self.tab_informations = InformationsTabWidget(self.app.current_account,
                                                    self.community)
            self.tabs_account.addTab(self.tab_informations,
                                     QIcon(':/icons/informations_icon'),
                                    "Informations")

            # fix bug refresh_nodes launch on destroyed NetworkTabWidget
            logging.debug('Disconnect community.network.nodes_changed')
            try:
                self.community.network.nodes_changed.disconnect()
            except TypeError:
                logging.debug('No signals on community.network.nodes_changed')

            self.tab_network = NetworkTabWidget(self.community)
            self.tabs_account.addTab(self.tab_network,
                                     QIcon(":/icons/network_icon"),
                                     "Network")
            self.tab_informations.refresh()
            blockid = self.community.current_blockid()
            block_number = blockid['number']
            self.status_label.setText("Connected : Block {0}"
                                             .format(block_number))

    @pyqtSlot(str)
    def display_error(self, error):
        QMessageBox.critical(self, ":(",
                    error,
                    QMessageBox.Ok)

    @pyqtSlot(int)
    def refresh_block(self, block_number):
        if self.tab_wallets:
            self.tab_wallets.refresh()

        if self.table_history.model():
            self.table_history.model().dataChanged.emit(
                                                     QModelIndex(),
                                                     QModelIndex(),
                                                     [])

        self.persons_watcher_thread.start()

        text = "Connected : Block {0}".format(block_number)
        self.status_label.setText(text)

    def refresh_wallets(self):
        if self.app.current_account:
            self.tab_wallets.refresh()

    def wallet_context_menu(self, point):
        index = self.list_wallets.indexAt(point)
        model = self.list_wallets.model()
        if index.row() < model.rowCount(QModelIndex()):
            wallet = model.wallets[index.row()]
            menu = QMenu(model.data(index, Qt.DisplayRole), self)

            rename = QAction("Rename", self)
            rename.triggered.connect(self.rename_wallet)
            rename.setData(index)

            copy_pubkey = QAction("Copy pubkey to clipboard", self)
            copy_pubkey.triggered.connect(self.copy_pubkey_to_clipboard)
            copy_pubkey.setData(wallet)

            menu.addAction(rename)
            menu.addAction(copy_pubkey)
            # Show the context menu.
            menu.exec_(QCursor.pos())

    def history_context_menu(self, point):
        index = self.table_history.indexAt(point)
        model = self.table_history.model()
        if index.row() < model.rowCount(QModelIndex()):
            menu = QMenu("Actions", self)
            source_index = model.mapToSource(index)
            state_col = model.sourceModel().column_types.index('state')
            state_index = model.sourceModel().index(source_index.row(),
                                                   state_col)
            state_data = model.sourceModel().data(state_index, Qt.DisplayRole)

            pubkey_col = model.sourceModel().column_types.index('uid')
            person_index = model.sourceModel().index(source_index.row(),
                                                    pubkey_col)
            person = model.sourceModel().data(person_index, Qt.DisplayRole)
            transfer = model.sourceModel().transfers[source_index.row()]
            if state_data == Transfer.REFUSED or state_data == Transfer.TO_SEND:
                send_back = QAction("Send again", self)
                send_back.triggered.connect(self.send_again)
                send_back.setData(transfer)
                menu.addAction(send_back)

                cancel = QAction("Cancel", self)
                cancel.triggered.connect(self.cancel_transfer)
                cancel.setData(transfer)
                menu.addAction(cancel)

            copy_pubkey = QAction("Copy pubkey to clipboard", self)
            copy_pubkey.triggered.connect(self.copy_pubkey_to_clipboard)
            copy_pubkey.setData(person)
            menu.addAction(copy_pubkey)
            # Show the context menu.
            menu.exec_(QCursor.pos())

    def copy_pubkey_to_clipboard(self):
        data = self.sender().data()
        clipboard = QApplication.clipboard()
        if data.__class__ is Wallet:
            clipboard.setText(data.pubkey)
        elif data.__class__ is Person:
            clipboard.setText(data.pubkey)
        elif data.__class__ is str:
            clipboard.setText(data)

    def send_again(self):
        transfer = self.sender().data()
        dialog = TransferMoneyDialog(self.app.current_account,
                                     self.password_asker)
        dialog.accepted.connect(self.refresh_wallets)
        sender = transfer.metadata['issuer']
        wallet_index = [w.pubkey for w in self.app.current_account.wallets].index(sender)
        dialog.combo_wallets.setCurrentIndex(wallet_index)
        dialog.edit_pubkey.setText(transfer.metadata['receiver'])
        dialog.combo_community.setCurrentText(self.community.name)
        dialog.spinbox_amount.setValue(transfer.metadata['amount'])
        dialog.radio_pubkey.setChecked(True)
        dialog.edit_message.setText(transfer.metadata['comment'])
        result = dialog.exec_()
        if result == QDialog.Accepted:
            transfer.drop()
            self.table_history.model().invalidate()

    def cancel_transfer(self):
        reply = QMessageBox.warning(self, "Warning",
                             """Are you sure ?
This money transfer will be removed and not sent.""",
QMessageBox.Ok | QMessageBox.Cancel)
        if reply == QMessageBox.Ok:
            transfer = self.sender().data()
            transfer.drop()
            self.table_history.model().invalidate()

    def showEvent(self, event):
        blockid = self.community.current_blockid()
        block_number = blockid['number']
        self.status_label.setText("Connected : Block {0}"
                                         .format(block_number))

    def closeEvent(self, event):
        super().closeEvent(event)
        self.bc_watcher.deleteLater()
        self.watcher_thread.deleteLater()

    def dates_changed(self, datetime):
        ts_from = self.date_from.dateTime().toTime_t()
        ts_to = self.date_to.dateTime().toTime_t()
        if self.table_history.model():
            self.table_history.model().set_period(ts_from, ts_to)
            self.table_history.model().invalidate()

    def referential_changed(self):
        if self.table_history.model():
            self.table_history.model().dataChanged.emit(
                                                     QModelIndex(),
                                                     QModelIndex(),
                                                     [])

        if self.tab_wallets:
            self.tab_wallets.refresh()

        if self.tab_informations:
            self.tab_informations.refresh()