diff --git a/b_asic/GUI/gui_interface.py b/b_asic/GUI/gui_interface.py index ba60e736047e327b3969d8571d8ee9df4d7da968..d7f19149a65751edad231e38109401aee354f943 100644 --- a/b_asic/GUI/gui_interface.py +++ b/b_asic/GUI/gui_interface.py @@ -1,13 +1,7 @@ # -*- coding: utf-8 -*- +# Originally generated from QT designer, but now manually maintained -# Form implementation generated from reading ui file 'gui_interface.ui' -# -# Created by: PyQt5 UI code generator 5.14.2 -# -# WARNING! All changes made in this file will be lost! - - -from qtpy import QtCore, QtGui, QtWidgets +from qtpy import QtCore, QtWidgets class Ui_main_window(object): diff --git a/b_asic/GUI/main_window.py b/b_asic/GUI/main_window.py index 501201465ce236f4668fdef7651279feae5968e2..bc1bee7e4f7738a389959a98ee169f6d2686247d 100644 --- a/b_asic/GUI/main_window.py +++ b/b_asic/GUI/main_window.py @@ -333,8 +333,8 @@ class MainWindow(QMainWindow): if dequelen > 0: for i in range(dequelen): action = self.recentFilesList[i] - action.setText(rfp[i].fileName()) - action.setData(rfp[i]) + action.setText(rfp[i]) + action.setData(QFileInfo(rfp[i])) action.setVisible(True) for i in range(dequelen, self.maxFileNr): @@ -348,13 +348,12 @@ class MainWindow(QMainWindow): rfp = settings.value("SFG/recentFiles") - recentFile = QFileInfo(module) if rfp: - if recentFile not in rfp: - rfp.append(recentFile) + if module not in rfp: + rfp.append(module) else: rfp = deque(maxlen=self.maxFileNr) - rfp.append(recentFile) + rfp.append(module) settings.setValue("SFG/recentFiles", rfp) diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py index 28c6e5507154b42270a21e4656cf75d00d51c173..7778d7b62f9c64ed6b2b9842616f5e68ff739751 100644 --- a/b_asic/scheduler_gui/main_window.py +++ b/b_asic/scheduler_gui/main_window.py @@ -11,6 +11,7 @@ import inspect import os import sys import webbrowser +from collections import deque from copy import deepcopy from importlib.machinery import SourceFileLoader from typing import Optional, Union, cast @@ -22,6 +23,7 @@ import qtpy from qtpy.QtCore import ( QByteArray, QCoreApplication, + QFileInfo, QRectF, QSettings, QStandardPaths, @@ -31,6 +33,7 @@ from qtpy.QtCore import ( from qtpy.QtGui import QCloseEvent from qtpy.QtWidgets import ( QAbstractButton, + QAction, QApplication, QCheckBox, QFileDialog, @@ -85,10 +88,8 @@ if __debug__: # The following QCoreApplication values is used for QSettings among others QCoreApplication.setOrganizationName("Linköping University") QCoreApplication.setOrganizationDomain("liu.se") -QCoreApplication.setApplicationName("B-ASIC Scheduler") -QCoreApplication.setApplicationVersion( - __version__ -) # TODO: read from packet __version__ +QCoreApplication.setApplicationName("B-ASIC Scheduling GUI") +QCoreApplication.setApplicationVersion(__version__) class MainWindow(QMainWindow, Ui_MainWindow): @@ -129,7 +130,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.menu_node_info.triggered.connect(self.show_info_table) self.menu_exit_dialog.triggered.connect(self.hide_exit_dialog) self.actionReorder.triggered.connect(self._actionReorder) - self.actionT.triggered.connect(self._actionTbtn) + self.actionPlot_schedule.triggered.connect(self._actionTbtn) self.splitter.splitterMoved.connect(self._splitter_moved) self.actionDocumentation.triggered.connect(self._open_documentation) self.actionAbout.triggered.connect(self._open_about_window) @@ -148,6 +149,12 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.splitter.setCollapsible(0, False) self.splitter.setCollapsible(1, True) + # Recent files + self.maxFileNr = 4 + self.recentFilesList = [] + self.recentFilePaths = deque(maxlen=self.maxFileNr) + self.createActionsAndMenus() + def _init_graphics(self) -> None: """Initialize the QGraphics framework""" self._scene = QGraphicsScene() @@ -217,15 +224,19 @@ class MainWindow(QMainWindow, Ui_MainWindow): QStandardPaths.HomeLocation )[0] - abs_path_filename, _ = QFileDialog.getOpenFileName( + abs_path_filename, accepted = QFileDialog.getOpenFileName( self, self.tr("Open python file"), last_file, self.tr("Python Files (*.py *.py3)"), ) - if not abs_path_filename: # return if empty filename (QFileDialog was canceled) + if not abs_path_filename or not accepted: return + + self._load_from_file(abs_path_filename) + + def _load_from_file(self, abs_path_filename): log.debug("abs_path_filename = {}.".format(abs_path_filename)) module_name = inspect.getmodulename(abs_path_filename) @@ -242,6 +253,8 @@ class MainWindow(QMainWindow, Ui_MainWindow): ) return + self.addRecentFile(abs_path_filename) + schedule_obj_list = dict( inspect.getmembers(module, (lambda x: isinstance(x, Schedule))) ) @@ -285,6 +298,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.open(schedule) del module + settings = QSettings() settings.setValue("scheduler/last_opened_file", abs_path_filename) @Slot() @@ -630,6 +644,55 @@ class MainWindow(QMainWindow, Ui_MainWindow): else: log.error("'Operator' not found in info table. It may have been renamed.") + def createActionsAndMenus(self): + for i in range(self.maxFileNr): + recentFileAction = QAction(self.menu_Recent_Schedule) + recentFileAction.setVisible(False) + recentFileAction.triggered.connect( + lambda b=0, x=recentFileAction: self.openRecent(x) + ) + self.recentFilesList.append(recentFileAction) + self.menu_Recent_Schedule.addAction(recentFileAction) + + self.updateRecentActionList() + + def updateRecentActionList(self): + settings = QSettings() + + rfp = settings.value("scheduler/recentFiles") + + # print(rfp) + if rfp: + dequelen = len(rfp) + if dequelen > 0: + for i in range(dequelen): + action = self.recentFilesList[i] + action.setText(rfp[i]) + action.setData(QFileInfo(rfp[i])) + action.setVisible(True) + + for i in range(dequelen, self.maxFileNr): + self.recentFilesList[i].setVisible(False) + + def openRecent(self, action): + self._load_from_file(action.data().filePath()) + + def addRecentFile(self, module): + settings = QSettings() + + rfp = settings.value("scheduler/recentFiles") + + if rfp: + if module not in rfp: + rfp.append(module) + else: + rfp = deque(maxlen=self.maxFileNr) + rfp.append(module) + + settings.setValue("scheduler/recentFiles", rfp) + + self.updateRecentActionList() + def start_gui() -> None: app = QApplication(sys.argv) diff --git a/b_asic/scheduler_gui/main_window.ui b/b_asic/scheduler_gui/main_window.ui index 539d3281f3904e94a6988b4b0a6c56904ac849a9..a5ae4d2c160d4aac9e82ec1dd934a1de6456f23a 100644 --- a/b_asic/scheduler_gui/main_window.ui +++ b/b_asic/scheduler_gui/main_window.ui @@ -209,11 +209,18 @@ <property name="title"> <string>&File</string> </property> + <widget class="QMenu" name="menu_Recent_Schedule"> + <property name="title"> + <string>&Recent Schedule</string> + </property> + </widget> <addaction name="menu_load_from_file"/> <addaction name="menu_close_schedule"/> <addaction name="menu_save"/> <addaction name="menu_save_as"/> <addaction name="separator"/> + <addaction name="menu_Recent_Schedule"/> + <addaction name="separator"/> <addaction name="menu_quit"/> </widget> <widget class="QMenu" name="menuView"> @@ -221,6 +228,8 @@ <string>&View</string> </property> <addaction name="menu_node_info"/> + <addaction name="separator"/> + <addaction name="actionPlot_schedule"/> </widget> <widget class="QMenu" name="menu_Edit"> <property name="title"> @@ -263,7 +272,6 @@ <addaction name="menu_save_as"/> <addaction name="separator"/> <addaction name="menu_node_info"/> - <addaction name="actionT"/> <addaction name="actionReorder"/> </widget> <action name="menu_load_from_file"> @@ -401,6 +409,11 @@ <string>Reorder schedule based on start time</string> </property> </action> + <action name="actionPlot_schedule"> + <property name="text"> + <string>Plot schedule</string> + </property> + </action> </widget> <resources/> <connections/> diff --git a/b_asic/scheduler_gui/ui_main_window.py b/b_asic/scheduler_gui/ui_main_window.py index f42657c3d7b4f2066c3d72e06c4e76096c8ae22f..a5e1cb743815c613b2440d27929a4a0e72272dcc 100644 --- a/b_asic/scheduler_gui/ui_main_window.py +++ b/b_asic/scheduler_gui/ui_main_window.py @@ -20,9 +20,7 @@ class Ui_MainWindow(object): ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth( - MainWindow.sizePolicy().hasHeightForWidth() - ) + sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) MainWindow.setSizePolicy(sizePolicy) icon = QtGui.QIcon() icon.addPixmap( @@ -57,21 +55,15 @@ class Ui_MainWindow(object): self.view.setRenderHints( QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing ) - self.view.setViewportUpdateMode( - QtWidgets.QGraphicsView.FullViewportUpdate - ) + self.view.setViewportUpdateMode(QtWidgets.QGraphicsView.FullViewportUpdate) self.view.setObjectName("view") self.info_table = QtWidgets.QTableWidget(self.splitter) self.info_table.setStyleSheet( "alternate-background-color: #fadefb;background-color: #ebebeb;" ) - self.info_table.setEditTriggers( - QtWidgets.QAbstractItemView.NoEditTriggers - ) + self.info_table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) self.info_table.setAlternatingRowColors(True) - self.info_table.setSelectionBehavior( - QtWidgets.QAbstractItemView.SelectRows - ) + self.info_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) self.info_table.setRowCount(2) self.info_table.setColumnCount(2) self.info_table.setObjectName("info_table") @@ -139,6 +131,8 @@ class Ui_MainWindow(object): self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") + self.menu_Recent_Schedule = QtWidgets.QMenu(self.menuFile) + self.menu_Recent_Schedule.setObjectName("menu_Recent_Schedule") self.menuView = QtWidgets.QMenu(self.menubar) self.menuView.setObjectName("menuView") self.menu_Edit = QtWidgets.QMenu(self.menubar) @@ -208,13 +202,19 @@ class Ui_MainWindow(object): self.actionDocumentation.setObjectName("actionDocumentation") self.actionReorder = QtWidgets.QAction(MainWindow) self.actionReorder.setObjectName("actionReorder") + self.actionPlot_schedule = QtWidgets.QAction(MainWindow) + self.actionPlot_schedule.setObjectName("actionPlot_schedule") self.menuFile.addAction(self.menu_load_from_file) self.menuFile.addAction(self.menu_close_schedule) self.menuFile.addAction(self.menu_save) self.menuFile.addAction(self.menu_save_as) self.menuFile.addSeparator() + self.menuFile.addAction(self.menu_Recent_Schedule.menuAction()) + self.menuFile.addSeparator() self.menuFile.addAction(self.menu_quit) self.menuView.addAction(self.menu_node_info) + self.menuView.addSeparator() + self.menuView.addAction(self.actionPlot_schedule) self.menuWindow.addAction(self.menu_exit_dialog) self.menuHelp.addAction(self.actionDocumentation) self.menuHelp.addSeparator() @@ -229,7 +229,6 @@ class Ui_MainWindow(object): self.toolBar.addAction(self.menu_save_as) self.toolBar.addSeparator() self.toolBar.addAction(self.menu_node_info) - self.toolBar.addAction(self.actionT) self.toolBar.addAction(self.actionReorder) self.retranslateUi(MainWindow) @@ -253,6 +252,7 @@ class Ui_MainWindow(object): item.setText(_translate("MainWindow", "Operator")) self.info_table.setSortingEnabled(__sortingEnabled) self.menuFile.setTitle(_translate("MainWindow", "&File")) + self.menu_Recent_Schedule.setTitle(_translate("MainWindow", "&Recent Schedule")) self.menuView.setTitle(_translate("MainWindow", "&View")) self.menu_Edit.setTitle(_translate("MainWindow", "&Edit")) self.menuWindow.setTitle(_translate("MainWindow", "&Window")) @@ -264,9 +264,7 @@ class Ui_MainWindow(object): self.menu_load_from_file.setToolTip( _translate("MainWindow", "Load schedule from python script") ) - self.menu_load_from_file.setShortcut( - _translate("MainWindow", "Ctrl+O") - ) + self.menu_load_from_file.setShortcut(_translate("MainWindow", "Ctrl+O")) self.menu_save.setText(_translate("MainWindow", "&Save")) self.menu_save.setToolTip(_translate("MainWindow", "Save schedule")) self.menu_save.setShortcut(_translate("MainWindow", "Ctrl+S")) @@ -278,21 +276,14 @@ class Ui_MainWindow(object): self.menu_quit.setText(_translate("MainWindow", "&Quit")) self.menu_quit.setShortcut(_translate("MainWindow", "Ctrl+Q")) self.menu_save_as.setText(_translate("MainWindow", "Save &As...")) - self.menu_exit_dialog.setText( - _translate("MainWindow", "&Hide exit dialog") - ) - self.menu_exit_dialog.setToolTip( - _translate("MainWindow", "Hide exit dialog") - ) + self.menu_exit_dialog.setText(_translate("MainWindow", "&Hide exit dialog")) + self.menu_exit_dialog.setToolTip(_translate("MainWindow", "Hide exit dialog")) self.actionT.setText(_translate("MainWindow", "T")) - self.menu_close_schedule.setText( - _translate("MainWindow", "&Close Schedule") - ) + self.menu_close_schedule.setText(_translate("MainWindow", "&Close Schedule")) self.actionAbout.setText(_translate("MainWindow", "About")) - self.actionDocumentation.setText( - _translate("MainWindow", "Documentation") - ) + self.actionDocumentation.setText(_translate("MainWindow", "Documentation")) self.actionReorder.setText(_translate("MainWindow", "Reorder")) self.actionReorder.setToolTip( _translate("MainWindow", "Reorder schedule based on start time") ) + self.actionPlot_schedule.setText(_translate("MainWindow", "Plot schedule"))