diff --git a/README.md b/README.md
index a182d35..203c8d3 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[](pypi.org/project/PEtab-GUI/)
+[](https://pypi.org/project/PEtab-GUI/)
[](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: