diff --git a/src/cutecoin/gui/busy.py b/src/cutecoin/gui/busy.py new file mode 100644 index 0000000000000000000000000000000000000000..5c8246f3dfaa6fd8eacf80d3e7a06a30b1a3e2b2 --- /dev/null +++ b/src/cutecoin/gui/busy.py @@ -0,0 +1,49 @@ +from PyQt5.QtWidgets import QWidget +from PyQt5.QtGui import QPalette, QPainter, QColor, QBrush, QPen +from PyQt5.QtCore import Qt + +import math + + +class Busy(QWidget): + def __init__(self, parent = None): + QWidget.__init__(self, parent) + palette = QPalette(self.palette()) + palette.setColor(palette.Background, Qt.transparent) + self.setPalette(palette) + self.timer = None + + def paintEvent(self, event): + painter = QPainter() + painter.begin(self) + painter.setRenderHint(QPainter.Antialiasing) + painter.fillRect(event.rect(), QBrush(QColor(255, 255, 255, 127))) + painter.setPen(QPen(Qt.NoPen)) + + for i in range(12): + if self.counter % 12 == i: + painter.setBrush(QBrush(QColor(165, 165, 165, (self.counter % 12)*22))) + else: + painter.setBrush(QBrush(QColor(165, 165, 165))) + painter.drawEllipse( + self.width()/2 + 50 * math.cos(2 * math.pi * i / 12.0) - 5, + self.height()/2 + 50 * math.sin(2 * math.pi * i / 12.0) - 5, + 12, 12) + + painter.end() + + def showEvent(self, event): + self.timer = self.startTimer(150) + self.counter = 0 + super().showEvent(event) + + def hideEvent(self, event): + if self.timer: + self.killTimer(self.timer) + self.timer = None + super().hideEvent(event) + + def timerEvent(self, event): + self.counter += 1 + self.update() + super().timerEvent(event) diff --git a/src/cutecoin/gui/identities_tab.py b/src/cutecoin/gui/identities_tab.py index 4121bc1fcd8354f0e9249ee2b67dc98e72d46fc6..41d1e60fb7e50c47829db138990125040d32e449 100644 --- a/src/cutecoin/gui/identities_tab.py +++ b/src/cutecoin/gui/identities_tab.py @@ -14,6 +14,7 @@ from ..gen_resources.identities_tab_uic import Ui_IdentitiesTab from .contact import ConfigureContactDialog from .member import MemberDialog from .transfer import TransferMoneyDialog +from .busy import Busy from .certification import CertificationDialog import asyncio from ..core.net.api import bma as qtbma @@ -62,11 +63,15 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): self.button_search.addAction(direct_connections) self.button_search.clicked.connect(self._async_execute_search_text) + self.busy = Busy(self.table_identities) + self.busy.hide() + def cancel_once_tasks(self): cancel_once_task(self, self.identity_context_menu) cancel_once_task(self, self._async_execute_search_text) cancel_once_task(self, self._async_search_members) cancel_once_task(self, self._async_search_direct_connections) + cancel_once_task(self, self.refresh_identities) def change_account(self, account, password_asker): self.cancel_once_tasks() @@ -173,6 +178,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): @asyncify @asyncio.coroutine def _async_execute_search_text(self, checked): + self.busy.show() text = self.edit_textsearch.text() if len(text) < 2: return @@ -184,6 +190,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): self.edit_textsearch.clear() self.refresh_identities(identities) + self.busy.hide() @once_at_a_time @asyncify @@ -193,6 +200,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): Search members of community and display found members """ if self.community: + self.busy.show() pubkeys = yield from self.community.members_pubkeys() identities = [] for p in pubkeys: @@ -201,6 +209,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): self.edit_textsearch.clear() self.refresh_identities(identities) + self.busy.hide() @once_at_a_time @asyncify @@ -210,6 +219,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): Search members of community and display found members """ if self.account and self.community: + self.busy.show() self_identity = yield from self.account.identity(self.community) account_connections = [] certs_of = yield from self_identity.unique_valid_certifiers_of(self.app.identities_registry, self.community) @@ -223,14 +233,24 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): if p.pubkey not in [i.pubkey for i in certifiers_of]] identities = certifiers_of + certified_by self.refresh_identities(identities) + self.busy.hide() + @once_at_a_time + @asyncify + @asyncio.coroutine def refresh_identities(self, identities): """ Refresh the table with specified identities. If no identities is passed, use the account connections. """ - self.table_identities.model().sourceModel().refresh_identities(identities) + self.busy.show() + yield from self.table_identities.model().sourceModel().refresh_identities(identities) self.table_identities.resizeColumnsToContents() + self.busy.hide() + + def resizeEvent(self, event): + self.busy.resize(event.size()) + super().resizeEvent(event) def changeEvent(self, event): """ diff --git a/src/cutecoin/gui/wot_tab.py b/src/cutecoin/gui/wot_tab.py index 2a6548cfcc9ed2a797fd9b50d24d6938084a8b8a..3a12fbc56d9310bb9f55984293c1f5eed4f3259a 100644 --- a/src/cutecoin/gui/wot_tab.py +++ b/src/cutecoin/gui/wot_tab.py @@ -17,6 +17,7 @@ from .contact import ConfigureContactDialog from ..gen_resources.wot_tab_uic import Ui_WotTabWidget from cutecoin.gui.views.wot import NODE_STATUS_HIGHLIGHTED, NODE_STATUS_SELECTED, NODE_STATUS_OUT, ARC_STATUS_STRONG, \ ARC_STATUS_WEAK +from .busy import Busy class WotTabWidget(QWidget, Ui_WotTabWidget): @@ -40,6 +41,9 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): # the edited text is not added in the item list self.comboBoxSearch.setInsertPolicy(QComboBox.NoInsert) + self.busy = Busy(self.graphicsView) + self.busy.hide() + # add scene events self.graphicsView.scene().node_clicked.connect(self.handle_node_click) self.graphicsView.scene().node_signed.connect(self.sign_node) @@ -177,6 +181,7 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): :param cutecoin.core.registry.Identity identity: Graph node identity """ logging.debug("Draw graph - " + identity.uid) + self.busy.show() if self.community: identity_account = yield from self.account.identity(self.community) @@ -217,6 +222,7 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): path = yield from graph.get_shortest_path_between_members(identity, identity_account) if path: self.graphicsView.scene().update_path(path) + self.busy.hide() @once_at_a_time @asyncify @@ -322,6 +328,10 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): if result == QDialog.Accepted: self.window().refresh_contacts() + def resizeEvent(self, event): + self.busy.resize(event.size()) + super().resizeEvent(event) + def changeEvent(self, event): """ Intercepte LanguageChange event to translate UI diff --git a/src/cutecoin/models/identities.py b/src/cutecoin/models/identities.py index 431416c03d8edc0b199c0ea6264618c0e26d7350..c47717eaf6fc7498866910836c59129bf358feab 100644 --- a/src/cutecoin/models/identities.py +++ b/src/cutecoin/models/identities.py @@ -40,37 +40,38 @@ class IdentitiesFilterProxyModel(QSortFilterProxyModel): def data(self, index, role): source_index = self.mapToSource(index) - source_data = self.sourceModel().data(source_index, role) - expiration_col = self.sourceModel().columns_ids.index('expiration') - expiration_index = self.sourceModel().index(source_index.row(), expiration_col) - expiration_data = self.sourceModel().data(expiration_index, Qt.DisplayRole) - current_time = QDateTime().currentDateTime().toMSecsSinceEpoch() - sig_validity = self.sourceModel().sig_validity() - warning_expiration_time = int(sig_validity / 3) - #logging.debug("{0} > {1}".format(current_time, expiration_data)) - if expiration_data is not None: - will_expire_soon = (current_time > expiration_data*1000 - warning_expiration_time*1000) - if role == Qt.DisplayRole: - if source_index.column() == self.sourceModel().columns_ids.index('renewed') \ - or source_index.column() == self.sourceModel().columns_ids.index('expiration'): - if source_data is not None: - return QLocale.toString( - QLocale(), - QDateTime.fromTime_t(source_data).date(), - QLocale.dateFormat(QLocale(), QLocale.ShortFormat) - ) + if source_index.isValid(): + source_data = self.sourceModel().data(source_index, role) + expiration_col = self.sourceModel().columns_ids.index('expiration') + expiration_index = self.sourceModel().index(source_index.row(), expiration_col) + expiration_data = self.sourceModel().data(expiration_index, Qt.DisplayRole) + current_time = QDateTime().currentDateTime().toMSecsSinceEpoch() + sig_validity = self.sourceModel().sig_validity() + warning_expiration_time = int(sig_validity / 3) + #logging.debug("{0} > {1}".format(current_time, expiration_data)) + if expiration_data is not None: + will_expire_soon = (current_time > expiration_data*1000 - warning_expiration_time*1000) + if role == Qt.DisplayRole: + if source_index.column() == self.sourceModel().columns_ids.index('renewed') \ + or source_index.column() == self.sourceModel().columns_ids.index('expiration'): + if source_data is not None: + return QLocale.toString( + QLocale(), + QDateTime.fromTime_t(source_data).date(), + QLocale.dateFormat(QLocale(), QLocale.ShortFormat) + ) + else: + return "" + if source_index.column() == self.sourceModel().columns_ids.index('pubkey'): + return "pub:{0}".format(source_data[:5]) + + if role == Qt.ForegroundRole: + if expiration_data: + if will_expire_soon: + return QColor(Qt.red) else: - return "" - if source_index.column() == self.sourceModel().columns_ids.index('pubkey'): - return "pub:{0}".format(source_data[:5]) - - if role == Qt.ForegroundRole: - if expiration_data: - if will_expire_soon: - return QColor(Qt.red) - else: - return QColor(Qt.blue) - return source_data + return QColor(Qt.blue) + return source_data class IdentitiesTableModel(QAbstractTableModel): @@ -95,7 +96,6 @@ class IdentitiesTableModel(QAbstractTableModel): self._sig_validity = 0 def change_community(self, community): - cancel_once_task(self, self.refresh_identities) self.community = community def sig_validity(self): @@ -119,8 +119,6 @@ class IdentitiesTableModel(QAbstractTableModel): return (identity.uid, identity.pubkey, join_date, expiration_date) - @once_at_a_time - @asyncify @asyncio.coroutine def refresh_identities(self, identities): """ @@ -153,7 +151,8 @@ class IdentitiesTableModel(QAbstractTableModel): if role == Qt.DisplayRole: row = index.row() col = index.column() - return self.identities_data[row][col] + identity_data = self.identities_data[row] + return identity_data[col] def identity_index(self, pubkey): try: