Source code for controllers.control_recent_project

"""
This module defines the `RecentOpen` class, which represents a PyQt6-based GUI application for managing recent projects and directories.

The `RecentOpen` class provides functionality for opening recent projects, displaying files in selected directories, and managing recent projects in the UI.

It includes methods for handling click events, processing directories, managing recent projects in the UI, and opening recent project images.

Classes:
- RecentOpen: Represents the main application window for managing recent projects and directories.
"""

import glob
import os

from PyQt6 import QtCore, QtWidgets
from PyQt6.QtWidgets import QFrame


[docs] class RecentOpen(QtWidgets.QMainWindow): """ The `RecentOpen` class represents a PyQt6-based GUI application for managing recent projects and directories. Attributes: - controller: The controller object responsible for managing the application. - _model: The model object containing the application's data and logic. - _stylesheet: The stylesheet object for defining the visual appearance of the UI. - directory_open_list: A list to store the paths of files in the selected directory. Methods: - __init__: Initializes the RecentOpen instance. - click_open_directory: Handles the click event of the open directory button. - process_open_directory: Processes the selected directory and displays the files in the UI. - combo_box_selected: Handles the selection of options from the combo box. - detect_available_on_recent: Detects if a given path is available in the recent project list. - click_push_button_open_file_directory: Handles the click event of the push button to open a project. - clear_item_layout_directory_open: Clears the directory item projects in the user interface. - get_list_recent_project: Retrieves the list of recent projects and displays them in the UI. - add_list_recent_project_to_ui: Adds recent projects to the user interface. - click_push_button_open: Handles the click event of the push button to open a recent project. - click_push_button_delete: Handles the click event of the push button to delete a recent project. - clear_item_layout: Clears the items from the layout. - open_image_from_directory: Opens an image from the selected directory. - open_recent_image: Opens a recent project image. - remove_recent_image: Removes a recent project image. """ def __init__(self, controller): QtWidgets.QMainWindow.__init__(self) self._controller = controller self._model = controller.model self._stylesheet = controller.model.get_stylesheet self._ui_object = controller.ui_object self.directory_open_list = [] self._ui_object.pushButton_open_directory.clicked.connect(self.click_open_directory) self._ui_object.pushButton_open_directory.setStyleSheet(self._model.get_stylesheet.pushbutton_stylesheet()) self._ui_object.lineEdit_open_directory.setStyleSheet(self._model.get_stylesheet.line_edit_stylesheet())
[docs] def click_open_directory(self): """ Handle the click event of the open directory button. """ dir_path = self._model.select_directory() if dir_path is None or dir_path == "": dir_path = self._model.open_directory_path else: self._model.open_directory_path = dir_path self._ui_object.lineEdit_open_directory.setText(dir_path) self.process_open_directory()
[docs] def process_open_directory(self): """ Process the selected directory and display the files in the UI. This method retrieves files with specific extensions from the selected directory, creates UI elements for each file, and adds them to the layout. Return: None """ dir_path = self._ui_object.lineEdit_open_directory.text() if dir_path is None or dir_path == "" or not os.path.exists(dir_path): dir_path = self._model.open_directory_path self._ui_object.lineEdit_open_directory.setText(dir_path) extensions = ["png", "jpg", "jpeg", "avi", 'mp4', 'MOV'] self.directory_open_list = [] self.clear_item_layout_directory_open() for ext in extensions: files = glob.glob(f"{dir_path}/*.{ext}") files = [file.replace("\\", "/") for file in files] self.directory_open_list.extend(files) if self.directory_open_list: for index, path in enumerate(self.directory_open_list): frame = QFrame() frame.setFrameShape(QFrame.Shape.Box) # Set the shape of the frame frame.setLineWidth(50) # Set the width of the frame line frame.setStyleSheet("QToolTip {\n" "font: 9pt \"Segoe UI\";\n" "color: rgb(0, 0, 0);\n" "background-image: none;\n" "background-color: rgb(238, 238, 236);\n" "background-repeat: no-repeat;\n" "border: none;\n" "border-left: 5px solid rgb(40, 44, 52);\n" "text-align: left;\n" "padding-left: 8px;\n" "margin: 0px;\n" "}\n") vertical_layout_1 = QtWidgets.QVBoxLayout(frame) vertical_layout_1.setObjectName("vertical_layout_1") vertical_layout_1.setSpacing(1) horizontal_layout = QtWidgets.QHBoxLayout() horizontal_layout.setObjectName("horizontal_layout") horizontal_layout.setSpacing(1) vertical_layout_2 = QtWidgets.QVBoxLayout() vertical_layout_2.setObjectName("vertical_layout_2") vertical_layout_2.setSpacing(1) push_button_open = QtWidgets.QPushButton(os.path.basename(str(path))) push_button_open.setObjectName(str(index)) _, _, theme = self.detect_available_on_recent(str(path)) push_button_open.setStyleSheet(self._stylesheet.stylesheet_button_additional(theme)) push_button_open.clicked.connect(self.click_push_button_open_file_directory) push_button_open.setMaximumWidth(210) # 120 or 220 push_button_open.setMinimumWidth(210) # 120 or 220 push_button_open.setMinimumHeight(30) _translate = QtCore.QCoreApplication.translate try: push_button_open.setToolTip(_translate("MainWindow", "Path :" + path)) except FileNotFoundError: print(f"File not found: {path}") except PermissionError: print(f"Permission denied: {path}") vertical_layout_2.addWidget(push_button_open) horizontal_layout.addLayout(vertical_layout_2) combo_box = QtWidgets.QComboBox() combo_box.setObjectName(str(index)) combo_box.setMaximumWidth(100) combo_box.setMinimumWidth(100) combo_box.setMinimumHeight(30) combo_box.addItem("Save") combo_box.addItem("Save As") combo_box.addItem("Rename") combo_box.activated.connect(lambda ind=index: self.combo_box_selected()) vertical_layout_1.addLayout(horizontal_layout) self._ui_object.verticalLayout_directory_file.addWidget(frame)
[docs] def combo_box_selected(self): """ Handle the selection of options from the combo box. Retrieves the index of the selected combo box and performs further actions based on the selection. Return: None """
# sender = self.sender() # combo_box = self._ui_object.scrollArea_8.findChild(QtWidgets.QComboBox, sender.objectName()) # index = combo_box.objectName()
[docs] def detect_available_on_recent(self, path): """ Detects if the given path is available in the recent project list. Checks if the provided path matches any of the paths stored in the recent project list. Arg: path (str): The path to be checked. Return: tuple: - status (bool): True if the path is found in the recent project list, False otherwise. - index_recent_list (int or None): The index of the matching path in the recent project list, or None if not found. - theme (str): The theme of the detected path ('install' if found, 'None' otherwise). """ status = False index_recent_list = None for i, recent_path in enumerate(self._model.recent_project_list): config = self._model.model_config.load_json_file_project(recent_path) if path == config["Media_path"]: status = True index_recent_list = i break # Exit the loop once a match is found if status: return status, index_recent_list, "install" return status, index_recent_list, "None" # Moved outside the loop
[docs] def click_push_button_open_file_directory(self): """ Handle the click event of the push button to open a project. Retrieve the index of the clicked push button and opens the corresponding project. Return: None """ if self._model.debug_mode: self._model.activity_logger.info("RecentOpen: click_push_button_open(), " "OnClick push button open project") sender = self.sender() push_button = self._ui_object.scrollArea_8.findChild(QtWidgets.QPushButton, sender.objectName()) index = push_button.objectName() if push_button: self.open_image_from_directory(int(index)) self.process_open_directory()
[docs] def clear_item_layout_directory_open(self): """ Clear the directory item projects in the user interface. Remove all widgets from the vertical layout containing directory item projects. Return: None """ if self._model.debug_mode: self._model.activity_logger.info("RecentOpen: clear_item_layout_directory_open(), " "OnClick clear directory item project in user interface") while self._ui_object.verticalLayout_directory_file.count(): item = self._ui_object.verticalLayout_directory_file.takeAt(0) widget = item.widget() widget.deleteLater()
[docs] def get_list_recent_project(self): """ Retrieve the list of recent projects and displays them in the UI. """ if self._model.debug_mode: self._model.activity_logger.info("RecentOpen: get_list_recent_project(), " "Get list of recent project and show it to user interface") self._model.model_config.read_recent_config_path() self.process_open_directory() self.add_list_recent_project_to_ui()
[docs] def add_list_recent_project_to_ui(self): """ Add recent projects to the user interface. """ if self._model.debug_mode: self._model.activity_logger.info("RecentOpen: add_list_recent_project_to_ui(), " "Add list recent project to user interface") self.clear_item_layout() for index, path in enumerate(self._model.recent_project_list): config = self._model.model_config.load_json_file_project(path) frame = QFrame() frame.setFrameShape(QFrame.Shape.Box) # Set the shape of the frame frame.setLineWidth(50) # Set the width of the frame line frame.setStyleSheet("QToolTip {\n" "font: 9pt \"Segoe UI\";\n" "color: rgb(0, 0, 0);\n" "background-image: none;\n" "background-color: rgb(238, 238, 236);\n" "background-repeat: no-repeat;\n" "border: none;\n" "border-left: 5px solid rgb(40, 44, 52);\n" "text-align: left;\n" "padding-left: 8px;\n" "margin: 0px;\n" "}\n") vertical_layout_1 = QtWidgets.QVBoxLayout(frame) vertical_layout_1.setObjectName("vertical_layout_1") vertical_layout_1.setSpacing(1) horizontal_layout = QtWidgets.QHBoxLayout() horizontal_layout.setObjectName("horizontal_layout") horizontal_layout.setSpacing(1) vertical_layout_2 = QtWidgets.QVBoxLayout() vertical_layout_2.setObjectName("vertical_layout_2") vertical_layout_2.setSpacing(1) push_button_open = QtWidgets.QPushButton(os.path.basename(str(config["Media_path"]))) push_button_open.setObjectName(str(index)) push_button_open.setStyleSheet(self._stylesheet.stylesheet_button_additional("install")) push_button_open.clicked.connect(self.click_push_button_open) push_button_open.setMaximumWidth(180) push_button_open.setMinimumWidth(180) push_button_open.setMinimumHeight(30) _translate = QtCore.QCoreApplication.translate try: push_button_open.setToolTip(_translate("MainWindow", f"Path : {config['Media_path']}")) except KeyError as e: print(f"KeyError occurred while setting tooltip: {e}") vertical_layout_2.addWidget(push_button_open) horizontal_layout.addLayout(vertical_layout_2) push_button_close = QtWidgets.QPushButton("X") push_button_close.setObjectName(str(index)) push_button_close.setStyleSheet(self._stylesheet.stylesheet_button_additional("remove")) push_button_close.clicked.connect(self.click_push_button_delete) push_button_close.setMaximumWidth(30) push_button_close.setMinimumWidth(30) push_button_close.setMinimumHeight(30) horizontal_layout.addWidget(push_button_close) vertical_layout_1.addLayout(horizontal_layout) self._ui_object.verticalLayout_recent_open.addWidget(frame)
[docs] def click_push_button_open(self): """ Handle the click event of the push button to open a recent project. Retrieve the index of the clicked button and opens the corresponding recent project. """ if self._model.debug_mode: self._model.activity_logger.info("RecentOpen: click_push_button_open(), " "OnClick push button open project") sender = self.sender() push_button = self._ui_object.scrollArea_7.findChild(QtWidgets.QPushButton, sender.objectName()) index = push_button.objectName() if push_button: self.open_recent_image(int(index))
[docs] def click_push_button_delete(self): """ Handle the click event of the push button to delete a recent project. Retrieve the index of the clicked button and removes the corresponding recent project. """ if self._model.debug_mode: self._model.activity_logger.info("RecentOpen: click_push_button_delete(), " "OnClick push button delete project") sender = self.sender() push_button = self._ui_object.scrollArea_7.findChild(QtWidgets.QPushButton, sender.objectName()) index_button = push_button.objectName() if push_button: self.remove_recent_image(int(index_button)) self.process_open_directory()
[docs] def clear_item_layout(self): """ Clear the items from the layout. Remove all items from the recent projects layout in the user interface. """ if self._model.debug_mode: self._model.activity_logger.info("RecentOpen: clear_item_layout(), " "OnClick clear item project in user interface") while self._ui_object.verticalLayout_recent_open.count(): item = self._ui_object.verticalLayout_recent_open.takeAt(0) widget = item.widget() widget.deleteLater()
[docs] def open_image_from_directory(self, index): """ Open an image from the selected directory. If the image is already part of the recent projects, it opens that project. Otherwise, it sets the selected image as the main project, updates the model configuration accordingly, and displays the image in the user interface. Arg: index (int): The index of the selected image in the directory. Return: bool: True if the operation is successful, False otherwise. """ if self._model.debug_mode: self._model.activity_logger.info("RecentOpen: open_recent_image_directory(), " "Process open project image from directory image") status, index_recent, _ = self.detect_available_on_recent(str(self.directory_open_list[index])) if status: self.open_recent_image(index_recent) return True self._ui_object.checkBox_reverse_view.setChecked(False) if self.directory_open_list[index].endswith(('.mp4', '.MOV', '.avi')): parameter_name = self._model.select_parameter_name() else: parameter_name = self._model.read_camera_type(self.directory_open_list[index]) if parameter_name is None: parameter_name = self._model.select_parameter_name() if parameter_name is None: return False self._model.main_config["Media_path"] = self.directory_open_list[index] self._model.main_config["Cam_type"] = "opencv_usb_cam" self._model.main_config["Source_type"] = "Load Media" self._model.main_config["Parameter_name"] = parameter_name if os.path.exists(self._model.main_config["Media_path"]): self._controller.update_model_and_create_original_image(self._model.main_config["Source_type"], self._model.main_config["Cam_type"], self._model.main_config["Media_path"], self._model.main_config["Parameter_name"]) else: self._controller.ctrl_message_box.display_message_box(message="Image is not available, " "please check again! \n" f"{self._model.main_config['Media_path']}", type_mode="warning") return False self.add_list_recent_project_to_ui() return True
[docs] def open_recent_image(self, index): """ Open a recent project image. Arg: index (int): The index of the recent project to open. """ if self._model.debug_mode: self._model.activity_logger.info("RecentOpen: open_recent_image(), " "Process open recent project image") self._ui_object.checkBox_reverse_view.setChecked(False) config = self._model.model_config.load_json_file_project(self._model.recent_project_list[index]) self._model.model_config.update_main_config_from_recent(config) cam_type = config["Cam_type"] source_type = config["Source_type"] source_path = config["Media_path"] parameter_name = config["Parameter_name"] if os.path.exists(source_path): self._model.view_properties.rotate_degree = config["Rotate_result"] self._model.recenter_mode_view = config["Recenter_view"] self._model.mode_view = config["Recent_view"] self._model.active_view_mode = config["Active_view"] self._model.set_image_resize = False self._controller.timer.stop() self._controller.ctrl_stylesheet.reset_style(self._ui_object.btn_fisheye_view) self._controller.ctrl_stylesheet.reset_style(self._ui_object.btn_anypoint_view) self._controller.ctrl_stylesheet.reset_style(self._ui_object.btn_panorama_view) self._controller.update_model_and_create_original_image(source_type, cam_type, source_path, parameter_name) else: self._controller.ctrl_message_box.display_message_box(message="Image is not available, " "please check again! \n" f"{source_path}", type_mode="warning") self.add_list_recent_project_to_ui()
[docs] def remove_recent_image(self, index): """ Remove a recent project image. Arg: index (int): The index of the recent project to remove. """ if self._model.debug_mode: self._model.activity_logger.info("RecentOpen: remove_recent_image(), " "Process remove recent project image") config_name = self._model.recent_project_list[index] self._model.model_config.remove_json_file_project(config_name) self._model.model_config.read_recent_config_path() self.add_list_recent_project_to_ui() if index == 0 and len(self._model.recent_project_list) != 0: self.open_recent_image(0) if len(self._model.recent_project_list) == 0: self._controller.onclick_clear_user_interface() self._controller.onclick_button_setting_menu(1)