/
Flipper
/
Marginal
Обзор
Документация
Войти
/
Flipper
/
Marginal
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
1
CI/CD
Аналитика
Безопасность
master
src/UI/MainWindow.py
422 строки
13 KB
Alex
Bug fixes.
12 янв 2026, 13:17
12 янв 2026, 13:17
e907759
Код
Авторство
О чём код?
import os from src.utils import getBasePath, openFolder from .CustomUI.DragNDropArea import DragDropArea as DragNDropArea from .CustomUI.LineDirSelector import FolderLineEdit as LineDirSelector from PySide6.QtWidgets import ( QMainWindow, QLabel, QVBoxLayout, QWidget, QPushButton, QTextEdit, QLineEdit, QCheckBox, QComboBox, QHBoxLayout, QMenuBar ) from PySide6.QtCore import Qt from PySide6.QtGui import QIcon class MainWindow(QMainWindow): """ Main application window for Marginal. Provides UI for file selection, configuration, and running calculations. Includes drag-and-drop file areas, export settings, and logging output. """ def __init__(self, parent): """ Initialize MainWindow with parent UIManager. Args: parent (UIManager): Parent UI manager instance. """ super().__init__() self.parent = parent self.backbone = self.parent.backbone self.translate = self.backbone.translator.translate self.config = None # File extension support and configuration defaults self.supportedOutputExtensions = [".xlsx", ".csv"] self.outputExtension = str() self.exportPath = str() self.inputDataSearchFolder = str() self.profilesSearchFolder = str() self.exportSearchFolder = str() # UI state flags self.stayOnTop = False self.openOnFinish = True self.flagCalcLog = False self.validFilename = True # Initialize configuration and UI self.useConfig() self.initWindow() self.initUI() def initWindow(self): """ Set up main window properties (title, icon, size). Returns: None """ self.setWindowTitle("Marginal") self.setWindowIcon(QIcon(":/resources/sprites/Icon_small.png")) self.setGeometry(100, 100, 600, 600) self.setFixedSize(600, 600) def initUI(self): """ Initialize all UI components and their layout. Returns: None """ self.setUpCentralWidget() self.setUpMenuBar() self.setUpDragNDrop() self.setUpExportPathInput() self.setUpFilenameInput() self.setUpFileExtensionDropDown() self.setUpLogOutput() self.setUpCheckBoxes() self.setUpButtons() def useConfig(self, config: dict = None): """ Load and apply configuration settings. Args: config (dict, optional): Configuration dictionary. If None, loads from backbone config manager. Returns: None """ if config is not None: self.config = config else: self.config = self.backbone.getConfig("exportOptions") # Extract and store configuration values self.exportPath = os.path.join(getBasePath(), self.config["exportPath"]) self.outputExtension = self.config["extension"] self.profilesSearchFolder = os.path.join(getBasePath(), self.config["profileSearchFolder"]) self.inputDataSearchFolder = os.path.join(getBasePath(), self.config["inputDataSearchFolder"]) self.exportSearchFolder = os.path.join(getBasePath(), self.config["exportSearchPath"]) self.flagCalcLog = self.config["createCalcLog"] self.openOnFinish = self.config["openOnFinish"] def pushConfig(self): """ Push current configuration values to UI components. Returns: None """ # Update drag-and-drop area default directories self.inputDataDND.defaultDir = self.inputDataSearchFolder self.profileDataDND.defaultDir = self.profilesSearchFolder # Update export path input self.exportPathInput.setText(self.exportPath) self.exportPathInput.defaultDir = self.exportSearchFolder # Update file extension dropdown self.fileExtensionDropdown.setCurrentIndex( self.fileExtensionDropdown.findText(self.outputExtension) ) # Update checkbox states self.makeCalcLogCB.setChecked(self.flagCalcLog) self.openOnFinishCB.setChecked(self.openOnFinish) def setUpCentralWidget(self): """ Set up the central widget and main layout. Returns: None """ self.centralWidget = QWidget() self.setCentralWidget(self.centralWidget) self.mainLayout = QVBoxLayout() self.centralWidget.setLayout(self.mainLayout) def setUpMenuBar(self): """ Create the menu bar with File, Tools, and Help menus. Returns: None """ self.menuBar = QMenuBar(self) # File menu self.fileMenu = self.menuBar.addMenu(self.translate("File")) self.settingsAction = self.fileMenu.addAction(self.translate("Settings")) self.settingsAction.triggered.connect(self.parent.openSettings) self.openOutputFolderAction = self.fileMenu.addAction(self.translate("Go to exports")) self.openOutputFolderAction.triggered.connect(self.openExportsFolder) self.clearAction = self.fileMenu.addAction(self.translate("Clear sources")) self.clearAction.triggered.connect(self.clearSources) self.exitAction = self.fileMenu.addAction(self.translate("Exit")) self.exitAction.triggered.connect(self.parent.quit) # Tools menu self.toolMenu = self.menuBar.addMenu(self.translate("Tools")) self.stayOnTopAction = self.toolMenu.addAction(self.translate("Stay On Top")) self.stayOnTopAction.setCheckable(True) self.stayOnTopAction.triggered.connect(self.toggleStayOnTop) # Debug submenu self.debugToolsMenu = self.toolMenu.addMenu(self.translate("Debug")) self.openLogsDirectory = self.debugToolsMenu.addAction(self.translate("Open logs folder")) self.openLogsDirectory.triggered.connect( lambda: openFolder("logs") if self.backbone.getAccess() else None ) self.deleteLogsAction = self.debugToolsMenu.addAction(self.translate("Delete logs")) self.deleteLogsAction.triggered.connect(self.parent.cullLogs) # Help menu self.helpMenu = self.menuBar.addMenu(self.translate("Help")) self.aboutAction = self.helpMenu.addAction(self.translate("About")) self.aboutAction.triggered.connect(self.parent.openAbout) self.setMenuBar(self.menuBar) def setUpDragNDrop(self): """ Set up drag-and-drop areas for input data and profile files. Returns: None """ # Experimental data drag-and-drop area (Excel files) self.inputDataDND = DragNDropArea(f"{self.translate('Experimental Data')}\n.xlsx") self.inputDataDND.setFilter( acceptedExtensions=[".xlsx", ".xls"], filterName="Excel Files" ) self.inputDataDND.defaultDir = self.inputDataSearchFolder self.inputDataDND.translateFunc = self.translate # Profile data drag-and-drop area (JSON files) self.profileDataDND = DragNDropArea(f"{self.translate('Profile')}.json") self.profileDataDND.setFilter( acceptedExtensions=".json", filterName="Profile Files" ) self.profileDataDND.defaultDir = self.profilesSearchFolder self.profileDataDND.translateFunc = self.translate # Arrange drag-and-drop areas side by side fileLayout = QHBoxLayout() fileLayout.addWidget(self.inputDataDND) fileLayout.addWidget(self.profileDataDND) self.mainLayout.addLayout(fileLayout) def setUpExportPathInput(self): """ Set up export path selection input with directory browser. Returns: None """ self.exportPathInput = LineDirSelector() self.exportPathInput.setTranslatorFunc(self.translate) self.exportPathInput.setText(self.exportPath) self.exportPathInput.textChanged.connect(self.exportPathInput.onTextChanged) self.exportPathInput.defaultDir = self.exportSearchFolder self.mainLayout.addWidget(QLabel(self.translate("Export path"))) self.mainLayout.addWidget(self.exportPathInput) def setUpFilenameInput(self): """ Set up filename input field with validation. Returns: None """ self.filenameInput = QLineEdit() self.filenameInput.setPlaceholderText( self.translate("Type in file name or leave empty for default option") ) self.filenameInput.textChanged.connect(self.checkFilename) fileNameLayout = QHBoxLayout() fileNameLayout.addWidget(QLabel(self.translate("File name"))) fileNameLayout.addWidget(self.filenameInput) self.mainLayout.addLayout(fileNameLayout) self.filenameInput.setFocus() # Start with focus on filename input def setUpFileExtensionDropDown(self): """ Set up file extension selection dropdown. Returns: None """ self.fileExtensionDropdown = QComboBox() self.fileExtensionDropdown.addItems(self.supportedOutputExtensions) self.fileExtensionDropdown.setCurrentIndex( self.fileExtensionDropdown.findText(self.outputExtension) ) extensionLayout = QHBoxLayout() extensionLayout.addWidget(QLabel(self.translate("Extension"))) extensionLayout.addWidget(self.fileExtensionDropdown) self.mainLayout.addLayout(extensionLayout) def setUpLogOutput(self): """ Set up log output text area. Returns: None """ self.logOutput = QTextEdit() self.logOutput.setReadOnly(True) self.logOutput.setText( "-------------------------------------------[ Marginal ©2025 ]----------------------------------------------" ) self.mainLayout.addWidget(self.logOutput) def setUpCheckBoxes(self): """ Set up option checkboxes. Returns: None """ self.makeCalcLogCB = QCheckBox(self.translate("Create calculations log")) self.makeCalcLogCB.setChecked(self.flagCalcLog) self.openOnFinishCB = QCheckBox(self.translate("Open on finish")) self.openOnFinishCB.setChecked(self.openOnFinish) self.mainLayout.addWidget(self.makeCalcLogCB) self.mainLayout.addWidget(self.openOnFinishCB) def setUpButtons(self): """ Set up action buttons (run calculation). Returns: None """ self.runButton = QPushButton(self.translate("Run")) self.mainLayout.addWidget(self.runButton) self.runButton.clicked.connect(self.runCalculations) def consoleWrite(self, message: str): """ Write a message to the console/log output area. Args: message (str): Message to display. Returns: None """ self.logOutput.append(f"{message}") def runCalculations(self): """ Collect UI inputs and trigger calculation via parent UIManager. Returns: None """ filename = self.filenameInput.text() if self.validFilename else None exportMode = self.fileExtensionDropdown.currentText() self.parent.handleRunCalculation( self.inputDataDND.filePath, self.profileDataDND.filePath, self.exportPathInput.text(), exportMode, self.makeCalcLogCB.isChecked(), filename, self.openOnFinishCB.isChecked() ) def toggleStayOnTop(self): """ Toggle window stay-on-top flag. Returns: None """ self.stayOnTop = not self.stayOnTop self.setWindowFlags(self.windowFlags() ^ Qt.WindowStaysOnTopHint) self.show() def checkFilename(self): """ Validate filename input and update visual feedback. Returns: None """ if self.backbone.validator.validateFilename(self.filenameInput.text()): self.filenameInput.setStyleSheet("") self.validFilename = True else: self.filenameInput.setStyleSheet( "border: 2px solid red; background-color: #DC758D;" ) self.validFilename = False def clearSources(self): """ Clear selected files from drag-and-drop areas. Returns: None """ self.inputDataDND.clear() self.profileDataDND.clear() def openExportsFolder(self): """ Open the exports folder in system file explorer. Returns: None """ if self.exportPathInput.validPath or self.exportPathInput.lastValidPath is not None: openFolder(self.exportPathInput.getFolder()) def updateConfig(self): """ Update UI configuration from backbone and push to components. Returns: None """ self.useConfig() self.pushConfig() def retranslateUI(self): """ Retranslate all UI text after language change. Returns: None """ self.initUI() def setRunControlsEnabled(self, state: bool): """ Enable or disable run controls (during calculation). Args: state (bool): True to enable, False to disable. Returns: None """ self.runButton.setEnabled(state)