Skip to content
Snippets Groups Projects
mainwindow.py 14.1 KiB
Newer Older
inso's avatar
inso committed
'''
Created on 1 févr. 2014

@author: inso
'''
inso's avatar
inso committed
from ..gen_resources.mainwindow_uic import Ui_MainWindow
from ..gen_resources.about_uic import Ui_AboutPopup
from ..gen_resources.homescreen_uic import Ui_HomeScreenWidget

from PyQt5.QtWidgets import QMainWindow, QAction, QFileDialog, QProgressBar, \
        QMessageBox, QLabel, QComboBox, QDialog
inso's avatar
inso committed
from PyQt5.QtCore import QSignalMapper, QObject, QThread, \
    pyqtSlot, pyqtSignal, QDate, QDateTime, QTimer, QUrl
from PyQt5.QtGui import QIcon, QDesktopServices

from .process_cfg_account import ProcessConfigureAccount
from .transfer import TransferMoneyDialog
from .currency_tab import CurrencyTabWidget
inso's avatar
inso committed
from .contact import ConfigureContactDialog
from .import_account import ImportAccountDialog
from .certification import CertificationDialog
from .password_asker import PasswordAskerDialog
from ..tools.exceptions import NoPeerAvailable
inso's avatar
inso committed
from .homescreen import HomeScreenWidget
inso's avatar
inso committed
from ..core.account import Account
inso's avatar
inso committed
from ..__init__ import __version__
inso's avatar
inso committed

inso's avatar
inso committed
import logging
inso's avatar
inso committed
import requests
inso's avatar
inso committed
class Loader(QObject):
    def __init__(self, app):
        super().__init__()
        self.app = app
        self.account_name = ""

    loaded = pyqtSignal()
    connection_error = pyqtSignal(str)
inso's avatar
inso committed

    def set_account_name(self, name):
        self.account_name = name

    @pyqtSlot()
    def load(self):
        if self.account_name != "":
inso's avatar
inso committed
            try:
                account = self.app.get_account(self.account_name)
                self.app.change_current_account(account)
inso's avatar
inso committed
            except requests.exceptions.RequestException as e:
                self.connection_error.emit(str(e))
                self.loaded.emit()
            except NoPeerAvailable as e:
                self.connection_error.emit(str(e))
                self.loaded.emit()
inso's avatar
inso committed
        self.loaded.emit()


inso's avatar
inso committed
class MainWindow(QMainWindow, Ui_MainWindow):
inso's avatar
inso committed
    '''
    classdocs
    '''

    def __init__(self, app):
inso's avatar
inso committed
        '''
        Constructor
        '''
        # Set up the user interface from Designer.
inso's avatar
inso committed
        super().__init__()
inso's avatar
inso committed
        self.setupUi(self)
        self.password_asker = None
inso's avatar
inso committed
        self.initialized = False
inso's avatar
inso committed
        self.busybar = QProgressBar(self.statusbar)
        self.busybar.setMinimum(0)
        self.busybar.setMaximum(0)
        self.busybar.setValue(-1)
        self.statusbar.addWidget(self.busybar)
        self.busybar.hide()

        self.combo_referential = QComboBox(self)
        self.combo_referential.setEnabled(False)
inso's avatar
inso committed
        self.combo_referential.currentTextChanged.connect(self.referential_changed)
inso's avatar
inso committed
        self.status_label = QLabel("", self)

        self.label_time = QLabel("", self)

        self.statusbar.addPermanentWidget(self.status_label, 1)
inso's avatar
inso committed
        self.statusbar.addPermanentWidget(self.label_time)
        self.statusbar.addPermanentWidget(self.combo_referential)
inso's avatar
inso committed
        self.update_time()
inso's avatar
inso committed

        self.loader_thread = QThread()
        self.loader = Loader(self.app)
        self.loader.moveToThread(self.loader_thread)
        self.loader.loaded.connect(self.loader_finished)
        self.loader.loaded.connect(self.loader_thread.quit)
        self.loader.connection_error.connect(self.display_error)
inso's avatar
inso committed
        self.loader_thread.started.connect(self.loader.load)
inso's avatar
inso committed

        self.homescreen = HomeScreenWidget(self.app)
inso's avatar
inso committed
        self.centralWidget().layout().addWidget(self.homescreen)
        self.homescreen.button_new.clicked.connect(self.open_add_account_dialog)
        self.homescreen.button_import.clicked.connect(self.import_account)
        self.open_ucoin_info = lambda: QDesktopServices.openUrl(QUrl("http://ucoin.io/theoretical/"))
        self.homescreen.button_info.clicked.connect(self.open_ucoin_info)

        #TODO: There are too much refresh() calls on startup
        self.refresh()
    def open_add_account_dialog(self):
        dialog = ProcessConfigureAccount(self.app, None)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.action_change_account(self.app.current_account.name)
inso's avatar
inso committed
    @pyqtSlot()
    def loader_finished(self):
        self.refresh()
inso's avatar
inso committed
        self.busybar.hide()
        self.app.disconnect()
        self.app.monitor.start_watching()
inso's avatar
inso committed

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

inso's avatar
inso committed
    @pyqtSlot(str)
    def referential_changed(self, text):
        if self.app.current_account:
inso's avatar
inso committed
            self.app.current_account.set_display_referential(text)
            if self.currencies_tabwidget.currentWidget():
                self.currencies_tabwidget.currentWidget().referential_changed()
inso's avatar
inso committed
    @pyqtSlot()
    def update_time(self):
        date = QDate.currentDate()
Vincent Texier's avatar
Vincent Texier committed
        self.label_time.setText("{0}".format(date.toString("dd/MM/yyyy")))
inso's avatar
inso committed
        next_day = date.addDays(1)
inso's avatar
inso committed
        current_time = QDateTime().currentDateTime().toMSecsSinceEpoch()
inso's avatar
inso committed
        next_time = QDateTime(next_day).toMSecsSinceEpoch()
        timer = QTimer()
        timer.timeout.connect(self.update_time)
        timer.start(next_time - current_time)

    @pyqtSlot()
    def delete_contact(self):
        contact = self.sender().data()
        self.app.current_account.contacts.remove(contact)
        self.refresh_contacts()

    @pyqtSlot()
    def edit_contact(self):
inso's avatar
inso committed
        index = self.sender().data()
        dialog = ConfigureContactDialog(self.app.current_account, self, None, index)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.window().refresh_contacts()

inso's avatar
inso committed
    def action_change_account(self, account_name):
        def loading_progressed(value, maximum):
            logging.debug("Busybar : {:} : {:}".format(value, maximum))
            self.busybar.setValue(value)
            self.busybar.setMaximum(maximum)
        self.app.current_account = None
        self.refresh()
        self.app.loading_progressed.connect(loading_progressed)
        self.busybar.setMinimum(0)
        self.busybar.setMaximum(0)
        self.busybar.setValue(-1)
inso's avatar
inso committed
        self.busybar.show()
        self.status_label.setText("Loading account {0}".format(account_name))
        self.loader.set_account_name(account_name)
        self.loader_thread.start(QThread.LowPriority)
inso's avatar
inso committed
        self.homescreen.button_new.hide()
        self.homescreen.button_import.hide()
    def open_transfer_money_dialog(self):
        dialog = TransferMoneyDialog(self.app.current_account,
                                     self.password_asker)
inso's avatar
inso committed
        dialog.accepted.connect(self.refresh_wallets)
        if dialog.exec_() == QDialog.Accepted:
            currency_tab = self.currencies_tabwidget.currentWidget()
            currency_tab.table_history.model().invalidate()
    def open_certification_dialog(self):
        dialog = CertificationDialog(self.app.current_account,
                                     self.password_asker)
    def open_add_contact_dialog(self):
        dialog = ConfigureContactDialog(self.app.current_account, self)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.window().refresh_contacts()
inso's avatar
inso committed

    def open_configure_account_dialog(self):
        dialog = ProcessConfigureAccount(self.app, self.app.current_account)
inso's avatar
inso committed
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.action_change_account(self.app.current_account.name)
inso's avatar
inso committed

Vincent Texier's avatar
Vincent Texier committed
    def open_about_popup(self):
        """
        Open about popup window
        """
        aboutDialog = QDialog(self)
        aboutUi = Ui_AboutPopup()
        aboutUi.setupUi(aboutDialog)

        latest = self.app.latest_version()
        version_info = ""
        version_url = ""
        if not latest[0]:
            version_info = "Latest release : {version}" \
                            .format(version='.'.join(latest[1]))
            version_url = latest[2]

        new_version_text = """
            <p><b>{version_info}</b></p>
            <p><a href={version_url}>Download link</a></p>
            """.format(version_info=version_info,
                       version_url=version_url)
Vincent Texier's avatar
Vincent Texier committed
        text = """
        <h1>Cutecoin</h1>

        <p>Python/Qt uCoin client</p>

        <p>Version : {:}</p>
Vincent Texier's avatar
Vincent Texier committed

        <p>License : MIT</p>

        <p><b>Authors</b></p>

        <p>inso</p>
        <p>vit</p>
        <p>canercandan</p>
        """.format(__version__,
                   new_version_text=new_version_text)
Vincent Texier's avatar
Vincent Texier committed
        aboutUi.label.setText(text)
        aboutDialog.show()

inso's avatar
inso committed
    def refresh_wallets(self):
        currency_tab = self.currencies_tabwidget.currentWidget()
        if currency_tab:
            currency_tab.refresh_wallets()
inso's avatar
inso committed

    def refresh_communities(self):
        self.currencies_tabwidget.clear()
        if self.app.current_account:
            for community in self.app.current_account.communities:
                try:
                    tab_currency = CurrencyTabWidget(self.app, community,
                                                     self.password_asker,
                                                     self.status_label)
                    tab_currency.refresh()
                    self.currencies_tabwidget.addTab(tab_currency,
                                                     QIcon(":/icons/currency_icon"),
                                                     community.name)
                except NoPeerAvailable as e:
                    QMessageBox.critical(self, "Could not join {0}".format(community.currency),
                                str(e),
                                QMessageBox.Ok)
                    continue
                except requests.exceptions.RequestException as e:
                    QMessageBox.critical(self, ":(",
                                str(e),
                                QMessageBox.Ok)
    def refresh_accounts(self):
        self.menu_change_account.clear()
        signal_mapper = QSignalMapper(self)

        for account_name in sorted(self.app.accounts.keys()):
            action = QAction(account_name, self)
            self.menu_change_account.addAction(action)
            signal_mapper.setMapping(action, account_name)
            action.triggered.connect(signal_mapper.map)
            signal_mapper.mapped[str].connect(self.action_change_account)

    def refresh_contacts(self):
        self.menu_contacts_list.clear()
        if self.app.current_account:
inso's avatar
inso committed
            for index, contact in enumerate(self.app.current_account.contacts):
                contact_menu = self.menu_contacts_list.addMenu(contact['name'])
                edit_action = contact_menu.addAction("Edit")
                edit_action.triggered.connect(self.edit_contact)
inso's avatar
inso committed
                edit_action.setData(index)
                delete_action = contact_menu.addAction("Delete")
                delete_action.setData(contact)
                delete_action.triggered.connect(self.delete_contact)
inso's avatar
inso committed
    def set_as_default_account(self):
        self.app.default_account = self.app.current_account.name
        logging.debug(self.app.current_account)
        self.app.save(self.app.current_account)
        self.action_set_as_default.setEnabled(False)

    def refresh(self):
inso's avatar
inso committed
        '''
        Refresh main window
        When the selected account changes, all the widgets
        in the window have to be refreshed
        '''
        logging.debug("Refresh started")
        self.refresh_accounts()
        if self.app.current_account is None:
inso's avatar
inso committed
            self.currencies_tabwidget.hide()
            self.homescreen.show()
            self.setWindowTitle("CuteCoin {0}".format(__version__))
inso's avatar
inso committed
            self.menu_contacts.setEnabled(False)
            self.menu_actions.setEnabled(False)
            self.action_configure_parameters.setEnabled(False)
inso's avatar
inso committed
            self.action_set_as_default.setEnabled(False)
            self.combo_referential.setEnabled(False)
            self.status_label.setText("")
            self.password_asker = None
inso's avatar
inso committed
            self.currencies_tabwidget.show()
            self.homescreen.hide()
inso's avatar
inso committed
            self.action_set_as_default.setEnabled(self.app.current_account.name
                                                  != self.app.default_account)
            self.password_asker = PasswordAskerDialog(self.app.current_account)
inso's avatar
inso committed

            self.combo_referential.blockSignals(True)
inso's avatar
inso committed
            self.combo_referential.clear()
            self.combo_referential.addItems(sorted(Account.referentials.keys()))
            self.combo_referential.setEnabled(True)
            self.combo_referential.blockSignals(False)
            self.combo_referential.setCurrentText(self.app.current_account.referential)
inso's avatar
inso committed
            self.menu_contacts.setEnabled(True)
            self.action_configure_parameters.setEnabled(True)
inso's avatar
inso committed
            self.menu_actions.setEnabled(True)
            self.password_asker = PasswordAskerDialog(self.app.current_account)
inso's avatar
inso committed
            self.setWindowTitle("CuteCoin {0} - Account : {1}".format(__version__,
                self.app.current_account.name))
inso's avatar
inso committed

        self.refresh_communities()
        self.refresh_wallets()
        self.refresh_contacts()

    def import_account(self):
        dialog = ImportAccountDialog(self.app, self)
        dialog.accepted.connect(self.refresh)
        dialog.exec_()

    def export_account(self):
        selected_file = QFileDialog.getSaveFileName(self,
                                          "Export an account",
                                          "",
                                          "All account files (*.acc)")
        path = ""
        if selected_file[0][-4:] == ".acc":
            path = selected_file[0]
        else:
            path = selected_file[0] + ".acc"
        self.app.export_account(path, self.app.current_account)

    def closeEvent(self, event):
        if self.app.current_account:
            self.app.save_cache(self.app.current_account)
inso's avatar
inso committed
        self.app.save_persons()
inso's avatar
inso committed
        self.loader.deleteLater()
        self.loader_thread.deleteLater()
        super().closeEvent(event)

inso's avatar
inso committed
    def showEvent(self, event):
        super().showEvent(event)
        if not self.initialized:
            if self.app.default_account != "":
                logging.debug("Loading default account")
                self.action_change_account(self.app.default_account)
            self.initialized = True