diff --git a/src/cutecoin/core/account.py b/src/cutecoin/core/account.py index 737db4da354bdc54497a72559833d3fcdfab0ea4..9b43b8f378731f0382f6d74f520d1fedfbb91f36 100644 --- a/src/cutecoin/core/account.py +++ b/src/cutecoin/core/account.py @@ -33,7 +33,6 @@ class Account(QObject): """ loading_progressed = pyqtSignal(int, int) loading_finished = pyqtSignal(list) - inner_data_changed = pyqtSignal(str) wallets_changed = pyqtSignal() membership_broadcasted = pyqtSignal() certification_broadcasted = pyqtSignal() @@ -209,6 +208,7 @@ class Account(QObject): "Wallet", self._identities_registry) self.wallets.append(wallet) + @asyncio.coroutine def identity(self, community): """ Get the account identity in the specified community @@ -216,7 +216,7 @@ class Account(QObject): :return: The account identity in the community :rtype: cutecoin.core.registry.Identity """ - identity = self._identities_registry.find(self.pubkey, community) + identity = yield from self._identities_registry.future_find(self.pubkey, community) if identity.local_state == LocalState.NOT_FOUND: identity.uid = self.name return identity diff --git a/src/cutecoin/core/community.py b/src/cutecoin/core/community.py index ad75564beeb035d2c8fee27e9e8c94485b048264..18be5087c8972ee7f4a8fe1999eaaed8d5f6754e 100644 --- a/src/cutecoin/core/community.py +++ b/src/cutecoin/core/community.py @@ -26,8 +26,6 @@ class Community(QObject): .. warning:: The currency name is supposed to be unique in cutecoin but nothing exists in ucoin to assert that a currency name is unique. """ - inner_data_changed = pyqtSignal(str) - def __init__(self, currency, network, bma_access): """ Initialize community attributes with a currency and a network. diff --git a/src/cutecoin/core/registry/identities.py b/src/cutecoin/core/registry/identities.py index 3e733a056a66335d67468bd6c0c2cf6c562c6c35..4749dc2e086ed9acf910e99a9a7ea9ac25a6c74c 100644 --- a/src/cutecoin/core/registry/identities.py +++ b/src/cutecoin/core/registry/identities.py @@ -42,29 +42,6 @@ class IdentitiesRegistry: identities_json.append(identity.jsonify()) return {'registry': identities_json} - def find(self, pubkey, community): - """ - Get a person from the pubkey found in a community - - :param str pubkey: The person pubkey - :param cutecoin.core.community.Community community: The community in which to look for the pubkey - :param bool cached: True if the person should be searched in the - cache before requesting the community. - - :return: A new person if the pubkey was unknown or\ - the known instance if pubkey was already known. - :rtype: cutecoin.core.registry.Identity - """ - if pubkey in self._instances: - identity = self._instances[pubkey] - self._instances[pubkey] = identity - else: - identity = Identity.empty(pubkey) - self._instances[pubkey] = identity - reply = community.bma_access.simple_request(qtbma.wot.CertifiersOf, req_args={'search': pubkey}) - reply.finished.connect(lambda: self.handle_certifiersof(reply, identity, community)) - return identity - @asyncio.coroutine def future_find(self, pubkey, community): def handle_certifiersof_reply(reply, tries=0): @@ -133,68 +110,6 @@ class IdentitiesRegistry: yield from future_identity return identity - def handle_certifiersof(self, reply, identity, community, tries=0): - """ - :param PyQt5.QtNetwork.QNetworkReply reply - :param cutecoin.core.registry.identity.Identity identity: The looked up identity - :return: - """ - if reply.error() == QNetworkReply.NoError: - status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) - if status_code == 200: - strdata = bytes(reply.readAll()).decode('utf-8') - data = json.loads(strdata) - identity.uid = data['uid'] - identity.local_state = LocalState.PARTIAL - identity.blockchain_state = BlockchainState.VALIDATED - logging.debug("Lookup : found {0}".format(identity)) - identity.inner_data_changed.emit(str(qtbma.wot.CertifiersOf)) - else: - reply = community.bma_access.simple_request(qtbma.wot.Lookup, - req_args={'search': identity.pubkey}) - reply.finished.connect(lambda: self.handle_lookup(reply, identity, - community, tries=0)) - else: - logging.debug("Error in reply : {0}".format(reply.error())) - if tries < 3: - tries += 1 - reply = community.bma_access.simple_request(qtbma.wot.CertifiersOf, - req_args={'search': identity.pubkey}) - reply.finished.connect(lambda: self.handle_certifiersof(reply, identity, - community, tries=tries)) - - def handle_lookup(self, reply, identity, community, tries=0): - """ - :param cutecoin.core.registry.identity.Identity identity: The looked up identity - :return: - """ - - if reply.error() == QNetworkReply.NoError: - strdata = bytes(reply.readAll()).decode('utf-8') - data = json.loads(strdata) - - timestamp = 0 - for result in data['results']: - if result["pubkey"] == identity.pubkey: - uids = result['uids'] - identity_uid = "" - for uid_data in uids: - if uid_data["meta"]["timestamp"] > timestamp: - timestamp = uid_data["meta"]["timestamp"] - identity_uid = uid_data["uid"] - identity.uid = identity_uid - identity.status = Identity.FOUND - logging.debug("Lookup : found {0}".format(identity)) - identity.inner_data_changed.emit(str(qtbma.wot.Lookup)) - else: - logging.debug("Error in reply : {0}".format(reply.error())) - if tries < 3: - tries += 1 - reply = community.bma_access.simple_request(qtbma.wot.Lookup, - req_args={'search': identity.pubkey}) - reply.finished.connect(lambda: self.handle_lookup(reply, identity, - community, tries=tries)) - def from_handled_data(self, uid, pubkey, blockchain_state): """ Get a person from a metadata dict. diff --git a/src/cutecoin/core/registry/identity.py b/src/cutecoin/core/registry/identity.py index 10daff2398d36ec07f74b5f88c60b486549be9de..fb65737c7cf07982ea385fe2968737ab47dc5c5b 100644 --- a/src/cutecoin/core/registry/identity.py +++ b/src/cutecoin/core/registry/identity.py @@ -48,8 +48,6 @@ class Identity(QObject): """ A person with a uid and a pubkey """ - inner_data_changed = pyqtSignal(str) - def __init__(self, uid, pubkey, local_state, blockchain_state): """ Initializing a person object. diff --git a/src/cutecoin/core/wallet.py b/src/cutecoin/core/wallet.py index 3f0cdc8a7ef2402547f99bc98d680e55ea8a5bca..faa268b8085d264aa73ea57eec32a5cc9b1eec89 100644 --- a/src/cutecoin/core/wallet.py +++ b/src/cutecoin/core/wallet.py @@ -24,8 +24,6 @@ class Wallet(QObject): """ A wallet is used to manage money with a unique key. """ - - inner_data_changed = pyqtSignal(str) refresh_progressed = pyqtSignal(int, int, str) refresh_finished = pyqtSignal(list) transfer_broadcasted = pyqtSignal(str) diff --git a/src/cutecoin/gui/certification.py b/src/cutecoin/gui/certification.py index f8b8c0837c12ecb727a729403ad85be4e3b8a542..cd2baf04c42615f0f39132f7622adf2c0dd2db55 100644 --- a/src/cutecoin/gui/certification.py +++ b/src/cutecoin/gui/certification.py @@ -86,7 +86,8 @@ class CertificationDialog(QDialog, Ui_CertificationDialog): @asyncify @asyncio.coroutine def refresh(self): - is_member = yield from self.account.identity(self.community).is_member(self.community) + account_identity = yield from self.account.identity(self.community) + is_member = yield from account_identity.is_member(self.community) block_0 = yield from self.community.get_block(0) if is_member or block_0 == qtbma.blockchain.Block.null_value: self.button_box.button(QDialogButtonBox.Ok).setEnabled(True) diff --git a/src/cutecoin/gui/community_tile.py b/src/cutecoin/gui/community_tile.py index 205b3ec4c2584905ac8f2b9a01fee38c96acadbc..c5f51be382f34aa73b70044eb4994e117b95204b 100644 --- a/src/cutecoin/gui/community_tile.py +++ b/src/cutecoin/gui/community_tile.py @@ -16,7 +16,6 @@ class CommunityTile(QFrame): super().__init__(parent) self.app = app self.community = community - self.community.inner_data_changed.connect(self.refresh) self.text_label = QLabel() self.setLayout(QVBoxLayout()) self.layout().setSizeConstraint(QLayout.SetFixedSize) diff --git a/src/cutecoin/gui/community_view.py b/src/cutecoin/gui/community_view.py index 2d77b6a13582476b92817913b9bb347098aefbd2..84965adeb930e5af54b5b4c76148d315e754593a 100644 --- a/src/cutecoin/gui/community_view.py +++ b/src/cutecoin/gui/community_view.py @@ -93,6 +93,7 @@ class CommunityWidget(QWidget, Ui_CommunityWidget): self.password_asker = password_asker self.tab_wot.change_account(account, self.password_asker) self.tab_identities.change_account(account, self.password_asker) + self.tab_history.change_account(account, self.password_asker) def change_community(self, community): self.tab_network.change_community(community) @@ -103,11 +104,9 @@ class CommunityWidget(QWidget, Ui_CommunityWidget): if self.community: self.community.network.new_block_mined.disconnect(self.refresh_block) self.community.network.nodes_changed.disconnect(self.refresh_status) - self.community.inner_data_changed.disconnect(self.refresh_status) if community: community.network.new_block_mined.connect(self.refresh_block) community.network.nodes_changed.connect(self.refresh_status) - community.inner_data_changed.connect(self.refresh_status) self.label_currency.setText(community.currency) self.community = community self.refresh_quality_buttons() @@ -161,14 +160,12 @@ class CommunityWidget(QWidget, Ui_CommunityWidget): self.tab_history.start_progress() self.refresh_data() - def refresh_quality_buttons(self): - pass - def refresh_data(self): """ Refresh data when the blockchain watcher finished handling datas """ self.tab_history.refresh_balance() + self.tab_identities.refresh_data() self.refresh_status() @asyncify @@ -210,10 +207,11 @@ class CommunityWidget(QWidget, Ui_CommunityWidget): def refresh_quality_buttons(self): if self.account and self.community: try: - published_uid = yield from self.account.identity(self.community).published_uid(self.community) + account_identity = yield from self.account.identity(self.community) + published_uid = account_identity.published_uid(self.community) if published_uid: logging.debug("UID Published") - is_member = yield from self.account.identity(self.community).is_member(self.community) + is_member = account_identity.is_member(self.community) if is_member: self.button_membership.setText(self.tr("Renew membership")) self.button_membership.show() diff --git a/src/cutecoin/gui/identities_tab.py b/src/cutecoin/gui/identities_tab.py index 58923594858ebd3ade5750b567f293a4f6c7cae9..603e738353714de4298556e74d095d1c0fee6af8 100644 --- a/src/cutecoin/gui/identities_tab.py +++ b/src/cutecoin/gui/identities_tab.py @@ -59,7 +59,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): direct_connections = QAction(self.tr("Direct connections"), self) direct_connections.triggered.connect(self._async_search_direct_connections) self.button_search.addAction(direct_connections) - self.button_search.clicked.connect(self.search_text) + self.button_search.clicked.connect(self._async_execute_search_text) def change_account(self, account, password_asker): self.account = account @@ -72,7 +72,15 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): self.table_identities.model().change_community(community) self._async_search_direct_connections() + @asyncify + @asyncio.coroutine def identity_context_menu(self, point): + def exec_menu(menu): + future = asyncio.Future() + menu.triggered.connect(future.set_result(True)) + menu.popup(QCursor.pos()) + return future + index = self.table_identities.indexAt(point) model = self.table_identities.model() if index.row() < model.rowCount(): @@ -81,7 +89,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): pubkey_index = model.sourceModel().index(source_index.row(), pubkey_col) pubkey = model.sourceModel().data(pubkey_index, Qt.DisplayRole) - identity = self.app.identities_registry.find(pubkey, self.community) + identity = yield from self.app.identities_registry.future_find(pubkey, self.community) menu = QMenu(self) informations = QAction(self.tr("Informations"), self) @@ -110,7 +118,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): menu.addAction(view_wot) # Show the context menu. - menu.exec_(QCursor.pos()) + yield from exec_menu(menu) def menu_informations(self): person = self.sender().data() @@ -158,19 +166,12 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): identity = self.sender().data() self.view_in_wot.emit(identity) - def search_text(self): - """ - Search text and display found identities - """ + @asyncify + @asyncio.coroutine + def _async_execute_search_text(self): text = self.edit_textsearch.text() - if len(text) < 2: - return False - else: - asyncio.async(self._async_execute_search_text(text)) - - @asyncio.coroutine - def _async_execute_search_text(self, text): + return response = yield from self.community.bma_access.future_request(qtbma.wot.Lookup, {'search': text}) identities = [] for identity_data in response['results']: @@ -202,7 +203,7 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): Search members of community and display found members """ if self.account and self.community: - self_identity = self.account.identity(self.community) + 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) for p in certs_of: diff --git a/src/cutecoin/gui/member.py b/src/cutecoin/gui/member.py index 5dca00466feaf95f7693128d6065012c614591b0..d3ca7c1a83a44ba8101b42b25bc5b79e95d525f5 100644 --- a/src/cutecoin/gui/member.py +++ b/src/cutecoin/gui/member.py @@ -53,8 +53,9 @@ class MemberDialog(QDialog, Ui_DialogMember): # if selected member is not the account member... if self.identity.pubkey != self.account.pubkey: # add path from selected member to account member + account_identity = yield from self.account.identity(self.community) path = yield from graph.get_shortest_path_between_members(self.identity, - self.account.identity(self.community)) + account_identity) text = self.tr(""" <table cellpadding="5"> @@ -70,8 +71,8 @@ class MemberDialog(QDialog, Ui_DialogMember): if path: distance = len(path) - 1 text += self.tr( - """<tr><td align="right"><b>{:}</b></div></td><td>{:}</td></tr>""".format(self.tr('Distance'), - distance)) + """<tr><td align="right"><b>{:}</b></div></td><td>{:}</td></tr>""" + .format(self.tr('Distance'), distance)) if distance > 1: index = 0 for node in path: @@ -91,4 +92,3 @@ class MemberDialog(QDialog, Ui_DialogMember): # set text in label self.label_properties.setText(text) - diff --git a/src/cutecoin/gui/transactions_tab.py b/src/cutecoin/gui/transactions_tab.py index 534bc085ecbde8123615cfae391f64051f55b9f1..96b5213ea634e52d52f5416a52b686ba311d363e 100644 --- a/src/cutecoin/gui/transactions_tab.py +++ b/src/cutecoin/gui/transactions_tab.py @@ -1,10 +1,14 @@ from PyQt5.QtWidgets import QWidget, QAbstractItemView, QHeaderView, QDialog, \ QMenu, QAction, QApplication, QMessageBox -from PyQt5.QtCore import Qt, QDateTime, QTime, QModelIndex, QCoreApplication, pyqtSlot, QEvent +from PyQt5.QtCore import Qt, QDateTime, QTime, QModelIndex, pyqtSignal, pyqtSlot, QEvent from PyQt5.QtGui import QCursor from ..gen_resources.transactions_tab_uic import Ui_transactionsTabWidget from ..models.txhistory import HistoryTableModel, TxFilterProxyModel from ..core.transfer import Transfer +from .contact import ConfigureContactDialog +from .member import MemberDialog +from .transfer import TransferMoneyDialog +from .certification import CertificationDialog from ..core.wallet import Wallet from ..core.registry import Identity from ..tools.decorators import asyncify @@ -19,6 +23,7 @@ class TransactionsTabWidget(QWidget, Ui_transactionsTabWidget): """ classdocs """ + view_in_wot = pyqtSignal(Identity) def __init__(self, app): """ @@ -31,16 +36,17 @@ class TransactionsTabWidget(QWidget, Ui_transactionsTabWidget): super().__init__() self.setupUi(self) self.app = app + self.account = None self.community = None self.password_asker = None self.progressbar.hide() self.refresh() + def change_account(self, account, password_asker): + self.account = account + self.password_asker = password_asker + def change_community(self, community): - if self.community: - self.community.inner_data_changed.disconnect(self.refresh_minimum_maximum) - if community: - community.inner_data_changed.connect(self.refresh_minimum_maximum) self.community = community self.refresh() self.stop_progress([]) @@ -152,23 +158,23 @@ class TransactionsTabWidget(QWidget, Ui_transactionsTabWidget): else: if isinstance(identity, Identity): informations = QAction(self.tr("Informations"), self) - informations.triggered.connect(self.currency_tab.tab_community.menu_informations) + informations.triggered.connect(self.menu_informations) informations.setData(identity) menu.addAction(informations) add_as_contact = QAction(self.tr("Add as contact"), self) - add_as_contact.triggered.connect(self.currency_tab.tab_community.menu_add_as_contact) + add_as_contact.triggered.connect(self.menu_add_as_contact) add_as_contact.setData(identity) menu.addAction(add_as_contact) send_money = QAction(self.tr("Send money"), self) - send_money.triggered.connect(self.currency_tab.tab_community.menu_send_money) + send_money.triggered.connect(self.menu_send_money) send_money.setData(identity) menu.addAction(send_money) if isinstance(identity, Identity): view_wot = QAction(self.tr("View in Web of Trust"), self) - view_wot.triggered.connect(self.currency_tab.tab_community.view_wot) + view_wot.triggered.connect(self.view_wot) view_wot.setData(identity) menu.addAction(view_wot) @@ -190,11 +196,52 @@ class TransactionsTabWidget(QWidget, Ui_transactionsTabWidget): elif data.__class__ is str: clipboard.setText(data) + def menu_informations(self): + person = self.sender().data() + self.identity_informations(person) + + def menu_add_as_contact(self): + person = self.sender().data() + self.add_identity_as_contact({'name': person.uid, + 'pubkey': person.pubkey}) + + def menu_send_money(self): + identity = self.sender().data() + self.send_money_to_identity(identity) + + def identity_informations(self, person): + dialog = MemberDialog(self.app, self.account, self.community, person) + dialog.exec_() + + def add_identity_as_contact(self, person): + dialog = ConfigureContactDialog(self.account, self.window(), person) + result = dialog.exec_() + if result == QDialog.Accepted: + self.window().refresh_contacts() + + def send_money_to_identity(self, identity): + if isinstance(identity, str): + pubkey = identity + else: + pubkey = identity.pubkey + result = TransferMoneyDialog.send_money_to_identity(self.app, self.account, self.password_asker, + self.community, identity) + if result == QDialog.Accepted: + currency_tab = self.window().currencies_tabwidget.currentWidget() + currency_tab.tab_history.table_history.model().sourceModel().refresh_transfers() + + def certify_identity(self, identity): + CertificationDialog.certify_identity(self.app, self.account, self.password_asker, + self.community, identity) + + def view_wot(self): + identity = self.sender().data() + self.view_in_wot.emit(identity) + def send_again(self): transfer = self.sender().data() dialog = TransferMoneyDialog(self.app, self.app.current_account, self.password_asker) - dialog.accepted.connect(self.currency_tab.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) diff --git a/src/cutecoin/gui/wot_tab.py b/src/cutecoin/gui/wot_tab.py index 300b24fbeffd744b2a2096c7fdbd107de9374e7b..57631e2e1e6da486aca9758dc0b5a14cd43b008e 100644 --- a/src/cutecoin/gui/wot_tab.py +++ b/src/cutecoin/gui/wot_tab.py @@ -72,7 +72,7 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): def refresh_informations_frame(self): parameters = self.community.parameters try: - identity = self.account.identity(self.community) + identity = yield from self.account.identity(self.community) membership = identity.membership(self.community) renew_block = membership['blockNumber'] last_renewal = self.community.get_block(renew_block)['medianTime'] @@ -168,7 +168,7 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): logging.debug("Draw graph - " + identity.uid) if self.community: - identity_account = self.account.identity(self.community) + identity_account = yield from self.account.identity(self.community) #Connect new identity if self._current_identity != identity: @@ -207,14 +207,15 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): if path: self.graphicsView.scene().update_path(path) + @asyncify + @asyncio.coroutine def reset(self): """ Reset graph scene to wallet identity """ if self.account: - self.draw_graph( - self.account.identity(self.community) - ) + identity = yield from self.account.identity(self.community) + self.draw_graph(identity) def refresh(self): """ diff --git a/src/cutecoin/models/txhistory.py b/src/cutecoin/models/txhistory.py index b95d7b61581085835e701c69bea638e4b9ad6ca3..e37faf30fb9b07fd99e38976fc0016a2d0db1ed3 100644 --- a/src/cutecoin/models/txhistory.py +++ b/src/cutecoin/models/txhistory.py @@ -181,7 +181,7 @@ class HistoryTableModel(QAbstractTableModel): self.account._current_ref self.transfers_data = [] self.refresh_transfers() - self._max_validation = 0 + self._max_validations = 0 self.columns_types = ( 'date', @@ -291,11 +291,11 @@ class HistoryTableModel(QAbstractTableModel): if data: self.transfers_data.append(data) members_pubkeys = yield from self.community.members_pubkeys() - self._max_validation = self.community.network.fork_window(members_pubkeys) + 1 + self._max_validations = self.community.network.fork_window(members_pubkeys) + 1 self.endResetModel() - def max_validation(self): - return self._max_validation + def max_validations(self): + return self._max_validations def rowCount(self, parent): return len(self.transfers_data)