diff --git a/README.md b/README.md index a182d35..203c8d3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![PyPI - Version](https://badge.fury.io/py/PEtab-GUI.svg)](pypi.org/project/PEtab-GUI/) +[![PyPI - Version](https://badge.fury.io/py/PEtab-GUI.svg)](https://pypi.org/project/PEtab-GUI/) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15355753.svg)](https://doi.org/10.5281/zenodo.15355753) # PEtabGUI diff --git a/pyproject.toml b/pyproject.toml index 18ec992..f5a9423 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,8 @@ dependencies = [ "petab[combine]>=0.6.0", "qtawesome", "copasi-basico", - "copasi-petab-importer" + "copasi-petab-importer", + "pyobjc; sys_platform == 'darwin'" ] license-files = ["LICENSE"] diff --git a/src/petab_gui/C.py b/src/petab_gui/C.py index 01ebaec..09e43f3 100644 --- a/src/petab_gui/C.py +++ b/src/petab_gui/C.py @@ -2,6 +2,11 @@ import numpy as np +#: Application name +APP_NAME = "PEtabGUI" +#: Base URL of the repository +REPO_URL = "https://github.com/PaulJonasJost/PEtab_GUI" + COLUMNS = { "measurement": { "observableId": {"type": np.object_, "optional": False}, diff --git a/src/petab_gui/app.py b/src/petab_gui/app.py index 9d18fd2..15340ee 100644 --- a/src/petab_gui/app.py +++ b/src/petab_gui/app.py @@ -9,6 +9,7 @@ from PySide6.QtGui import QFileOpenEvent, QIcon from PySide6.QtWidgets import QApplication +from .C import APP_NAME from .controllers import MainController from .models import PEtabModel from .views import MainWindow @@ -59,6 +60,7 @@ def __init__(self, file: str | Path = None): """ super().__init__(sys.argv) + self.setApplicationName(APP_NAME) self.setWindowIcon(get_icon()) self.model = PEtabModel() self.view = MainWindow() @@ -120,7 +122,7 @@ def main(): except PackageNotFoundError: pkg_version = "unknown" - parser = argparse.ArgumentParser(description="PEtabGUI: A PEtab editor") + parser = argparse.ArgumentParser(description=f"{APP_NAME}: A PEtab editor") parser.add_argument( "--version", action="version", @@ -132,6 +134,13 @@ def main(): ) args = parser.parse_args() + if sys.platform == "darwin": + from Foundation import NSBundle # type: type: ignore[import] + + bundle = NSBundle.mainBundle() + info = bundle.localizedInfoDictionary() or bundle.infoDictionary() + info["CFBundleName"] = APP_NAME + app = PEtabGuiApp(args.petab_yaml) sys.exit(app.exec()) diff --git a/src/petab_gui/controllers/mother_controller.py b/src/petab_gui/controllers/mother_controller.py index af28083..7ee6e5a 100644 --- a/src/petab_gui/controllers/mother_controller.py +++ b/src/petab_gui/controllers/mother_controller.py @@ -4,6 +4,7 @@ import tempfile import zipfile from functools import partial +from importlib.metadata import version from io import BytesIO from pathlib import Path @@ -32,6 +33,7 @@ QWidget, ) +from ..C import APP_NAME, REPO_URL from ..models import PEtabModel, SbmlViewerModel from ..settings_manager import SettingsDialog, settings_manager from ..utils import ( @@ -164,7 +166,7 @@ def window_title(self): """Return the window title based on the model.""" if isinstance(self.model.sbml, SbmlViewerModel): return self.model.sbml.model_id - return "PEtab Editor" + return APP_NAME def setup_context_menu(self): """Sets up context menus for the tables.""" @@ -438,6 +440,12 @@ def setup_actions(self): self._whats_this_filter = _WhatsThisClickHelp(actions["whats_this"]) actions["whats_this"].toggled.connect(self._toggle_whats_this_mode) + # About action + actions["about"] = QAction( + qta.icon("mdi6.information"), "&About", self.view + ) + actions["about"].triggered.connect(self.about) + # connect actions actions["reset_view"] = QAction( qta.icon("mdi6.view-grid-plus"), "Reset View", self.view @@ -1158,6 +1166,24 @@ def _show_help_welcome(self): if dont.isChecked(): settings.setValue("help_mode/welcome_disabled", True) + def about(self): + """Show an about dialog.""" + config_file = settings_manager.settings.fileName() + QMessageBox.about( + self.view, + f"About {APP_NAME}", + f"{APP_NAME}
" + f"Version: {version('petab-gui')}
" + f"PEtab version: {version('petab')}

" + f"{APP_NAME} is a tool for editing and visualizing PEtab " + f"problems.

" + f"Visit the GitHub repository at " + f"{REPO_URL} " + "for more information.

" + f"Settings are stored in " + f"{config_file}", + ) + def get_current_problem(self): """Get the current PEtab problem from the model.""" return self.model.current_petab_problem diff --git a/src/petab_gui/views/main_view.py b/src/petab_gui/views/main_view.py index 721b928..530f158 100644 --- a/src/petab_gui/views/main_view.py +++ b/src/petab_gui/views/main_view.py @@ -12,6 +12,7 @@ QWidget, ) +from ..C import APP_NAME from ..models.tooltips import ( COND_TABLE_TOOLTIP, DATA_PLOT_TOOLTIP, @@ -39,7 +40,7 @@ def __init__(self): self.allow_close = False - self.setWindowTitle("PEtabGUI") + self.setWindowTitle(APP_NAME) self.setGeometry(100, 100, 1200, 800) # Logger: used in both tabs diff --git a/src/petab_gui/views/task_bar.py b/src/petab_gui/views/task_bar.py index ed85ed2..408221c 100644 --- a/src/petab_gui/views/task_bar.py +++ b/src/petab_gui/views/task_bar.py @@ -137,6 +137,7 @@ def __init__(self, parent, actions): # Add actions to the menu for re-adding tables self.menu.addAction(actions["open_documentation"]) self.menu.addAction(actions["whats_this"]) + self.menu.addAction(actions["about"]) class TaskBar: