gui: bypass XDG portal for all file/dir dialogs in Flatpak
The v0.1.2 fix that forced Qt's non-native dialog for the "open test" dialog only covered one call site. The same XDG-portal-vs-sibling-files problem applies to every other QFileDialog in the GUI (save report, log file path, default report/log dirs in preferences, python/lua interpreter pickers). Extracted a single ``file_dialog.options()`` helper in main_win/ and threaded it through every getOpenFileName / getSaveFileName / getExistingDirectory call in main_win/. Outside Flatpak the helper returns an empty Options(), so the native dialog stays in use on KDE / GNOME / Windows / macOS. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,22 @@
|
|||||||
|
version 0.1.3
|
||||||
|
==============
|
||||||
|
- Stop interrupts engaged blocking steps (console, py_func, lua_func,
|
||||||
|
json_rpc, sleep) within ~200 ms instead of waiting for the step
|
||||||
|
to finish.
|
||||||
|
- GUI Start / Stop / Pause flow simplified.
|
||||||
|
- lua_func: a function returning nil is no longer reported as a failure.
|
||||||
|
- ``-d python_bin=...`` and the GUI ``python_bin`` preference now reach
|
||||||
|
the eval subprocess (used to be silently ignored). ``param.yaml`` can
|
||||||
|
also override ``python_bin`` for py_func / cycle / post_exec.
|
||||||
|
- Validation suite: ``test/validation/run.sh`` (and ``run.bat``)
|
||||||
|
runs the suite inside a dedicated venv in the system temp dir.
|
||||||
|
- build_all.sh: ``release_note.txt`` and the user manual copied into
|
||||||
|
``dist/``; warning if the file has no entry for the version being built.
|
||||||
|
- Flatpak: every GUI file/directory dialog (open test, save report, log
|
||||||
|
path, default report/log dirs, python/lua interpreter pickers) now
|
||||||
|
bypasses the XDG document portal — the v0.1.2 fix was only on the
|
||||||
|
"open test" dialog.
|
||||||
|
|
||||||
version 0.1.2
|
version 0.1.2
|
||||||
==============
|
==============
|
||||||
- Flatpak: opening a test from the GUI now correctly finds its companion
|
- Flatpak: opening a test from the GUI now correctly finds its companion
|
||||||
|
|||||||
21
src/testium/main_win/file_dialog.py
Normal file
21
src/testium/main_win/file_dialog.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
"""Helpers for Qt file/directory dialogs.
|
||||||
|
|
||||||
|
In Flatpak the native QFileDialog goes through the XDG document portal,
|
||||||
|
which returns ``/run/user/UID/doc/.../<file>`` and only exposes the
|
||||||
|
selected file — sibling files (param.yaml, scripts, recent paths in
|
||||||
|
preferences, ...) are unreachable. Forcing Qt's own non-native dialog
|
||||||
|
makes it walk the real filesystem mounted via ``--filesystem=home``
|
||||||
|
and return a regular path.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from PySide6.QtWidgets import QFileDialog
|
||||||
|
|
||||||
|
|
||||||
|
def options():
|
||||||
|
"""Default ``QFileDialog`` options for the current runtime."""
|
||||||
|
opts = QFileDialog.Options()
|
||||||
|
if os.path.isfile("/.flatpak-info"):
|
||||||
|
opts |= QFileDialog.Option.DontUseNativeDialog
|
||||||
|
return opts
|
||||||
@@ -3,6 +3,7 @@ from PySide6.QtWidgets import QDialog, QFileDialog
|
|||||||
from PySide6.QtGui import QFont
|
from PySide6.QtGui import QFont
|
||||||
|
|
||||||
from main_win.preference_win.preference_core_win import Ui_preferenceWindow
|
from main_win.preference_win.preference_core_win import Ui_preferenceWindow
|
||||||
|
from main_win import file_dialog
|
||||||
|
|
||||||
import interpreter.utils.settings as prefs
|
import interpreter.utils.settings as prefs
|
||||||
|
|
||||||
@@ -193,6 +194,7 @@ class PrefWindow(QDialog):
|
|||||||
self,
|
self,
|
||||||
caption="Select the default report directory",
|
caption="Select the default report directory",
|
||||||
dir=self.ui.editDefaultReportPath.text(),
|
dir=self.ui.editDefaultReportPath.text(),
|
||||||
|
options=file_dialog.options(),
|
||||||
)
|
)
|
||||||
if path:
|
if path:
|
||||||
self.ui.editDefaultReportPath.setText(path)
|
self.ui.editDefaultReportPath.setText(path)
|
||||||
@@ -203,6 +205,7 @@ class PrefWindow(QDialog):
|
|||||||
self,
|
self,
|
||||||
caption="Select the default log directory",
|
caption="Select the default log directory",
|
||||||
dir=self.ui.editDefaultLogPath.text(),
|
dir=self.ui.editDefaultLogPath.text(),
|
||||||
|
options=file_dialog.options(),
|
||||||
)
|
)
|
||||||
if path:
|
if path:
|
||||||
self.ui.editDefaultLogPath.setText(path)
|
self.ui.editDefaultLogPath.setText(path)
|
||||||
@@ -213,6 +216,7 @@ class PrefWindow(QDialog):
|
|||||||
self,
|
self,
|
||||||
caption="Select the python interpreter",
|
caption="Select the python interpreter",
|
||||||
dir=self.ui.editPythonPath.text(),
|
dir=self.ui.editPythonPath.text(),
|
||||||
|
options=file_dialog.options(),
|
||||||
)
|
)
|
||||||
if path:
|
if path:
|
||||||
self.ui.editPythonPath.setText(path)
|
self.ui.editPythonPath.setText(path)
|
||||||
@@ -220,7 +224,10 @@ class PrefWindow(QDialog):
|
|||||||
@Slot()
|
@Slot()
|
||||||
def on_butLuaPath_pressed(self):
|
def on_butLuaPath_pressed(self):
|
||||||
path, _ = QFileDialog.getOpenFileName(
|
path, _ = QFileDialog.getOpenFileName(
|
||||||
self, caption="Select the lua interpreter", dir=self.ui.editLuaPath.text()
|
self,
|
||||||
|
caption="Select the lua interpreter",
|
||||||
|
dir=self.ui.editLuaPath.text(),
|
||||||
|
options=file_dialog.options(),
|
||||||
)
|
)
|
||||||
if path:
|
if path:
|
||||||
self.ui.editLuaPath.setText(path)
|
self.ui.editLuaPath.setText(path)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from PySide6.QtWidgets import QApplication, QFileDialog, QProgressDialog
|
|||||||
from interpreter.process import TestProcess
|
from interpreter.process import TestProcess
|
||||||
from interpreter.utils.test_ctrl import TestSetController
|
from interpreter.utils.test_ctrl import TestSetController
|
||||||
from main_win.test_controller_service import TestControllerService
|
from main_win.test_controller_service import TestControllerService
|
||||||
|
from main_win import file_dialog
|
||||||
import interpreter.utils.settings as prefs
|
import interpreter.utils.settings as prefs
|
||||||
from runtime.tum_except import ETUMFileError, ETUMRuntimeError
|
from runtime.tum_except import ETUMFileError, ETUMRuntimeError
|
||||||
|
|
||||||
@@ -212,17 +213,9 @@ class TestFileManager:
|
|||||||
d = ""
|
d = ""
|
||||||
if w.testFile is not None:
|
if w.testFile is not None:
|
||||||
d = os.path.dirname(w.testFile)
|
d = os.path.dirname(w.testFile)
|
||||||
# In Flatpak the native dialog goes through the XDG document portal,
|
|
||||||
# which returns /run/user/UID/doc/.../test.tum and only exposes the
|
|
||||||
# selected file — sibling files (param.yaml, .py, etc.) are unreachable.
|
|
||||||
# Force Qt's own dialog, which walks the real filesystem mounted via
|
|
||||||
# --filesystem=home and returns a regular path with sibling access.
|
|
||||||
options = QFileDialog.Options()
|
|
||||||
if os.path.isfile("/.flatpak-info"):
|
|
||||||
options |= QFileDialog.Option.DontUseNativeDialog
|
|
||||||
file_name, _ = QFileDialog.getOpenFileName(
|
file_name, _ = QFileDialog.getOpenFileName(
|
||||||
w, "Open the test file", d,
|
w, "Open the test file", d,
|
||||||
"testium file (*.tum);;All Files (*)", options=options
|
"testium file (*.tum);;All Files (*)", options=file_dialog.options()
|
||||||
)
|
)
|
||||||
if file_name:
|
if file_name:
|
||||||
self.reload(file_name)
|
self.reload(file_name)
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ from interpreter.utils.icons import icon_prefix
|
|||||||
|
|
||||||
from main_win.test_run.outlog import OutLog
|
from main_win.test_run.outlog import OutLog
|
||||||
from main_win.test_run.test_run import ThreadTestStatus
|
from main_win.test_run.test_run import ThreadTestStatus
|
||||||
|
from main_win import file_dialog
|
||||||
import interpreter.utils.settings as prefs
|
import interpreter.utils.settings as prefs
|
||||||
from runtime.stdout_redirect import stdio_redir
|
from runtime.stdout_redirect import stdio_redir
|
||||||
import api.testium as tm
|
import api.testium as tm
|
||||||
@@ -484,7 +485,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
else:
|
else:
|
||||||
initialPath = None
|
initialPath = None
|
||||||
fileName, _ = QFileDialog.getSaveFileName(
|
fileName, _ = QFileDialog.getSaveFileName(
|
||||||
self, "Path to Log file", initialPath, "Log Files (*.log);;All Files (*)"
|
self, "Path to Log file", initialPath, "Log Files (*.log);;All Files (*)",
|
||||||
|
options=file_dialog.options(),
|
||||||
)
|
)
|
||||||
if fileName:
|
if fileName:
|
||||||
shutil.copy(self.logFileName, fileName)
|
shutil.copy(self.logFileName, fileName)
|
||||||
@@ -525,7 +527,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
else:
|
else:
|
||||||
initialPath = None
|
initialPath = None
|
||||||
fileName, _ = QFileDialog.getSaveFileName(
|
fileName, _ = QFileDialog.getSaveFileName(
|
||||||
self, "Path to log file", initialPath, "Log Files (*.log);;All Files (*)"
|
self, "Path to log file", initialPath, "Log Files (*.log);;All Files (*)",
|
||||||
|
options=file_dialog.options(),
|
||||||
)
|
)
|
||||||
if fileName:
|
if fileName:
|
||||||
self.editLogFilePath.setText(fileName)
|
self.editLogFilePath.setText(fileName)
|
||||||
|
|||||||
Reference in New Issue
Block a user