diff --git a/res/ui/explorer_tab.ui b/res/ui/explorer_tab.ui index 1fdfca6504d575258272ea6e605da2bb1dcae9d4..58aa9891db98f11f4f66fcf45a3be4913937e123 100644 --- a/res/ui/explorer_tab.ui +++ b/res/ui/explorer_tab.ui @@ -14,6 +14,9 @@ <string>Form</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="SearchUserWidget" name="search_user_widget" native="true"/> + </item> <item> <widget class="ExplorerView" name="graphicsView"> <property name="viewportUpdateMode"> @@ -73,6 +76,12 @@ <extends>QGraphicsView</extends> <header>sakia.gui.views</header> </customwidget> + <customwidget> + <class>SearchUserWidget</class> + <extends>QWidget</extends> + <header>sakia.gui.widgets.search_user</header> + <container>1</container> + </customwidget> </customwidgets> <resources> <include location="../icons/icons.qrc"/> diff --git a/res/ui/wot_tab.ui b/res/ui/wot_tab.ui index 4175fed16225067b2a604095fda034c93f571fb3..d71654c11480961021b3679b84a89243a1b1e3b2 100644 --- a/res/ui/wot_tab.ui +++ b/res/ui/wot_tab.ui @@ -14,33 +14,6 @@ <string>Form</string> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QComboBox" name="comboBoxSearch"> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QPushButton" name="pushButtonReset"> - <property name="maximumSize"> - <size> - <width>85</width> - <height>27</height> - </size> - </property> - <property name="toolTip"> - <string>Center the view on me</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="../icons/icons.qrc"> - <normaloff>:/icons/home_icon</normaloff>:/icons/home_icon</iconset> - </property> - </widget> - </item> <item row="1" column="0" colspan="2"> <widget class="WotView" name="graphicsView"> <property name="viewportUpdateMode"> @@ -48,6 +21,9 @@ </property> </widget> </item> + <item row="0" column="0" colspan="2"> + <widget class="SearchUserWidget" name="search_user_widget" native="true"/> + </item> </layout> </widget> <customwidgets> @@ -56,44 +32,17 @@ <extends>QGraphicsView</extends> <header>sakia.gui.views.wot</header> </customwidget> + <customwidget> + <class>SearchUserWidget</class> + <extends>QWidget</extends> + <header>sakia.gui.widgets.search_user</header> + <container>1</container> + </customwidget> </customwidgets> <resources> <include location="../icons/icons.qrc"/> </resources> - <connections> - <connection> - <sender>pushButtonReset</sender> - <signal>clicked()</signal> - <receiver>WotTabWidget</receiver> - <slot>reset()</slot> - <hints> - <hint type="sourcelabel"> - <x>516</x> - <y>23</y> - </hint> - <hint type="destinationlabel"> - <x>284</x> - <y>198</y> - </hint> - </hints> - </connection> - <connection> - <sender>comboBoxSearch</sender> - <signal>currentIndexChanged(int)</signal> - <receiver>WotTabWidget</receiver> - <slot>select_node()</slot> - <hints> - <hint type="sourcelabel"> - <x>215</x> - <y>22</y> - </hint> - <hint type="destinationlabel"> - <x>260</x> - <y>220</y> - </hint> - </hints> - </connection> - </connections> + <connections/> <slots> <slot>reset()</slot> <slot>search()</slot> diff --git a/src/sakia/core/graph/explorer_graph.py b/src/sakia/core/graph/explorer_graph.py index af804f5fbc2f2f7beb9d30868f9822aaf27a0156..420b4b48a4cc9b106188fd30cb9d3cbad434231e 100644 --- a/src/sakia/core/graph/explorer_graph.py +++ b/src/sakia/core/graph/explorer_graph.py @@ -33,8 +33,8 @@ class ExplorerGraph(BaseGraph): if self.exploration_task: if self.explored_identity is not identity or steps != self.steps: self.exploration_task.cancel() - #else: - # return + else: + return self.nx_graph.clear() self.explored_identity = identity self.steps = steps diff --git a/src/sakia/gui/graphs/explorer_tab.py b/src/sakia/gui/graphs/explorer_tab.py index d764a4a346e2d08b447e6faa5c11822f8f98574b..75321719cb4994d532b1b4e070209e5a437735a5 100644 --- a/src/sakia/gui/graphs/explorer_tab.py +++ b/src/sakia/gui/graphs/explorer_tab.py @@ -2,7 +2,10 @@ import logging from PyQt5.QtCore import QEvent, pyqtSignal, QT_TRANSLATE_NOOP +from ucoinpy.api import bma + from ...tools.decorators import asyncify, once_at_a_time, cancel_once_task +from ...tools.exceptions import NoPeerAvailable from ...core.graph import ExplorerGraph from .graph_tab import GraphTabWidget from ...gen_resources.explorer_tab_uic import Ui_ExplorerTabWidget @@ -12,8 +15,6 @@ class ExplorerTabWidget(GraphTabWidget, Ui_ExplorerTabWidget): money_sent = pyqtSignal() - _search_placeholder = QT_TRANSLATE_NOOP("ExplorerTabWidget", "Research a pubkey, an uid...") - def __init__(self, app): """ :param sakia.core.app.Application app: Application instance @@ -21,6 +22,8 @@ class ExplorerTabWidget(GraphTabWidget, Ui_ExplorerTabWidget): # construct from qtDesigner super().__init__(app) self.setupUi(self) + self.search_user_widget.init(app) + self.set_scene(self.graphicsView.scene()) self.account = None @@ -36,12 +39,15 @@ class ExplorerTabWidget(GraphTabWidget, Ui_ExplorerTabWidget): # create node metadata from account self._current_identity = None self.button_go.clicked.connect(self.go_clicked) + self.search_user_widget.identity_selected.connect(self.draw_graph) + self.search_user_widget.reset.connect(self.reset) def cancel_once_tasks(self): cancel_once_task(self, self.refresh_informations_frame) cancel_once_task(self, self.reset) def change_account(self, account, password_asker): + self.search_user_widget.change_account(account) self.account = account self.password_asker = password_asker @@ -51,6 +57,7 @@ class ExplorerTabWidget(GraphTabWidget, Ui_ExplorerTabWidget): self.graph.stop_exploration() self.graph = ExplorerGraph(self.app, self.community) self.graph.graph_changed.connect(self.refresh) + self.search_user_widget.change_community(community) self.graph.current_identity_changed.connect(self.graphicsView.scene().update_current_identity) self.reset() diff --git a/src/sakia/gui/graphs/graph_tab.py b/src/sakia/gui/graphs/graph_tab.py index 57afd78a4edf0892904867b36781bdca89d9a4bb..6b4fee5cf6f54a5aabdd71522ee9355c546e3ca4 100644 --- a/src/sakia/gui/graphs/graph_tab.py +++ b/src/sakia/gui/graphs/graph_tab.py @@ -147,24 +147,6 @@ class GraphTabWidget(QWidget): """ pass - def select_node(self, index): - """ - Select node in graph when item is selected in combobox - """ - if index < 0 or index >= len(self.nodes): - return False - node = self.nodes[index] - metadata = {'id': node['pubkey'], 'text': node['uid']} - self.draw_graph( - self.app.identities_registry.from_handled_data( - metadata['text'], - metadata['id'], - None, - BlockchainState.VALIDATED, - self.community - ) - ) - def identity_informations(self, pubkey, metadata): identity = self.app.identities_registry.from_handled_data( metadata['text'], diff --git a/src/sakia/gui/graphs/wot_tab.py b/src/sakia/gui/graphs/wot_tab.py index 5c54dee2ba34156e24fb9f4f8ebb34128a0dc5d6..ce12bd290e659bde210edc643d3f2d9b80427e2b 100644 --- a/src/sakia/gui/graphs/wot_tab.py +++ b/src/sakia/gui/graphs/wot_tab.py @@ -1,22 +1,17 @@ import logging import asyncio -from PyQt5.QtWidgets import QComboBox from PyQt5.QtCore import QEvent, pyqtSignal, QT_TRANSLATE_NOOP -from ucoinpy.api import bma - from ...tools.decorators import asyncify, once_at_a_time, cancel_once_task from ...core.graph import WoTGraph from ...gen_resources.wot_tab_uic import Ui_WotTabWidget from ...gui.widgets.busy import Busy -from ...tools.exceptions import NoPeerAvailable from .graph_tab import GraphTabWidget class WotTabWidget(GraphTabWidget, Ui_WotTabWidget): money_sent = pyqtSignal() - _search_placeholder = QT_TRANSLATE_NOOP("WotTabWidget", "Research a pubkey, an uid...") def __init__(self, app): """ @@ -25,15 +20,7 @@ class WotTabWidget(GraphTabWidget, Ui_WotTabWidget): super().__init__(app) # construct from qtDesigner self.setupUi(self) - - # Default text when combo lineEdit is empty - self.comboBoxSearch.lineEdit().setPlaceholderText(self.tr(WotTabWidget._search_placeholder)) - # Â add combobox events - self.comboBoxSearch.lineEdit().returnPressed.connect(self.search) - #Â To fix a recall of the same item with different case, - #Â the edited text is not added in the item list - self.comboBoxSearch.setInsertPolicy(QComboBox.NoInsert) - + self.search_user_widget.init(app) self.busy = Busy(self.graphicsView) self.busy.hide() @@ -45,8 +32,8 @@ class WotTabWidget(GraphTabWidget, Ui_WotTabWidget): self.app = app self.draw_task = None - #Â nodes list for menu from search - self.nodes = list() + self.search_user_widget.identity_selected.connect(self.draw_graph) + self.search_user_widget.reset.connect(self.reset) # create node metadata from account self._current_identity = None @@ -58,11 +45,13 @@ class WotTabWidget(GraphTabWidget, Ui_WotTabWidget): def change_account(self, account, password_asker): self.cancel_once_tasks() + self.search_user_widget.change_account(account) self.account = account self.password_asker = password_asker def change_community(self, community): self.cancel_once_tasks() + self.search_user_widget.change_community(community) self._auto_refresh(community) self.community = community self.reset() @@ -127,40 +116,6 @@ class WotTabWidget(GraphTabWidget, Ui_WotTabWidget): else: self.reset() - @asyncify - async def search(self): - """ - Search nodes when return is pressed in combobox lineEdit - """ - text = self.comboBoxSearch.lineEdit().text() - - if len(text) < 2: - return False - try: - response = await self.community.bma_access.future_request(bma.wot.Lookup, {'search': text}) - - nodes = {} - for identity in response['results']: - nodes[identity['pubkey']] = identity['uids'][0]['uid'] - - if nodes: - self.nodes = list() - self.comboBoxSearch.clear() - self.comboBoxSearch.lineEdit().setText(text) - for pubkey, uid in nodes.items(): - self.nodes.append({'pubkey': pubkey, 'uid': uid}) - self.comboBoxSearch.addItem(uid) - self.comboBoxSearch.showPopup() - except NoPeerAvailable: - pass - - def retranslateUi(self, widget): - """ - Retranslate missing widgets from generated code - """ - self.comboBoxSearch.lineEdit().setPlaceholderText(self.tr(WotTabWidget._search_placeholder)) - super().retranslateUi(self) - def resizeEvent(self, event): self.busy.resize(event.size()) super().resizeEvent(event) diff --git a/src/sakia/gui/widgets/search_user.py b/src/sakia/gui/widgets/search_user.py new file mode 100644 index 0000000000000000000000000000000000000000..94114755631209cefe8ea8551beecb72cc4d0a59 --- /dev/null +++ b/src/sakia/gui/widgets/search_user.py @@ -0,0 +1,106 @@ +import logging + +from PyQt5.QtCore import QEvent, pyqtSignal, QT_TRANSLATE_NOOP +from PyQt5.QtWidgets import QComboBox, QWidget + +from ucoinpy.api import bma + +from ...tools.decorators import asyncify +from ...tools.exceptions import NoPeerAvailable +from ...core.registry import BlockchainState, Identity +from ...gen_resources.search_user_view_uic import Ui_SearchUserWidget + + +class SearchUserWidget(QWidget, Ui_SearchUserWidget): + _search_placeholder = QT_TRANSLATE_NOOP("SearchUserWidget", "Research a pubkey, an uid...") + + identity_selected = pyqtSignal(Identity) + reset = pyqtSignal() + + def __init__(self, parent): + """ + :param sakia.core.app.Application app: Application instance + """ + # construct from qtDesigner + super().__init__(parent) + self.setupUi(self) + # Default text when combo lineEdit is empty + self.combobox_search.lineEdit().setPlaceholderText(self.tr(SearchUserWidget._search_placeholder)) + # Â add combobox events + self.combobox_search.lineEdit().returnPressed.connect(self.search) + #Â To fix a recall of the same item with different case, + #Â the edited text is not added in the item list + self.combobox_search.setInsertPolicy(QComboBox.NoInsert) + self.combobox_search.activated.connect(self.select_node) + self.button_reset.clicked.connect(self.reset) + self.nodes = list() + self.community = None + self.account = None + self.app = None + + def init(self, app): + """ + Initialize the widget + :param sakia.core.Application app: the application + """ + self.app = app + + def change_account(self, account): + self.account = account + + def change_community(self, community): + self.community = community + + @asyncify + async def search(self): + """ + Search nodes when return is pressed in combobox lineEdit + """ + text = self.combobox_search.lineEdit().text() + + if len(text) < 2: + return False + try: + response = await self.community.bma_access.future_request(bma.wot.Lookup, {'search': text}) + + nodes = {} + for identity in response['results']: + nodes[identity['pubkey']] = identity['uids'][0]['uid'] + + if nodes: + self.nodes = list() + self.blockSignals(True) + self.combobox_search.clear() + self.combobox_search.lineEdit().setText(text) + for pubkey, uid in nodes.items(): + self.nodes.append({'pubkey': pubkey, 'uid': uid}) + self.combobox_search.addItem(uid) + self.blockSignals(False) + self.combobox_search.showPopup() + except NoPeerAvailable: + pass + + def select_node(self, index): + """ + Select node in graph when item is selected in combobox + """ + if index < 0 or index >= len(self.nodes): + return False + node = self.nodes[index] + metadata = {'id': node['pubkey'], 'text': node['uid']} + self.identity_selected.emit( + self.app.identities_registry.from_handled_data( + metadata['text'], + metadata['id'], + None, + BlockchainState.VALIDATED, + self.community + ) + ) + + def retranslateUi(self, widget): + """ + Retranslate missing widgets from generated code + """ + self.combobox_search.lineEdit().setPlaceholderText(self.tr(SearchUserWidget._search_placeholder)) + super().retranslateUi(self) diff --git a/src/sakia/tests/unit/gui/views/test_base_node.py b/src/sakia/tests/unit/gui/views/test_base_node.py index 3f3363af510c08e100264cfff1a4387fb83b0b50..4162afe55fb9dcd61b44a60b675d70e154e84921 100644 --- a/src/sakia/tests/unit/gui/views/test_base_node.py +++ b/src/sakia/tests/unit/gui/views/test_base_node.py @@ -27,8 +27,8 @@ class TestBaseNode(unittest.TestCase, QuamashTest): node = BaseNode(("A", metadata), nx_pos) self.assertEqual(node.id, "A") self.assertEqual(node.metadata['status'], NodeStatus.NEUTRAL) - self.assertEqual(node.x, 0) - self.assertEqual(node.y, 5) + self.assertEqual(node.x(), 0) + self.assertEqual(node.y(), 5) self.assertEqual(node.status_wallet, False) self.assertEqual(node.status_member, True) self.assertEqual(node.text, "UserA") diff --git a/src/sakia/tests/unit/gui/views/test_explorer_edge.py b/src/sakia/tests/unit/gui/views/test_explorer_edge.py index 0f113c0ac6b251566b51fe6065aae208de2d183a..5732190cbca2a56b3f0e6cfa14cf4eb520f3ccdd 100644 --- a/src/sakia/tests/unit/gui/views/test_explorer_edge.py +++ b/src/sakia/tests/unit/gui/views/test_explorer_edge.py @@ -27,10 +27,10 @@ class TestExplorerEdge(unittest.TestCase, QuamashTest): edge = ExplorerEdge("A", "B", metadata, nx_pos, 0, 0) self.assertEqual(edge.source, "A") self.assertEqual(edge.destination, "B") - self.assertAlmostEqual(edge.destination_point.x(), 10.0) - self.assertAlmostEqual(edge.destination_point.y(), 20.0) - self.assertAlmostEqual(edge.source_point.x(), 0.0) - self.assertAlmostEqual(edge.source_point.y(), 5.0) + self.assertAlmostEqual(edge.destination_point.x(), 10.0, delta=5) + self.assertAlmostEqual(edge.destination_point.y(), 20.0, delta=5) + self.assertAlmostEqual(edge.source_point.x(), 10.0, delta=5) + self.assertAlmostEqual(edge.source_point.y(), 20.0, delta=5) self.assertEqual(edge.status, EdgeStatus.STRONG) self.lp.run_until_complete(exec_test()) @@ -68,9 +68,9 @@ class TestExplorerEdge(unittest.TestCase, QuamashTest): async def exec_test(): edge = ExplorerEdge("A", "B", metadata, nx_pos, 0, 0) bounding_rect = edge.boundingRect() - self.assertAlmostEqual(bounding_rect.x(), -3.0) - self.assertAlmostEqual(bounding_rect.y(), 2.0) - self.assertAlmostEqual(bounding_rect.width(), 16.0) - self.assertAlmostEqual(bounding_rect.height(), 21.0) + self.assertAlmostEqual(bounding_rect.x(), 7.0, delta=5) + self.assertAlmostEqual(bounding_rect.y(), 17.0, delta=5) + self.assertAlmostEqual(bounding_rect.width(), 6.0, delta=5) + self.assertAlmostEqual(bounding_rect.height(), 6.0, delta=5) self.lp.run_until_complete(exec_test()) diff --git a/src/sakia/tests/unit/gui/views/test_explorer_node.py b/src/sakia/tests/unit/gui/views/test_explorer_node.py index 1d51f4bc418fae20e6fd1d8b2c4186b5f2e72829..cd54b19f534f54e2931d1f092d872f1d1f3bc993 100644 --- a/src/sakia/tests/unit/gui/views/test_explorer_node.py +++ b/src/sakia/tests/unit/gui/views/test_explorer_node.py @@ -1,6 +1,6 @@ import unittest from unittest.mock import patch -from PyQt5.QtCore import QLocale +from PyQt5.QtCore import QLocale, QPointF from PyQt5.QtGui import QPainter from PyQt5.QtWidgets import QStyleOptionGraphicsItem, QWidget from sakia.tests import QuamashTest @@ -27,11 +27,11 @@ class TestExplorerNode(unittest.TestCase, QuamashTest): "B": (10, 20) } async def exec_test(): - node = ExplorerNode(("A", metadata), nx_pos, 0, 1) + node = ExplorerNode(("A", metadata), QPointF(0, 0), nx_pos, 0, 1) self.assertEqual(node.id, "A") self.assertEqual(node.metadata['status'], NodeStatus.NEUTRAL) - self.assertEqual(node.x, 0) - self.assertEqual(node.y, 5) + self.assertEqual(node.x(), 0) + self.assertEqual(node.y(), 0) self.assertEqual(node.status_wallet, False) self.assertEqual(node.status_member, True) self.assertEqual(node.text, "UserA") @@ -52,7 +52,7 @@ class TestExplorerNode(unittest.TestCase, QuamashTest): "B": (10, 20) } async def exec_test(): - node = ExplorerNode(("A", metadata), nx_pos, 0, 1) + node = ExplorerNode(("A", metadata), QPointF(0, 0), nx_pos, 0, 1) node.paint(painter, QStyleOptionGraphicsItem(), widget) self.lp.run_until_complete(exec_test()) @@ -70,10 +70,10 @@ class TestExplorerNode(unittest.TestCase, QuamashTest): "B": (10, 20) } async def exec_test(): - node = ExplorerNode(("A", metadata), nx_pos, 0, 1) + node = ExplorerNode(("A", metadata), QPointF(0, 0), nx_pos, 0, 1) bounding_rect = node.boundingRect() - self.assertAlmostEqual(bounding_rect.x(), -0.5, delta=1) - self.assertAlmostEqual(bounding_rect.y(), -0.5, delta=1) + self.assertAlmostEqual(bounding_rect.x(), -0.5, delta=5) + self.assertAlmostEqual(bounding_rect.y(), -0.5, delta=5) self.assertAlmostEqual(bounding_rect.width(), 19.59375, delta=5) self.assertAlmostEqual(bounding_rect.height(), 37.0, delta=5) diff --git a/src/sakia/tests/unit/gui/views/test_wot_edge.py b/src/sakia/tests/unit/gui/views/test_wot_edge.py index 1dc8ea2687eabba5d92156d2e2d4b69fee521e0c..6c0632b97e15f9e5eace680549297129cec79ba9 100644 --- a/src/sakia/tests/unit/gui/views/test_wot_edge.py +++ b/src/sakia/tests/unit/gui/views/test_wot_edge.py @@ -68,9 +68,9 @@ class TestWotEdge(unittest.TestCase, QuamashTest): async def exec_test(): edge = WotEdge("A", "B", metadata, nx_pos) bounding_rect = edge.boundingRect() - self.assertAlmostEqual(bounding_rect.x(), -3.0) - self.assertAlmostEqual(bounding_rect.y(), 2.0) - self.assertAlmostEqual(bounding_rect.width(), 16.0) - self.assertAlmostEqual(bounding_rect.height(), 21.0) + self.assertAlmostEqual(bounding_rect.x(), -3.0, delta=5) + self.assertAlmostEqual(bounding_rect.y(), 2.0, delta=5) + self.assertAlmostEqual(bounding_rect.width(), 16.0, delta=5) + self.assertAlmostEqual(bounding_rect.height(), 21.0, delta=5) self.lp.run_until_complete(exec_test()) diff --git a/src/sakia/tests/unit/gui/views/test_wot_node.py b/src/sakia/tests/unit/gui/views/test_wot_node.py index e3057453030b7765a90c0e41abcfd5f52b5724b1..a92ba2daa72a6309c08b885178f3a16274b989db 100644 --- a/src/sakia/tests/unit/gui/views/test_wot_node.py +++ b/src/sakia/tests/unit/gui/views/test_wot_node.py @@ -30,8 +30,8 @@ class TestWotNode(unittest.TestCase, QuamashTest): node = WotNode(("A", metadata), nx_pos) self.assertEqual(node.id, "A") self.assertEqual(node.metadata['status'], NodeStatus.NEUTRAL) - self.assertEqual(node.x, 0) - self.assertEqual(node.y, 5) + self.assertEqual(node.x(), 0) + self.assertEqual(node.y(), 5) self.assertEqual(node.status_wallet, False) self.assertEqual(node.status_member, True) self.assertEqual(node.text, "UserA")