Compare commits

..
6 Commits
Author SHA1 Message Date
david-spacil 39dac12bad Merge pull request #61 from ARUP-CAS/fix/qt6-kompatibilita
fix: kompatibilita s Qt6 / QGIS 4 a úklid lintů
2026-09-01 23:22:56 +02:00
david-spacil b708930ca2 update metadata 2026-09-01 23:21:04 +02:00
david-spacil 3f7839c818 fix: znovu odstraněn BOM a zalomen dlouhý import
Commit 9aba283 vrátil UTF-8 BOM do amcr_dialog.py a amcr_tools.py –
patrně ho doplnil editor při uložení. Oficiální pyqgis4-checker na nich
kvůli tomu znovu padal na SyntaxError, tedy přesně to, co d398d2c
opravoval.

Zároveň zalomen sloučený import z qgis.core v amcr_dialog.py, který měl
87 znaků.
2026-09-01 23:15:28 +02:00
david-spacil 9aba28317a chore: pořadí importů 2026-09-01 23:13:18 +02:00
david-spacil 048ffe4e2a chore: úklid nálezů z lintů
Bez změny chování. Kontroly, které pouští plugins.qgis.org (flake8),
plus ruff.

flake8: odstraněny koncové bílé znaky, srovnány nadbytečné prázdné řádky
a zalomeno 12 řádků přes 79 znaků. Hlášku o HTTP chybě v login_to_api()
si nešlo jen zalomit – tělo odpovědi je nově v proměnné `telo`, výsledný
text je stejný.

ruff: odstraněny zbytečné prefixy u'' u překládaných řetězců (6×),
.format() nahrazen f-stringem, str() uvnitř f-stringu převedeno na !s,
`k in dict.keys()` na `k in dict`, prázdný komentář; nepoužitá rozbalená
proměnná `existing_cfg` nahrazena `_`.

Vědomě neřešeno:
- resources.py (5 zbylých nálezů flake8) je generovaný výstup pyrcc,
  nese hlavičku "All changes made in this file will be lost", není nikde
  importovaný a v repu k němu chybí zdrojový .qrc.
- ruff BLE001 (10×) hlásí `except Exception`. Ty jsou v pluginu záměrné:
  drží pád mimo QGIS a chybu ukážou v liště zpráv. Změna by byla zásah
  do chování, ne úklid.
- ruff SIM103 (2×) navrhuje sloučit strážní podmínky do jednoho výrazu.
  Obě místa mají ke každé větvi vysvětlující komentář, sloučením by se
  staly hůř čitelnými.
- ruff UP009 a I001 (coding hlavička a řazení importů) jsou celoprojektová
  konvence; jejich změna patří do samostatného rozhodnutí, ne sem.

Ověřeno v QGIS 3.44.13 (Qt5) i QGIS 4.2.1 (Qt6): importy, vytvoření tasku
i všechny tři filtrační dialogy fungují shodně. Bandit, detect-secrets
i pyqgis4-checker hlásí nula nálezů.
2026-09-01 23:10:33 +02:00
david-spacil d398d2cd1b fix: kompatibilita s Qt6 / QGIS 4
Oficiální kontrola pyqgis4-checker (skript pyqt5_to_pyqt6.py z QGISu)
hlásila u pluginu 13 nekompatibilit a tři soubory vůbec nepřečetla.

Odstraněn UTF-8 BOM z amcr_codelists.py, amcr_dialog.py a amcr_tools.py.
Checker čte zdroják jako UTF-8 bez utf-8-sig a na BOM padá na
SyntaxError: invalid non-printable character U+FEFF, takže se ty soubory
nezkontrolovaly vůbec. Pythonu při běhu BOM nevadí, proto to nikdy
nevyskočilo. heslar.csv si BOM ponechává, tam je kvůli Excelu.

Enumy převedeny na plně kvalifikované tvary (13 míst):
Qgis.{Info,Warning,Critical} -> Qgis.MessageLevel.*,
QgsTask.CanCancel -> QgsTask.Flag.CanCancel,
QgsWkbTypes.*Geometry -> QgsWkbTypes.GeometryType.*Geometry.
Zkrácené tvary v QGIS 4.2.1 zatím fungují, ale kontrola je vytýká
a aliasy do budoucna mizí. Zbytek kódu už scoped tvary používal.

Do AGENTS.md doplněna sekce o kompatibilitě s Qt6 / QGIS 4 se závaznými
pravidly a příkazy na ověření.

Ověřeno spuštěním v QGIS 3.44.13 (Qt 5.15.18) i QGIS 4.2.1 (Qt 6.10.3):
importy, vytvoření tasku i všechny tři filtrační dialogy fungují shodně.
Log pyqgis4-checkeru je nově prázdný.
2026-09-01 23:05:02 +02:00
7 changed files with 197 additions and 86 deletions

No files matched your search

+52
View File
@@ -83,6 +83,58 @@ Další pravidla:
definice pole (`QgsField`), naplnění hodnoty z dokumentu, překlad hlavičky definice pole (`QgsField`), naplnění hodnoty z dokumentu, překlad hlavičky
sloupce a export atributů. sloupce a export atributů.
### Kompatibilita s Qt6 / QGIS 4
Plugin cílí na QGIS 3.44 i na QGIS 4 (`qgisMaximumVersion=4.99.0`), tedy na
Qt5 i Qt6 zároveň. **Tohle se drží rigorózně** – ne až před releasem, ale při
každé změně kódu. Chování obou větví se liší tiše: pod Qt5 projde i to, co
QGIS 4 odmítne, takže lokální „funguje mi to“ nic nedokazuje.
Závazná pravidla:
- **Nikdy neimportuj přímo z `PyQt5` ani z `PyQt6`.** Vždy přes shim
`qgis.PyQt.*`. Ten mimo jiné pod Qt6 přetahuje `QAction`, `QActionGroup`
a `QShortcut` z `QtGui`, takže import z `qgis.PyQt.QtWidgets` je správně.
- **Enumy vždy plně kvalifikované (scoped).** `Qgis.MessageLevel.Info`, ne
`Qgis.Info`; `QgsTask.Flag.CanCancel`, ne `QgsTask.CanCancel`;
`QgsWkbTypes.GeometryType.PointGeometry`, ne `QgsWkbTypes.PointGeometry`.
Totéž pro Qt: `Qt.CheckState.Checked`, `QDialogButtonBox.StandardButton.Ok`.
Zkrácené tvary sice v QGIS 4.2 zatím fungují, ale oficiální kontrola je
hlásí a do budoucna mizí.
- **Zdrojové `.py` soubory ukládej bez BOM.** Kontrolní skript čte soubor
jako UTF-8 bez `utf-8-sig` a na BOM spadne s
`SyntaxError: invalid non-printable character U+FEFF`, takže se takový
soubor **vůbec nezkontroluje**. (`codelists/heslar.csv` BOM mít smí, tam je
kvůli Excelu.)
- Nepoužívej API zrušená v Qt6: `exec_()`, `QRegExp`, `QDesktopWidget`,
`QApplication.desktop()`, `Qt.MidButton`, `QFontMetrics.width()`,
`setResizeMode`, atributy `AA_EnableHighDpiScaling` / `AA_UseHighDpiPixmaps`.
- `supportsQt6=True` v `metadata.txt` **nepatří** – bylo zrušeno; o zařazení
mezi „QGIS 4 Ready“ rozhoduje rozsah `qgisMinimumVersion` až
`qgisMaximumVersion`.
Ověření před PR, který mění Python kód:
```sh
# oficiální kontrola, kterou pouští i plugins.qgis.org (pyqgis4-checker)
docker run --rm --pull always --user $(id -u):$(id -g) \
--workdir /workspace/ -v "$(pwd):/workspace/" \
ghcr.io/qgis/pyqgis4-checker:main-ubuntu \
pyqt5_to_pyqt6.py --dry_run --logfile /workspace/pyqt6_checker.log .
```
Prázdný log = čisté. Kontrola je na plugins.qgis.org informativní
(neblokuje schválení), ale nález znamená, že plugin v QGIS 4 dříve nebo
později přestane fungovat.
Když je po ruce QGIS 4 (např. flatpak `org.qgis.qgis`), ověř navíc, že se
plugin pod Qt6 opravdu načte:
```sh
flatpak run --command=sh org.qgis.qgis -c \
'PYTHONPATH=/app/share/qgis/python python3 -c "import qgis.core"'
```
## Verzování a release ## Verzování a release
- Verze pluginu žije v **`amcr_viewer/metadata.txt`** (`version=`). - Verze pluginu žije v **`amcr_viewer/metadata.txt`** (`version=`).
-1
View File
@@ -31,6 +31,5 @@ def classFactory(iface): # pylint: disable=invalid-name
:param iface: A QGIS interface instance. :param iface: A QGIS interface instance.
:type iface: QgsInterface :type iface: QgsInterface
""" """
#
from .amcr_viewer import AmcrViewer from .amcr_viewer import AmcrViewer
return AmcrViewer(iface) return AmcrViewer(iface)
+16 -13
View File
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
import csv import csv
import requests import os
import xml.etree.ElementTree as ET # nosec
import time import time
from qgis.core import QgsMessageLog, Qgis import xml.etree.ElementTree as ET # nosec
import requests
from qgis.core import Qgis, QgsMessageLog
# Define paths for the plugin and its codelists directory # Define paths for the plugin and its codelists directory
PLUGIN_DIR = os.path.dirname(__file__) PLUGIN_DIR = os.path.dirname(__file__)
@@ -90,7 +91,7 @@ def parse_codelist_file(filename, target_dict=None):
except Exception as e: except Exception as e:
QgsMessageLog.logMessage( QgsMessageLog.logMessage(
f"AMČR Codelist Read Error for {filename}: {e}", f"AMČR Codelist Read Error for {filename}: {e}",
"AMČR", Qgis.Critical) "AMČR", Qgis.MessageLevel.Critical)
return target_dict return target_dict
@@ -98,7 +99,7 @@ def parse_codelist_file(filename, target_dict=None):
def load_all_data(): def load_all_data():
"""Loads the codelist during plugin startup.""" """Loads the codelist during plugin startup."""
ensure_codelists_dir() ensure_codelists_dir()
categorized_data = {k: {} for k in slovnicek.keys()} categorized_data = {k: {} for k in slovnicek}
parse_codelist_file('heslar.csv', categorized_data) parse_codelist_file('heslar.csv', categorized_data)
return categorized_data return categorized_data
@@ -124,7 +125,9 @@ def fetch_set(base_url, internal_name, api_set, task=None):
try: try:
if "digiarchiv" not in base_url: if "digiarchiv" not in base_url:
response = requests.get(base_url, params=params_amcr, timeout=30) response = requests.get(
base_url, params=params_amcr, timeout=30
)
response.raise_for_status() response.raise_for_status()
root = ET.fromstring(response.content) # nosec root = ET.fromstring(response.content) # nosec
@@ -193,7 +196,7 @@ def fetch_set(base_url, internal_name, api_set, task=None):
time.sleep(0.5) time.sleep(0.5)
else: else:
break break
else: else:
response = requests.get(base_url, params=params_da, timeout=30) response = requests.get(base_url, params=params_da, timeout=30)
response.raise_for_status() response.raise_for_status()
@@ -210,13 +213,13 @@ def fetch_set(base_url, internal_name, api_set, task=None):
'Kód': nazev, 'Kód': nazev,
'Kategorie': internal_name 'Kategorie': internal_name
}) })
break break
except Exception as e: except Exception as e:
QgsMessageLog.logMessage( QgsMessageLog.logMessage(
f"Chyba u setu {api_set}: {e}", f"Chyba u setu {api_set}: {e}",
"AMČR", Qgis.Warning) "AMČR", Qgis.MessageLevel.Warning)
break break
return dataset return dataset
@@ -240,7 +243,7 @@ def download_heslare(task=None):
QgsMessageLog.logMessage( QgsMessageLog.logMessage(
f"Zpracovávám kategorii: {interni}...", f"Zpracovávám kategorii: {interni}...",
"AMČR", Qgis.Info) "AMČR", Qgis.MessageLevel.Info)
# Pass the task correctly to the updated fetch function # Pass the task correctly to the updated fetch function
data = fetch_set(base_url, interni, api_nazev, task=task) data = fetch_set(base_url, interni, api_nazev, task=task)
+71 -29
View File
@@ -1,23 +1,57 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from qgis.PyQt.QtWidgets import (QDialog, QVBoxLayout, from qgis.core import (
QLineEdit, QDialogButtonBox, Qgis,
QCheckBox, QGroupBox, QPushButton, QgsApplication,
QListWidget, QListWidgetItem, QHBoxLayout, QgsAuthMethodConfig,
QMessageBox, QLabel, QFormLayout, QgsMessageLog,
QGridLayout, QScrollArea, QFrame, QWidget) QgsTask,
from qgis.PyQt.QtCore import Qt, QSettings )
from qgis.core import (QgsTask, QgsApplication,
QgsMessageLog, Qgis, QgsAuthMethodConfig)
from qgis.gui import QgsDateEdit from qgis.gui import QgsDateEdit
from qgis.PyQt.QtCore import QSettings, Qt
from qgis.PyQt.QtWidgets import (
QCheckBox,
QDialog,
QDialogButtonBox,
QFormLayout,
QFrame,
QGridLayout,
QGroupBox,
QHBoxLayout,
QLabel,
QLineEdit,
QListWidget,
QListWidgetItem,
QMessageBox,
QPushButton,
QScrollArea,
QVBoxLayout,
QWidget,
)
from qgis.utils import iface 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,
LOKALITA_ZACHOVALOST, PRISTUPNOST,
NALEZ_KATEGORIE, DRUH_NALEZU, SPECIFIKACE,
NALEZOVE_OKOLNOSTI, NALEZCE,
download_heslare, refresh_globals)
from .amcr_codelists import (
AREAL,
DRUH_LOKALITY,
DRUH_NALEZU,
JISTOTA,
KATASTRY,
KRAJE,
LOKALITA_ZACHOVALOST,
NALEZ_KATEGORIE,
NALEZCE,
NALEZOVE_OKOLNOSTI,
OBDOBI,
OKRESY,
ORGANIZACE,
PIAN_PRESNOST,
PRISTUPNOST,
SPECIFIKACE,
TYP_AKCE,
TYP_LOKALITY,
VEDOUCI,
download_heslare,
refresh_globals,
)
# The date filter of the API requires both bounds; a one-sided range makes # The date filter of the API requires both bounds; a one-sided range makes
# the server fail with an ArrayIndexOutOfBoundsException and '*' is not # the server fail with an ArrayIndexOutOfBoundsException and '*' is not
@@ -38,7 +72,7 @@ _ACTIVE_TASKS = []
class UpdateCodelistsTask(QgsTask): class UpdateCodelistsTask(QgsTask):
def __init__(self, description): def __init__(self, description):
super().__init__(description, QgsTask.CanCancel) super().__init__(description, QgsTask.Flag.CanCancel)
self.success = False self.success = False
self.exception = None self.exception = None
@@ -59,18 +93,18 @@ class UpdateCodelistsTask(QgsTask):
refresh_globals() refresh_globals()
QgsMessageLog.logMessage( QgsMessageLog.logMessage(
"Hesláře AMČR byly úspěšně aktualizovány.", "Hesláře AMČR byly úspěšně aktualizovány.",
"AMČR", Qgis.Info "AMČR", Qgis.MessageLevel.Info
) )
else: else:
if self.isCanceled(): if self.isCanceled():
QgsMessageLog.logMessage( QgsMessageLog.logMessage(
"Aktualizace heslářů byla zrušena.", "Aktualizace heslářů byla zrušena.",
"AMČR", Qgis.Warning "AMČR", Qgis.MessageLevel.Warning
) )
else: else:
QgsMessageLog.logMessage( QgsMessageLog.logMessage(
f"Chyba aktualizace: {self.exception}", f"Chyba aktualizace: {self.exception}",
"AMČR", Qgis.Critical "AMČR", Qgis.MessageLevel.Critical
) )
@@ -608,7 +642,7 @@ class AmcrFilterDialog(QDialog):
# This will show exactly what went wrong (e.g. PermissionError) # This will show exactly what went wrong (e.g. PermissionError)
msg = ( msg = (
"Aktualizace selhala z důvodu chyby:\n" "Aktualizace selhala z důvodu chyby:\n"
f"{str(task.exception)}" f"{task.exception!s}"
) )
else: else:
msg = "Aktualizace byla zrušena uživatelem." msg = "Aktualizace byla zrušena uživatelem."
@@ -660,7 +694,7 @@ class AmcrFilterDialog(QDialog):
filters['f_vedouci'] = self.selection_cache['vedouci'] filters['f_vedouci'] = self.selection_cache['vedouci']
if self.selection_cache['organizace']: if self.selection_cache['organizace']:
filters['f_organizace'] = self.selection_cache['organizace'] filters['f_organizace'] = self.selection_cache['organizace']
if self.selection_cache['typ_lokality']: if self.selection_cache['typ_lokality']:
filters['f_typ_lokality'] = self.selection_cache['typ_lokality'] filters['f_typ_lokality'] = self.selection_cache['typ_lokality']
@@ -669,7 +703,9 @@ class AmcrFilterDialog(QDialog):
if self.selection_cache['jistota']: if self.selection_cache['jistota']:
filters['f_jistota'] = self.selection_cache['jistota'] filters['f_jistota'] = self.selection_cache['jistota']
if self.selection_cache['lokalita_zachovalost']: if self.selection_cache['lokalita_zachovalost']:
filters['f_lokalita_zachovalost'] = self.selection_cache['lokalita_zachovalost'] filters['f_lokalita_zachovalost'] = (
self.selection_cache['lokalita_zachovalost']
)
# Samostatné nálezy # Samostatné nálezy
if self.selection_cache['nalez_kategorie']: if self.selection_cache['nalez_kategorie']:
@@ -679,7 +715,9 @@ class AmcrFilterDialog(QDialog):
if self.selection_cache['specifikace']: if self.selection_cache['specifikace']:
filters['f_specifikace'] = self.selection_cache['specifikace'] filters['f_specifikace'] = self.selection_cache['specifikace']
if self.selection_cache['nalezove_okolnosti']: if self.selection_cache['nalezove_okolnosti']:
filters['f_nalezove_okolnosti'] = self.selection_cache['nalezove_okolnosti'] filters['f_nalezove_okolnosti'] = (
self.selection_cache['nalezove_okolnosti']
)
if self.selection_cache['nalezce']: if self.selection_cache['nalezce']:
filters['f_nalezce'] = self.selection_cache['nalezce'] filters['f_nalezce'] = self.selection_cache['nalezce']
@@ -718,7 +756,8 @@ class LoginDialog(QDialog):
- storeAuthenticationConfig() and loadAuthenticationConfig() both have - storeAuthenticationConfig() and loadAuthenticationConfig() both have
SIP_INOUT on their config parameter, so Python bindings return a tuple SIP_INOUT on their config parameter, so Python bindings return a tuple
(bool, QgsAuthMethodConfig) rather than just bool. Always unpack both. (bool, QgsAuthMethodConfig) rather than just bool. Always unpack both.
- loadAuthenticationConfig() with full=False loads only metadata (name, method, - loadAuthenticationConfig() with full=False loads only metadata
(name, method,
id) but NOT the config() values like username/password. Use full=True to id) but NOT the config() values like username/password. Use full=True to
access those. access those.
""" """
@@ -949,7 +988,7 @@ class LoginDialog(QDialog):
# We skip hasConfigId() as it may return False # We skip hasConfigId() as it may return False
# despite the config existing # despite the config existing
# (in-memory cache may not be populated yet in QGIS 4). # (in-memory cache may not be populated yet in QGIS 4).
ok_load, existing_cfg = ( ok_load, _ = (
self._load_config(existing_id, full=False) self._load_config(existing_id, full=False)
if existing_id if existing_id
else (False, None) else (False, None)
@@ -978,7 +1017,9 @@ class LoginDialog(QDialog):
settings = QSettings() settings = QSettings()
existing_id = settings.value(self.SETTINGS_KEY, "") existing_id = settings.value(self.SETTINGS_KEY, "")
if existing_id: if existing_id:
QgsApplication.authManager().removeAuthenticationConfig(existing_id) QgsApplication.authManager().removeAuthenticationConfig(
existing_id
)
settings.remove(self.SETTINGS_KEY) settings.remove(self.SETTINGS_KEY)
QMessageBox.information( QMessageBox.information(
self, self,
@@ -1013,4 +1054,5 @@ class LoginDialog(QDialog):
if not ok: if not ok:
return "", "" return "", ""
return cfg.config("username", ""), cfg.config("password", "") # nosec B106 return (cfg.config("username", ""),
cfg.config("password", "")) # nosec B106
+37 -27
View File
@@ -1,15 +1,24 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from qgis.core import (QgsProject, QgsVectorLayer, QgsFeature, QgsGeometry,
QgsField, QgsCoordinateReferenceSystem,
QgsCoordinateTransform, QgsWkbTypes, Qgis,
QgsMessageLog)
from qgis.utils import iface
from qgis.PyQt.QtCore import Qt, QMetaType
from qgis.PyQt.QtWidgets import QApplication
from qgis.PyQt.QtGui import QCursor
import requests
import json import json
import requests
from qgis.core import (
Qgis,
QgsCoordinateReferenceSystem,
QgsCoordinateTransform,
QgsFeature,
QgsField,
QgsGeometry,
QgsMessageLog,
QgsProject,
QgsVectorLayer,
QgsWkbTypes,
)
from qgis.PyQt.QtCore import QMetaType, Qt
from qgis.PyQt.QtGui import QCursor
from qgis.PyQt.QtWidgets import QApplication
from qgis.utils import iface
# Global cache to store translated terms from the Digital Archive # Global cache to store translated terms from the Digital Archive
TRANSLATIONS = {} TRANSLATIONS = {}
@@ -109,8 +118,9 @@ def login_to_api(username: str, password: str):
except requests.exceptions.HTTPError as e: except requests.exceptions.HTTPError as e:
status = e.response.status_code if e.response is not None else None status = e.response.status_code if e.response is not None else None
_log(f"CHYBA HTTP {status if status else '?'}: " telo = (e.response.text[:300] if e.response is not None
f"{e.response.text[:300] if e.response is not None else 'žádná odpověď'}", else "žádná odpověď")
_log(f"CHYBA HTTP {status if status else '?'}: {telo}",
Qgis.MessageLevel.Critical) Qgis.MessageLevel.Critical)
LAST_LOGIN_ERROR = 'auth' if status in (401, 403) else 'network' LAST_LOGIN_ERROR = 'auth' if status in (401, 403) else 'network'
return None return None
@@ -623,7 +633,8 @@ def load_amcr_data(canvas, bb, filters=None,
for dj in djs: for dj in djs:
# Skip negative evidence units if requested # Skip negative evidence units if requested
if skip_negativni and dj.get('dj_negativni_jednotka') is True: if (skip_negativni
and dj.get('dj_negativni_jednotka') is True):
continue continue
komps = dj.get('dj_komponenta', []) komps = dj.get('dj_komponenta', [])
@@ -643,7 +654,8 @@ def load_amcr_data(canvas, bb, filters=None,
dj_id = dj.get('ident_cely') dj_id = dj.get('ident_cely')
dj_typ = dj.get('dj_typ') dj_typ = dj.get('dj_typ')
# Merge shared metadata with documentation unit-specific fields # Merge shared metadata with documentation
# unit-specific fields
dj_meta = { dj_meta = {
**meta, **meta,
'dj_id': dj_id, 'dj_id': dj_id,
@@ -690,7 +702,8 @@ def load_amcr_data(canvas, bb, filters=None,
or {} or {}
).get('value', ""), ).get('value', ""),
} }
pian_lookup[dj_pian_value].append(komp_meta) pian_lookup[dj_pian_value].append(
komp_meta)
target_pian_ids_count += 1 target_pian_ids_count += 1
else: else:
# DJ without components — still include # DJ without components — still include
@@ -704,7 +717,8 @@ def load_amcr_data(canvas, bb, filters=None,
'komponenta_areal': "", 'komponenta_areal': "",
'komponenta_obdobi': "", 'komponenta_obdobi': "",
} }
pian_lookup[dj_pian_value].append(empty_meta) pian_lookup[dj_pian_value].append(
empty_meta)
target_pian_ids_count += 1 target_pian_ids_count += 1
else: else:
target_pian_ids_count += 1 target_pian_ids_count += 1
@@ -907,9 +921,6 @@ def load_amcr_data(canvas, bb, filters=None,
) )
return return
# ========================================== # ==========================================
# D) LAYER CREATION (QGIS Memory Layers) # D) LAYER CREATION (QGIS Memory Layers)
# ========================================== # ==========================================
@@ -947,7 +958,6 @@ def load_amcr_data(canvas, bb, filters=None,
QgsField("typ_dj", QMetaType.Type.QString), QgsField("typ_dj", QMetaType.Type.QString),
] ]
cols += [ cols += [
QgsField(typ_dat, QMetaType.Type.QString), QgsField(typ_dat, QMetaType.Type.QString),
QgsField("definicni_body", QMetaType.Type.QString), QgsField("definicni_body", QMetaType.Type.QString),
@@ -1138,11 +1148,11 @@ def load_amcr_data(canvas, bb, filters=None,
if geom.isGeosValid(): if geom.isGeosValid():
t = geom.type() t = geom.type()
target_list = None target_list = None
if t == QgsWkbTypes.PolygonGeometry: if t == QgsWkbTypes.GeometryType.PolygonGeometry:
target_list = feats_p target_list = feats_p
elif t == QgsWkbTypes.LineGeometry: elif t == QgsWkbTypes.GeometryType.LineGeometry:
target_list = feats_l target_list = feats_l
elif t == QgsWkbTypes.PointGeometry: elif t == QgsWkbTypes.GeometryType.PointGeometry:
target_list = feats_pt target_list = feats_pt
if target_list is None: if target_list is None:
@@ -1227,11 +1237,11 @@ def load_amcr_data(canvas, bb, filters=None,
if geom.isGeosValid(): if geom.isGeosValid():
t = geom.type() t = geom.type()
target_list = None target_list = None
if t == QgsWkbTypes.PolygonGeometry: if t == QgsWkbTypes.GeometryType.PolygonGeometry:
target_list = feats_p target_list = feats_p
elif t == QgsWkbTypes.LineGeometry: elif t == QgsWkbTypes.GeometryType.LineGeometry:
target_list = feats_l target_list = feats_l
elif t == QgsWkbTypes.PointGeometry: elif t == QgsWkbTypes.GeometryType.PointGeometry:
target_list = feats_pt target_list = feats_pt
if target_list is None: if target_list is None:
@@ -1265,7 +1275,7 @@ def load_amcr_data(canvas, bb, filters=None,
] ]
feat.setAttributes(atributy) feat.setAttributes(atributy)
target_list.append(feat) target_list.append(feat)
except Exception as ex: except Exception as ex:
QgsMessageLog.logMessage( QgsMessageLog.logMessage(
f"Chyba při tvorbě feature: {ex}", f"Chyba při tvorbě feature: {ex}",
+17 -15
View File
@@ -1,13 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication, QUrl
from qgis.PyQt.QtGui import QIcon, QDesktopServices
from qgis.PyQt.QtWidgets import QMenu, QAction, QToolButton, QDialog
from qgis.core import Qgis
from .amcr_tools import load_amcr_data, login_to_api
from .amcr_dialog import AmcrFilterDialog, LoginDialog
import os.path import os.path
from qgis.core import Qgis
from qgis.PyQt.QtCore import QCoreApplication, QSettings, QTranslator, QUrl
from qgis.PyQt.QtGui import QDesktopServices, QIcon
from qgis.PyQt.QtWidgets import QAction, QDialog, QMenu, QToolButton
from .amcr_dialog import AmcrFilterDialog, LoginDialog
from .amcr_tools import load_amcr_data, login_to_api
class AmcrViewer: class AmcrViewer:
""" """
@@ -29,7 +30,7 @@ class AmcrViewer:
locale_path = os.path.join( locale_path = os.path.join(
self.plugin_dir, self.plugin_dir,
'i18n', 'i18n',
'AmcrViewer_{}.qm'.format(locale) f'AmcrViewer_{locale}.qm'
) )
# Install the translator if a translation file # Install the translator if a translation file
@@ -41,7 +42,7 @@ class AmcrViewer:
# Initialize internal state # Initialize internal state
self.actions = [] self.actions = []
self.menu = self.tr(u'&AMČR Viewer') self.menu = self.tr('&AMČR Viewer')
self.first_start = None self.first_start = None
def tr(self, message): def tr(self, message):
@@ -102,7 +103,7 @@ class AmcrViewer:
# custom dropdown menu # custom dropdown menu
self.action_download_akce = self.add_action( self.action_download_akce = self.add_action(
icon_path=icon_akce_path, icon_path=icon_akce_path,
text=self.tr(u'Stáhnout data akcí | AMČR Viewer'), text=self.tr('Stáhnout data akcí | AMČR Viewer'),
callback=lambda checked=False: self.run_download('akce'), callback=lambda checked=False: self.run_download('akce'),
parent=self.iface.mainWindow(), parent=self.iface.mainWindow(),
add_to_menu=False, add_to_menu=False,
@@ -112,8 +113,9 @@ class AmcrViewer:
self.action_download_pas = self.add_action( self.action_download_pas = self.add_action(
icon_path=icon_pas_path, icon_path=icon_pas_path,
text=self.tr(u'Stáhnout data samostatných nálezů | AMČR Viewer'), text=self.tr('Stáhnout data samostatných nálezů | AMČR Viewer'),
callback=lambda checked=False: self.run_download('samostatny_nalez'), callback=lambda checked=False: self.run_download(
'samostatny_nalez'),
parent=self.iface.mainWindow(), parent=self.iface.mainWindow(),
add_to_menu=False, add_to_menu=False,
add_to_toolbar=False add_to_toolbar=False
@@ -122,7 +124,7 @@ class AmcrViewer:
self.action_download_lokality = self.add_action( self.action_download_lokality = self.add_action(
icon_path=icon_lokality_path, icon_path=icon_lokality_path,
text=self.tr(u'Stáhnout data lokalit | AMČR Viewer'), text=self.tr('Stáhnout data lokalit | AMČR Viewer'),
callback=lambda checked=False: self.run_download('lokalita'), callback=lambda checked=False: self.run_download('lokalita'),
parent=self.iface.mainWindow(), parent=self.iface.mainWindow(),
add_to_menu=False, add_to_menu=False,
@@ -132,7 +134,7 @@ class AmcrViewer:
self.action_login_dialog = self.add_action( self.action_login_dialog = self.add_action(
icon_path=icon_pas_path, icon_path=icon_pas_path,
text=self.tr(u'Přihlásit se | AMČR Viewer'), text=self.tr('Přihlásit se | AMČR Viewer'),
callback=lambda checked=False: self.login(), callback=lambda checked=False: self.login(),
parent=self.iface.mainWindow(), parent=self.iface.mainWindow(),
add_to_menu=False, add_to_menu=False,
@@ -142,7 +144,7 @@ class AmcrViewer:
self.action_amcr_help = self.add_action( self.action_amcr_help = self.add_action(
icon_path=icon_amcr_help_path, icon_path=icon_amcr_help_path,
text=self.tr(u'Nápověda AMČR Help | AMČR Viewer'), text=self.tr('Nápověda AMČR Help | AMČR Viewer'),
callback=lambda checked=False: self.open_help(), callback=lambda checked=False: self.open_help(),
parent=self.iface.mainWindow(), parent=self.iface.mainWindow(),
add_to_menu=False, add_to_menu=False,
+4 -1
View File
@@ -8,7 +8,7 @@ name=AMČR Viewer
qgisMinimumVersion=3.44.0 qgisMinimumVersion=3.44.0
qgisMaximumVersion=4.99.0 qgisMaximumVersion=4.99.0
description=Viewing and downloading the AMČR data. description=Viewing and downloading the AMČR data.
version=2.1.1 version=2.1.2
author=David Spáčil author=David Spáčil
email=spacil@arub.cz email=spacil@arub.cz
@@ -24,6 +24,9 @@ hasProcessingProvider=no
# Uncomment the following line and add your changelog: # Uncomment the following line and add your changelog:
changelog= changelog=
Plný seznam změn v češtině je dostupný zde: https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer/releases/tag/v2.1.1 Plný seznam změn v češtině je dostupný zde: https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer/releases/tag/v2.1.1
v2.1.2 (2026-09-01)
* Qt6 compatibility
* Code clean-up
v2.1.1 (2026-09-01) v2.1.1 (2026-09-01)
* Added download of Individual finds (PAS), including a dedicated menu entry * Added download of Individual finds (PAS), including a dedicated menu entry
* Added filtering by date * Added filtering by date