From 9e7f39957bb243502a28780d28e68ffd9761a59f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 14:41:02 +0100 Subject: [PATCH 01/28] removed unused import --- pype/tools/tray/pype_tray.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index c27df16276..b5fbd2598a 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -8,10 +8,6 @@ from pype.api import Logger, resources from pype.modules import TrayModulesManager, ITrayService from pype.settings.lib import get_system_settings import pype.version -try: - import configparser -except Exception: - import ConfigParser as configparser class TrayManager: From 81b081c24f78f129d7cb5f52155fabfdf8399f7f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 14:41:59 +0100 Subject: [PATCH 02/28] removed unused working widget --- pype/tools/tray/pype_tray.py | 55 ++---------------------------------- 1 file changed, 3 insertions(+), 52 deletions(-) diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index b5fbd2598a..27f00c8065 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -124,63 +124,14 @@ class TrayMainWindow(QtWidgets.QMainWindow): Every widget should have set this window as parent because QSystemTrayIcon widget is not allowed to be a parent of any widget. - - :param app: Qt application manages application's control flow - :type app: QtWidgets.QApplication - - .. note:: - *TrayMainWindow* has ability to show **working** widget. - Calling methods: - - ``show_working()`` - - ``hide_working()`` - .. todo:: Hide working widget if idle is too long """ def __init__(self, app): - super().__init__() + super(TrayMainWindow, self).__init__() self.app = app - self.set_working_widget() - - self.trayIcon = SystemTrayIcon(self) - self.trayIcon.show() - - def set_working_widget(self): - image_file = resources.get_resource("icons", "working.svg") - img_pix = QtGui.QPixmap(image_file) - if image_file.endswith('.svg'): - widget = QtSvg.QSvgWidget(image_file) - else: - widget = QtWidgets.QLabel() - widget.setPixmap(img_pix) - - # Set widget properties - widget.setGeometry(img_pix.rect()) - widget.setMask(img_pix.mask()) - widget.setWindowFlags( - QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.FramelessWindowHint - ) - widget.setAttribute(QtCore.Qt.WA_TranslucentBackground, True) - - self.center_widget(widget) - self._working_widget = widget - self.helper = DragAndDropHelper(self._working_widget) - - def center_widget(self, widget): - frame_geo = widget.frameGeometry() - screen = self.app.desktop().cursor().pos() - center_point = self.app.desktop().screenGeometry( - self.app.desktop().screenNumber(screen) - ).center() - frame_geo.moveCenter(center_point) - widget.move(frame_geo.topLeft()) - - def show_working(self): - self._working_widget.show() - - def hide_working(self): - self.center_widget(self._working_widget) - self._working_widget.hide() + self.tray_widget = SystemTrayIcon(self) + self.tray_widget.show() class DragAndDropHelper: From 70fedd42bc08666f670a4e1ea11fb556c270f0b8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 14:42:31 +0100 Subject: [PATCH 03/28] PypeTrayApplication does not change application name on windows --- pype/tools/tray/pype_tray.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index 27f00c8065..48bc9fcb0c 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -177,17 +177,10 @@ class PypeTrayApplication(QtWidgets.QApplication): """Qt application manages application's control flow.""" def __init__(self): - super(self.__class__, self).__init__(sys.argv) + super(PypeTrayApplication, self).__init__(sys.argv) # Allows to close widgets without exiting app self.setQuitOnLastWindowClosed(False) - # Allow show icon istead of python icon in task bar (Windows) - if os.name == "nt": - import ctypes - ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID( - u"pype_tray" - ) - # Sets up splash splash_widget = self.set_splash() From 27c860ffe1a4819b7c305806c7594a122bb95214 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 14:42:50 +0100 Subject: [PATCH 04/28] removed drag and drop helper --- pype/tools/tray/pype_tray.py | 39 ------------------------------------ 1 file changed, 39 deletions(-) diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index 48bc9fcb0c..8e0757ec9d 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -134,45 +134,6 @@ class TrayMainWindow(QtWidgets.QMainWindow): self.tray_widget.show() -class DragAndDropHelper: - """ Helper adds to widget drag and drop ability - - :param widget: Qt Widget where drag and drop ability will be added - """ - - def __init__(self, widget): - self.widget = widget - self.widget.mousePressEvent = self.mousePressEvent - self.widget.mouseMoveEvent = self.mouseMoveEvent - self.widget.mouseReleaseEvent = self.mouseReleaseEvent - - def mousePressEvent(self, event): - self.__mousePressPos = None - self.__mouseMovePos = None - if event.button() == QtCore.Qt.LeftButton: - self.__mousePressPos = event.globalPos() - self.__mouseMovePos = event.globalPos() - - def mouseMoveEvent(self, event): - if event.buttons() == QtCore.Qt.LeftButton: - # adjust offset from clicked point to origin of widget - currPos = self.widget.mapToGlobal( - self.widget.pos() - ) - globalPos = event.globalPos() - diff = globalPos - self.__mouseMovePos - newPos = self.widget.mapFromGlobal(currPos + diff) - self.widget.move(newPos) - self.__mouseMovePos = globalPos - - def mouseReleaseEvent(self, event): - if self.__mousePressPos is not None: - moved = event.globalPos() - self.__mousePressPos - if moved.manhattanLength() > 3: - event.ignore() - return - - class PypeTrayApplication(QtWidgets.QApplication): """Qt application manages application's control flow.""" From 29f6c1e88a7e6bdf939b1f97b0091bf369882b0b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 14:44:10 +0100 Subject: [PATCH 05/28] removed working svg --- pype/resources/icons/working.svg | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 pype/resources/icons/working.svg diff --git a/pype/resources/icons/working.svg b/pype/resources/icons/working.svg deleted file mode 100644 index fe73f15a31..0000000000 --- a/pype/resources/icons/working.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - Working... - From eeb4529b8835735d1d659ff6a752c585c0d7e094 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 14:44:42 +0100 Subject: [PATCH 06/28] tray manager sends it's pointer to modules manager --- pype/modules/base.py | 4 +++- pype/tools/tray/pype_tray.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pype/modules/base.py b/pype/modules/base.py index 7efd00e39e..b295746b9b 100644 --- a/pype/modules/base.py +++ b/pype/modules/base.py @@ -638,8 +638,10 @@ class TrayModulesManager(ModulesManager): self.modules_by_id = {} self.modules_by_name = {} self._report = {} + self.tray_manager = None - def initialize(self, tray_menu): + def initialize(self, tray_manager, tray_menu): + self.tray_manager = tray_manager self.initialize_modules() self.tray_init() self.connect_modules() diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index 8e0757ec9d..7413fe399b 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -32,7 +32,7 @@ class TrayManager: def initialize_modules(self): """Add modules to tray.""" - self.modules_manager.initialize(self.tray_widget.menu) + self.modules_manager.initialize(self, self.tray_widget.menu) # Add services if they are services_submenu = ITrayService.services_submenu(self.tray_widget.menu) From 6695a452f6496a076497353974667ca13ef7f80e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 14:45:05 +0100 Subject: [PATCH 07/28] tray manger has method to show tray message --- pype/tools/tray/pype_tray.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index 7413fe399b..062d825c09 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -54,6 +54,26 @@ class TrayManager: # Print time report self.modules_manager.print_report() + def show_tray_message(self, title, message, icon=None, msecs=None): + """Show tray message. + + Args: + title (str): Title of message. + message (str): Content of message. + icon (QSystemTrayIcon.MessageIcon): Message's icon. Default is + Information icon, may differ by Qt version. + msecs (int): Duration of message visibility in miliseconds. + Default is 10000 msecs, may differ by Qt version. + """ + args = [title, message] + kwargs = {} + if icon: + kwargs["icon"] = icon + if msecs: + kwargs["msecs"] = msecs + + self.tray_widget.showMessage(*args, **kwargs) + def _add_version_item(self): subversion = os.environ.get("PYPE_SUBVERSION") client_name = os.environ.get("PYPE_CLIENT") From e49749d307fd6b5b999bba76a04e176a28c024e6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 14:45:21 +0100 Subject: [PATCH 08/28] tray modules can show tray message --- pype/modules/base.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pype/modules/base.py b/pype/modules/base.py index b295746b9b..03a5965841 100644 --- a/pype/modules/base.py +++ b/pype/modules/base.py @@ -108,6 +108,7 @@ class ITrayModule: would do nothing. """ tray_initialized = False + _tray_manager = None @abstractmethod def tray_init(self): @@ -138,6 +139,20 @@ class ITrayModule: """ pass + def show_tray_message(self, title, message, icon=None, msecs=None): + """Show tray message. + + Args: + title (str): Title of message. + message (str): Content of message. + icon (QSystemTrayIcon.MessageIcon): Message's icon. Default is + Information icon, may differ by Qt version. + msecs (int): Duration of message visibility in miliseconds. + Default is 10000 msecs, may differ by Qt version. + """ + if self._tray_manager: + self._tray_manager.show_tray_message(title, message, icon, msecs) + class ITrayAction(ITrayModule): """Implementation of Tray action. @@ -660,6 +675,7 @@ class TrayModulesManager(ModulesManager): prev_start_time = time_start for module in self.get_enabled_tray_modules(): try: + module._tray_manager = self.tray_manager module.tray_init() module.tray_initialized = True except Exception: From cfa0f4add963a04f16f1dc7d9cc5956705cdbe10 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 14:50:22 +0100 Subject: [PATCH 09/28] small cleanup of tray file --- pype/tools/tray/pype_tray.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index 062d825c09..202b801343 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -15,13 +15,12 @@ class TrayManager: Load submenus, actions, separators and modules into tray's context. """ - available_sourcetypes = ["python", "file"] def __init__(self, tray_widget, main_window): self.tray_widget = tray_widget self.main_window = main_window - self.log = Logger().get_logger(self.__class__.__name__) + self.log = Logger.get_logger(self.__class__.__name__) self.module_settings = get_system_settings()["modules"] @@ -101,9 +100,9 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon): """ def __init__(self, parent): - self.icon = QtGui.QIcon(resources.pype_icon_filepath()) + icon = QtGui.QIcon(resources.pype_icon_filepath()) - QtWidgets.QSystemTrayIcon.__init__(self, self.icon, parent) + super(SystemTrayIcon, self).__init__(icon, parent) # Store parent - QtWidgets.QMainWindow() self.parent = parent @@ -116,15 +115,15 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon): self.tray_man = TrayManager(self, self.parent) self.tray_man.initialize_modules() - # Catch activate event - self.activated.connect(self.on_systray_activated) + # Catch activate event for left click if not on MacOS + # - MacOS has this ability by design so menu would be doubled + if platform.system().lower() != "darwin": + self.activated.connect(self.on_systray_activated) # Add menu to Context of SystemTrayIcon self.setContextMenu(self.menu) def on_systray_activated(self, reason): # show contextMenu if left click - if platform.system().lower() == "darwin": - return if reason == QtWidgets.QSystemTrayIcon.Trigger: position = QtGui.QCursor().pos() self.contextMenu().popup(position) From 5e7d057da13a2c38b2f7fa09381c20d0d2b2fa21 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 15:35:47 +0100 Subject: [PATCH 10/28] tray shows small widget with basic information on version click --- pype/tools/tray/pype_tray.py | 56 ++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index 202b801343..5870db9c49 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -10,6 +10,51 @@ from pype.settings.lib import get_system_settings import pype.version +class PypeInfoWidget(QtWidgets.QWidget): + not_allowed = "N/A" + + def __init__(self, parent=None): + super(PypeInfoWidget, self).__init__(parent) + + self.setStyleSheet(style.load_stylesheet()) + + main_layout = QtWidgets.QFormLayout(self) + + if getattr(sys, "frozen", False): + version_end = "build" + else: + version_end = "code" + version_value = "{} ({})".format( + pype.version.__version__, version_end + ) + + lable_value = [ + # Pype version + ("Pype version:", version_value), + ("Pype location:", os.environ.get("PYPE_ROOT")), + + # Mongo URL + ("Pype Mongo URL:", os.environ.get("PYPE_MONGO")) + ] + + for label, value in lable_value: + main_layout.addRow( + label, + QtWidgets.QLabel(value or self.not_allowed) + ) + + def showEvent(self, event): + result = super(PypeInfoWidget, self).showEvent(event) + screen_center = ( + QtWidgets.QApplication.desktop().availableGeometry(self).center() + ) + self.move( + screen_center.x() - (self.width() / 2), + screen_center.y() - (self.height() / 2) + ) + return result + + class TrayManager: """Cares about context of application. @@ -20,6 +65,8 @@ class TrayManager: self.tray_widget = tray_widget self.main_window = main_window + self.pype_info_widget = None + self.log = Logger.get_logger(self.__class__.__name__) self.module_settings = get_system_settings()["modules"] @@ -85,12 +132,21 @@ class TrayManager: version_string += ", {}".format(client_name) version_action = QtWidgets.QAction(version_string, self.tray_widget) + version_action.triggered.connect(self._on_version_action) self.tray_widget.menu.addAction(version_action) self.tray_widget.menu.addSeparator() def on_exit(self): self.modules_manager.on_exit() + def _on_version_action(self): + if self.pype_info_widget is None: + self.pype_info_widget = PypeInfoWidget() + + self.pype_info_widget.show() + self.pype_info_widget.raise_() + self.pype_info_widget.activateWindow() + class SystemTrayIcon(QtWidgets.QSystemTrayIcon): """Tray widget. From 7c9df14fc33f4957e7ddac91f643e88cb5eb8953 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 16:06:40 +0100 Subject: [PATCH 11/28] changed window icon and title --- pype/tools/tray/pype_tray.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index 5870db9c49..8e6a351efd 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -18,6 +18,10 @@ class PypeInfoWidget(QtWidgets.QWidget): self.setStyleSheet(style.load_stylesheet()) + icon = QtGui.QIcon(resources.pype_icon_filepath()) + self.setWindowIcon(icon) + self.setWindowTitle("Pype info") + main_layout = QtWidgets.QFormLayout(self) if getattr(sys, "frozen", False): From 409504927211bafa179de6140a23e922a673d4fa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 16:13:57 +0100 Subject: [PATCH 12/28] change label alignment --- pype/tools/tray/pype_tray.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index 8e6a351efd..b6ee033484 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -23,7 +23,7 @@ class PypeInfoWidget(QtWidgets.QWidget): self.setWindowTitle("Pype info") main_layout = QtWidgets.QFormLayout(self) - + main_layout.setLabelAlignment(QtCore.Qt.AlignRight) if getattr(sys, "frozen", False): version_end = "build" else: From a39f9d74c3909ec1f784fb86bd6fd767943b3827 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 18:12:41 +0100 Subject: [PATCH 13/28] moved pype info widget to separate file --- pype/tools/tray/pype_info_widget.py | 77 +++++++++++++++++++++++++++++ pype/tools/tray/pype_tray.py | 52 +------------------ 2 files changed, 79 insertions(+), 50 deletions(-) create mode 100644 pype/tools/tray/pype_info_widget.py diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py new file mode 100644 index 0000000000..7c961687f1 --- /dev/null +++ b/pype/tools/tray/pype_info_widget.py @@ -0,0 +1,77 @@ +import os +import sys + +from avalon import style +from Qt import QtCore, QtGui, QtWidgets +from pype.api import Logger, resources +import pype.version + + +class PypeInfoWidget(QtWidgets.QWidget): + not_allowed = "N/A" + + def __init__(self, parent=None): + super(PypeInfoWidget, self).__init__(parent) + + self.setStyleSheet(style.load_stylesheet()) + + icon = QtGui.QIcon(resources.pype_icon_filepath()) + self.setWindowIcon(icon) + self.setWindowTitle("Pype info") + + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.addWidget(self._create_pype_info_widget()) + + def _create_pype_info_widget(self): + """Create widget with information about pype application.""" + pype_root = os.environ["PYPE_ROOT"] + if getattr(sys, "frozen", False): + version_end = "build" + executable_path = sys.executable + else: + version_end = "code" + executable_path = os.path.join(pype_root, "start.py") + version_value = "{} ({})".format( + pype.version.__version__, version_end + ) + + lable_value = [ + # Pype version + ("Pype version:", version_value), + ("Pype executable:", executable_path), + ("Pype location:", pype_root), + + # Mongo URL + ("Pype Mongo URL:", os.environ.get("PYPE_MONGO")) + ] + + info_widget = QtWidgets.QWidget(self) + info_layout = QtWidgets.QGridLayout(info_widget) + + title_label = QtWidgets.QLabel(info_widget) + title_label.setText("Application information") + title_label.setStyleSheet("font-weight: bold;") + info_layout.addWidget(title_label, 0, 0, 1, 2) + + for label, value in lable_value: + row = info_layout.rowCount() + info_layout.addWidget( + QtWidgets.QLabel(label), row, 0, 1, 1 + ) + value_label = QtWidgets.QLabel(value or self.not_allowed) + info_layout.addWidget( + value_label, row, 1, 1, 1 + ) + return info_widget + + def showEvent(self, event): + """Center widget to center of desktop on show.""" + result = super(PypeInfoWidget, self).showEvent(event) + screen_center = ( + QtWidgets.QApplication.desktop().availableGeometry(self).center() + ) + self.move( + screen_center.x() - (self.width() / 2), + screen_center.y() - (self.height() / 2) + ) + return result diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index b6ee033484..2d37c04136 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -3,60 +3,12 @@ import sys import platform from avalon import style -from Qt import QtCore, QtGui, QtWidgets, QtSvg +from Qt import QtCore, QtGui, QtWidgets from pype.api import Logger, resources from pype.modules import TrayModulesManager, ITrayService from pype.settings.lib import get_system_settings import pype.version - - -class PypeInfoWidget(QtWidgets.QWidget): - not_allowed = "N/A" - - def __init__(self, parent=None): - super(PypeInfoWidget, self).__init__(parent) - - self.setStyleSheet(style.load_stylesheet()) - - icon = QtGui.QIcon(resources.pype_icon_filepath()) - self.setWindowIcon(icon) - self.setWindowTitle("Pype info") - - main_layout = QtWidgets.QFormLayout(self) - main_layout.setLabelAlignment(QtCore.Qt.AlignRight) - if getattr(sys, "frozen", False): - version_end = "build" - else: - version_end = "code" - version_value = "{} ({})".format( - pype.version.__version__, version_end - ) - - lable_value = [ - # Pype version - ("Pype version:", version_value), - ("Pype location:", os.environ.get("PYPE_ROOT")), - - # Mongo URL - ("Pype Mongo URL:", os.environ.get("PYPE_MONGO")) - ] - - for label, value in lable_value: - main_layout.addRow( - label, - QtWidgets.QLabel(value or self.not_allowed) - ) - - def showEvent(self, event): - result = super(PypeInfoWidget, self).showEvent(event) - screen_center = ( - QtWidgets.QApplication.desktop().availableGeometry(self).center() - ) - self.move( - screen_center.x() - (self.width() / 2), - screen_center.y() - (self.height() / 2) - ) - return result +from .pype_info_widget import PypeInfoWidget class TrayManager: From bc4f46cf0d8496774bc7dd5b5dbe2356d6775a54 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 5 Mar 2021 19:11:57 +0100 Subject: [PATCH 14/28] added environments view --- pype/tools/tray/pype_info_widget.py | 85 ++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index 7c961687f1..d48dcb0f9c 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -1,12 +1,61 @@ import os import sys +import json +import collections from avalon import style from Qt import QtCore, QtGui, QtWidgets -from pype.api import Logger, resources +from pype.api import resources import pype.version +class EnvironmentsView(QtWidgets.QTreeView): + def __init__(self, model, parent=None): + super(EnvironmentsView, self).__init__(parent) + self.setModel(model) + self.setIndentation(0) + self.header().setSectionResizeMode( + 0, QtWidgets.QHeaderView.ResizeToContents + ) + self.setSelectionMode(QtWidgets.QTreeView.MultiSelection) + + def get_all_as_dict(self): + pass + + def get_selection_as_dict(self): + indexes = self.selectionModel().selectedIndexes() + mapping = collections.defaultdict(dict) + for index in indexes: + row = index.row() + value = index.data(QtCore.Qt.DisplayRole) + if index.column() == 0: + key = "key" + else: + key = "value" + mapping[row][key] = value + result = {} + for item in mapping.values(): + result[item["key"]] = item["value"] + return result + + def keyPressEvent(self, event): + if ( + event.type() == QtGui.QKeyEvent.KeyPress + and event.matches(QtGui.QKeySequence.Copy) + ): + selected_dict = self.get_selection_as_dict() + selected_str = json.dumps(selected_dict, indent=4) + + mime_data = QtCore.QMimeData() + mime_data.setText(selected_str) + QtWidgets.QApplication.instance().clipboard().setMimeData( + mime_data + ) + event.accept() + else: + return super(EnvironmentsView, self).keyPressEvent(event) + + class PypeInfoWidget(QtWidgets.QWidget): not_allowed = "N/A" @@ -21,6 +70,34 @@ class PypeInfoWidget(QtWidgets.QWidget): main_layout = QtWidgets.QVBoxLayout(self) main_layout.addWidget(self._create_pype_info_widget()) + main_layout.addWidget(self._create_environ_widget()) + + def _create_environ_widget(self): + env_widget = QtWidgets.QWidget(self) + + env_label_widget = QtWidgets.QLabel("Environments", env_widget) + env_label_widget.setStyleSheet("font-weight: bold;") + + env_model = QtGui.QStandardItemModel() + + env = os.environ.copy() + keys = [] + values = [] + for key in sorted(env.keys()): + keys.append(QtGui.QStandardItem(key)) + values.append(QtGui.QStandardItem(env[key])) + + env_model.appendColumn(keys) + env_model.appendColumn(values) + env_model.setHorizontalHeaderLabels(["Key", "Value"]) + + env_view = EnvironmentsView(env_model, env_widget) + + env_layout = QtWidgets.QVBoxLayout(env_widget) + env_layout.addWidget(env_label_widget) + env_layout.addWidget(env_view) + + return env_widget def _create_pype_info_widget(self): """Create widget with information about pype application.""" @@ -47,6 +124,9 @@ class PypeInfoWidget(QtWidgets.QWidget): info_widget = QtWidgets.QWidget(self) info_layout = QtWidgets.QGridLayout(info_widget) + # Add spacer to 3rd column + info_layout.addWidget(QtWidgets.QWidget(info_widget), 0, 2) + info_layout.setColumnStretch(2, 1) title_label = QtWidgets.QLabel(info_widget) title_label.setText("Application information") @@ -59,6 +139,9 @@ class PypeInfoWidget(QtWidgets.QWidget): QtWidgets.QLabel(label), row, 0, 1, 1 ) value_label = QtWidgets.QLabel(value or self.not_allowed) + value_label.setTextInteractionFlags( + QtCore.Qt.TextSelectableByMouse + ) info_layout.addWidget( value_label, row, 1, 1, 1 ) From 7c1118c31af4c33bc31fb76af809675139b64b21 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 8 Mar 2021 10:40:46 +0100 Subject: [PATCH 15/28] added local settings view --- pype/tools/tray/pype_info_widget.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index d48dcb0f9c..0a105ede9f 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -7,6 +7,7 @@ from avalon import style from Qt import QtCore, QtGui, QtWidgets from pype.api import resources import pype.version +from pype.settings.lib import get_local_settings class EnvironmentsView(QtWidgets.QTreeView): @@ -69,8 +70,29 @@ class PypeInfoWidget(QtWidgets.QWidget): self.setWindowTitle("Pype info") main_layout = QtWidgets.QVBoxLayout(self) - main_layout.addWidget(self._create_pype_info_widget()) - main_layout.addWidget(self._create_environ_widget()) + main_layout.addWidget(self._create_pype_info_widget(), 0) + main_layout.addWidget(self._create_local_settings_widget(), 0) + main_layout.addWidget(self._create_environ_widget(), 1) + + def _create_local_settings_widget(self): + local_settings = get_local_settings() + + local_settings_widget = QtWidgets.QWidget(self) + + label_widget = QtWidgets.QLabel( + "Local settings", local_settings_widget + ) + label_widget.setStyleSheet("font-weight: bold;") + settings_input = QtWidgets.QPlainTextEdit(local_settings_widget) + settings_input.setReadOnly(True) + settings_input.setMinimumHeight(20) + settings_input.setPlainText(json.dumps(local_settings, indent=4)) + + local_settings_layout = QtWidgets.QVBoxLayout(local_settings_widget) + local_settings_layout.addWidget(label_widget) + local_settings_layout.addWidget(settings_input) + + return local_settings_widget def _create_environ_widget(self): env_widget = QtWidgets.QWidget(self) From 0f02db0997acef1935c070bc517f8728f59982e0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 8 Mar 2021 11:42:45 +0100 Subject: [PATCH 16/28] removed minimum height --- pype/tools/tray/pype_info_widget.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index 0a105ede9f..bd9bc8d3ee 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -85,7 +85,6 @@ class PypeInfoWidget(QtWidgets.QWidget): label_widget.setStyleSheet("font-weight: bold;") settings_input = QtWidgets.QPlainTextEdit(local_settings_widget) settings_input.setReadOnly(True) - settings_input.setMinimumHeight(20) settings_input.setPlainText(json.dumps(local_settings, indent=4)) local_settings_layout = QtWidgets.QVBoxLayout(local_settings_widget) From 4ed74637b2568519dde90e423a395789695804f5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 8 Mar 2021 11:55:40 +0100 Subject: [PATCH 17/28] envs and local settings are collapsible --- pype/tools/tray/pype_info_widget.py | 102 ++++++++++++++++++++++++---- 1 file changed, 87 insertions(+), 15 deletions(-) diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index bd9bc8d3ee..b958aa637b 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -57,6 +57,88 @@ class EnvironmentsView(QtWidgets.QTreeView): return super(EnvironmentsView, self).keyPressEvent(event) +class ClickableWidget(QtWidgets.QWidget): + clicked = QtCore.Signal() + + def mouseReleaseEvent(self, event): + if event.button() == QtCore.Qt.LeftButton: + self.clicked.emit() + super(ClickableWidget, self).mouseReleaseEvent(event) + + +class CollapsibleWidget(QtWidgets.QWidget): + def __init__(self, label, parent): + super(CollapsibleWidget, self).__init__(parent) + + self.content_widget = None + + top_part = ClickableWidget(parent=self) + + button_size = QtCore.QSize(5, 5) + button_toggle = QtWidgets.QToolButton(parent=top_part) + button_toggle.setIconSize(button_size) + button_toggle.setArrowType(QtCore.Qt.RightArrow) + button_toggle.setCheckable(True) + button_toggle.setChecked(False) + + label_widget = QtWidgets.QLabel(label, parent=top_part) + spacer_widget = QtWidgets.QWidget(top_part) + + top_part_layout = QtWidgets.QHBoxLayout(top_part) + top_part_layout.setContentsMargins(0, 0, 0, 0) + top_part_layout.addWidget(button_toggle) + top_part_layout.addWidget(label_widget) + top_part_layout.addWidget(spacer_widget, 1) + + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) + + self.button_toggle = button_toggle + self.label_widget = label_widget + + top_part.clicked.connect(self._top_part_clicked) + self.button_toggle.clicked.connect(self._btn_clicked) + + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + main_layout.setAlignment(QtCore.Qt.AlignTop) + main_layout.addWidget(top_part) + + self.main_layout = main_layout + + def set_content_widget(self, content_widget): + content_widget.setVisible(self.button_toggle.isChecked()) + self.main_layout.addWidget(content_widget) + self.content_widget = content_widget + + def _btn_clicked(self): + self.toggle_content(self.button_toggle.isChecked()) + + def _top_part_clicked(self): + self.toggle_content() + + def toggle_content(self, *args): + if len(args) > 0: + checked = args[0] + else: + checked = not self.button_toggle.isChecked() + arrow_type = QtCore.Qt.RightArrow + if checked: + arrow_type = QtCore.Qt.DownArrow + self.button_toggle.setChecked(checked) + self.button_toggle.setArrowType(arrow_type) + if self.content_widget: + self.content_widget.setVisible(checked) + self.parent().updateGeometry() + + def resizeEvent(self, event): + super(CollapsibleWidget, self).resizeEvent(event) + if self.content_widget: + self.content_widget.updateGeometry() + + class PypeInfoWidget(QtWidgets.QWidget): not_allowed = "N/A" @@ -70,6 +152,7 @@ class PypeInfoWidget(QtWidgets.QWidget): self.setWindowTitle("Pype info") main_layout = QtWidgets.QVBoxLayout(self) + main_layout.setAlignment(QtCore.Qt.AlignTop) main_layout.addWidget(self._create_pype_info_widget(), 0) main_layout.addWidget(self._create_local_settings_widget(), 0) main_layout.addWidget(self._create_environ_widget(), 1) @@ -77,27 +160,18 @@ class PypeInfoWidget(QtWidgets.QWidget): def _create_local_settings_widget(self): local_settings = get_local_settings() - local_settings_widget = QtWidgets.QWidget(self) + local_settings_widget = CollapsibleWidget("Local settings", self) - label_widget = QtWidgets.QLabel( - "Local settings", local_settings_widget - ) - label_widget.setStyleSheet("font-weight: bold;") settings_input = QtWidgets.QPlainTextEdit(local_settings_widget) settings_input.setReadOnly(True) settings_input.setPlainText(json.dumps(local_settings, indent=4)) - local_settings_layout = QtWidgets.QVBoxLayout(local_settings_widget) - local_settings_layout.addWidget(label_widget) - local_settings_layout.addWidget(settings_input) + local_settings_widget.set_content_widget(settings_input) return local_settings_widget def _create_environ_widget(self): - env_widget = QtWidgets.QWidget(self) - - env_label_widget = QtWidgets.QLabel("Environments", env_widget) - env_label_widget.setStyleSheet("font-weight: bold;") + env_widget = CollapsibleWidget("Environments", self) env_model = QtGui.QStandardItemModel() @@ -114,9 +188,7 @@ class PypeInfoWidget(QtWidgets.QWidget): env_view = EnvironmentsView(env_model, env_widget) - env_layout = QtWidgets.QVBoxLayout(env_widget) - env_layout.addWidget(env_label_widget) - env_layout.addWidget(env_view) + env_widget.set_content_widget(env_view) return env_widget From b9e84d078f0dfc807fd929cb94fa14b496b7ded4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 8 Mar 2021 11:56:45 +0100 Subject: [PATCH 18/28] don't center widget --- pype/tools/tray/pype_info_widget.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index b958aa637b..7bce740305 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -239,15 +239,3 @@ class PypeInfoWidget(QtWidgets.QWidget): value_label, row, 1, 1, 1 ) return info_widget - - def showEvent(self, event): - """Center widget to center of desktop on show.""" - result = super(PypeInfoWidget, self).showEvent(event) - screen_center = ( - QtWidgets.QApplication.desktop().availableGeometry(self).center() - ) - self.move( - screen_center.x() - (self.width() / 2), - screen_center.y() - (self.height() / 2) - ) - return result From 17a499225fc11f07b80c23d24c684cb8e0a6d81a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 8 Mar 2021 12:00:29 +0100 Subject: [PATCH 19/28] minor modifications --- pype/tools/tray/pype_info_widget.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index 7bce740305..7915e20be1 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -85,7 +85,7 @@ class CollapsibleWidget(QtWidgets.QWidget): spacer_widget = QtWidgets.QWidget(top_part) top_part_layout = QtWidgets.QHBoxLayout(top_part) - top_part_layout.setContentsMargins(0, 0, 0, 0) + top_part_layout.setContentsMargins(0, 0, 0, 5) top_part_layout.addWidget(button_toggle) top_part_layout.addWidget(label_widget) top_part_layout.addWidget(spacer_widget, 1) @@ -154,9 +154,18 @@ class PypeInfoWidget(QtWidgets.QWidget): main_layout = QtWidgets.QVBoxLayout(self) main_layout.setAlignment(QtCore.Qt.AlignTop) main_layout.addWidget(self._create_pype_info_widget(), 0) + main_layout.addWidget(self._create_separator(), 0) main_layout.addWidget(self._create_local_settings_widget(), 0) + main_layout.addWidget(self._create_separator(), 0) main_layout.addWidget(self._create_environ_widget(), 1) + def _create_separator(self): + separator_widget = QtWidgets.QWidget(self) + separator_widget.setStyleSheet("background: #222222;") + separator_widget.setMinimumHeight(2) + separator_widget.setMaximumHeight(2) + return separator_widget + def _create_local_settings_widget(self): local_settings = get_local_settings() From 7ad4567534b815cd6a1d06a8dbc3ff864926d5d5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 8 Mar 2021 13:20:45 +0100 Subject: [PATCH 20/28] changed selection mode --- pype/tools/tray/pype_info_widget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index 7915e20be1..0aa618c42b 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -18,7 +18,7 @@ class EnvironmentsView(QtWidgets.QTreeView): self.header().setSectionResizeMode( 0, QtWidgets.QHeaderView.ResizeToContents ) - self.setSelectionMode(QtWidgets.QTreeView.MultiSelection) + self.setSelectionMode(QtWidgets.QTreeView.ExtendedSelection) def get_all_as_dict(self): pass From 44e03989d452d333e164229dbd133f9e81d547bd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 8 Mar 2021 20:01:07 +0100 Subject: [PATCH 21/28] added pype info getters to pype.lib --- pype/lib/pype_info.py | 73 +++++++++++++++++++++++++++++ pype/tools/tray/pype_info_widget.py | 29 +++++------- 2 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 pype/lib/pype_info.py diff --git a/pype/lib/pype_info.py b/pype/lib/pype_info.py new file mode 100644 index 0000000000..8db43a654f --- /dev/null +++ b/pype/lib/pype_info.py @@ -0,0 +1,73 @@ +import os +import sys +import json +import datetime +import platform +import getpass +import socket + +import pype.version +from pype.settings.lib import get_local_settings +from .execute import get_pype_execute_args +from .local_settings import get_local_site_id + + +def get_pype_version(): + return pype.version.__version__ + + +def get_pype_info(): + executable_args = get_pype_execute_args() + if len(executable_args) == 1: + version_type = "build" + else: + version_type = "code" + + return { + "version": get_pype_version(), + "version_type": version_type, + "executable": executable_args[-1], + "pype_root": os.environ["PYPE_ROOT"], + "mongo_url": os.environ["PYPE_MONGO"] + } + + +def get_workstation_info(): + host_name = socket.gethostname() + try: + host_ip = socket.gethostbyname(host_name) + except socket.gaierror: + host_ip = "127.0.0.1" + + return { + "hostname": host_name, + "hostip": host_ip, + "username": getpass.getuser(), + "system_name": platform.system(), + "local_id": get_local_site_id() + } + + +def get_all_data(): + return { + "pype": get_pype_info(), + "workstation": get_workstation_info(), + "env": os.environ.copy(), + "local_settings": get_local_settings() + } + + +def extract_pype_info_to_file(dirpath): + filename = "{}_{}_{}.json".format( + get_pype_version(), + get_local_site_id(), + datetime.datetime.now().strftime("%y%m%d%H%M%S") + ) + filepath = os.path.join(dirpath, filename) + data = get_all_data() + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + with open(filepath, "w") as file_stream: + json.dump(data, file_stream) + return filepath diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index 0aa618c42b..d08cd404cd 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -8,6 +8,11 @@ from Qt import QtCore, QtGui, QtWidgets from pype.api import resources import pype.version from pype.settings.lib import get_local_settings +from pype.lib.pype_info import ( + get_pype_info, + get_workstation_info, + extract_pype_info_to_file +) class EnvironmentsView(QtWidgets.QTreeView): @@ -20,9 +25,6 @@ class EnvironmentsView(QtWidgets.QTreeView): ) self.setSelectionMode(QtWidgets.QTreeView.ExtendedSelection) - def get_all_as_dict(self): - pass - def get_selection_as_dict(self): indexes = self.selectionModel().selectedIndexes() mapping = collections.defaultdict(dict) @@ -203,25 +205,20 @@ class PypeInfoWidget(QtWidgets.QWidget): def _create_pype_info_widget(self): """Create widget with information about pype application.""" - pype_root = os.environ["PYPE_ROOT"] - if getattr(sys, "frozen", False): - version_end = "build" - executable_path = sys.executable - else: - version_end = "code" - executable_path = os.path.join(pype_root, "start.py") - version_value = "{} ({})".format( - pype.version.__version__, version_end - ) + pype_info = get_pype_info() + version_value = "{} ({})".format( + pype_info["version"], + pype_info["version_type"] + ) lable_value = [ # Pype version ("Pype version:", version_value), - ("Pype executable:", executable_path), - ("Pype location:", pype_root), + ("Pype executable:", pype_info["executable"]), + ("Pype location:", pype_info["pype_root"]), # Mongo URL - ("Pype Mongo URL:", os.environ.get("PYPE_MONGO")) + ("Pype Mongo URL:", pype_info["mongo_url"]) ] info_widget = QtWidgets.QWidget(self) From 9cc95a9ac36ddf31c1e6a36534f3f38a1f05aefe Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 8 Mar 2021 20:18:47 +0100 Subject: [PATCH 22/28] fixed environments editability --- pype/tools/tray/pype_info_widget.py | 45 +++++++++++++++++++---------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index d08cd404cd..6e638616e5 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -15,11 +15,39 @@ from pype.lib.pype_info import ( ) +class EnvironmentValueDelegate(QtWidgets.QStyledItemDelegate): + def createEditor(self, parent, option, index): + edit_widget = QtWidgets.QLineEdit(parent) + edit_widget.setReadOnly(True) + return edit_widget + + class EnvironmentsView(QtWidgets.QTreeView): - def __init__(self, model, parent=None): + def __init__(self, parent=None): super(EnvironmentsView, self).__init__(parent) + + model = QtGui.QStandardItemModel() + + env = os.environ.copy() + keys = [] + values = [] + for key in sorted(env.keys()): + key_item = QtGui.QStandardItem(key) + key_item.setFlags( + QtCore.Qt.ItemIsSelectable + | QtCore.Qt.ItemIsEnabled + ) + keys.append(key_item) + values.append(QtGui.QStandardItem(env[key])) + + model.appendColumn(keys) + model.appendColumn(values) + model.setHorizontalHeaderLabels(["Key", "Value"]) + self.setModel(model) self.setIndentation(0) + delegate = EnvironmentValueDelegate(self) + self.setItemDelegateForColumn(1, delegate) self.header().setSectionResizeMode( 0, QtWidgets.QHeaderView.ResizeToContents ) @@ -184,20 +212,7 @@ class PypeInfoWidget(QtWidgets.QWidget): def _create_environ_widget(self): env_widget = CollapsibleWidget("Environments", self) - env_model = QtGui.QStandardItemModel() - - env = os.environ.copy() - keys = [] - values = [] - for key in sorted(env.keys()): - keys.append(QtGui.QStandardItem(key)) - values.append(QtGui.QStandardItem(env[key])) - - env_model.appendColumn(keys) - env_model.appendColumn(values) - env_model.setHorizontalHeaderLabels(["Key", "Value"]) - - env_view = EnvironmentsView(env_model, env_widget) + env_view = EnvironmentsView(env_widget) env_widget.set_content_widget(env_view) From 276a7df3157c172176f6938d84e5e6177502813d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 9 Mar 2021 09:45:33 +0100 Subject: [PATCH 23/28] added workstation info --- pype/tools/tray/pype_info_widget.py | 91 ++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index 6e638616e5..f3ad668429 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -170,7 +170,7 @@ class CollapsibleWidget(QtWidgets.QWidget): class PypeInfoWidget(QtWidgets.QWidget): - not_allowed = "N/A" + not_applicable = "N/A" def __init__(self, parent=None): super(PypeInfoWidget, self).__init__(parent) @@ -185,6 +185,8 @@ class PypeInfoWidget(QtWidgets.QWidget): main_layout.setAlignment(QtCore.Qt.AlignTop) main_layout.addWidget(self._create_pype_info_widget(), 0) main_layout.addWidget(self._create_separator(), 0) + main_layout.addWidget(self._create_workstation_widget(), 0) + main_layout.addWidget(self._create_separator(), 0) main_layout.addWidget(self._create_local_settings_widget(), 0) main_layout.addWidget(self._create_separator(), 0) main_layout.addWidget(self._create_environ_widget(), 1) @@ -196,6 +198,56 @@ class PypeInfoWidget(QtWidgets.QWidget): separator_widget.setMaximumHeight(2) return separator_widget + def _create_workstation_widget(self): + key_label_mapping = { + "system_name": "System:", + "local_id": "Local ID:", + "username": "Username:", + "hostname": "Hostname:", + "hostip": "Host IP:" + } + keys_order = [ + "system_name", + "local_id", + "username", + "hostname", + "hostip" + ] + workstation_info = get_workstation_info() + for key in workstation_info.keys(): + if key not in keys_order: + keys_order.append(key) + + wokstation_info_widget = CollapsibleWidget("Workstation info", self) + + info_widget = QtWidgets.QWidget(self) + info_layout = QtWidgets.QGridLayout(info_widget) + # Add spacer to 3rd column + info_layout.addWidget(QtWidgets.QWidget(info_widget), 0, 2) + info_layout.setColumnStretch(2, 1) + + for key in keys_order: + if key not in workstation_info: + continue + + label = key_label_mapping.get(key, key) + value = workstation_info[key] + row = info_layout.rowCount() + info_layout.addWidget( + QtWidgets.QLabel(label), row, 0, 1, 1 + ) + value_label = QtWidgets.QLabel(value) + value_label.setTextInteractionFlags( + QtCore.Qt.TextSelectableByMouse + ) + info_layout.addWidget( + value_label, row, 1, 1, 1 + ) + + wokstation_info_widget.set_content_widget(info_widget) + + return wokstation_info_widget + def _create_local_settings_widget(self): local_settings = get_local_settings() @@ -221,21 +273,28 @@ class PypeInfoWidget(QtWidgets.QWidget): def _create_pype_info_widget(self): """Create widget with information about pype application.""" + # Get pype info data pype_info = get_pype_info() + # Modify version key/values version_value = "{} ({})".format( - pype_info["version"], - pype_info["version_type"] + pype_info.pop("version", self.not_applicable), + pype_info.pop("version_type", self.not_applicable) ) - lable_value = [ - # Pype version - ("Pype version:", version_value), - ("Pype executable:", pype_info["executable"]), - ("Pype location:", pype_info["pype_root"]), - - # Mongo URL - ("Pype Mongo URL:", pype_info["mongo_url"]) - ] + pype_info["version_value"] = version_value + # Prepare lable mapping + key_label_mapping = { + "version_value": "Pype version:", + "executable": "Pype executable:", + "pype_root": "Pype location:", + "mongo_url": "Pype Mongo URL:" + } + # Prepare keys order + keys_order = ["version_value", "executable", "pype_root", "mongo_url"] + for key in pype_info.keys(): + if key not in keys_order: + keys_order.append(key) + # Create widgets info_widget = QtWidgets.QWidget(self) info_layout = QtWidgets.QGridLayout(info_widget) # Add spacer to 3rd column @@ -247,12 +306,16 @@ class PypeInfoWidget(QtWidgets.QWidget): title_label.setStyleSheet("font-weight: bold;") info_layout.addWidget(title_label, 0, 0, 1, 2) - for label, value in lable_value: + for key in keys_order: + if key not in pype_info: + continue + value = pype_info[key] + label = key_label_mapping.get(key, key) row = info_layout.rowCount() info_layout.addWidget( QtWidgets.QLabel(label), row, 0, 1, 1 ) - value_label = QtWidgets.QLabel(value or self.not_allowed) + value_label = QtWidgets.QLabel(value) value_label.setTextInteractionFlags( QtCore.Qt.TextSelectableByMouse ) From 841c1b3918c9a7cbef8145eddb2ee1171cb26abf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 9 Mar 2021 10:14:54 +0100 Subject: [PATCH 24/28] added buttons to copy or extract information --- pype/lib/pype_info.py | 2 +- pype/tools/tray/pype_info_widget.py | 53 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/pype/lib/pype_info.py b/pype/lib/pype_info.py index 8db43a654f..b52fc71635 100644 --- a/pype/lib/pype_info.py +++ b/pype/lib/pype_info.py @@ -69,5 +69,5 @@ def extract_pype_info_to_file(dirpath): os.makedirs(dirpath) with open(filepath, "w") as file_stream: - json.dump(data, file_stream) + json.dump(data, file_stream, indent=4) return filepath diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index f3ad668429..691bc12db5 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -9,6 +9,7 @@ from pype.api import resources import pype.version from pype.settings.lib import get_local_settings from pype.lib.pype_info import ( + get_all_data, get_pype_info, get_workstation_info, extract_pype_info_to_file @@ -190,6 +191,58 @@ class PypeInfoWidget(QtWidgets.QWidget): main_layout.addWidget(self._create_local_settings_widget(), 0) main_layout.addWidget(self._create_separator(), 0) main_layout.addWidget(self._create_environ_widget(), 1) + main_layout.addWidget(self._create_btns_section(), 0) + + def _create_btns_section(self): + btns_widget = QtWidgets.QWidget(self) + btns_layout = QtWidgets.QHBoxLayout(btns_widget) + btns_layout.setContentsMargins(0, 0, 0, 0) + + copy_to_clipboard_btn = QtWidgets.QPushButton( + "Copy to clipboard", btns_widget + ) + export_to_file_btn = QtWidgets.QPushButton( + "Export", btns_widget + ) + btns_layout.addWidget(QtWidgets.QWidget(btns_widget)) + btns_layout.addWidget(copy_to_clipboard_btn) + btns_layout.addWidget(export_to_file_btn) + + copy_to_clipboard_btn.clicked.connect(self._on_copy_to_clipboard) + export_to_file_btn.clicked.connect(self._on_export_to_file) + + return btns_widget + + def _on_export_to_file(self): + dst_dir_path = QtWidgets.QFileDialog.getExistingDirectory( + self, + "Choose directory", + os.path.expanduser("~"), + QtWidgets.QFileDialog.ShowDirsOnly + ) + if not dst_dir_path or not os.path.exists(dst_dir_path): + return + + filepath = extract_pype_info_to_file(dst_dir_path) + title = "Extraction done" + message = "Extraction is done. Destination filepath is \"{}\"".format( + filepath.replace("\\", "/") + ) + dialog = QtWidgets.QMessageBox(self) + dialog.setIcon(QtWidgets.QMessageBox.NoIcon) + dialog.setWindowTitle(title) + dialog.setText(message) + dialog.exec_() + + def _on_copy_to_clipboard(self): + all_data = get_all_data() + all_data_str = json.dumps(all_data, indent=4) + + mime_data = QtCore.QMimeData() + mime_data.setText(all_data_str) + QtWidgets.QApplication.instance().clipboard().setMimeData( + mime_data + ) def _create_separator(self): separator_widget = QtWidgets.QWidget(self) From 24c49a7cc3e8e4101c84e64d05cf0918a6318899 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 9 Mar 2021 10:21:44 +0100 Subject: [PATCH 25/28] added some docstrings --- pype/lib/pype_info.py | 19 +++++++++++++++++-- pype/tools/tray/pype_info_widget.py | 4 ++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/pype/lib/pype_info.py b/pype/lib/pype_info.py index b52fc71635..4c1bbccba0 100644 --- a/pype/lib/pype_info.py +++ b/pype/lib/pype_info.py @@ -13,10 +13,12 @@ from .local_settings import get_local_site_id def get_pype_version(): + """Version of pype that is currently used.""" return pype.version.__version__ def get_pype_info(): + """Information about currently used Pype process.""" executable_args = get_pype_execute_args() if len(executable_args) == 1: version_type = "build" @@ -33,6 +35,7 @@ def get_pype_info(): def get_workstation_info(): + """Basic information about workstation.""" host_name = socket.gethostname() try: host_ip = socket.gethostbyname(host_name) @@ -48,7 +51,8 @@ def get_workstation_info(): } -def get_all_data(): +def get_all_current_info(): + """All information about current process in one dictionary.""" return { "pype": get_pype_info(), "workstation": get_workstation_info(), @@ -58,13 +62,24 @@ def get_all_data(): def extract_pype_info_to_file(dirpath): + """Extract all current info to a file. + + It is possible to define onpy directory path. Filename is concatenated with + pype version, workstation site id and timestamp. + + Args: + dirpath (str): Path to directory where file will be stored. + + Returns: + filepath (str): Full path to file where data were extracted. + """ filename = "{}_{}_{}.json".format( get_pype_version(), get_local_site_id(), datetime.datetime.now().strftime("%y%m%d%H%M%S") ) filepath = os.path.join(dirpath, filename) - data = get_all_data() + data = get_all_current_info() if not os.path.exists(dirpath): os.makedirs(dirpath) diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index 691bc12db5..fcd820b0b2 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -9,7 +9,7 @@ from pype.api import resources import pype.version from pype.settings.lib import get_local_settings from pype.lib.pype_info import ( - get_all_data, + get_all_current_info, get_pype_info, get_workstation_info, extract_pype_info_to_file @@ -235,7 +235,7 @@ class PypeInfoWidget(QtWidgets.QWidget): dialog.exec_() def _on_copy_to_clipboard(self): - all_data = get_all_data() + all_data = get_all_current_info() all_data_str = json.dumps(all_data, indent=4) mime_data = QtCore.QMimeData() From 75fd04ca2b36cab4f183c80d6f39b1c0d3c09469 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 9 Mar 2021 10:30:05 +0100 Subject: [PATCH 26/28] fixed buttons expandings --- pype/tools/tray/pype_info_widget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index fcd820b0b2..1a3fba0277 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -204,7 +204,7 @@ class PypeInfoWidget(QtWidgets.QWidget): export_to_file_btn = QtWidgets.QPushButton( "Export", btns_widget ) - btns_layout.addWidget(QtWidgets.QWidget(btns_widget)) + btns_layout.addWidget(QtWidgets.QWidget(btns_widget), 1) btns_layout.addWidget(copy_to_clipboard_btn) btns_layout.addWidget(export_to_file_btn) From aa62be3662f2c0bcec8346b839dfa6aaeaa279aa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 9 Mar 2021 10:54:50 +0100 Subject: [PATCH 27/28] added ability to show separated paths --- pype/tools/tray/pype_info_widget.py | 43 +++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index 1a3fba0277..dd59bc03f2 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -1,5 +1,4 @@ import os -import sys import json import collections @@ -15,6 +14,8 @@ from pype.lib.pype_info import ( extract_pype_info_to_file ) +IS_MAIN_ROLE = QtCore.Qt.UserRole + class EnvironmentValueDelegate(QtWidgets.QStyledItemDelegate): def createEditor(self, parent, option, index): @@ -38,17 +39,36 @@ class EnvironmentsView(QtWidgets.QTreeView): QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) + key_item.setData(True, IS_MAIN_ROLE) keys.append(key_item) - values.append(QtGui.QStandardItem(env[key])) + + value = env[key] + value_item = QtGui.QStandardItem(value) + value_item.setData(True, IS_MAIN_ROLE) + values.append(value_item) + + value_parts = [ + part + for part in value.split(os.pathsep) if part + ] + if len(value_parts) < 2: + continue + + sub_parts = [] + for part_value in value_parts: + part_item = QtGui.QStandardItem(part_value) + part_item.setData(False, IS_MAIN_ROLE) + sub_parts.append(part_item) + key_item.appendRows(sub_parts) model.appendColumn(keys) model.appendColumn(values) model.setHorizontalHeaderLabels(["Key", "Value"]) self.setModel(model) - self.setIndentation(0) + # self.setIndentation(0) delegate = EnvironmentValueDelegate(self) - self.setItemDelegateForColumn(1, delegate) + self.setItemDelegate(delegate) self.header().setSectionResizeMode( 0, QtWidgets.QHeaderView.ResizeToContents ) @@ -56,17 +76,22 @@ class EnvironmentsView(QtWidgets.QTreeView): def get_selection_as_dict(self): indexes = self.selectionModel().selectedIndexes() - mapping = collections.defaultdict(dict) + + main_mapping = collections.defaultdict(dict) for index in indexes: + is_main = index.data(IS_MAIN_ROLE) + if not is_main: + continue row = index.row() value = index.data(QtCore.Qt.DisplayRole) if index.column() == 0: key = "key" else: key = "value" - mapping[row][key] = value + main_mapping[row][key] = value + result = {} - for item in mapping.values(): + for item in main_mapping.values(): result[item["key"]] = item["value"] return result @@ -75,8 +100,8 @@ class EnvironmentsView(QtWidgets.QTreeView): event.type() == QtGui.QKeyEvent.KeyPress and event.matches(QtGui.QKeySequence.Copy) ): - selected_dict = self.get_selection_as_dict() - selected_str = json.dumps(selected_dict, indent=4) + selected_data = self.get_selection_as_dict() + selected_str = json.dumps(selected_data, indent=4) mime_data = QtCore.QMimeData() mime_data.setText(selected_str) From 208d8301ed0df2a31848403e25731276baf0a449 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 9 Mar 2021 10:57:31 +0100 Subject: [PATCH 28/28] imports cleanup --- pype/lib/pype_info.py | 1 - pype/tools/tray/pype_info_widget.py | 1 - 2 files changed, 2 deletions(-) diff --git a/pype/lib/pype_info.py b/pype/lib/pype_info.py index 4c1bbccba0..cbcc5811a0 100644 --- a/pype/lib/pype_info.py +++ b/pype/lib/pype_info.py @@ -1,5 +1,4 @@ import os -import sys import json import datetime import platform diff --git a/pype/tools/tray/pype_info_widget.py b/pype/tools/tray/pype_info_widget.py index dd59bc03f2..a4c52eb1d0 100644 --- a/pype/tools/tray/pype_info_widget.py +++ b/pype/tools/tray/pype_info_widget.py @@ -5,7 +5,6 @@ import collections from avalon import style from Qt import QtCore, QtGui, QtWidgets from pype.api import resources -import pype.version from pype.settings.lib import get_local_settings from pype.lib.pype_info import ( get_all_current_info,