Add context menu with copy and piCtory actions to revpi search dialog

This commit is contained in:
2023-01-03 13:45:32 +01:00
parent 9ec1f1b622
commit 2400bd6951
4 changed files with 87 additions and 5 deletions

View File

@@ -2,9 +2,10 @@
# Form implementation generated from reading ui file 'avahisearch.ui' # Form implementation generated from reading ui file 'avahisearch.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.15.7
# #
# WARNING! All changes made in this file will be lost! # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
@@ -64,9 +65,15 @@ class Ui_diag_search(object):
self.btn_box.setStandardButtons(QtWidgets.QDialogButtonBox.Close) self.btn_box.setStandardButtons(QtWidgets.QDialogButtonBox.Close)
self.btn_box.setObjectName("btn_box") self.btn_box.setObjectName("btn_box")
self.gridLayout.addWidget(self.btn_box, 3, 0, 1, 2) self.gridLayout.addWidget(self.btn_box, 3, 0, 1, 2)
self.act_copy_host = QtWidgets.QAction(diag_search)
self.act_copy_host.setObjectName("act_copy_host")
self.act_copy_ip = QtWidgets.QAction(diag_search)
self.act_copy_ip.setObjectName("act_copy_ip")
self.act_open_pictory = QtWidgets.QAction(diag_search)
self.act_open_pictory.setObjectName("act_open_pictory")
self.retranslateUi(diag_search) self.retranslateUi(diag_search)
self.btn_box.rejected.connect(diag_search.reject) self.btn_box.rejected.connect(diag_search.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(diag_search) QtCore.QMetaObject.connectSlotsByName(diag_search)
def retranslateUi(self, diag_search): def retranslateUi(self, diag_search):
@@ -81,6 +88,9 @@ class Ui_diag_search(object):
item.setText(_translate("diag_search", "IP address")) item.setText(_translate("diag_search", "IP address"))
self.btn_connect.setText(_translate("diag_search", "&Connect to Revolution Pi")) self.btn_connect.setText(_translate("diag_search", "&Connect to Revolution Pi"))
self.btn_save.setText(_translate("diag_search", "&Save connection")) self.btn_save.setText(_translate("diag_search", "&Save connection"))
self.act_copy_host.setText(_translate("diag_search", "Copy host name"))
self.act_copy_ip.setText(_translate("diag_search", "Copy IP address"))
self.act_open_pictory.setText(_translate("diag_search", "Open piCtory"))
from . import ressources_rc from . import ressources_rc

View File

@@ -120,6 +120,21 @@
</widget> </widget>
</item> </item>
</layout> </layout>
<action name="act_copy_host">
<property name="text">
<string>Copy host name</string>
</property>
</action>
<action name="act_copy_ip">
<property name="text">
<string>Copy IP address</string>
</property>
</action>
<action name="act_open_pictory">
<property name="text">
<string>Open piCtory</string>
</property>
</action>
</widget> </widget>
<resources> <resources>
<include location="ressources.qrc"/> <include location="ressources.qrc"/>

View File

@@ -4,8 +4,10 @@ __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2020 Sven Sager" __copyright__ = "Copyright (C) 2020 Sven Sager"
__license__ = "GPLv3" __license__ = "GPLv3"
import webbrowser
from os import name as osname from os import name as osname
from re import compile from re import compile
from sys import platform
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from zeroconf import IPVersion, ServiceBrowser, Zeroconf from zeroconf import IPVersion, ServiceBrowser, Zeroconf
@@ -92,6 +94,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
super(AvahiSearch, self).__init__(parent) super(AvahiSearch, self).__init__(parent)
self.setupUi(self) self.setupUi(self)
self.clipboard = QtGui.QGuiApplication.clipboard()
self.connect_index = -1 self.connect_index = -1
self.known_hosts = {} self.known_hosts = {}
self.th_zero_conf = AvahiSearchThread(self) self.th_zero_conf = AvahiSearchThread(self)
@@ -106,6 +109,23 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
for i in range(self.tb_revpi.columnCount()): for i in range(self.tb_revpi.columnCount()):
self.tb_revpi.setColumnWidth(i, int(column_sizes[i])) self.tb_revpi.setColumnWidth(i, int(column_sizes[i]))
# Global context menus
self.cm_quick_actions = QtWidgets.QMenu(self)
self.cm_quick_actions.addAction(self.act_open_pictory)
self.cm_quick_actions.addSeparator()
self.cm_quick_actions.addAction(self.act_copy_ip)
self.cm_quick_actions.addAction(self.act_copy_host)
self.tb_revpi.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.tb_revpi.customContextMenuRequested.connect(self._context_menu)
@QtCore.pyqtSlot(QtCore.QPoint)
def _context_menu(self, position: QtCore.QPoint) -> None:
sender = self.sender()
action = self.cm_quick_actions.exec(sender.mapToGlobal(position))
if action:
action.trigger()
def _load_known_hosts(self) -> None: def _load_known_hosts(self) -> None:
"""Load existing connections to show hostname of existing ip addresses""" """Load existing connections to show hostname of existing ip addresses"""
self.known_hosts.clear() self.known_hosts.clear()
@@ -201,6 +221,40 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
self.th_zero_conf.requestInterruption() self.th_zero_conf.requestInterruption()
return rc return rc
@QtCore.pyqtSlot()
def on_act_copy_host_triggered(self) -> None:
"""Copy ip address of selected item to clipboard."""
selected_items = self.tb_revpi.selectedItems()
if not selected_items:
return
item = selected_items[0]
host_name = item.data(WidgetData.host_name)
if platform == "win32":
# Strip hostname on Windows systems, it can not resolve .local addresses
host_name = host_name[:host_name.find(".")]
self.clipboard.setText(host_name)
@QtCore.pyqtSlot()
def on_act_copy_ip_triggered(self) -> None:
"""Copy ip address of selected item to clipboard."""
selected_items = self.tb_revpi.selectedItems()
if not selected_items:
return
item = selected_items[0]
self.clipboard.setText(item.data(WidgetData.address))
@QtCore.pyqtSlot()
def on_act_open_pictory_triggered(self) -> None:
"""Open piCtory in default browser of operating system."""
selected_items = self.tb_revpi.selectedItems()
if not selected_items:
return
item = selected_items[0]
if platform == "win32":
webbrowser.open("http://{0}/".format(item.data(WidgetData.address)))
else:
webbrowser.open("http://{0}/".format(item.data(WidgetData.host_name)))
@QtCore.pyqtSlot(str, str, int, str, str) @QtCore.pyqtSlot(str, str, int, str, str)
def on_avahi_added(self, name: str, server: str, port: int, conf_type: str, ip: str) -> None: def on_avahi_added(self, name: str, server: str, port: int, conf_type: str, ip: str) -> None:
"""New Revolution Pi found.""" """New Revolution Pi found."""
@@ -224,14 +278,16 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
item_name = self.tb_revpi.item(index, 0) item_name = self.tb_revpi.item(index, 0)
item_ip = self.tb_revpi.item(index, 1) item_ip = self.tb_revpi.item(index, 1)
host_name = server[:-1]
item_name.setIcon(QtGui.QIcon(":/main/ico/cpu.ico")) item_name.setIcon(QtGui.QIcon(":/main/ico/cpu.ico"))
if ip in self.known_hosts: if ip in self.known_hosts:
item_name.setText("{0} ({1})".format(server[:-1], self.known_hosts[ip])) item_name.setText("{0} ({1})".format(host_name, self.known_hosts[ip]))
else: else:
item_name.setText(server[:-1]) item_name.setText(host_name)
item_name.setData(WidgetData.object_name, name) item_name.setData(WidgetData.object_name, name)
item_name.setData(WidgetData.address, ip) item_name.setData(WidgetData.address, ip)
item_name.setData(WidgetData.port, port) item_name.setData(WidgetData.port, port)
item_name.setData(WidgetData.host_name, host_name)
item_ip.setText(ip) item_ip.setText(ip)
@QtCore.pyqtSlot(str, str) @QtCore.pyqtSlot(str, str)

View File

@@ -27,6 +27,7 @@ class WidgetData(IntEnum):
port = 264 port = 264
object_name = 265 object_name = 265
timeout = 266 timeout = 266
host_name = 267
last_dir_upload = 301 last_dir_upload = 301
last_file_upload = 302 last_file_upload = 302
last_dir_pictory = 303 last_dir_pictory = 303