from datetime import datetime as dt from PyQt5.QtWidgets import ( QWidget, QPushButton, QMenuBar, QHBoxLayout, QVBoxLayout, QLabel, QDockWidget, QTabWidget, QProgressBar, QAction, QMainWindow, QGridLayout ) from PyQt5.QtGui import QIcon from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QSizePolicy as QSP from gui.settings_window import SystemSettings, OperatorSettings, FilterSettings from gui.report_gui import ReportSettings from base.base import PlotItems class StartWidget(QWidget): """ Виджет выбора режима работы приложения. Содержит кнопки для перехода в различные режимы: - Сканирование папки в реальном времени - Редактор отчётов - Обработка клиентских трейсов """ def __init__(self) -> None: super().__init__() self._build_main_layout() def get_widget(self) -> QWidget: """ Возвращает текущий виджет. """ return self def _build_main_layout(self) -> None: """ Строит макет виджета с заголовком и кнопками выбора режима. """ self.resize(800, 800) # Создаем кнопки для различных режимов работы self.btn_scanning = QPushButton("Real time folder scanning") self.btn_scanning.setFixedWidth(350) self.btn_report = QPushButton("Raport editor") self.btn_report.setFixedWidth(350) self.btn_client = QPushButton("Client trace processor") self.btn_client.setFixedWidth(350) # Размещение кнопок в горизонтальном макете button_layout = QHBoxLayout() button_layout.setSpacing(2) button_layout.addWidget(self.btn_scanning) button_layout.addWidget(self.btn_report) button_layout.addWidget(self.btn_client) button_container = QWidget() button_container.setLayout(button_layout) # Создаем основной вертикальный макет с заголовком и кнопками main_layout = QVBoxLayout() title_label = QLabel("Select work mode") title_label.setStyleSheet( """QLabel{ color: #ffffff; font-size: 40px; font-weight: bold; font-family: "Segoe UI", sans-serif; }""" ) main_layout.addWidget(title_label, alignment=Qt.AlignCenter) main_layout.addWidget(button_container) self.setLayout(main_layout) class CustomStatusBar(QWidget): """ Кастомный виджет для статус-бара, отображающий режим, заметку и прогресс. """ def __init__(self) -> None: super().__init__() self._build_status_bar() def get_widget(self) -> QWidget: """ Возвращает виджет статус-бара. """ return self def set_mode(self, msg: str = '') -> None: """ Устанавливает текст режима в статус-баре. :param msg: Сообщение для отображения. """ if not isinstance(msg, str): msg = str(msg) self._mode_label.setText(msg) self._mode_label.adjustSize() def set_note(self, msg: str = '') -> None: """ Устанавливает текст заметки в статус-баре. :param msg: Сообщение для отображения. """ if not isinstance(msg, str): msg = str(msg) self._note_label.setText(msg) self._note_label.adjustSize() def set_progress(self, percent: int = 0) -> None: """ Устанавливает значение прогресс-бара. :param percent: Значение прогресса (от 0 до 100). """ if not isinstance(percent, int): percent = 0 elif percent < 0: percent = 0 elif percent > 100: percent = 100 self._progress_bar.setValue(percent) def _build_status_bar(self) -> None: """ Создает и настраивает компоненты статус-бара. """ # Создаем горизонтальный макет с отступами и промежутками layout = QHBoxLayout() layout.setContentsMargins(10, 1, 10, 1) layout.setSpacing(15) # Инициализируем компоненты статус-бара self._mode_label = QLabel() self._note_label = QLabel() self._progress_bar = QProgressBar() self._progress_bar.setRange(0, 100) self._progress_bar.setValue(0) self._progress_bar.setMinimumWidth(250) self._progress_bar.setMaximumHeight(10) self._progress_bar.setTextVisible(False) # Устанавливаем политику размеров для компонентов self._mode_label.setSizePolicy(QSP.Policy.Preferred, QSP.Policy.Preferred) self._note_label.setSizePolicy(QSP.Policy.MinimumExpanding, QSP.Policy.Preferred) self._progress_bar.setSizePolicy(QSP.Policy.Fixed, QSP.Policy.Preferred) # Добавляем компоненты в макет layout.addWidget(self._progress_bar) layout.addWidget(self._note_label) layout.addStretch(1) layout.addWidget(self._mode_label) self.setLayout(layout) self.setSizePolicy(QSP.Policy.Expanding, QSP.Policy.Preferred) class CustomTabWidget(QTabWidget): """ Кастомный виджет-вкладка. Позволяет создавать вкладки с виджетом графика и закрывать их. """ def __init__(self): super().__init__() self._build_tab_widget() def get_widget(self) -> QWidget: """ Возвращает виджет. """ return self def _build_tab_widget(self) -> None: """ Настраивает виджет вкладок: включает возможность закрытия вкладок. """ self.setTabsClosable(True) self.tabCloseRequested.connect(self.close_tab) def create_tab(self, plot_widget: QWidget) -> None: """ Создает новую вкладку с виджетом графика. Извлекает из виджета необходимые данные, сохраняет их в свойствах вкладки. :param plot_widget: Виджет, содержащий график. """ # Извлекаем объект PlotItems, сохранённый в свойстве виджета plot_items: PlotItems = plot_widget.property("pyqt_container") new_tab = QWidget() new_tab.setProperty("reg_items", plot_items.regions) new_tab.setProperty("curve_items", plot_items.curves) new_tab.setProperty("qt_items", plot_items.qt_items) grid_layout = QGridLayout() grid_layout.addWidget(plot_widget) new_tab.setLayout(grid_layout) tab_label = "SF_trace_" + dt.now().strftime('%Y_%m_%d-%H_%M_%S') self.addTab(new_tab, tab_label) self.setCurrentWidget(new_tab) def close_tab(self, index: int) -> None: """ Закрывает вкладку по заданному индексу. :param index: Индекс вкладки для закрытия. """ if self.count() > index and index >= 0: self.removeTab(index) class CustomMenuBar(QMenuBar): """ Кастомное главное меню с док-виджетами для различных настроек. """ def __init__(self, operator_settings: OperatorSettings, system_settings: SystemSettings, report_settings: ReportSettings, filter_settings: FilterSettings) -> None: super().__init__() self._operator_settings = operator_settings self._system_settings = system_settings self._report_settings = report_settings self._filter_settings = filter_settings self._build_dock_widgets() self._build_menu() def get_widget(self) -> QWidget: """ Возвращает виджет меню. """ return self def setup(self, parent: QMainWindow) -> None: """ Добавляет док-виджеты и устанавливает главное меню для главного окна. :param parent: Главное окно приложения. """ parent.addDockWidget(Qt.RightDockWidgetArea, self._operator_dock) parent.addDockWidget(Qt.RightDockWidgetArea, self._system_dock) parent.addDockWidget(Qt.RightDockWidgetArea, self._report_dock) parent.addDockWidget(Qt.RightDockWidgetArea, self._filter_dock) parent.setMenuBar(self) def _build_dock_widgets(self) -> None: """ Инициализирует док-виджеты для настроек и скрывает их по умолчанию. """ # Док-виджет для настроек оператора self._operator_dock = QDockWidget("Operator Settings", self) self._operator_dock.setWidget(self._operator_settings) self._operator_dock.setObjectName("OperatorSettings") self._operator_dock.hide() # Док-виджет для системных настроек self._system_dock = QDockWidget("System Settings", self) self._system_dock.setWidget(self._system_settings) self._system_dock.setObjectName("SystemSettings") self._system_dock.hide() # Док-виджет для настроек представления отчёта self._report_dock = QDockWidget("View settings", self) self._report_dock.setWidget(self._report_settings) self._report_dock.setObjectName("ReportSettings") self._report_dock.hide() # Док-виджет для фильтр-настроек self._filter_dock = QDockWidget("Filter settings", self) self._filter_dock.setWidget(self._filter_settings) self._filter_dock.setObjectName("FilterSetting") self._filter_dock.hide() # Устанавливаем функциональные возможности для каждого док-виджета self._set_dock_features(self._operator_dock) self._set_dock_features(self._system_dock) self._set_dock_features(self._report_dock) self._set_dock_features(self._filter_dock) def _build_menu(self) -> None: """ Инициализирует элементы главного меню. """ # Создаем меню для выбора режима и настроек modes_menu = self.addMenu("Mode") settings_menu = self.addMenu("Settings") # Действия для переключения режимов self.action_scanning = QAction("Real time folder scanning", self) self.action_report = QAction("Raport editor", self) self.action_client = QAction("Client trace processor", self) # Действия для настроек system_settings_action = QAction("System settings", self) system_settings_action.setIcon(QIcon('resources/system_ico.png')) system_settings_action.triggered.connect(lambda: self._toggle_visibility(self._system_dock)) operator_settings_action = QAction("Operator settings", self) operator_settings_action.setIcon(QIcon('resources/operator_ico.png')) operator_settings_action.triggered.connect(lambda: self._toggle_visibility(self._operator_dock)) self.action_view_settings = QAction("View settings", self) self.action_view_settings.setIcon(QIcon('resources/view_ico.png')) self.action_view_settings.triggered.connect(lambda: self._toggle_visibility(self._report_dock)) self.action_filter_settings = QAction("Filter settings", self) self.action_filter_settings.triggered.connect(lambda: self._toggle_visibility(self._filter_dock)) # Добавляем действия в меню "Mode" modes_menu.addAction(self.action_scanning) modes_menu.addAction(self.action_report) modes_menu.addAction(self.action_client) # Добавляем действия в меню "Settings" settings_menu.addAction(system_settings_action) settings_menu.addAction(operator_settings_action) settings_menu.addAction(self.action_view_settings) settings_menu.addAction(self.action_filter_settings) def _toggle_visibility(self, dock: QDockWidget = None) -> None: """ Переключает видимость указанного док-виджета. :param dock: Док-виджет для переключения. """ if dock: is_visible = dock.isVisible() dock.setVisible(not is_visible) @staticmethod def _set_dock_features(dock: QDockWidget = None) -> None: """ Устанавливает возможность перемещения, закрытия и открепления для док-виджета. :param dock: Док-виджет для настройки. """ if dock: features = QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetFloatable dock.setFeatures(features) class RaportWidget(QWidget): """ Виджет для режима редактирования отчёта. Содержит вкладки и кнопки для сохранения состояния и открытия файла. """ def __init__(self, tab_widget: CustomTabWidget): super().__init__() self._tab_widget = tab_widget self._build_widget() def get_widget(self) -> QWidget: """ Возвращает виджет. """ return self def _build_widget(self) -> None: """ Строит макет виджета с вкладками и кнопками управления. """ main_layout = QVBoxLayout() self.btn_save_state = QPushButton("Save state") self.btn_save_state.setFixedWidth(185) self.btn_open_file = QPushButton("Open file") self.btn_open_file.setFixedWidth(185) button_layout = QHBoxLayout() button_layout.setSpacing(2) button_layout.addWidget(self.btn_save_state) button_layout.addWidget(self.btn_open_file) button_container = QWidget() button_container.setLayout(button_layout) main_layout.addWidget(self._tab_widget) main_layout.addWidget(button_container) self.setLayout(main_layout) class SeekingWidget(QWidget): """ Виджет для режима поиска (сканирования папок). """ def __init__(self, tab_widget: CustomTabWidget): super().__init__() self._tab_widget = tab_widget self._build_widget() def get_widget(self) -> QWidget: """ Возвращает виджет. """ return self def _build_widget(self) -> None: """ Создает макет виджета с вкладками. """ main_layout = QVBoxLayout() button_layout = QHBoxLayout() button_layout.setSpacing(2) button_container = QWidget() button_container.setLayout(button_layout) main_layout.addWidget(self._tab_widget) main_layout.addWidget(button_container) self.setLayout(main_layout) class ClientAnalyzerWidget(QWidget): """ Виджет для клиентского анализа трассировки. Содержит вкладки и кнопки для сохранения состояния, открытия папки и расчёта TCW. """ def __init__(self, tab_widget: CustomTabWidget): super().__init__() self._tab_widget = tab_widget self._build_widget() def get_widget(self) -> QWidget: """ Возвращает виджет. """ return self def _build_widget(self) -> None: """ Строит макет виджета с вкладками и управляющими кнопками. """ main_layout = QVBoxLayout() self.btn_save_state = QPushButton("Save state") self.btn_save_state.setFixedWidth(185) self.btn_open_folder = QPushButton("Open folder") self.btn_open_folder.setFixedWidth(185) self.btn_calc_tcw = QPushButton("Calculate TCW") self.btn_calc_tcw.setFixedWidth(185) button_layout = QHBoxLayout() button_layout.setSpacing(2) button_layout.addWidget(self.btn_save_state) button_layout.addWidget(self.btn_open_folder) button_layout.addWidget(self.btn_calc_tcw) button_container = QWidget() button_container.setLayout(button_layout) main_layout.addWidget(self._tab_widget) main_layout.addWidget(button_container) self.setLayout(main_layout)