mirror of
https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer.git
synced 2026-06-17 11:22:53 +02:00
Oprava pádů: chybějící locale při startu a životní cyklus úlohy aktualizace heslářů
- amcr_viewer.py: QSettings().value('locale/userLocale') může být None na
čisté instalaci QGIS – ošetřen fallback na 'en', jinak plugin spadne
na TypeError hned při načtení.
- amcr_viewer.py: odstraněn nepoužívaný hvězdičkový import resources.
- amcr_dialog.py: úloha aktualizace heslářů se drží v modulové referenci,
aby GC neuklidil Python wrapper QgsTask před dokončením (známá příčina
pádů QGIS).
- amcr_dialog.py: tlačítko aktualizace se po spuštění zakáže – nelze už
spustit několik stahování paralelně přepisujících heslar.csv.
- amcr_dialog.py: závěrečné QMessageBoxy se parentují na hlavní okno QGIS
místo dialogu, který může být v době dokončení úlohy už zavřený
(smazaný C++ objekt → pád).
This commit is contained in:
@@ -7,6 +7,7 @@ from qgis.PyQt.QtWidgets import (QDialog, QVBoxLayout,
|
||||
from qgis.PyQt.QtCore import Qt, QSettings
|
||||
from qgis.core import (QgsTask, QgsApplication,
|
||||
QgsMessageLog, Qgis, QgsAuthMethodConfig)
|
||||
from qgis.utils import iface
|
||||
from .amcr_codelists import (OBDOBI, TYP_AKCE, KRAJE, AREAL, ORGANIZACE,
|
||||
OKRESY, KATASTRY, VEDOUCI, PIAN_PRESNOST,
|
||||
TYP_LOKALITY, DRUH_LOKALITY, JISTOTA,
|
||||
@@ -14,6 +15,12 @@ from .amcr_codelists import (OBDOBI, TYP_AKCE, KRAJE, AREAL, ORGANIZACE,
|
||||
download_heslare, refresh_globals)
|
||||
|
||||
|
||||
# Keep Python references to running tasks. QgsTaskManager only holds the
|
||||
# C++ object; without a Python-side reference the wrapper can be garbage
|
||||
# collected before the task finishes, which crashes QGIS.
|
||||
_ACTIVE_TASKS = []
|
||||
|
||||
|
||||
class UpdateCodelistsTask(QgsTask):
|
||||
def __init__(self, description):
|
||||
super().__init__(description, QgsTask.CanCancel)
|
||||
@@ -370,21 +377,38 @@ class AmcrFilterDialog(QDialog):
|
||||
return row_widget
|
||||
|
||||
def action_update_heslare(self):
|
||||
# Create the task instance
|
||||
# Create the task instance and keep a reference so the Python
|
||||
# wrapper survives until the task finishes
|
||||
task = UpdateCodelistsTask("Aktualizace heslářů AMČR")
|
||||
_ACTIVE_TASKS.append(task)
|
||||
|
||||
# Re-enable the button regardless of the outcome
|
||||
task.taskCompleted.connect(lambda: self.btn_update.setEnabled(True))
|
||||
task.taskTerminated.connect(lambda: self.btn_update.setEnabled(True))
|
||||
# Prevent parallel downloads overwriting heslar.csv
|
||||
self.btn_update.setEnabled(False)
|
||||
|
||||
task.taskCompleted.connect(lambda: QMessageBox.information(
|
||||
self,
|
||||
# Message boxes are parented to the main window, not to this dialog –
|
||||
# the dialog may already be closed (and its C++ object deleted)
|
||||
# by the time the minute-long task finishes.
|
||||
parent_win = iface.mainWindow() if iface else None
|
||||
|
||||
def _cleanup():
|
||||
if task in _ACTIVE_TASKS:
|
||||
_ACTIVE_TASKS.remove(task)
|
||||
try:
|
||||
self.btn_update.setEnabled(True)
|
||||
except RuntimeError:
|
||||
pass # dialog already closed
|
||||
|
||||
def on_completed():
|
||||
_cleanup()
|
||||
QMessageBox.information(
|
||||
parent_win,
|
||||
"Hotovo",
|
||||
"Hesláře byly úspěšně aktualizovány."
|
||||
))
|
||||
)
|
||||
|
||||
# Show the exact error if the task fails
|
||||
def on_error():
|
||||
_cleanup()
|
||||
if task.exception:
|
||||
# This will show exactly what went wrong (e.g. PermissionError)
|
||||
msg = (
|
||||
@@ -393,8 +417,9 @@ class AmcrFilterDialog(QDialog):
|
||||
)
|
||||
else:
|
||||
msg = "Aktualizace byla zrušena uživatelem."
|
||||
QMessageBox.warning(self, "Chyba / Zrušeno", msg)
|
||||
QMessageBox.warning(parent_win, "Chyba / Zrušeno", msg)
|
||||
|
||||
task.taskCompleted.connect(on_completed)
|
||||
task.taskTerminated.connect(on_error)
|
||||
|
||||
QgsApplication.taskManager().addTask(task)
|
||||
|
||||
@@ -6,7 +6,6 @@ from qgis.core import Qgis
|
||||
|
||||
from .amcr_tools import load_amcr_data, login_to_api
|
||||
from .amcr_dialog import AmcrFilterDialog, LoginDialog
|
||||
from .resources import *
|
||||
import os.path
|
||||
|
||||
|
||||
@@ -24,8 +23,9 @@ class AmcrViewer:
|
||||
self.iface = iface
|
||||
self.plugin_dir = os.path.dirname(__file__)
|
||||
|
||||
# Determine the user's locale to load appropriate translation files
|
||||
locale = QSettings().value('locale/userLocale')[0:2]
|
||||
# Determine the user's locale to load appropriate translation files.
|
||||
# The setting may be missing (None) on a fresh QGIS install.
|
||||
locale = str(QSettings().value('locale/userLocale') or 'en')[0:2]
|
||||
locale_path = os.path.join(
|
||||
self.plugin_dir,
|
||||
'i18n',
|
||||
|
||||
Reference in New Issue
Block a user