diff --git a/src/petab_gui/controllers/mother_controller.py b/src/petab_gui/controllers/mother_controller.py index 9124e77..4cb6dd7 100644 --- a/src/petab_gui/controllers/mother_controller.py +++ b/src/petab_gui/controllers/mother_controller.py @@ -19,7 +19,7 @@ ConditionController, ParameterController from .logger_controller import LoggerController from ..views import TaskBar -from .utils import prompt_overwrite_or_append +from .utils import prompt_overwrite_or_append, RecentFilesManager from functools import partial @@ -83,6 +83,8 @@ def __init__(self, view, model: PEtabModel): self.condition_controller, self.sbml_controller ] + # Recent Files + self.recent_files_manager = RecentFilesManager(max_files=10) # Checkbox states for Find + Replace self.petab_checkbox_states = { "measurement": False, @@ -180,6 +182,10 @@ def setup_connections(self): self.view.plot_dock.visibilityChanged.connect( lambda visible: self.actions["show_plot"].setChecked(visible) ) + # Recent Files + self.recent_files_manager.open_file.connect( + partial(self.open_file, mode="overwrite") + ) def setup_actions(self): """Setup actions for the main controller.""" @@ -265,6 +271,8 @@ def setup_actions(self): actions["reset_model"].triggered.connect( self.sbml_controller.reset_to_original_model ) + # Recent Files + actions["recent_files"] = self.recent_files_manager.tool_bar_menu # Filter widget filter_widget = QWidget() @@ -470,6 +478,7 @@ def open_file(self, file_path=None, mode=None): mode = prompt_overwrite_or_append(self) if mode is None: return + self.recent_files_manager.add_file(file_path) self._open_file(actionable, file_path, sep, mode) def _open_file(self, actionable, file_path, sep, mode): diff --git a/src/petab_gui/controllers/utils.py b/src/petab_gui/controllers/utils.py index 4745e15..a9f2500 100644 --- a/src/petab_gui/controllers/utils.py +++ b/src/petab_gui/controllers/utils.py @@ -1,4 +1,6 @@ -from PySide6.QtWidgets import QMessageBox +from PySide6.QtWidgets import QMessageBox, QMenu +from PySide6.QtCore import QObject, Signal, QSettings +from PySide6.QtGui import QAction def prompt_overwrite_or_append(controller): @@ -17,4 +19,52 @@ def prompt_overwrite_or_append(controller): elif msg_box.clickedButton() == overwrite_button: return "overwrite" elif msg_box.clickedButton() == append_button: - return "append" \ No newline at end of file + return "append" + + +class RecentFilesManager(QObject): + """Manage a list of recent files.""" + open_file = Signal(str) # Signal to open a file + + def __init__(self, max_files=10): + super().__init__() + self.max_files = max_files + # TODO: link together with other settings, i.e. move settings to mc + self.settings = QSettings("PEtab_GUI", "PEtab_GUI") + self.recent_files = self.load_recent_files() + self.tool_bar_menu = QMenu("Recent Files") + self.update_tool_bar_menu() + + def add_file(self, file_path): + """Add a file to the recent files list.""" + if file_path in self.recent_files: + self.recent_files.remove(file_path) + self.recent_files.insert(0, file_path) + self.recent_files = self.recent_files[:self.max_files] + self.save_recent_files() + self.update_tool_bar_menu() + + def load_recent_files(self): + """Load recent files from settings.""" + return self.settings.value("recent_files", []) + + def save_recent_files(self): + """Save recent files to settings.""" + self.settings.setValue("recent_files", self.recent_files) + + def update_tool_bar_menu(self): + """Create a menu for the tool bar.""" + self.tool_bar_menu.clear() + for idx, file_path in enumerate(self.recent_files): + action = QAction(file_path, self.tool_bar_menu) + action.triggered.connect(lambda: self.open_file.emit(file_path)) + self.tool_bar_menu.addAction(action) + self.tool_bar_menu.addSeparator() + clear_action = QAction("Clear Recent Files", self.tool_bar_menu) + clear_action.triggered.connect(self.clear_recent_files) + + def clear_recent_files(self): + """Clear the recent files list.""" + self.recent_files = [] + self.save_recent_files() + self.update_tool_bar_menu() diff --git a/src/petab_gui/utils.py b/src/petab_gui/utils.py index 0c9f031..5b1b344 100644 --- a/src/petab_gui/utils.py +++ b/src/petab_gui/utils.py @@ -10,7 +10,6 @@ from .C import ROW, COLUMN, INDEX import antimony import os -import numpy as np import math @@ -24,6 +23,7 @@ def _checkAntimonyReturnCode(code): if code < 0: raise Exception('Antimony: {}'.format(antimony.getLastError())) + def sbmlToAntimony(sbml): """ Convert SBML to antimony string. @@ -46,6 +46,7 @@ def sbmlToAntimony(sbml): _checkAntimonyReturnCode(code) return antimony.getAntimonyString(None) + def antimonyToSBML(ant): """ Convert Antimony to SBML string. diff --git a/src/petab_gui/views/task_bar.py b/src/petab_gui/views/task_bar.py index adb0a87..fb96bcd 100644 --- a/src/petab_gui/views/task_bar.py +++ b/src/petab_gui/views/task_bar.py @@ -49,6 +49,7 @@ def __init__(self, parent, actions): self.menu.addAction(actions["open"]) self.menu.addAction(actions["add"]) self.menu.addAction(actions["save"]) + self.menu.addMenu(actions["recent_files"]) self.menu.addSeparator() self.menu.addAction(actions["close"])