diff --git a/ibridgesgui/__main__.py b/ibridgesgui/__main__.py index a215d57d..0e4a9f96 100755 --- a/ibridgesgui/__main__.py +++ b/ibridgesgui/__main__.py @@ -5,9 +5,9 @@ import sys from pathlib import Path -import PyQt6.QtGui -import PyQt6.QtWidgets -import PyQt6.uic +import PySide6.QtGui +import PySide6.QtWidgets +import PySide6.QtUiTools import setproctitle from ibridgesgui.browser import Browser @@ -18,6 +18,7 @@ from ibridgesgui.popup_widgets import CheckConfig from ibridgesgui.search import Search from ibridgesgui.sync import Sync +from ibridgesgui.gui_utils import UI_FILE_DIR, load_ui from ibridgesgui.ui_files.MainMenu import Ui_MainWindow from ibridgesgui.welcome import Welcome @@ -30,16 +31,19 @@ THIS_APPLICATION = "ibridges-gui" # Application globals -app = PyQt6.QtWidgets.QApplication(sys.argv) +app = PySide6.QtWidgets.QApplication(sys.argv) -class MainMenu(PyQt6.QtWidgets.QMainWindow, Ui_MainWindow): +class MainMenu(PySide6.QtWidgets.QMainWindow, Ui_MainWindow): """Set up the GUI Main Menu.""" def __init__(self, app_name): """Initialise the main window.""" super().__init__() - super().setupUi(self) + if getattr(sys, "frozen", False) or ("__compiled__" in globals()): + super().setupUi(self) + else: + load_ui(UI_FILE_DIR / "MainMenu.ui", self) app.aboutToQuit.connect(self.close_event) @@ -101,14 +105,14 @@ def connect(self): def exit(self): """Quit program.""" quit_msg = "Are you sure you want to exit the program?" - reply = PyQt6.QtWidgets.QMessageBox.question( + reply = PySide6.QtWidgets.QMessageBox.question( self, "Message", quit_msg, - PyQt6.QtWidgets.QMessageBox.StandardButton.Yes, - PyQt6.QtWidgets.QMessageBox.StandardButton.No, + PySide6.QtWidgets.QMessageBox.StandardButton.Yes, + PySide6.QtWidgets.QMessageBox.StandardButton.No, ) - if reply == PyQt6.QtWidgets.QMessageBox.StandardButton.Yes: + if reply == PySide6.QtWidgets.QMessageBox.StandardButton.Yes: self.disconnect() sys.exit() else: @@ -182,7 +186,7 @@ def main(): set_log_level("debug") init_logger(THIS_APPLICATION, "debug") ensure_irods_location() - main_widget = PyQt6.QtWidgets.QStackedWidget() + main_widget = PySide6.QtWidgets.QStackedWidget() main_app = MainMenu(THIS_APPLICATION) main_widget.addWidget(main_app) main_widget.show() diff --git a/ibridgesgui/browser.py b/ibridgesgui/browser.py index 56c085da..8463b0e0 100644 --- a/ibridgesgui/browser.py +++ b/ibridgesgui/browser.py @@ -5,10 +5,9 @@ from typing import Union import irods.exception -import PyQt6.QtCore -import PyQt6.QtGui -import PyQt6.QtWidgets -import PyQt6.uic +import PySide6.QtCore +import PySide6.QtGui +import PySide6.QtWidgets from ibridges import IrodsPath from ibridges.permissions import Permissions from ibridges.util import obj_replicas @@ -18,12 +17,13 @@ get_irods_item, populate_table, populate_textfield, + load_ui ) from ibridgesgui.popup_widgets import CreateCollection, DownloadData, Rename, UploadData from ibridgesgui.ui_files.tabBrowser import Ui_tabBrowser -class Browser(PyQt6.QtWidgets.QWidget, Ui_tabBrowser): +class Browser(PySide6.QtWidgets.QWidget, Ui_tabBrowser): """Browser view for iRODS session.""" def __init__(self, session, app_name: str): @@ -32,7 +32,7 @@ def __init__(self, session, app_name: str): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - PyQt6.uic.loadUi(UI_FILE_DIR / "tabBrowser.ui", self) + load_ui(UI_FILE_DIR / "tabBrowser.ui", self) self.logger = logging.getLogger(app_name) self.session = session @@ -166,14 +166,14 @@ def delete_data(self): item_name = self.browser_table.item(self.browser_table.currentRow(), 1).text() irods_path = IrodsPath(self.session, "/", *self.input_path.text().split("/"), item_name) quit_msg = f"Are you sure you want to delete {str(irods_path)}?" - reply = PyQt6.QtWidgets.QMessageBox.critical( + reply = PySide6.QtWidgets.QMessageBox.critical( self, "Message", quit_msg, - PyQt6.QtWidgets.QMessageBox.StandardButton.Yes, - PyQt6.QtWidgets.QMessageBox.StandardButton.No, + PySide6.QtWidgets.QMessageBox.StandardButton.Yes, + PySide6.QtWidgets.QMessageBox.StandardButton.No, ) - if reply == PyQt6.QtWidgets.QMessageBox.StandardButton.Yes: + if reply == PySide6.QtWidgets.QMessageBox.StandardButton.Yes: try: irods_path.remove() self.logger.info("Delete data %s", str(irods_path)) @@ -275,7 +275,7 @@ def delete_icat_meta(self): self.error_label.setText(repr(error)) # @PyQt6.QtCore.pyqtSlot(PyQt6.QtCore.QModelIndex) - def edit_metadata(self, index: PyQt6.QtCore.QModelIndex): + def edit_metadata(self, index: PySide6.QtCore.QModelIndex): """Load selected metadata info edit fields.""" self.error_label.clear() self.meta_key_field.clear() @@ -293,7 +293,7 @@ def edit_metadata(self, index: PyQt6.QtCore.QModelIndex): self.meta_units_field.setText(units) # @PyQt6.QtCore.pyqtSlot(PyQt6.QtCore.QModelIndex) - def edit_permission(self, index: PyQt6.QtCore.QModelIndex): + def edit_permission(self, index: PySide6.QtCore.QModelIndex): """Load selected acl into editing fields.""" self.error_label.clear() self.acl_user_field.clear() diff --git a/ibridgesgui/gui_utils.py b/ibridgesgui/gui_utils.py index 582d3084..e3c656fe 100644 --- a/ibridgesgui/gui_utils.py +++ b/ibridgesgui/gui_utils.py @@ -3,8 +3,11 @@ import pathlib from typing import Union +import os import irods -import PyQt6 +import PySide6.QtWidgets +import PySide6.QtUiTools +import PySide6.QtCore from ibridges import IrodsPath from ibridges.executor import Operations @@ -20,6 +23,33 @@ LOGO_DIR = files(__package__) / "icons" +class UiLoader(PySide6.QtUiTools.QUiLoader): + """UILoader to allow custom widgets""" + def __init__(self, base_instance): + PySide6.QtUiTools.QUiLoader.__init__(self, base_instance) + self.base_instance = base_instance + + def createWidget(self, class_name, parent=None, name=''): + if parent is None and self.base_instance: + return self.base_instance + else: + # create a new widget for child widgets + widget = PySide6.QtUiTools.QUiLoader.createWidget(self, class_name, parent, name) + if self.base_instance: + setattr(self.base_instance, name, widget) + return widget + + +def load_ui(ui_file, base_instance=None): + """load ui, as available in pyqt""" + ui_dir = os.path.dirname(ui_file) + os.chdir(ui_dir) + loader = UiLoader(base_instance) + widget = loader.load(ui_file) + PySide6.QtCore.QMetaObject.connectSlotsByName(widget) + return widget + + # Widget utils def populate_table(table_widget, rows: int, data_by_row: list): """Populate a table-like pyqt widget with data.""" @@ -28,7 +58,7 @@ def populate_table(table_widget, rows: int, data_by_row: list): for row, data in enumerate(data_by_row): for col, item in enumerate(data): - table_widget.setItem(row, col, PyQt6.QtWidgets.QTableWidgetItem(str(item))) + table_widget.setItem(row, col, PySide6.QtWidgets.QTableWidgetItem(str(item))) table_widget.resizeColumnsToContents() @@ -38,7 +68,7 @@ def append_table(table_widget, curr_len_table, data_by_row): for data in data_by_row: for col, item in enumerate(data): table_widget.setItem(curr_len_table, col, - PyQt6.QtWidgets.QTableWidgetItem(str(item))) + PySide6.QtWidgets.QTableWidgetItem(str(item))) curr_len_table+=1 table_widget.resizeColumnsToContents() diff --git a/ibridgesgui/info.py b/ibridgesgui/info.py index 7a7e1bac..beac1e0c 100644 --- a/ibridgesgui/info.py +++ b/ibridgesgui/info.py @@ -2,17 +2,15 @@ import sys -import PyQt6 -import PyQt6.QtWidgets -import PyQt6.uic +import PySide6.QtWidgets from ibridges.resources import Resources from ibridgesgui.config import CONFIG_DIR -from ibridgesgui.gui_utils import UI_FILE_DIR, populate_table, populate_textfield +from ibridgesgui.gui_utils import UI_FILE_DIR, load_ui, populate_table, populate_textfield from ibridgesgui.ui_files.tabInfo import Ui_tabInfo -class Info(PyQt6.QtWidgets.QWidget, Ui_tabInfo): +class Info(PySide6.QtWidgets.QWidget, Ui_tabInfo): """Set iRODS information in the GUI.""" def __init__(self, session): @@ -21,7 +19,7 @@ def __init__(self, session): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - PyQt6.uic.loadUi(UI_FILE_DIR / "tabInfo.ui", self) + load_ui(UI_FILE_DIR / "tabInfo.ui", self) self.session = session self.refresh_button.clicked.connect(self.refresh_info) @@ -30,7 +28,7 @@ def __init__(self, session): def refresh_info(self): """Find and set the information of the connected iRODS system.""" self.resc_table.setRowCount(0) - self.setCursor(PyQt6.QtGui.QCursor(PyQt6.QtCore.Qt.CursorShape.WaitCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.WaitCursor)) # irods Zone self.zone_label.setText(self.session.zone) # irods user @@ -50,4 +48,4 @@ def refresh_info(self): resc_info = Resources(self.session).root_resources populate_table(self.resc_table, len(resc_info[0]), resc_info) self.resc_table.resizeColumnsToContents() - self.setCursor(PyQt6.QtGui.QCursor(PyQt6.QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) diff --git a/ibridgesgui/irods_tree_model.py b/ibridgesgui/irods_tree_model.py index bcb27a8d..add28244 100644 --- a/ibridgesgui/irods_tree_model.py +++ b/ibridgesgui/irods_tree_model.py @@ -7,14 +7,14 @@ import irods import irods.exception -import PyQt6 -import PyQt6.QtCore -import PyQt6.QtGui -import PyQt6.QtWidgets + +import PySide6.QtCore +import PySide6.QtGui +import PySide6.QtWidgets from ibridges import IrodsPath -class IrodsTreeModel(PyQt6.QtGui.QStandardItemModel): +class IrodsTreeModel(PySide6.QtGui.QStandardItemModel): """Model for an iRODS tree view.""" def __init__(self, tree_view, irods_root_path: IrodsPath): @@ -43,24 +43,24 @@ def __init__(self, tree_view, irods_root_path: IrodsPath): self.clear() def _tree_row_from_irods_item(self, item, parent_id, level, display_path=False): - icon_provider = PyQt6.QtWidgets.QFileIconProvider() + icon_provider = PySide6.QtWidgets.QFileIconProvider() if display_path: - display = PyQt6.QtGui.QStandardItem(item.path) + display = PySide6.QtGui.QStandardItem(item.path) else: - display = PyQt6.QtGui.QStandardItem(item.name) + display = PySide6.QtGui.QStandardItem(item.name) if isinstance(item, irods.collection.iRODSCollection): - display.setIcon(icon_provider.icon(PyQt6.QtWidgets.QFileIconProvider.IconType.Folder)) + display.setIcon(icon_provider.icon(PySide6.QtWidgets.QFileIconProvider.IconType.Folder)) datatype = "C" else: - display.setIcon(icon_provider.icon(PyQt6.QtWidgets.QFileIconProvider.IconType.File)) + display.setIcon(icon_provider.icon(PySide6.QtWidgets.QFileIconProvider.IconType.File)) datatype = "d" row = [ display, # display name - PyQt6.QtGui.QStandardItem(str(level + 1)), # item level in the tree - PyQt6.QtGui.QStandardItem(str(item.id)), # id in iRODS - PyQt6.QtGui.QStandardItem(str(parent_id)), # parent id - PyQt6.QtGui.QStandardItem(datatype), # C or d - PyQt6.QtGui.QStandardItem(item.path), # absolute irods path + PySide6.QtGui.QStandardItem(str(level + 1)), # item level in the tree + PySide6.QtGui.QStandardItem(str(item.id)), # id in iRODS + PySide6.QtGui.QStandardItem(str(parent_id)), # parent id + PySide6.QtGui.QStandardItem(datatype), # C or d + PySide6.QtGui.QStandardItem(item.path), # absolute irods path ] return row diff --git a/ibridgesgui/login.py b/ibridgesgui/login.py index 831b7fce..995e5266 100644 --- a/ibridgesgui/login.py +++ b/ibridgesgui/login.py @@ -9,8 +9,8 @@ from ibridges.resources import Resources from ibridges.session import LoginError, PasswordError from irods.exception import ResourceDoesNotExist -from PyQt6.QtWidgets import QDialog, QLineEdit -from PyQt6.uic import loadUi +from PySide6.QtWidgets import QDialog, QLineEdit + from ibridgesgui.config import ( IRODSA, @@ -20,7 +20,7 @@ save_current_settings, set_last_ienv_path, ) -from ibridgesgui.gui_utils import UI_FILE_DIR +from ibridgesgui.gui_utils import UI_FILE_DIR, load_ui from ibridgesgui.ui_files.irodsLogin import Ui_irodsLogin @@ -37,7 +37,7 @@ def __init__(self, session_dict, app_name): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - loadUi(UI_FILE_DIR / "irodsLogin.ui", self) + load_ui(UI_FILE_DIR / "irodsLogin.ui", self) self.logger = logging.getLogger(app_name) self.irods_config_dir = Path("~", ".irods").expanduser() diff --git a/ibridgesgui/logviewer.py b/ibridgesgui/logviewer.py index 9a85f021..4ae77b90 100644 --- a/ibridgesgui/logviewer.py +++ b/ibridgesgui/logviewer.py @@ -3,33 +3,31 @@ import logging import sys -import PyQt6 +import PySide6 + from ibridgesgui.config import CONFIG_DIR -from ibridgesgui.gui_utils import UI_FILE_DIR +from ibridgesgui.gui_utils import UI_FILE_DIR, load_ui from ibridgesgui.ui_files.tabLogging import Ui_tabLogging -class QPlainTextEditLogger(logging.Handler, PyQt6.QtCore.QObject): - """A thread safe log handler.""" - - append_plain_text = PyQt6.QtCore.pyqtSignal(str) +class QPlainTextEditLogger(logging.Handler, PySide6.QtCore.QObject): + """log handler.""" - def __init__(self, widget: PyQt6.QtWidgets.QPlainTextEdit): + def __init__(self, widget: PySide6.QtWidgets.QPlainTextEdit): """Initialize the log handler.""" + PySide6.QtCore.QObject.__init__(self) super().__init__() - PyQt6.QtCore.QObject.__init__(self) self.widget = widget self.widget.setReadOnly(True) - self.append_plain_text.connect(self.widget.insertPlainText) def emit(self, record: logging.LogRecord): """Pass `record` to all connected slots.""" msg = self.format(record)+"\n" - self.append_plain_text.emit(msg) + self.widget.insertPlainText(msg) -class LogViewer(PyQt6.QtWidgets.QWidget, Ui_tabLogging): +class LogViewer(PySide6.QtWidgets.QWidget, Ui_tabLogging): """Set iBridges logging in GUI.""" def __init__(self, logger): @@ -38,7 +36,7 @@ def __init__(self, logger): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - PyQt6.uic.loadUi(UI_FILE_DIR / "tabLogging.ui", self) + load_ui(UI_FILE_DIR / "tabLogging.ui", self) self.logger = logger self.log_label.setText(str(CONFIG_DIR)) diff --git a/ibridgesgui/popup_widgets.py b/ibridgesgui/popup_widgets.py index cd33bbe7..0bc90c7d 100644 --- a/ibridgesgui/popup_widgets.py +++ b/ibridgesgui/popup_widgets.py @@ -9,12 +9,13 @@ import irods from ibridges import IrodsPath, download, upload from ibridges.util import find_environment_provider, get_environment_providers -from PyQt6 import QtCore, QtGui -from PyQt6.QtWidgets import QDialog, QFileDialog, QMessageBox -from PyQt6.uic import loadUi +import PySide6.QtCore +import PySide6.QtGui +import PySide6.QtWidgets +#from PyQt6.QtWidgets import QDialog, QFileDialog, QMessageBox from ibridgesgui.config import _read_json, check_irods_config, get_last_ienv_path, save_irods_config -from ibridgesgui.gui_utils import UI_FILE_DIR, combine_operations, populate_textfield +from ibridgesgui.gui_utils import UI_FILE_DIR, load_ui, combine_operations, populate_textfield from ibridgesgui.threads import TransferDataThread from ibridgesgui.ui_files.configCheck import Ui_configCheck from ibridgesgui.ui_files.createCollection import Ui_createCollection @@ -23,7 +24,7 @@ from ibridgesgui.ui_files.uploadData import Ui_uploadData -class CreateCollection(QDialog, Ui_createCollection): +class CreateCollection(PySide6.QtWidgets.QDialog, Ui_createCollection): """Popup window to create a new collection.""" def __init__(self, parent, logger): @@ -32,11 +33,11 @@ def __init__(self, parent, logger): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - loadUi(UI_FILE_DIR / "createCollection.ui", self) + load_ui(UI_FILE_DIR / "createCollection.ui", self) self.logger = logger self.setWindowTitle("Create iRODS collection") - self.setWindowFlags(QtCore.Qt.WindowType.WindowStaysOnTopHint) + self.setWindowFlags(PySide6.QtCore.Qt.WindowType.WindowStaysOnTopHint) self.parent = parent self.label.setText(str(self.parent) + "/") self.buttonBox.accepted.connect(self.accept) @@ -62,7 +63,7 @@ def accept(self): self.error_label.setText(f"Could not create {new_coll_path}, consult the logs.") -class CreateDirectory(QDialog, Ui_createCollection): +class CreateDirectory(PySide6.QtWidgets.QDialog, Ui_createCollection): """Popup window to create a new directory.""" def __init__(self, parent): @@ -71,9 +72,9 @@ def __init__(self, parent): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - loadUi(UI_FILE_DIR / "createCollection.ui", self) + load_ui(UI_FILE_DIR / "createCollection.ui", self) self.setWindowTitle("Create Directory") - self.setWindowFlags(QtCore.Qt.WindowType.WindowStaysOnTopHint) + self.setWindowFlags(PySide6.QtCore.Qt.WindowType.WindowStaysOnTopHint) self.parent = parent self.label.setText(self.parent + os.sep) self.buttonBox.accepted.connect(self.accept) @@ -94,7 +95,7 @@ def accept(self): self.error_label.setText("ERROR: insufficient rights.") -class Rename(QDialog, Ui_renameItem): +class Rename(PySide6.QtWidgets.QDialog, Ui_renameItem): """Popup window to rename and move a collection or data object.""" def __init__(self, irods_path: IrodsPath, logger): @@ -103,11 +104,11 @@ def __init__(self, irods_path: IrodsPath, logger): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - loadUi(UI_FILE_DIR / "renameItem.ui", self) + load_ui(UI_FILE_DIR / "renameItem.ui", self) self.logger = logger self.setWindowTitle("Create iRODS collection") - self.setWindowFlags(QtCore.Qt.WindowType.WindowStaysOnTopHint) + self.setWindowFlags(PySide6.QtCore.Qt.WindowType.WindowStaysOnTopHint) self.irods_path = irods_path self.item_path_label.setText(str(irods_path)) self.item_path_input.setText(str(irods_path)) @@ -131,7 +132,7 @@ def accept(self): self.error_label.setText(f"Could not create {new_path}, consult the logs.") -class CheckConfig(QDialog, Ui_configCheck): +class CheckConfig(PySide6.QtWidgets.QDialog, Ui_configCheck): """Popup window to edit, create and check an environment.json.""" def __init__(self, logger, env_path): @@ -140,7 +141,7 @@ def __init__(self, logger, env_path): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - loadUi(UI_FILE_DIR / "configCheck.ui", self) + load_ui(UI_FILE_DIR / "configCheck.ui", self) self.logger = logger self.env_path = env_path @@ -252,10 +253,10 @@ def save_env(self): def save_env_as(self): """Choose file to save text field as json.""" self.error_label.clear() - dialog = QFileDialog(self) - dialog.setFileMode(QFileDialog.FileMode.AnyFile) + dialog = PySide6.QtWidgets.QFileDialog(self) + dialog.setFileMode(PySide6.QtWidgets.QFileDialog.FileMode.AnyFile) dialog.setNameFilter("(*.json)") - create_file = QFileDialog.getSaveFileName( + create_file = PySide6.QtWidgets.QFileDialog.getSaveFileName( self, "Save as File", str(self.env_path), "(*.json)" ) if create_file[0] != "": @@ -274,7 +275,7 @@ def save_env_as(self): self.error_label.setText("File type needs to be .json") -class UploadData(QDialog, Ui_uploadData): +class UploadData(PySide6.QtWidgets.QDialog, Ui_uploadData): """Popup window to upload data to browser.""" def __init__(self, logger, session, irods_path): @@ -283,7 +284,7 @@ def __init__(self, logger, session, irods_path): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - loadUi(UI_FILE_DIR / "uploadData.ui", self) + load_ui(UI_FILE_DIR / "uploadData.ui", self) self.active_upload = False self.upload_thread = None @@ -302,14 +303,14 @@ def __init__(self, logger, session, irods_path): def close_window(self): """Close window while data transfer stays in progress.""" if self.active_upload: - reply = QMessageBox.critical( + reply = PySide6.QtWidgets.QMessageBox.critical( self, "Message", "Do you want to close the window while the transfer continues?", - QMessageBox.StandardButton.Yes, - QMessageBox.StandardButton.No, + PySide6.QtWidgets.QMessageBox.StandardButton.Yes, + PySide6.QtWidgets.QMessageBox.StandardButton.No, ) - if reply == QMessageBox.StandardButton.Yes: + if reply == PySide6.QtWidgets.QMessageBox.StandardButton.Yes: self.active_upload = False self.close() @@ -321,7 +322,7 @@ def closeEvent(self, evnt): # noqa def select_file(self): """Open file selector.""" - select_file = QFileDialog.getOpenFileName(self, "Open Filie") + select_file = PySide6.QtWidgets.QFileDialog.getOpenFileName(self, "Open Filie") path = self._fs_select(select_file) if path is None or str(path) == "." or path in self.sources_list.toPlainText(): return @@ -329,7 +330,7 @@ def select_file(self): def select_folder(self): """Open folder selctor.""" - select_dir = QFileDialog.getExistingDirectory(self, "Select Directory") + select_dir = PySide6.QtWidgets.QFileDialog.getExistingDirectory(self, "Select Directory") path = self._fs_select(select_dir) if path is None or str(path) == "." or path in self.sources_list.toPlainText(): return @@ -345,7 +346,7 @@ def _get_upload_params(self): self._start_upload(local_paths) def _start_upload(self, lpaths): - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.WaitCursor)) self.error_label.setText(f"Uploading to {str(self.irods_path)} ....") env_path = Path("~").expanduser().joinpath(".irods", get_last_ienv_path()) @@ -365,7 +366,7 @@ def _start_upload(self, lpaths): if len(ops.upload) == 0: self.error_label.setText("Data already present and up to date.") - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) else: self._enable_buttons(False) self.active_upload = True @@ -379,19 +380,19 @@ def _start_upload(self, lpaths): except FileExistsError: self.error_label.setText("Data already exists. Check 'overwrite' to overwrite.") - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) self._enable_buttons(True) return except Exception as err: self.error_label.setText( f"Could not instantiate a new session from {env_path}: {repr(err)}." ) - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) self._enable_buttons(True) return def _finish_upload(self): - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) del self.upload_thread def _upload_status(self, state): @@ -424,7 +425,7 @@ def _fs_select(self, path_select): return path -class DownloadData(QDialog, Ui_downloadData): +class DownloadData(PySide6.QtWidgets.QDialog, Ui_downloadData): """Popup window to dowload data from browser.""" def __init__(self, logger, session, irods_path): @@ -433,7 +434,7 @@ def __init__(self, logger, session, irods_path): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - loadUi(UI_FILE_DIR / "downloadData.ui", self) + load_ui(UI_FILE_DIR / "downloadData.ui", self) self.active_download = False self.download_thread = None @@ -455,14 +456,14 @@ def __init__(self, logger, session, irods_path): def close_window(self): """Close window while data transfer stays in progress.""" if self.active_download: - reply = QMessageBox.critical( + reply = PySide6.QtWidgets.QMessageBox.critical( self, "Message", "Do you want to close the window while the transfer continues?", - QMessageBox.StandardButton.Yes, - QMessageBox.StandardButton.No, + PySide6.QtWidgets.QMessageBox.StandardButton.Yes, + PySide6.QtWidgets.QMessageBox.StandardButton.No, ) - if reply == QMessageBox.StandardButton.Yes: + if reply == PySide6.QtWidgets.QMessageBox.StandardButton.Yes: self.active_download = False self.close() @@ -486,7 +487,7 @@ def select_folder(self): """Select the download destination.""" self.error_label.clear() select_dir = Path( - QFileDialog.getExistingDirectory( + PySide6.QtWidgets.QFileDialog.getExistingDirectory( self, "Select Directory", directory=str(Path("~").expanduser()) ) ) @@ -519,7 +520,7 @@ def _enable_buttons(self, enable): self.metadata.setEnabled(enable) def _start_download(self, local_path): - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6. QtCore.Qt.CursorShape.WaitCursor)) self.error_label.setText(f"Downloading to {local_path} ....") env_path = Path("~").expanduser().joinpath(".irods", get_last_ienv_path()) try: @@ -534,7 +535,7 @@ def _start_download(self, local_path): if len(ops.download) == 0 and len(ops.meta_download) == 0: self.error_label.setText("Data already present and up to date.") - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) else: self._enable_buttons(False) self.active_download = True @@ -547,19 +548,19 @@ def _start_download(self, local_path): self.download_thread.start() except FileExistsError: self.error_label.setText("Data already exists. Check 'overwrite' to overwrite.") - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) self._enable_buttons(True) return except Exception as err: self.error_label.setText( f"Could not instantiate thread from {env_path}: {repr(err)}." ) - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) self._enable_buttons(True) return def _finish_download(self): - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) del self.download_thread def _download_status(self, state): diff --git a/ibridgesgui/search.py b/ibridgesgui/search.py index 80739ee8..76f480b7 100644 --- a/ibridgesgui/search.py +++ b/ibridgesgui/search.py @@ -4,19 +4,19 @@ import sys from pathlib import Path -import PyQt6.uic from ibridges import IrodsPath, download from ibridges.search import MetaSearch -from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt6.QtWidgets import QMessageBox +import PySide6.QtCore +import PySide6.QtGui +import PySide6.QtWidgets from ibridgesgui.config import get_last_ienv_path, is_session_from_config -from ibridgesgui.gui_utils import UI_FILE_DIR, append_table, combine_operations +from ibridgesgui.gui_utils import UI_FILE_DIR, load_ui, append_table, combine_operations from ibridgesgui.threads import SearchThread, TransferDataThread from ibridgesgui.ui_files.tabSearch import Ui_tabSearch -class Search(PyQt6.QtWidgets.QWidget, Ui_tabSearch): +class Search(PySide6.QtWidgets.QWidget, Ui_tabSearch): """Search view.""" def __init__(self, session, app_name, browser): @@ -39,7 +39,7 @@ def __init__(self, session, app_name, browser): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - PyQt6.uic.loadUi(UI_FILE_DIR / "tabSearch.ui", self) + load_ui(UI_FILE_DIR / "tabSearch.ui", self) self.logger = logging.getLogger(app_name) self.session = session @@ -83,7 +83,7 @@ def show_result_elements(self): def search(self): """Validate search parameters and start search.""" self.hide_result_elements() - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.WaitCursor)) self.error_label.clear() self.current_batch_num = 0 self.results = None @@ -101,7 +101,7 @@ def search(self): ) if msg is not None: self.error_label.setText(msg) - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) return self._start_search(search_path, path_pattern, meta_searches, checksum, case_sensitive) @@ -149,20 +149,20 @@ def load_results(self, batch_size=25): def download(self): """Determine iRODS paths, select destination and start download.""" - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.WaitCursor)) self.error_label.clear() irods_paths = self._retrieve_selected_paths() if len(irods_paths) == 0: self.error_label.setText("No data selected.") - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) return select_dir = Path( - QtWidgets.QFileDialog.getExistingDirectory( + PySide6.QtWidgets.QFileDialog.getExistingDirectory( self, "Select Directory", directory=str(Path("~").expanduser()) ) ) if str(select_dir) == "" or str(select_dir) == ".": - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) return info = f"Download to: {select_dir}\n" @@ -170,19 +170,19 @@ def download(self): overwrite = False if any(exists for _, exists in data_exists): - button_reply = QMessageBox.question( + button_reply = PySide6.QtWidgets.QMessageBox.question( self, "Message Box", info + f"Some data already exists in {select_dir}." + "\nOverwrite data?", ) else: - button_reply = QMessageBox.question(self, "Message Box", info) + button_reply = PySide6.QtWidgets.QMessageBox.question(self, "Message Box", info) - if button_reply == QMessageBox.StandardButton.Yes: + if button_reply == PySide6.QtWidgets.QMessageBox.StandardButton.Yes: overwrite = True self._start_download(irods_paths, select_dir, overwrite) else: - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) return def send_to_browser(self): @@ -259,7 +259,7 @@ def _start_download(self, irods_paths, folder, overwrite): self.error_label.setText( f"Could not instantiate a new session from {env_path}: {repr(err)}." ) - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) return self.download_thread.result.connect(self._download_fetch_result) self.download_thread.finished.connect(self._finish_download) @@ -270,7 +270,7 @@ def _finish_download(self): self.download_button.setEnabled(True) self.clear_button.setEnabled(True) self.search_button.setEnabled(True) - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) del self.download_thread def _download_status(self, state): @@ -283,7 +283,7 @@ def _download_fetch_result(self, thread: dict): self.error_label.setText("Download finished.") else: self.error_label.setText("Errors occurred during download. Consult the logs.") - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) def _start_search(self, search_path, path_pattern, meta_searches, checksum, case_sensitive): self.search_button.setEnabled(False) @@ -317,7 +317,7 @@ def _start_search(self, search_path, path_pattern, meta_searches, checksum, case def _finish_search(self): self.search_button.setEnabled(True) - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) del self.search_thread def _fetch_results(self, thread: dict): @@ -330,4 +330,4 @@ def _fetch_results(self, thread: dict): self.results = thread["results"] self.load_results() - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) diff --git a/ibridgesgui/sync.py b/ibridgesgui/sync.py index 9286302e..d4ba9e19 100644 --- a/ibridgesgui/sync.py +++ b/ibridgesgui/sync.py @@ -4,18 +4,18 @@ import sys from pathlib import Path -import PyQt6.uic from ibridges import IrodsPath -from PyQt6 import QtCore, QtGui +import PySide6.QtCore +import PySide6.QtGui -from ibridgesgui.gui_utils import UI_FILE_DIR, populate_table, prep_session_for_copy +from ibridgesgui.gui_utils import UI_FILE_DIR, load_ui, populate_table, prep_session_for_copy from ibridgesgui.irods_tree_model import IrodsTreeModel from ibridgesgui.popup_widgets import CreateCollection, CreateDirectory from ibridgesgui.threads import SyncThread, TransferDataThread from ibridgesgui.ui_files.tabSync import Ui_tabSync -class Sync(PyQt6.QtWidgets.QWidget, Ui_tabSync): +class Sync(PySide6.QtWidgets.QWidget, Ui_tabSync): """Sync view.""" def __init__(self, session, app_name): @@ -33,7 +33,7 @@ def __init__(self, session, app_name): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - PyQt6.uic.loadUi(UI_FILE_DIR / "tabSync.ui", self) + load_ui(UI_FILE_DIR / "tabSync.ui", self) self.logger = logging.getLogger(app_name) self.session = session @@ -59,10 +59,10 @@ def __init__(self, session, app_name): def _init_local_fs_tree(self): """Create local FS tree.""" - self.local_fs_model = QtGui.QFileSystemModel(self.local_fs_tree) + self.local_fs_model = PySide6.QtWidgets.QFileSystemModel(self.local_fs_tree) self.local_fs_tree.setModel(self.local_fs_model) - home_location = QtCore.QStandardPaths.standardLocations( - QtCore.QStandardPaths.StandardLocation.HomeLocation + home_location = PySide6.QtCore.QStandardPaths.standardLocations( + PySide6.QtCore.QStandardPaths.StandardLocation.HomeLocation )[0] index = self.local_fs_model.setRootPath(home_location) self.local_fs_tree.setCurrentIndex(index) @@ -194,7 +194,7 @@ def _enable_buttons(self, enable): def _start_data_sync(self): self._enable_buttons(False) - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.WaitCursor)) self.error_label.setText("Synchronising data ....") env_path = prep_session_for_copy(self.session, self.error_label) @@ -221,7 +221,7 @@ def _start_sync_diff(self, source, target): self.diff_table.setRowCount(0) self._enable_buttons(False) self.progress_bar.setValue(0) - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.WaitCursor)) self.error_label.setText("Calculating differences ....") @@ -243,14 +243,14 @@ def _start_sync_diff(self, source, target): def _finish_sync_diff(self): self._enable_buttons(True) - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) if self.sync_diff_thread: del self.sync_diff_thread def _finish_sync_data(self): self._enable_buttons(True) self.sync_button.hide() - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) if self.sync_data_thread: del self.sync_data_thread @@ -294,4 +294,4 @@ def _sync_diff_end(self, thread_output: dict): else: self.diffs = thread_output["result"] self.sync_button.show() - self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) + self.setCursor(PySide6.QtGui.QCursor(PySide6.QtCore.Qt.CursorShape.ArrowCursor)) diff --git a/ibridgesgui/threads.py b/ibridgesgui/threads.py index 1b7d7dbe..550d9351 100644 --- a/ibridgesgui/threads.py +++ b/ibridgesgui/threads.py @@ -5,13 +5,13 @@ from ibridges import IrodsPath, Session, search_data, sync from ibridges.executor import Operations, _obj_get, _obj_put from irods.exception import CAT_NO_ACCESS_PERMISSION, NetworkException -from PyQt6.QtCore import QThread, pyqtSignal +import PySide6.QtCore -class SearchThread(QThread): +class SearchThread(PySide6.QtCore.QThread): """Start iRODS search in an own thread using the same iRODS session.""" - result = pyqtSignal(dict) + result = PySide6.QtCore.Signal(dict) def __init__( self, @@ -63,11 +63,11 @@ def run(self): self.result.emit(search_out) -class TransferDataThread(QThread): +class TransferDataThread(PySide6.QtCore.QThread): """Transfer data between local and iRODS.""" - result = pyqtSignal(dict) - current_progress = pyqtSignal(list) + result = PySide6.QtCore.Signal(dict) + current_progress = PySide6.QtCore.Signal(list) def __init__(self, ienv_path: Path, logger, ops: Operations, overwrite: bool): """Pass parameters. @@ -186,10 +186,10 @@ def run(self): self.result.emit(transfer_out) -class SyncThread(QThread): +class SyncThread(PySide6.QtCore.QThread): """Sync between iRODS and local FS.""" - result = pyqtSignal(dict) + result = PySide6.QtCore.Signal(dict) def __init__(self, ienv_path, logger, source, target, dry_run: bool): """Pass download parameters.""" diff --git a/ibridgesgui/welcome.py b/ibridgesgui/welcome.py index 74f0018b..c1c4e082 100644 --- a/ibridgesgui/welcome.py +++ b/ibridgesgui/welcome.py @@ -3,16 +3,15 @@ import sys from datetime import datetime -import PyQt6.QtCore -import PyQt6.QtGui -import PyQt6.QtWidgets -import PyQt6.uic +import PySide6.QtCore +import PySide6.QtGui +import PySide6.QtWidgets -from ibridgesgui.gui_utils import LOGO_DIR, UI_FILE_DIR +from ibridgesgui.gui_utils import LOGO_DIR, UI_FILE_DIR, load_ui from ibridgesgui.ui_files.welcome import Ui_Welcome -class Welcome(PyQt6.QtWidgets.QWidget, Ui_Welcome): +class Welcome(PySide6.QtWidgets.QWidget, Ui_Welcome): """Welcome page.""" def __init__(self): @@ -21,23 +20,23 @@ def __init__(self): if getattr(sys, "frozen", False) or ("__compiled__" in globals()): super().setupUi(self) else: - PyQt6.uic.loadUi(UI_FILE_DIR / "welcome.ui", self) + load_ui(UI_FILE_DIR / "welcome.ui", self) if datetime.today().month == 12: - self.pixmap = PyQt6.QtGui.QPixmap(str(LOGO_DIR / "christmas-logo.png")) + self.pixmap = PySide6.QtGui.QPixmap(str(LOGO_DIR / "christmas-logo.png")) else: - self.pixmap = PyQt6.QtGui.QPixmap(str(LOGO_DIR / "logo.png")) - self.logo = PyQt6.QtWidgets.QLabel() + self.pixmap = PySide6.QtGui.QPixmap(str(LOGO_DIR / "logo.png")) + self.logo = PySide6.QtWidgets.QLabel() self.logo.setPixmap(self.pixmap) - self.logo.setAlignment(PyQt6.QtCore.Qt.AlignmentFlag.AlignCenter) + self.logo.setAlignment(PySide6.QtCore.Qt.AlignmentFlag.AlignCenter) self.logo.resize(self.pixmap.width(), self.pixmap.height()) - self.tag = PyQt6.QtWidgets.QLabel() + self.tag = PySide6.QtWidgets.QLabel() self.tag.setText("Bridging Science and Research Data Management.") - self.tag.setAlignment(PyQt6.QtCore.Qt.AlignmentFlag.AlignCenter) + self.tag.setAlignment(PySide6.QtCore.Qt.AlignmentFlag.AlignCenter) - self.grid = PyQt6.QtWidgets.QGridLayout() - self.grid.addWidget(PyQt6.QtWidgets.QLabel(), 0, 1) + self.grid = PySide6.QtWidgets.QGridLayout() + self.grid.addWidget(PySide6.QtWidgets.QLabel(), 0, 1) self.grid.addWidget(self.logo, 1, 1) self.grid.addWidget(self.tag, 2, 1) self.setLayout(self.grid)