From 5653084b0a4df709b46a54fa80243e5ccdf2f087 Mon Sep 17 00:00:00 2001 From: chStaiger Date: Thu, 6 Jun 2024 18:40:40 +0200 Subject: [PATCH] 135 rename (#194) * Setup of rename/move * Small bugfix * importlib.resources.files * Lift synchronise button up * Ruff * Ruff format * Pylint --------- Co-authored-by: Staiger, Christine --- ibridgesgui/browser.py | 19 +++- ibridgesgui/config.py | 1 + ibridgesgui/gui_utils.py | 7 +- ibridgesgui/popup_widgets.py | 38 ++++++++ ibridgesgui/ui_files/MainMenu.py | 48 +++++---- ibridgesgui/ui_files/MainMenu.ui | 5 +- ibridgesgui/ui_files/renameItem.py | 77 +++++++++++++++ ibridgesgui/ui_files/renameItem.ui | 151 +++++++++++++++++++++++++++++ ibridgesgui/ui_files/tabBrowser.ui | 28 +++++- ibridgesgui/ui_files/tabSync.py | 12 ++- ibridgesgui/ui_files/tabSync.ui | 22 ++++- pyproject.toml | 2 +- 12 files changed, 378 insertions(+), 32 deletions(-) create mode 100644 ibridgesgui/ui_files/renameItem.py create mode 100644 ibridgesgui/ui_files/renameItem.ui diff --git a/ibridgesgui/browser.py b/ibridgesgui/browser.py index 683e9a78..e014a243 100644 --- a/ibridgesgui/browser.py +++ b/ibridgesgui/browser.py @@ -22,7 +22,7 @@ populate_table, populate_textfield, ) -from ibridgesgui.popup_widgets import CreateCollection +from ibridgesgui.popup_widgets import CreateCollection, Rename from ibridgesgui.ui_files.tabBrowser import Ui_tabBrowser @@ -44,7 +44,6 @@ def __init__(self, session, app_name): if self.session.home is not None: root_path = IrodsPath(self.session).absolute() else: - root_path = IrodsPath( self.session, f"/{self.session.zone}/home/{self.session.username}" ) @@ -76,6 +75,7 @@ def browse(self): self.upload_dir_button.clicked.connect(self.folder_upload) self.download_button.clicked.connect(self.download) self.create_coll_button.clicked.connect(self.create_collection) + self.rename_button.clicked.connect(self.rename_item) # Browser table behaviour self.browser_table.doubleClicked.connect(self.update_path) @@ -105,7 +105,6 @@ def set_parent(self): self.path_input.setText(str(current_path.parent)) self.load_browser_table() - # @PyQt6.QtCore.pyqtSlot(PyQt6.QtCore.QModelIndex) def update_path(self, index): """Take path from path_input and loads browser table.""" self.error_label.clear() @@ -123,6 +122,20 @@ def create_collection(self): coll_widget.exec() self.load_browser_table() + def rename_item(self): + """Rename/move a collection or data object.""" + self.error_label.clear() + if self.browser_table.currentRow() == -1: + self.error_label.setText("Please select a row from the table first!") + return + item_name = self.browser_table.item(self.browser_table.currentRow(), 1).text() + irods_path = IrodsPath(self.session, "/" + self.path_input.text().strip("/")).joinpath( + item_name + ) + rename_widget = Rename(irods_path, self.logger) + rename_widget.exec() + self.load_browser_table() + def folder_upload(self): """Select a folder and upload.""" self.error_label.clear() diff --git a/ibridgesgui/config.py b/ibridgesgui/config.py index af94ef4c..b9c69585 100644 --- a/ibridgesgui/config.py +++ b/ibridgesgui/config.py @@ -128,6 +128,7 @@ def _get_config() -> Union[None, dict]: # irods config functions + def is_session_from_config(session: Session) -> Union[Session, None]: """Create a new session from the given session. diff --git a/ibridgesgui/gui_utils.py b/ibridgesgui/gui_utils.py index f0fa2c1b..288ee5d8 100644 --- a/ibridgesgui/gui_utils.py +++ b/ibridgesgui/gui_utils.py @@ -1,7 +1,6 @@ """Handy and reusable functions for the GUI.""" import pathlib -from importlib.resources import files from typing import Union import irods @@ -10,6 +9,12 @@ from ibridgesgui.config import get_last_ienv_path, is_session_from_config +try: + from importlib.resources import files +except ImportError: + from importlib_resources import files + + UI_FILE_DIR = files(__package__) / "ui_files" diff --git a/ibridgesgui/popup_widgets.py b/ibridgesgui/popup_widgets.py index c820e0ec..0914651a 100644 --- a/ibridgesgui/popup_widgets.py +++ b/ibridgesgui/popup_widgets.py @@ -14,6 +14,7 @@ from ibridgesgui.gui_utils import UI_FILE_DIR, populate_textfield from ibridgesgui.ui_files.configCheck import Ui_configCheck from ibridgesgui.ui_files.createCollection import Ui_createCollection +from ibridgesgui.ui_files.renameItem import Ui_renameItem class CreateCollection(QDialog, Ui_createCollection): @@ -85,6 +86,43 @@ def accept(self): self.error_label.setText("ERROR: insufficient rights.") +class Rename(QDialog, Ui_renameItem): + """Popup window to rename and move a collection or data object.""" + + def __init__(self, irods_path: IrodsPath, logger): + """Initialise window.""" + super().__init__() + if getattr(sys, "frozen", False): + super().setupUi(self) + else: + loadUi(UI_FILE_DIR / "renameItem.ui", self) + + self.logger = logger + self.setWindowTitle("Create iRODS collection") + self.setWindowFlags(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)) + self.buttonBox.accepted.connect(self.accept) + + def accept(self): + """Create new collection.""" + if self.item_path_input.text() != "": + new_path = IrodsPath(self.irods_path.session, self.item_path_input.text()) + if new_path.exists(): + self.error_label.setText(f"{new_path} already exists.") + else: + try: + new_irods_path = self.irods_path.rename(new_path) + self.logger.info(f"Rename/Move {self.irods_path} --> {new_irods_path}") + self.done(0) + except irods.exception.CAT_NO_ACCESS_PERMISSION: + self.error_label.setText(f"No access rights to {new_path}.") + except Exception as err: + self.logger.exception(f"Could not create {new_path}: {err}") + self.error_label.setText(f"Could not create {new_path}, consult the logs.") + + class CheckConfig(QDialog, Ui_configCheck): """Popup window to edit, create and check an environment.json.""" diff --git a/ibridgesgui/ui_files/MainMenu.py b/ibridgesgui/ui_files/MainMenu.py index a77a52d2..5a6cac2b 100644 --- a/ibridgesgui/ui_files/MainMenu.py +++ b/ibridgesgui/ui_files/MainMenu.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'ibridgesgui/ui_files/MainMenu.ui' # -# Created by: PyQt6 UI code generator 6.6.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -14,35 +14,44 @@ def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(1300, 850) MainWindow.setMinimumSize(QtCore.QSize(1300, 850)) - MainWindow.setStyleSheet( - "QWidget\n" - "{\n" - " color: rgb(86, 184, 139);\n" - " background-color: rgb(54, 54, 54);\n" - " selection-background-color: rgb(58, 152, 112);\n" - " font: 16pt;\n" - "}\n" - "\n" - "QTabBar::tab:top:selected {\n" - " background-color: rgb(58, 152, 112);\n" - " color: rgb(54, 54, 54);\n" - "}\n" - "" - ) + MainWindow.setStyleSheet("QWidget\n" +"{\n" +" color: rgb(86, 184, 139);\n" +" background-color: rgb(54, 54, 54);\n" +" selection-background-color: rgb(58, 152, 112);\n" +" font: 16pt;\n" +"}\n" +"\n" +"QTabBar::tab:top:selected {\n" +" background-color: rgb(58, 152, 112);\n" +" color: rgb(54, 54, 54);\n" +"}\n" +"\n" +"QLabel#error_label\n" +"{\n" +" color: rgb(217, 174, 23);\n" +" font: 18pt;\n" +"}\n" +"") self.centralwidget = QtWidgets.QWidget(parent=MainWindow) self.centralwidget.setStyleSheet("") self.centralwidget.setObjectName("centralwidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout.setObjectName("verticalLayout") self.tab_widget = QtWidgets.QTabWidget(parent=self.centralwidget) - self.tab_widget.setMinimumSize(QtCore.QSize(600, 300)) + self.tab_widget.setMinimumSize(QtCore.QSize(600, 500)) font = QtGui.QFont() font.setPointSize(16) font.setBold(False) font.setItalic(False) + font.setWeight(50) self.tab_widget.setFont(font) self.tab_widget.setObjectName("tab_widget") self.verticalLayout.addWidget(self.tab_widget) + self.error_label = QtWidgets.QLabel(parent=self.centralwidget) + self.error_label.setText("") + self.error_label.setObjectName("error_label") + self.verticalLayout.addWidget(self.error_label) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(parent=MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 1300, 24)) @@ -50,6 +59,7 @@ def setupUi(self, MainWindow): font.setPointSize(16) font.setBold(False) font.setItalic(False) + font.setWeight(50) self.menubar.setFont(font) self.menubar.setObjectName("menubar") self.main_menu = QtWidgets.QMenu(parent=self.menubar) @@ -57,14 +67,12 @@ def setupUi(self, MainWindow): font.setPointSize(16) font.setBold(False) font.setItalic(False) + font.setWeight(50) self.main_menu.setFont(font) self.main_menu.setObjectName("main_menu") self.config_menu = QtWidgets.QMenu(parent=self.menubar) self.config_menu.setObjectName("config_menu") MainWindow.setMenuBar(self.menubar) - self.statusbar = QtWidgets.QStatusBar(parent=MainWindow) - self.statusbar.setObjectName("statusbar") - MainWindow.setStatusBar(self.statusbar) self.action_close_session = QtGui.QAction(parent=MainWindow) font = QtGui.QFont() self.action_close_session.setFont(font) diff --git a/ibridgesgui/ui_files/MainMenu.ui b/ibridgesgui/ui_files/MainMenu.ui index db8e7068..b6a8e5a9 100644 --- a/ibridgesgui/ui_files/MainMenu.ui +++ b/ibridgesgui/ui_files/MainMenu.ui @@ -50,12 +50,13 @@ QLabel#error_label 600 - 300 + 500 16 + 50 false false @@ -86,6 +87,7 @@ QLabel#error_label 16 + 50 false false @@ -94,6 +96,7 @@ QLabel#error_label 16 + 50 false false diff --git a/ibridgesgui/ui_files/renameItem.py b/ibridgesgui/ui_files/renameItem.py new file mode 100644 index 00000000..591bfdff --- /dev/null +++ b/ibridgesgui/ui_files/renameItem.py @@ -0,0 +1,77 @@ +# Form implementation generated from reading ui file 'ibridgesgui/ui_files/renameItem.ui' +# +# Created by: PyQt6 UI code generator 6.4.2 +# +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets + + +class Ui_renameItem(object): + def setupUi(self, renameItem): + createCollection.setObjectName("createCollection") + createCollection.resize(500, 200) + createCollection.setMinimumSize(QtCore.QSize(500, 200)) + createCollection.setMaximumSize(QtCore.QSize(500, 200)) + createCollection.setStyleSheet("QWidget\n" +"{\n" +" color: rgb(86, 184, 139);\n" +" background-color: rgb(54, 54, 54);\n" +" font: 16pt\n" +"}\n" +"\n" +"QLineEdit\n" +"{\n" +" background-color: rgb(85, 87, 83);\n" +" border-color: rgb(217, 174, 23)\n" +"}\n" +"\n" +"QLabel#error_label\n" +"{\n" +" color: rgb(217, 174, 23);\n" +"}\n" +"\n" +"") + self.verticalLayout = QtWidgets.QVBoxLayout(createCollection) + self.verticalLayout.setObjectName("verticalLayout") + self.label = QtWidgets.QLabel(parent=createCollection) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.item_path_label = QtWidgets.QLabel(parent=createCollection) + self.item_path_label.setText("") + self.item_path_label.setObjectName("item_path_label") + self.horizontalLayout.addWidget(self.item_path_label) + self.verticalLayout.addLayout(self.horizontalLayout) + self.label_2 = QtWidgets.QLabel(parent=createCollection) + self.label_2.setObjectName("label_2") + self.verticalLayout.addWidget(self.label_2) + self.item_path_input = QtWidgets.QLineEdit(parent=createCollection) + self.item_path_input.setObjectName("item_path_input") + self.verticalLayout.addWidget(self.item_path_input) + self.error_label = QtWidgets.QLabel(parent=createCollection) + self.error_label.setStyleSheet("") + self.error_label.setText("") + self.error_label.setObjectName("error_label") + self.verticalLayout.addWidget(self.error_label) + spacerItem = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) + self.verticalLayout.addItem(spacerItem) + self.buttonBox = QtWidgets.QDialogButtonBox(parent=createCollection) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + + self.retranslateUi(createCollection) + self.buttonBox.accepted.connect(createCollection.accept) # type: ignore + self.buttonBox.rejected.connect(createCollection.reject) # type: ignore + QtCore.QMetaObject.connectSlotsByName(createCollection) + + def retranslateUi(self, createCollection): + _translate = QtCore.QCoreApplication.translate + createCollection.setWindowTitle(_translate("createCollection", "Rename/Move")) + self.label.setText(_translate("createCollection", "Rename or move:")) + self.label_2.setText(_translate("createCollection", "to new location:")) diff --git a/ibridgesgui/ui_files/renameItem.ui b/ibridgesgui/ui_files/renameItem.ui new file mode 100644 index 00000000..087e515f --- /dev/null +++ b/ibridgesgui/ui_files/renameItem.ui @@ -0,0 +1,151 @@ + + + renameItem + + + + 0 + 0 + 500 + 200 + + + + + 500 + 200 + + + + + 500 + 200 + + + + Rename/Move + + + QWidget +{ + color: rgb(86, 184, 139); + background-color: rgb(54, 54, 54); + font: 16pt +} + +QLineEdit +{ + background-color: rgb(85, 87, 83); + border-color: rgb(217, 174, 23) +} + +QLabel#error_label +{ + color: rgb(217, 174, 23); +} + + + + + + + + Rename or move: + + + + + + + + + + + + + + + + + + to new location: + + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 10 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + renameItem + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + renameItem + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ibridgesgui/ui_files/tabBrowser.ui b/ibridgesgui/ui_files/tabBrowser.ui index d27db280..dd39cabe 100644 --- a/ibridgesgui/ui_files/tabBrowser.ui +++ b/ibridgesgui/ui_files/tabBrowser.ui @@ -76,6 +76,7 @@ QPushButton#confirm_button 16 + 75 true @@ -156,6 +157,13 @@ QPushButton#confirm_button + + + + Rename/Move + + + @@ -231,6 +239,15 @@ QPushButton#confirm_button QAbstractItemView::NoEditTriggers + + false + + + false + + + false + false @@ -311,6 +328,7 @@ QPushButton#confirm_button + 50 false @@ -380,6 +398,7 @@ QPushButton#confirm_button + 75 true @@ -412,6 +431,7 @@ QPushButton#confirm_button + 75 true @@ -438,6 +458,7 @@ QPushButton#confirm_button 20 + 75 true @@ -460,6 +481,7 @@ QPushButton#confirm_button + 75 true @@ -532,6 +554,7 @@ QPushButton#confirm_button 20 + 75 true @@ -631,6 +654,7 @@ QPushButton#confirm_button + 75 true @@ -733,9 +757,8 @@ QPushButton#confirm_button <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -hr { height: 1px; border-width: 0; } </style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Summary</p></body></html> @@ -771,6 +794,7 @@ hr { height: 1px; border-width: 0; } 13 + 75 true diff --git a/ibridgesgui/ui_files/tabSync.py b/ibridgesgui/ui_files/tabSync.py index 36d352b8..a5d41cdf 100644 --- a/ibridgesgui/ui_files/tabSync.py +++ b/ibridgesgui/ui_files/tabSync.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'ibridgesgui/ui_files/tabSync.ui' # -# Created by: PyQt6 UI code generator 6.6.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -12,7 +12,7 @@ class Ui_tabSync(object): def setupUi(self, tabSync): tabSync.setObjectName("tabSync") - tabSync.resize(1234, 721) + tabSync.resize(1234, 749) tabSync.setStyleSheet("QWidget\n" "{\n" " color: rgb(86, 184, 139);\n" @@ -58,6 +58,7 @@ def setupUi(self, tabSync): font = QtGui.QFont() font.setPointSize(13) font.setBold(True) + font.setWeight(75) self.label_19.setFont(font) self.label_19.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.label_19.setObjectName("label_19") @@ -143,6 +144,7 @@ def setupUi(self, tabSync): font = QtGui.QFont() font.setPointSize(13) font.setBold(True) + font.setWeight(75) self.label_20.setFont(font) self.label_20.setTextFormat(QtCore.Qt.TextFormat.PlainText) self.label_20.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) @@ -196,6 +198,11 @@ def setupUi(self, tabSync): item = QtWidgets.QTableWidgetItem() self.diff_table.setHorizontalHeaderItem(2, item) self.verticalLayout_11.addWidget(self.diff_table) + self.sync_button = QtWidgets.QPushButton(parent=self.layoutWidget) + self.sync_button.setObjectName("sync_button") + self.verticalLayout_11.addWidget(self.sync_button) + spacerItem11 = QtWidgets.QSpacerItem(20, 100, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) + self.verticalLayout_11.addItem(spacerItem11) self.retranslateUi(tabSync) QtCore.QMetaObject.connectSlotsByName(tabSync) @@ -213,3 +220,4 @@ def retranslateUi(self, tabSync): item.setText(_translate("tabSync", "Destination")) item = self.diff_table.horizontalHeaderItem(2) item.setText(_translate("tabSync", "Size in Bytes")) + self.sync_button.setText(_translate("tabSync", "Synchronise")) diff --git a/ibridgesgui/ui_files/tabSync.ui b/ibridgesgui/ui_files/tabSync.ui index d472e579..6daa5b20 100644 --- a/ibridgesgui/ui_files/tabSync.ui +++ b/ibridgesgui/ui_files/tabSync.ui @@ -7,7 +7,7 @@ 0 0 1234 - 721 + 749 @@ -47,7 +47,7 @@ QLabel#error_label 771 - + QLayout::SetDefaultConstraint @@ -72,6 +72,7 @@ QLabel#error_label 13 + 75 true @@ -311,6 +312,7 @@ QLabel#error_label 13 + 75 true @@ -455,6 +457,22 @@ QLabel#error_label + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 100 + + + + diff --git a/pyproject.toml b/pyproject.toml index c2c7a3b4..014ae479 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,8 +24,8 @@ classifiers = [ dependencies = [ "PyQt6>=6.4.2", "ibridges==0.2.0", - # "pyinstaller==5.8.0", "setproctitle==1.3.3", + "importlib-resources;python_version<='3.9'", ] dynamic = ["version"]