diff --git a/res/ui/certification.ui b/res/ui/certification.ui index ff937b3a4ee56ce873ba3bbcbbb6b575ad76dcad..b65ffecfa69f9f79bc2af2230537110e13fcff5e 100644 --- a/res/ui/certification.ui +++ b/res/ui/certification.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>473</width> - <height>373</height> + <width>715</width> + <height>477</height> </rect> </property> <property name="windowTitle"> @@ -16,6 +16,12 @@ <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QGroupBox" name="groupBox_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="title"> <string>Community</string> </property> @@ -31,156 +37,167 @@ <property name="title"> <string>Certify user</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <widget class="QRadioButton" name="radio_contact"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Con&tact</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Maximum</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QComboBox" name="combo_contact"> - <property name="enabled"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </item> + <layout class="QHBoxLayout" name="horizontalLayout_5"> <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QRadioButton" name="radio_pubkey"> - <property name="text"> - <string>&User public key</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Maximum</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="edit_pubkey"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="inputMask"> - <string/> - </property> - <property name="text"> - <string/> - </property> - <property name="placeholderText"> - <string>Key</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_3"> + <layout class="QVBoxLayout" name="verticalLayout_3"> <property name="topMargin"> <number>6</number> </property> <item> - <widget class="QRadioButton" name="radio_search"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>S&earch user</string> - </property> - </widget> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QRadioButton" name="radio_contact"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Con&tact</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Maximum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QComboBox" name="combo_contact"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> </item> <item> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Maximum</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QRadioButton" name="radio_pubkey"> + <property name="text"> + <string>&User public key</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Maximum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="edit_pubkey"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="inputMask"> + <string/> + </property> + <property name="text"> + <string/> + </property> + <property name="placeholderText"> + <string>Key</string> + </property> + </widget> + </item> + </layout> </item> <item> - <widget class="SearchUserWidget" name="search_user" native="true"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <property name="topMargin"> + <number>6</number> + </property> + <item> + <widget class="QRadioButton" name="radio_search"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>S&earch user</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Maximum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="SearchUserWidget" name="search_user" native="true"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> </item> </layout> </item> </layout> </widget> </item> - <item> - <widget class="QGroupBox" name="groupBox_3"> - <property name="title"> - <string>User informations</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3"/> - </widget> - </item> <item> <widget class="QDialogButtonBox" name="button_box"> <property name="orientation"> diff --git a/res/ui/member.ui b/res/ui/member.ui index ca9b92019f0ad59dbb5e57fa2061ac2c2c5ef38b..7df367ca5605cdf36f8d6b41f1c46a2b97df7a14 100644 --- a/res/ui/member.ui +++ b/res/ui/member.ui @@ -1,17 +1,17 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> - <class>DialogMember</class> - <widget class="QDialog" name="DialogMember"> + <class>MemberView</class> + <widget class="QWidget" name="MemberView"> <property name="geometry"> <rect> <x>0</x> <y>0</y> - <width>501</width> - <height>288</height> + <width>392</width> + <height>251</height> </rect> </property> <property name="windowTitle"> - <string>Informations</string> + <string>Form</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> @@ -34,8 +34,14 @@ QGroupBox::title { <string>Member</string> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> + <item row="0" column="1"> <widget class="QLabel" name="label_icon"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="maximumSize"> <size> <width>81</width> @@ -53,7 +59,17 @@ QGroupBox::title { </property> </widget> </item> - <item row="0" column="1"> + <item row="2" column="1" colspan="2"> + <widget class="QLabel" name="label_properties"> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + </widget> + </item> + <item row="0" column="2"> <widget class="QLabel" name="label_uid"> <property name="maximumSize"> <size> @@ -62,17 +78,7 @@ QGroupBox::title { </size> </property> <property name="text"> - <string>uid</string> - </property> - </widget> - </item> - <item row="1" column="0" colspan="2"> - <widget class="QLabel" name="label_properties"> - <property name="text"> - <string>properties</string> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + <string/> </property> </widget> </item> @@ -83,7 +89,6 @@ QGroupBox::title { </widget> <resources> <include location="../icons/icons.qrc"/> - <include location="../icons/icons.qrc"/> </resources> <connections/> </ui> diff --git a/src/sakia/gui/certification.py b/src/sakia/gui/certification.py index 75019a208876c7cc3eb6bae050ad44082d146839..3ae4f3fafc88510034b93d5b825314019ced983c 100644 --- a/src/sakia/gui/certification.py +++ b/src/sakia/gui/certification.py @@ -11,31 +11,32 @@ from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QApplication, QMessageBox from PyQt5.QtCore import Qt, QObject from ..gen_resources.certification_uic import Ui_CertificationDialog -from sakia.gui.widgets import toast -from sakia.gui.widgets.dialogs import QAsyncMessageBox +from .widgets import toast +from .widgets.dialogs import QAsyncMessageBox +from .member import MemberDialog from ..tools.decorators import asyncify, once_at_a_time from ..tools.exceptions import NoPeerAvailable class CertificationDialog(QObject): """ - classdocs + A dialog to certify individuals """ - def __init__(self, app, account, password_asker, widget=QDialog, view=Ui_CertificationDialog): + def __init__(self, app, account, password_asker, widget, ui): """ Constructor if a certification dialog :param sakia.core.Application app: :param sakia.core.Account account: :param sakia.gui.password_asker.PasswordAsker password_asker: - :param class widget: the widget of the dialog - :param class view: the view of the certification dialog + :param PyQt5.QtWidgets widget: the widget of the dialog + :param sakia.gen_resources.certification_uic.Ui_CertificationDialog view: the view of the certification dialog :return: """ super().__init__() - self.widget = widget() - self.ui = view() + self.widget = widget + self.ui = ui self.ui.setupUi(self.widget) self.app = app self.account = account @@ -58,12 +59,33 @@ class CertificationDialog(QObject): self.ui.radio_pubkey.setChecked(True) self.ui.radio_contact.setEnabled(False) + self.ui.member_widget = MemberDialog.as_widget(self.ui.groupBox, self.app, self.account, self.community, None) + self.ui.horizontalLayout_5.addWidget(self.ui.member_widget.widget) + self.ui.search_user.button_reset.hide() self.ui.search_user.init(self.app) self.ui.search_user.change_account(self.account) self.ui.search_user.change_community(self.community) + self.ui.combo_contact.currentIndexChanged.connect(self.refresh_member) + self.ui.edit_pubkey.textChanged.connect(self.refresh_member) + self.ui.search_user.identity_selected.connect(self.refresh_member) + self.ui.radio_contact.toggled.connect(self.refresh_member) + self.ui.radio_search.toggled.connect(self.refresh_member) + self.ui.radio_pubkey.toggled.connect(self.refresh_member) self.ui.combo_community.currentIndexChanged.connect(self.change_current_community) + @classmethod + def open_dialog(cls, app, account, password_asker): + """ + Certify and identity + :param sakia.core.Application app: the application + :param sakia.core.Account account: the account certifying the identity + :param sakia.gui.password_asker.PasswordAsker password_asker: the password asker + :return: + """ + dialog = cls(app, account, password_asker, QDialog(), Ui_CertificationDialog()) + return dialog.exec() + @classmethod async def certify_identity(cls, app, account, password_asker, community, identity): """ @@ -75,7 +97,7 @@ class CertificationDialog(QObject): :param sakia.core.registry.Identity identity: the identity certified :return: """ - dialog = cls(app, account, password_asker) + dialog = cls(app, account, password_asker, QDialog(), Ui_CertificationDialog()) dialog.ui.combo_community.setCurrentText(community.name) dialog.ui.edit_pubkey.setText(identity.pubkey) dialog.ui.radio_pubkey.setChecked(True) @@ -83,6 +105,50 @@ class CertificationDialog(QObject): @asyncify async def accept(self): + """ + Validate the dialog + """ + pubkey = self.selected_pubkey() + if pubkey: + password = await self.password_asker.async_exec() + if password == "": + self.ui.button_box.setEnabled(True) + return + QApplication.setOverrideCursor(Qt.WaitCursor) + result = await self.account.certify(password, self.community, pubkey) + if result[0]: + if self.app.preferences['notifications']: + toast.display(self.tr("Certification"), + self.tr("Success sending certification")) + else: + await QAsyncMessageBox.information(self.widget, self.tr("Certification"), + self.tr("Success sending certification")) + QApplication.restoreOverrideCursor() + self.widget.accept() + else: + if self.app.preferences['notifications']: + toast.display(self.tr("Certification"), self.tr("Could not broadcast certification : {0}" + .format(result[1]))) + else: + await QAsyncMessageBox.critical(self.widget, self.tr("Certification"), + self.tr("Could not broadcast certification : {0}" + .format(result[1]))) + QApplication.restoreOverrideCursor() + self.ui.button_box.setEnabled(True) + + def change_current_community(self, index): + self.community = self.account.communities[index] + self.ui.search_user.change_community(self.community) + if self.isVisible(): + self.refresh() + + def selected_pubkey(self): + """ + Get selected pubkey in the widgets of the window + :return: the current pubkey + :rtype: str + """ + pubkey = None self.ui.button_box.setEnabled(False) if self.ui.radio_contact.isChecked(): for contact in self.account.contacts: @@ -92,42 +158,22 @@ class CertificationDialog(QObject): elif self.ui.radio_search.isChecked(): if self.ui.search_user.current_identity(): pubkey = self.ui.search_user.current_identity().pubkey - else: - return else: pubkey = self.ui.edit_pubkey.text() + return pubkey - password = await self.password_asker.async_exec() - if password == "": - self.ui.button_box.setEnabled(True) - return - QApplication.setOverrideCursor(Qt.WaitCursor) - result = await self.account.certify(password, self.community, pubkey) - if result[0]: - if self.app.preferences['notifications']: - toast.display(self.tr("Certification"), - self.tr("Success sending certification")) - else: - await QAsyncMessageBox.information(self.widget, self.tr("Certification"), - self.tr("Success sending certification")) - QApplication.restoreOverrideCursor() - self.widget.accept() + @asyncify + async def refresh_member(self, checked=False): + """ + Refresh the member widget + """ + current_pubkey = self.selected_pubkey() + if current_pubkey: + identity = await self.app.identities_registry.future_find(current_pubkey, self.community) else: - if self.app.preferences['notifications']: - toast.display(self.tr("Certification"), self.tr("Could not broadcast certification : {0}" - .format(result[1]))) - else: - await QAsyncMessageBox.critical(self.widget, self.tr("Certification"), - self.tr("Could not broadcast certification : {0}" - .format(result[1]))) - QApplication.restoreOverrideCursor() - self.ui.button_box.setEnabled(True) - - def change_current_community(self, index): - self.community = self.account.communities[index] - self.ui.search_user.change_community(self.community) - if self.isVisible(): - self.refresh() + identity = None + self.ui.member_widget.identity = identity + self.ui.member_widget.refresh() @once_at_a_time @asyncify diff --git a/src/sakia/gui/graphs/wot_tab.py b/src/sakia/gui/graphs/wot_tab.py index 62bc74f8b447bde1c3b0181be6e3cc73e0bde702..a3119357ab7964b474c826e578bbb92443d7cc14 100644 --- a/src/sakia/gui/graphs/wot_tab.py +++ b/src/sakia/gui/graphs/wot_tab.py @@ -30,6 +30,7 @@ class WotTabWidget(GraphTabWidget): self.ui.setupUi(self.widget) self.ui.search_user_widget.init(app) + self.widget.installEventFilter(self) self.busy = Busy(self.ui.graphicsView) self.busy.hide() @@ -125,9 +126,11 @@ class WotTabWidget(GraphTabWidget): else: self.reset() - def resizeEvent(self, event): - self.busy.resize(event.size()) - super().resizeEvent(event) + def eventFilter(self, source, event): + if event.type() == QEvent.Resize: + self.busy.resize(event.size()) + self.widget.resizeEvent(event) + return self.widget.eventFilter(source, event) def changeEvent(self, event): """ diff --git a/src/sakia/gui/mainwindow.py b/src/sakia/gui/mainwindow.py index 561a49f0b1459b11fa8af2c807cdbdf924a77b6a..808ce45a8cd7eaae3ae479da77da5133e1d943eb 100644 --- a/src/sakia/gui/mainwindow.py +++ b/src/sakia/gui/mainwindow.py @@ -180,10 +180,9 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.community_view.tab_history.table_history.model().sourceModel().refresh_transfers() def open_certification_dialog(self): - dialog = CertificationDialog(self.app, + CertificationDialog.open_dialog(self.app, self.app.current_account, self.password_asker) - dialog.exec() def open_add_contact_dialog(self): dialog = ConfigureContactDialog(self.app.current_account, self) diff --git a/src/sakia/gui/member.py b/src/sakia/gui/member.py index 94f027a2c1b3547acf7cae6b448253ff23697d13..22b68abaf480e52e0da5c66343f52ec5e1a30fa3 100644 --- a/src/sakia/gui/member.py +++ b/src/sakia/gui/member.py @@ -1,12 +1,12 @@ import datetime -import asyncio -from PyQt5.QtCore import QObject +from PyQt5.QtCore import QObject, QEvent from PyQt5.QtWidgets import QDialog, QWidget from ..core.graph import WoTGraph +from .widgets.busy import Busy from ..tools.decorators import asyncify -from ..gen_resources.member_uic import Ui_DialogMember +from ..gen_resources.member_uic import Ui_MemberView from ..tools.exceptions import MembershipNotFoundError @@ -31,78 +31,92 @@ class MemberDialog(QObject): self.widget = widget self.ui = ui self.ui.setupUi(self.widget) + self.ui.busy = Busy(self.widget) + self.widget.installEventFilter(self) self.app = app self.community = community self.account = account self.identity = identity - self.ui.label_uid.setText(identity.uid) self.refresh() @classmethod def open_dialog(cls, app, account, community, identity): - return cls(app, account, community, identity, QDialog(), Ui_DialogMember()).exec() + return cls(app, account, community, identity, QDialog(), Ui_MemberView()).exec() @classmethod - def as_widget(cls, app, account, community, identity): - return cls(app, account, community, identity, QWidget(), Ui_DialogMember()) + def as_widget(cls, parent_widget, app, account, community, identity): + return cls(app, account, community, identity, QWidget(parent_widget), Ui_MemberView()) @asyncify async def refresh(self): - try: - join_date = await self.identity.get_join_date(self.community) - except MembershipNotFoundError: - join_date = None - - if join_date is None: - join_date = self.tr('not a member') - else: - join_date = datetime.datetime.fromtimestamp(join_date).strftime("%d/%m/%Y %I:%M") - - # calculate path to account member - graph = WoTGraph(self.app, self.community) - path = None - # 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 = await self.account.identity(self.community) - path = await graph.get_shortest_path_to_identity(self.identity, - account_identity) - - text = self.tr(""" - <table cellpadding="5"> - <tr><td align="right"><b>{:}</b></div></td><td>{:}</td></tr> - <tr><td align="right"><b>{:}</b></div></td><td>{:}</td></tr> - """).format( - self.tr('Public key'), - self.identity.pubkey, - self.tr('Join date'), - join_date - ) - - 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)) - if distance > 1: - index = 0 - for node in path: - if index == 0: - text += self.tr("""<tr><td align="right"><b>{:}</b></div></td><td>{:}</td></tr>""").format( - self.tr('Path'), node['text']) - else: - text += self.tr("""<tr><td align="right"><b>{:}</b></div></td><td>{:}</td></tr>""").format('', - node[ - 'text']) - if index == distance and node['id'] != self.account.pubkey: - text += self.tr("""<tr><td align="right"><b>{:}</b></div></td><td>{:}</td></tr>""").format('', - self.account.name) - index += 1 - # close html text - text += "</table>" - - # set text in label - self.ui.label_properties.setText(text) + if self.identity: + self.ui.busy.show() + self.ui.label_uid.setText(self.identity.uid) + try: + join_date = await self.identity.get_join_date(self.community) + except MembershipNotFoundError: + join_date = None + + if join_date is None: + join_date = self.tr('not a member') + else: + join_date = datetime.datetime.fromtimestamp(join_date).strftime("%d/%m/%Y %I:%M") + + # calculate path to account member + graph = WoTGraph(self.app, self.community) + path = None + # 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 = await self.account.identity(self.community) + path = await graph.get_shortest_path_to_identity(self.identity, + account_identity) + + text = self.tr(""" + <table cellpadding="5"> + <tr><td align="right"><b>{:}</b></div></td><td>{:}</td></tr> + <tr><td align="right"><b>{:}</b></div></td><td>{:}</td></tr> + """).format( + self.tr('Public key'), + self.identity.pubkey, + self.tr('Join date'), + join_date + ) + + 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)) + if distance > 1: + index = 0 + for node in path: + if index == 0: + text += self.tr("""<tr><td align="right"><b>{:}</b></div></td><td>{:}</td></tr>""")\ + .format( + self.tr('Path'), node['text']) + else: + text += self.tr("""<tr><td align="right"><b>{:}</b></div></td><td>{:}</td></tr>""")\ + .format('', + node[ + 'text']) + if index == distance and node['id'] != self.account.pubkey: + text += self.tr("""<tr><td align="right"><b>{:}</b></div></td><td>{:}</td></tr>""")\ + .format('', + self.account.name) + index += 1 + # close html text + text += "</table>" + + # set text in label + self.ui.label_properties.setText(text) + self.ui.busy.hide() + + def eventFilter(self, source, event): + if event.type() == QEvent.Resize: + self.ui.busy.resize(event.size()) + self.widget.resizeEvent(event) + return self.widget.eventFilter(source, event) def exec(self): self.widget.exec()