Compare commits

..
59 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
david-spacil 2218719f98 metadata update 2026-09-01 22:31:28 +02:00
david-spacil 6300919c36 update workflow kvůli nové podmínce s immutable releases 2026-09-01 22:27:00 +02:00
david-spacil 7cffcdb235 Merge pull request #60 from ARUP-CAS/version/v2.1.0
release: AMČR Viewer 2.1.0
2026-09-01 22:11:36 +02:00
david-spacil 0af4a0cd92 chore: verze 2.1.0 a changelog
Shrnuje změny sloučené do této větve oproti main: projektové akce (#53), úklid kódu (#54), stahování samostatných nálezů (#57), diagnostiku prázdných výsledků z API (#58) a filtrování podle data se scrollovatelným dialogem (#59).
2026-09-01 21:59:34 +02:00
david-spacil 9b25863031 chore: update přibaleného hesláře 2026-09-01 21:58:08 +02:00
david-spacil 9ec71c7ed3 feat: filtrování záznamů podle data (#59)
* fix: scrollovatelný filtrační dialog

Obsah dialogu přesahoval okno u všech tří typů dat – u akcí zabíral
přes 1280 px v okně vysokém 750 px, takže spodní filtry i tlačítka
byly nedostupné.

Filtry se nově scrollují. Tlačítka OK / Aktualizovat hesláře / Cancel
zůstávají mimo scrollovanou oblast, aby se kvůli potvrzení dialogu
nemuselo scrollovat na konec seznamu.

* feat: filtrování záznamů podle data

Přidává filtr na datum zahájení a ukončení u akcí a na datum nálezu
u samostatných nálezů (#56). Lokalita filtr nedostává – v jejím indexu
žádné datumové pole není, takže by šlo o ovládací prvek bez účinku.

API vyžaduje obě meze intervalu: jednostranný rozsah shodí server na
ArrayIndexOutOfBoundsException a hvězdičku nepřijímá. Prázdné pole se
proto nahrazuje zarážkou 0001-01-01 / 9999-12-31, což jsou shodou
okolností i výchozí meze QgsDateEdit. Blok s oběma poli prázdnými
neposílá do dotazu nic.

Obrácené rozmezí vrací API jako nula záznamů bez chybové hlášky, což
je k nerozeznání od skutečně prázdného výsledku – dialog ho proto
odmítne už při potvrzení a vypíše, kterých filtrů se to týká.
2026-09-01 21:50:55 +02:00
david-spacil 4ed99d73d9 fix: diagnostika prázdných výsledků z API (#58)
- logování odeslané URL a chyb z těla odpovědi v _api_get_json
- výpis filtrů z dialogu před zahájením stahování
- rozlišení chyby API od prázdného výsledku (api_error)
- dávky geometrií PIAN hlásí chybějící blok 'response'

API vrací chyby s HTTP 200 a klíčem 'error' místo bloku 'response'; resp_json.get('response', {}) z toho udělal prázdný výsledek, takže neplatný parametr, prázdné okno mapy i chyba serveru končily stejnou hláškou "Žádné záznamy nenalezeny".
2026-09-01 20:39:55 +02:00
david-spacil 4699dd9c95 feat: stahování samostatných nálezů (PAS) (#57)
* feature: dialog: přidána nová pole
přidána pole samostatných nálezů pro filtrovací dialog + upravena viditelnost některých spolčných polí (např. skrýt areál, zobrazit organizaci nejen pro akce, ale i pro PAS, ...)

* feature: tlačítko v menu
v kontextové nabídce přibylo tlačítko pro filtrování PASových záznamů; ikona je zatím placeholder

* feature: rozšíření slovníčku
slovníček interních vs api klíčů byl rozšířen o nová pole (nálezce, okolnosti, ...) a zároveň byla změněna jeho struktura: nově obsahuje i base url vzhledem k tomu, že si skript pro data sahá do dvou různých API; přidáno base url pro digiarchiv

* feature: update funkcí pro stahování dat
funkce fetch_set a download_heslare byly upraveny pro stahování dat nejen z OAI-PMH API, ale nově i z API digiarchivu (= osoby se nově nestahují z hesláře osob, ale z facetek digiarchivu, kde mají osoby přidělené "role" nálezce/vedoucí)

* feature: globals pro PAS
založeny nové heslářové globals, pak přidány do funkce refresh_globals

* feature: nové heslářové globals + cache v dialogu

* feature: aktualizace hesláře

* fix: oprava typ_dat = "pas" na typ_dat = "samostatny_nalez"

* feature: dynamičtjší způsob interpretace typu dat
- archeologicky_zaznam nově čerpá human-readable název pro název vrstvy v typ_dat_vocab
- archeologicky_zaznam_l pro ověřování, jestli je současný typ_dat akce nebo lokalita

* feature (wip): první krůčky logiky pro parsování PAS záznamů
- dosavadní logika parsování platná pro akce a lokality je podmíněna typ_dat
- stub logiky parsování pro samostatné nálezy

* feature: čtení dat z JSON payload
získávání sn-specific dat, jako je nálezce, hloubka nálezu, ale i vlastní wkt, které není závislé na PIANu

* feature: párovací slovník metadat pro samostatné nálezy

* fix: Přístupnost přidána do hesláře aliasů

* fix: oprava chyb z dialogu znemožňujících stahování SN

* fix: předávání filtrů k samostatným nálezům z dialogu do "tools" skriptu

* feat: drobné změny
- escapování názvů vrstev (podtržítko místo mezery)
- `actions_with_geom` -> `entries_with_geom`
- čitelný `typ_dat` pro PAS: `PAS` -> `Samostatný nález`

* feat: dokončení smyčky na ukládání metadat k SN z docs

* feat: plnění vrstvy daty SN

* feat: update ikon pro samostatné nálezy a login
2026-09-01 20:28:31 +02:00
david-spacil 7ea2a99ada fix/small-fixes: drobné úpravy stylu a čitelnosti kódu (#54)
* small fixes

* fix: refactoring
rozbaleny listy, doplněny trailing commas
2026-06-28 11:03:15 +02:00
david-spacil 6772a99ead feature/projektové akce: filtrování a sloupec Projekt v akcích (#53)
* feature/projektove-akce: do dialogu akce přidán checkbox pro filtrování projektových akcí + backend logika

* feature/projektove-akce: do atributové tabulky akcí přidáno pole Projekt (prázdné, pokud nejde o projektovou akci)
2026-06-28 10:35:25 +02:00
Claude 9e8863b879 chore: sladění governance se vzorem aiscr-management
- ekosystémová poznámka (sibling hubu aiscr-management)
- konvence větví feat/fix/docs/chore + agents/<jméno>/<téma>
- pravidla pro AI agenty (git delivery)
- bezpečnost/soukromí (žádné secrets/PII)
- deterministické datum pro changelog
- PR šablona: pole Zapojení AI + položka konvence větví

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C8nJvecSSf6vB3NYZsMaVt
2026-06-28 10:26:06 +02:00
Claude 0eb8008e27 chore: PR šablona + AGENTS.md (a CLAUDE.md odkaz) pro standardizaci repozitáře
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C8nJvecSSf6vB3NYZsMaVt
2026-06-28 10:24:00 +02:00
david-spacil bc799452a3 Update metadata.txt 2026-06-13 12:16:27 +02:00
david-spacil ee558aa718 Merge pull request #49 from ARUP-CAS/agents/claude/fix-optim
Opravy chyb a optimalizace napříč pluginem

Souhrn revize celého kódu pluginu:

- Opravy pádů: chybějící locale při startu QGIS; životní cyklus
  úlohy aktualizace heslářů (GC reference, zákaz souběhu, message
  boxy nad hlavním oknem).
- Datová korektnost: transformace fallback geometrií WGS-84 do
  S-JTSK, oprava nevalidních polygonů přes makeValid(), normalizace
  hodnot pian_presnost/pian_typ, heslář přístupnosti bez záznamů
  s kódem None, ošetření null hodnot u komponent.
- Přihlašování a stahování: ověření údajů před uložením do správce
  autentizace, zřetelné hlášení síťových chyb a neúplných výsledků,
  jedno parsování JSON odpovědí, úspornější stránkování, guard proti
  souběžným stahováním, logování do QgsMessageLog.
- Metadata a CI: oprava ikony pluginu, akce ve workflow povýšeny na
  aktuální verze a připnuty na commit hash, poznámka o závislosti
  na requests v README.

Otestováno ručně v QGIS dle checklistu v PR (včetně hraničních
případů: výpadek sítě, expirovaná session, špatné heslo, zrušení
úlohy, prázdné výsledky, limit záznamů).
2026-06-12 13:59:46 +02:00
Claude eebd7668a5 Workflow: připnutí GitHub Actions na commit hash + aktualizace verzí
Reakce na CodeQL upozornění 'Unpinned tag for a non-immutable Action'.
Tag (v4/v2) může vlastník akce kdykoli přepsat na jiný commit; připnutí
na hash chrání release pipeline před podvržením závislosti.

Zároveň povýšeno na nejnovější verze: actions/checkout v6.0.3
a softprops/action-gh-release v3.0.0 (jen přechod na Node 24 runtime,
bez změn API; hashe ověřeny přes git ls-remote).
2026-06-12 13:46:47 +02:00
Claude fd11bee274 Ověření přihlašovacích údajů před uložením do správce autentizace
Špatné heslo zadané v přihlašovacím dialogu se dosud uložilo do QGIS
Authentication Manageru a chyba se ukázala až po zavření dialogu.

- Dialog nyní před uložením zkusí přihlášení k API; při neplatných
  údajích se nic neuloží a uživatel může údaje rovnou opravit.
- Pokud je server nedostupný (údaje nelze ověřit), uživatel si může
  zvolit, zda je uložit neověřené – změna hesla na webu u dříve
  uložených údajů tím není dotčena.
- login_to_api nově rozlišuje důvod selhání (LAST_LOGIN_ERROR:
  'auth' × 'network'), aby dialog uměl oba případy odlišit.
- Ověřuje se i změna samotného e-mailu (proti uloženému heslu).
2026-06-12 12:53:28 +02:00
Claude 93ed0ca810 Zřetelné hlášení síťových chyb během stahování
Při výpadku sítě uprostřed stahování se dosud chyba jen zapsala do logu:
stránkování se tiše ukončilo s částečnými daty a smyčka PIAN zkoušela
marně všechny zbývající dávky, takže uživatel skončil u hlášky 'Žádná
data k zobrazení' bez vysvětlení.

- Síťové chyby (requests.RequestException) se v obou smyčkách chytají
  zvlášť a stahování PIAN se po první z nich ihned ukončí.
- Pokud selže už stahování metadat, zobrazí se červená lišta
  'Stahování selhalo: chyba sítě'.
- Pokud se stihla vykreslit část dat, zobrazí se varování, že výsledek
  je neúplný a je třeba stahování zopakovat.
2026-06-12 12:35:51 +02:00
Claude 64ec1ea7fd Metadata, CI a dokumentace
- metadata.txt: icon ukazoval na neexistující download.png – plugin se
  ve správci zásuvných modulů zobrazoval bez ikony; nastaveno na akce.png.
- Workflow: actions/checkout v2→v4 (v2 je deprecated, Node 12)
  a softprops/action-gh-release v1→v2.
- README: poznámka, že knihovna requests nemusí být na Linuxu součástí
  systémové instalace QGIS.
2026-06-12 10:50:04 +02:00
Claude 27e5fe02ac Heslář pristupnost: přeskočení záznamů bez platného kódu
Pokud žádný titulek záznamu neprojde filtrem na jednopísmenný kód,
next() vrátil None a do heslar.csv se zapsal prázdný/None kód, který
se mohl dostat do API filtru jako hodnota 'None:or'. Takové záznamy
se nyní přeskakují.
2026-06-12 10:50:04 +02:00
Claude 46c09c4a09 Robustnější síťová vrstva a stahování dat
- login_to_api: ošetřena výjimka při parsování ne-JSON odpovědi
  (např. HTML chybová stránka za proxy) – dříve propadla až do QGIS.
- _api_get přejmenováno na _api_get_json: tělo odpovědi se parsuje jen
  jednou (kontrola expirované session ho znovu využije), místo dvojího
  json() na každé dávce.
- Stránkování porovnává počet stažených (ne unikátních) záznamů proti
  numFound – stránky plné duplicit už nevyvolávají zbytečné requesty.
- Přidán re-entrancy guard: během běžícího stahování (processEvents
  pumpuje event loop) nelze spustit druhé stahování.
- print() nahrazeno QgsMessageLog (záložka AMČR v panelu Zprávy).
2026-06-12 10:50:03 +02:00
Claude 444d1c4826 Oprava geometrií a filtrování PIAN
- Fallback geometrie z geom_wkt (WGS-84) se nyní transformuje do S-JTSK;
  dříve se souřadnice ve stupních vkládaly přímo do vrstvy EPSG:5514
  a prvek se vykreslil úplně mimo.
- Nevalidní geometrie (např. samoprůniky polygonů) se před zahozením
  zkusí opravit přes makeValid().
- Filtr přesnosti PIAN normalizuje hodnotu pian_presnost (API ji může
  vracet jako jednoprvkový seznam) – dříve mohl tiše zahazovat záznamy.
  Stejná normalizace pro pian_typ kvůli překladu kódu.
- Přístupy ke komponenta_areal/komponenta_obdobi a az_chranene_udaje
  ošetřeny proti hodnotě None (klíč existuje, ale je null).
2026-06-12 10:50:03 +02:00
Claude d9f5d2ae6e 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).
2026-06-12 10:50:03 +02:00
david-spacil d417a78b85 Update metadata.txt 2026-06-10 13:40:14 +02:00
david-spacil ca827321d8 Update README.md 2026-06-10 13:33:33 +02:00
david-spacil b2001c625c Hotfix: oprava minimální podporované QGIS verze (3.4→3.44) (#48) 2026-06-10 13:31:55 +02:00
david-spacil 88018aa432 Update README.md 2026-06-10 13:16:33 +02:00
david-spacil 45b6ab09b2 Update CITATION.cff 2026-06-05 14:12:54 +02:00
david-spacil 89e596802f Update metadata.txt 2026-06-05 13:44:36 +02:00
david-spacil 4ea679ec9e Přidat odkaz na nápovědu do menu pluginu (#47)
* ikona amcr-help

* přidán kód pro otevření nápovědy
2026-06-05 13:27:01 +02:00
david-spacil 830537f1a4 readme update v2.0.0 (#45) 2026-06-05 11:40:15 +02:00
david-spacil 785b83c9c5 přidána varovná hláška do amcr_dialog (#44) 2026-06-05 10:45:32 +02:00
david-spacil 493696c67b Chore/code cleanup (#43)
* čištění kódu podle flake8

* Update .gitignore

* Update .gitignore (#41)

* oprava komentářů a překlad do angličtiny

* oprava přihlašování
2026-06-04 17:32:32 +02:00
david-spacil b313fc6db0 Update .gitignore 2026-06-04 16:20:11 +02:00
david-spacil 9a935261e6 Update metadata.txt 2026-06-03 13:42:46 +02:00
david-spacil a4e30bf334 hardcoded AND filtering when filtering by period AND activity area (#39) 2026-06-02 22:25:29 +02:00
david-spacil 56389e27d7 nosec update (#38) 2026-05-19 15:44:36 +02:00
David Spáčil c8d42e2459 metadata.txt version update 2026-05-19 15:42:25 +02:00
david-spacil a6ebbce4cf Update metadata.txt 2026-05-19 15:25:38 +02:00
david-spacil 88149fbb30 Hotfix/security (#37)
* vyměnit xml.etree.ElementTree za defusedxml.ElementTree

* zpátky xml.etree.ElementTree, ale přidáno # nosec; jde o false positive

* switch z ukládání hesel v registrech na používání QGIS Auth Manager
2026-05-19 15:22:35 +02:00
david-spacil c0d054d22a Update metadata.txt
v2.0.0-alpha.1
experimental flag true
2026-05-19 13:12:32 +02:00
david-spacil ba41039468 Feature/login (#36)
* přidáno nové tlačítko do toolbaru

* přihlašovací dialog

* funkce pro přihlašování

* aplikace získávání dat z API přes session

* zastřešující akce v main skriptu

* ošetření prodlužování session/opětovné přihlášení

* přidání přístupnosti do hesláře

* aktualizace přibaleného hesláře

* oprava stahování hesláře (pristupnost vyžaduje písmeno [A/B/C/D], ne heslo; aktualizace hesláře

* aplikace přístupnosti do filtračního dialogu

* úpravy přihlašovacího dialogu
2026-05-19 13:05:07 +02:00
david-spacil 499b3b3f0a Fix/komponenta jako zaklad (#35)
* čištění amcr_tools.py od zbytečných prvků souvisejících se standalone tabulkou komponent

* aplikace nové logiky přípravy dat v případě požadavku na komponenty

* nové aliasy + přidání dat komponent do finálních tabulek

* oprava pořadí polí v tabulce
2026-05-16 14:18:17 +02:00
david-spacil 54f154b264 Feature/aktualizace heslaru (#32)
* přechod od statického hesláře k dynamickému načítání z OAI-PMH API AMČR

* aplikace načítání heslářů a task management (backend)

* frontend + debugging

* aktualizace přibaleného hesláře

* kosmetické drobnosti

* ošetření speciální případů při stahování hesláře (katastr, okres) + s tím spojená aktualizace přiloženého hesláře
2026-05-14 14:02:18 +02:00
david-spacil c679e776df Přejmenování názvů atributových polí (#31)
* changed attribute field names

* added aliases
2026-04-16 09:39:49 +02:00
david-spacil a5604dfaa8 Update README.md (#30)
* update README.md (v1.3.2)
2026-04-13 12:49:13 +02:00
david-spacil 11f44d025b Update metadata.txt 2026-03-19 09:38:32 +01:00
david-spacil 7f3b2b46fb Merge pull request #28 from ARUP-CAS/relation-fix
Fix polymorphic relations not creating in some cases
2026-03-19 09:36:37 +01:00
david-spacil be53edefa5 relation fix 2026-03-19 09:30:13 +01:00
david-spacil 3be7832b40 Update metadata.txt 2026-03-16 14:30:12 +01:00
david-spacil 8c0c540fa4 Merge pull request #26 from ARUP-CAS/polymorphic-relation
Polymorphic relation instead of the standard ones; code cleanup
2026-03-16 14:13:50 +01:00
David Spáčil 8088b32661 removed unnecessary imports 2026-03-16 14:01:32 +01:00
David Spáčil c17275ef66 changed from three 1:N relations to a polymorphic relation 2026-03-16 14:00:37 +01:00
david-spacil 9ec866f1d2 Update metadata.txt 2026-03-13 10:56:09 +01:00
17 changed files with 19416 additions and 14039 deletions

No files matched your search

+35
View File
@@ -0,0 +1,35 @@
<!--
Děkujeme za příspěvek! Vyplň prosím sekce níže.
Nepotřebné body můžeš smazat. Komentáře (<!-- ... -->) se v PR nezobrazují.
-->
## Souhrn
<!-- Stručně co a proč. 1–3 věty. -->
## Změny
<!-- Co se konkrétně mění, ideálně po souborech / oblastech. -->
-
## Testování
<!-- Jak ověřit, že to funguje (kroky v QGIS, scénáře). -->
-
## Zapojení AI
<!-- Byla u změny použita AI? Jak? Např. "text navržen AI, ručně zkontrolováno
a upraveno". Smaž, pokud AI použita nebyla. -->
-
## Kontrolní seznam
- [ ] Změny jsou v souladu se stylem projektu (viz `AGENTS.md`)
- [ ] Při změně funkcí povýšena verze v `amcr_viewer/metadata.txt` a doplněn `changelog`
- [ ] Otestováno v QGIS (min. podporovaná verze 3.44)
- [ ] PR míří do správné cílové větve
- [ ] Větev odpovídá konvenci (`feat/ fix/ docs/ chore/<téma>`, AI `agents/<jméno>/<téma>`)
## Související issue
<!-- Např. "Closes #123". Smaž, pokud se neváže k issue. -->
+22 -8
View File
@@ -1,17 +1,28 @@
name: Release QGIS Plugin
# Spouští se na push tagu, ne na publikaci releasu. Organizace má zapnuté
# immutable releases: k už publikovanému releasu nelze nic přiložit, příloha
# tedy musí vzniknout dřív, než se release zveřejní. Workflow proto založí
# koncept releasu i se ZIPem; text se dopisuje a publikuje ručně.
#
# Pozor: workflow se čte z commitu, na který tag ukazuje. Tag musí být
# založen až na commitu, který tento soubor obsahuje.
on:
release:
types: [published]
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
build-and-release:
runs-on: ubuntu-latest
steps:
# 1. Stáhne kód z repozitáře
# 1. Stáhne kód z tagu, který běh spustil
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# 2. Vytvoří ZIP (předpokládá, že kód je ve složce 'amcr_viewer')
- name: Zip Plugin
@@ -20,11 +31,14 @@ jobs:
# -r = rekurzivně, -x = ignorovat skryté git soubory
zip -r amcr_viewer.zip amcr_viewer -x "*.git*"
# 3. Nahraje ZIP k Releasu
- name: Upload Release Asset
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
# 3. Založí koncept releasu i s přílohou
# Tagy s pomlčkou (v2.0.0-alpha.1) se označí jako pre-release.
- name: Create draft release with asset
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with:
files: amcr_viewer.zip
draft: true
name: AMCR Viewer ${{ github.ref_name }}
prerelease: ${{ contains(github.ref_name, '-') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1
View File
@@ -211,3 +211,4 @@ __marimo__/
README_files/
README.html
amcr_viewer.zip
pyrefly.toml
+180
View File
@@ -0,0 +1,180 @@
# AGENTS.md
Pokyny pro AI agenty i lidské přispěvatele pracující v tomto repozitáři.
Tento soubor je jediný zdroj pravdy; `CLAUDE.md` na něj pouze odkazuje.
## O projektu
**AMČR Viewer** je plugin do QGIS pro stahování a vizualizaci dat z Digitálního
archivu Archeologické mapy ČR (AMČR / AIS CR) – akce (*Fieldwork events*),
lokality (*Sites*) a jejich komponenty. Podporuje anonymní i přihlášený přístup
přes AMČR účet.
Zdroj dat: https://digiarchiv.aiscr.cz/ · Nápověda: https://amcr-help.aiscr.cz/digiarchiv/qgis-viewer.html
## Zařazení v ekosystému AIS CR
Tento repozitář je jedním ze **sourozeneckých repozitářů** ekosystému AIS CR.
Centrální governance a AI konfigurace spravuje hub **`aiscr-management`**; konvence
v tomto souboru jsou s tímto vzorem sladěné a zjednodušené pro potřeby jednoho
QGIS pluginu. Těžkou mašinerii hubu (složka `.agents/`, OpenSpec, sync skripty,
multi-assistant generování) tento repozitář **záměrně nepřebírá**. Při širších
otázkách governance má přednost vzor z `aiscr-management`.
## Struktura repozitáře
```
amcr_viewer/ # vlastní kód pluginu (toto se balí do releasu)
amcr_viewer.py # vstupní bod pluginu, integrace do QGIS
amcr_dialog.py # dialogy a UI (filtry, přihlášení)
amcr_tools.py # stahování dat z API, sestavení vrstev a atributů
amcr_codelists.py # hesláře / číselníky (codelists)
codelists/heslar.csv # lokální kopie číselníků
metadata.txt # metadata pluginu + verze + changelog
i18n/ # překlady (.ts)
*.png # ikony
.github/workflows/ # CI – release pluginu
README.md # uživatelská dokumentace (anglicky)
```
## Konvence
### Jazyk
- **Kód a identifikátory:** anglicky. Atributová pole vrstev musí být ASCII
kompatibilní (bez diakritiky) – viz historie změn v `metadata.txt`.
- **README a uživatelská dokumentace:** anglicky.
- **Commity, PR a komentáře v issue:** česky.
### Commity
- Styl odpovídá historii: česky, věcně, popisně; jeden commit = jedna logická
změna.
- První řádek stručně a výstižně (ideálně v imperativu); podrobnosti do těla.
- Pokud je commit připraven s pomocí AI, uveď to v těle commitu nebo v popisu PR.
### Větve
Konvence názvů je sladěná s hubem `aiscr-management`:
- **lidé:** `feat/<téma>` (nová funkce), `fix/<téma>` (oprava), `docs/<téma>`
(dokumentace), `chore/<téma>` (údržba).
- **AI agenti:** `agents/<jméno-agenta>/<téma>` (např. `agents/claude/oprava-pian`).
Další pravidla:
- Cílová větev pro nový vývoj je aktuální `version/v2.x.y` (ne přímo do
výchozí větve bez PR).
- **Nikdy** nepushuj přímo do chráněných větví; vždy přes Pull Request.
- Standardizační / nefunkční změny drž v samostatné větvi, ať se nemíchají do
feature PR.
### Pravidla pro AI agenty (git)
- AI ve výchozím stavu zůstává u **lokální práce na aktuální větvi**.
- Bez **výslovného pokynu** uživatele AI nestageuje (`git add`), necommituje,
nepushuje ani samo nepřepíná/nezakládá větev pro vzdálené doručení.
- Při výslovném požadavku na push/PR použij větev `agents/<jméno-agenta>/<téma>`;
pokud aktuální větev tomuto vzoru neodpovídá, vyžádej si nejdřív potvrzení.
- Vytvoření větve, stage, commit, push ani draft PR AI běžně nenabízí; zmiňuj je
jen tehdy, když jsou pro splnění úkolu opravdu nutné.
### QGIS specifika
- Minimální podporovaná verze QGIS je **3.44** (`qgisMinimumVersion` v
`metadata.txt`); kód nesmí spoléhat na novější API.
- Vrstvy a atributy se sestavují přes `QgsField` / QGIS API v `amcr_tools.py`.
Při přidání atributu je potřeba doplnit ho konzistentně na všech místech:
definice pole (`QgsField`), naplnění hodnoty z dokumentu, překlad hlavičky
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
- Verze pluginu žije v **`amcr_viewer/metadata.txt`** (`version=`).
- **Při každé změně chování / nové funkci** povyš verzi a doplň položku do
`changelog=` v `metadata.txt` (formát `vX.Y.Z (RRRR-MM-DD)` + odrážky).
- Datum v changelogu ber z **deterministického zdroje**, ne z paměti, např.
`python -c "import datetime; print(datetime.date.today().isoformat())"`.
- Release se spouští **pushnutím tagu `vX.Y.Z`**, ne publikací releasu
v UI. Workflow `.github/workflows/release_plugin.yml` zabalí složku
`amcr_viewer/` do `amcr_viewer.zip` a založí **koncept** releasu i s touto
přílohou; text se dopíše a release zveřejní ručně. Do ZIPu se nesmí dostat
`.git*` soubory.
- Organizace má zapnuté **immutable releases** – k publikovanému releasu už
nelze nic přiložit. Proto příloha vzniká na konceptu, ještě před
zveřejněním; workflow spouštěný na `release: published` by vždy selhal.
- Workflow se čte z commitu, na který **tag ukazuje**. Tag proto zakládej až
na commitu, který obsahuje aktuální podobu workflow – jinak se nespustí nic.
## Pull requesty
- Používej PR šablonu (`.github/pull_request_template.md`): Souhrn / Změny /
Testování / Kontrolní seznam.
- PR musí mířit do správné `version/v2.x.y` větve.
- Před požádáním o review projdi kontrolní seznam v šabloně (zejména bump verze
v `metadata.txt`, pokud měníš chování).
- V popisu PR uveď **podíl AI** (např. „text navržen AI, ručně zkontrolováno")
a odkaz na související issue, pokud existuje.
## Bezpečnost a soukromí
- Do promptů, příkladů ani commitů **nevkládej** ostrá produkční data, plné
log dumpy ani reálné osobní údaje (PII).
- **Rediguj** secrets, tokeny, API klíče a hesla z čehokoli, co posíláš AI;
nikdy je necommituj do repozitáře (ani přihlašovací údaje k AMČR účtu).
- Pro interní infrastrukturu (URL, hostname, prostředí) používej placeholdery,
pokud konkrétní hodnota není nutná a povolená.
## Lokální ověření
Plugin se testuje načtením do QGIS (Plugins → Manage and Install Plugins →
Install from ZIP, nebo nasazením složky `amcr_viewer/` do adresáře pluginů
QGIS). Automatizované testy zatím repozitář neobsahuje – změny ověřuj ručně
v QGIS na podporované verzi.
+6 -7
View File
@@ -20,11 +20,10 @@ identifiers:
value: 10.5281/zenodo.18609813
repository-code: 'https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer'
abstract: >-
This QGIS plugin is intended for downloading the data
(Fieldwork events data only, at the time) from the
Digiarchive of the Archaeological Map of the Czech
Republic (AMCR). As of now, only publicly accessible data
can be downloaded.
This plugin is intended for downloading the data
(Fieldwork events, Sites, and their Components) from
the Digital archive of the Archaeological Map of the
Czech Republic (https://digiarchiv.aiscr.cz/).
license: GPL-3.0
version: '1.0.1'
date-released: '2026-02-11'
version: '2.0.0'
date-released: '2026-06-05'
+6
View File
@@ -0,0 +1,6 @@
# CLAUDE.md
Pokyny pro tento repozitář jsou v [`AGENTS.md`](./AGENTS.md).
Tento soubor je záměrně jen odkaz, aby existoval jeden zdroj pravdy a obsah se
nerozjel. Cokoli platí pro AI agenty v tomto projektu, najdeš v `AGENTS.md`.
+111 -52
View File
@@ -2,7 +2,7 @@
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
**Platform:** QGIS 3.4.x
**Platform:** QGIS 3.44.0–4.99.0
**Module Type:** Data Acquisition & Visualization
@@ -12,8 +12,7 @@
## 1. Overview
**AMCR Viewer** is a QGIS plugin designed to facilitate direct access to the Digital Archive of the Archaeological Map of the Czech Republic (AMČR). It allows researchers to **query, retrieve, and visualize *Fieldwork events* and *Sites* data (metadata and geometry) directly within the GIS environment**, eliminating the need to manually export data from the web interface. Both *Fieldwork events* and *Sites* layers may be accompanied by a *Components* layer with additional information. **Only publicly accessible data are supported at the time** (accessibility = anonymous).
**AMCR Viewer** is a QGIS plugin designed to facilitate direct access to the Digital Archive of the Archaeological Map of the Czech Republic (AMČR). It allows researchers to **query, retrieve, and visualize *Fieldwork events* and *Sites* data (metadata and geometry) directly within the GIS environment**, eliminating the need to manually export data from the web interface. Both *Fieldwork events* and *Sites* layers may optionally include component-level data (period and activity area) embedded directly in the attribute table. The plugin supports both **anonymous (public) access** and **authenticated access** for users with an AMČR account.
### Key Features
@@ -21,103 +20,163 @@
* **Advanced Attribute Filtering:** Supports multi-criteria filtering using controlled vocabularies.
* **Dynamic Geometry Retrieval:** Automatically downloads and categorizes spatial data into Point, Line, and Polygon layers.
* **Semantic Interoperability:** Automatically translates internal system codes into human-readable labels using the AIS CR API.
---
* **Authenticated Access:** Users with an AMČR account can log in to access non-public records.
## 2. Installation Guide
**Install the plugin from QGIS plugin repository.**
**Install the latest version of the plugin from the QGIS plugin repository.**
**OR**
**OR** (*in case you need older version*)
*1. Obtain the [plugin distribution package](https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer/releases) (ZIP archive containing the `amcr_viewer` directory).*
*2. Launch QGIS.*
*3. Navigate to Plugins → Manage and Install Plugins...*
*4. Select the Install from ZIP tab.*
*5. Locate the source ZIP file and click Install Plugin.*
*6. Upon successful installation, the AMCR download button (load AMCR data) will appear in the interface.*
---
1. *Obtain the [plugin distribution package](https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer/releases) (ZIP archive containing the `amcr_viewer` directory).*
2. *Launch QGIS.*
3. *Navigate to Plugins → Manage and Install Plugins...*
4. *Select the Install from ZIP tab.*
5. *Locate the source ZIP file and click Install Plugin.*
6. *Upon successful installation, the AMCR Viewer button will appear in the toolbar.*
## 3. User Manual
### 3.1 Data Retrieval
### 3.1 Authentication (Optional)
To initiate a search query, click either the **Stáhnout data akcí** or the **Stáhnout data lokalit** icon from the dropdown menu. The filter dialog provides the following options. Shown options vary based on the choosed tool.
By default, the plugin accesses only publicly available records (accessibility = anonymous). To access non-public data, log in using your AMČR account:
* **Spatial Filter:** *Checkbox "Limit search to current map extent":* If checked, the query is restricted to the geographical area currently visible in the QGIS canvas. If unchecked, the query searches the entire database (use with caution regarding data volume).
* It is possible to view only those Fieldwork events with positive outcome, if "Positive findings only" is checked. Only *PIANs* marked as (or rather *PIANs* belonging to Documentation units marked as) "Type of evidence" = "positive" are rendered.
* Click the dropdown arrow on the AMCR Viewer toolbar button and select **Přihlásit se**.
* Enter your e-mail and password. Credentials are encrypted and stored securely in the **QGIS Authentication Manager** (DPAPI on Windows, Keychain on macOS, encrypted SQLite on Linux).
* Stored credentials are reused automatically across sessions. To update or remove them, open the login dialog again.
### 3.2 Data Retrieval
To initiate a search query, click either the **Stáhnout data akcí** or the **Stáhnout data lokalit** option from the dropdown menu. The filter dialog provides the following options. Shown options vary based on the chosen tool.
* **Spatial Filter:** *Checkbox "Omezit vyhledávání rozsahem okna":* If checked, the query is restricted to the geographical area currently visible in the QGIS canvas. If unchecked, the query searches the entire database (use with caution regarding data volume).
* **Positive findings only:** If checked, only *PIANs* belonging to Documentation units marked as "Type of evidence" = "positive" are included. *(Fieldwork events only.)*
* **Attribute Filters:**
* The dialog utilizes "Picker" widgets for controlled vocabularies (common: Region, District, Cadastral area, Period, Activity Area, *PIAN* accuracy; *events* related: Organisation, Researcher, Event type; *sites* related: Site type and class, Level of confidence, State of preservation).
* Click **Select...** to open a searchable selection window. Multiple values can be selected simultaneously (Logic: OR).
* The dialog uses "Picker" widgets for controlled vocabularies (common: Region, District, Cadastral area, Period, Activity Area, *PIAN* accuracy, Accessibility; *events* related: Organisation, Researcher, Event type; *sites* related: Site type and class, Level of confidence, State of preservation).
* Click **Vybrat...** to open a searchable selection window. Multiple values can be selected simultaneously (Logic: OR).
* **Codelists (Hesláře):**
* Controlled vocabularies are downloaded from the AMČR OAI-PMH API and cached locally in `codelists/heslar.csv`.
* To refresh all codelists, click the **Aktualizovat hesláře 🔄** button in the filter dialog. This runs as a background task and may take a few minutes.
* **Fieldwork Manager (Dynamic List):**
* Due to the dynamic nature of the persons database, the list of Fieldwork Managers is retrieved from the AIS CR servers and needs to be updated the first time (and subsequently, if there is need).
* To refresh the list from the server, click the **Refresh (🔄)** button next to the selection field. This downloads the latest list of researchers from the API.
* **Components:** Check **Načíst komponenty** to include period and activity area data directly in the output layers.
> ⚠ When components are loaded, spatial features are duplicated — each feature corresponds to one component. Spatial analyses (areas, counts) may be inaccurate.
* **Components:** The *components* data are downloaded as well upon checking the corresponding check box. This enriches the main (*Events* and *Sites*) layers with additional information (period and activity area).
* If no filter is used, all accessible Fieldwork events/PIANs are returned (although the number of Fieldwork events to be loaded is capped at 20000 records; it is advisable to set at least one filter).
* If no filter is used, all accessible Fieldwork events/PIANs are returned (the number of records is capped at 20 000; it is advisable to set at least one filter).
For a more in-depth tutorial refer to the [AMČR Documentation](https://amcr-help.aiscr.cz/digiarchiv/qgis-viewer.html) (only in Czech).
### 3.3 Layer Structure & Attributes
Upon successful retrieval, the plugin generates up to three temporary memory layers:
### 3.2 Layer Structure & Attributes
1. **AMCR\_[Akce|Lokalita]\_Polygony**
2. **AMCR\_[Akce|Lokalita]\_Linie**
3. **AMCR\_[Akce|Lokalita]\_Body**
Upon successful retrieval, the plugin generates four temporary memory layers:
Layers are only created if the query returns features of the corresponding geometry type. All layers share the same attribute schema.
1. **AMCR Plochy (Polygons)**
2. **AMČR Linie (Lines)**
3. **AMČR Body (Points)**
4. **AMČR Komponenty (*Components*/no geometry)**
#### 3.3.1 Common fields
The Attribute Table includes standardized fields with important metadata. The components layer has no geometry on its own and depend solely on a relation with the other three layers.
| Field | Description |
| --- | --- |
| pian | PIAN (spatial identifier) ID |
| presnost | Spatial deviation \[units/tens/hundreds of meters/defined by cadastre\] |
| pian\_typ | \[point/line/polygon\] |
| dj | Documentation unit ID |
| typ\_dj | \[trench/event part/whole event/cadastral territory\] |
| definicni\_body | Feature centroid in WGS-84 coordinate system |
| akce / lokalita | Fieldwork event / Site ID |
| odkaz\_do\_digiarchivu | Link to the record in the Digital Archive |
| okres | District |
| katastr | Main cadastral area |
| dalsi\_katastry | Other cadastral areas, if the event extends beyond the main cadastre |
| Přístupnost | Record accessibility \[A/B/C/D\] |
---
#### 3.3.2 Fields related to *Fieldwork events*
| Field | Description |
| --- | --- |
| akce\_lokalizace | Verbal description of the event location |
| vedouci | Main fieldwork manager |
| organizace | Organisation conducting the research |
| specifikace\_data | \[exact date/exact years/sometime in years\] |
| zahajeni | Event start date |
| ukonceni | Event end date |
| hlavni\_typ | Primary research method |
| vedlejsi\_typ | Secondary research method |
| zjisteni | Did the research reveal archaeological contexts? \[positive/negative\] |
| nahrazuje\_NZ | Replaces a fieldwork report? \[yes/no\] |
#### 3.3.3 Fields related to *Sites*
| Field | Description |
| --- | --- |
| nazev\_lokality | Site name |
| popis\_lokality | Site description |
| typ\_lokality | Site classification by definition method |
| druh\_lokality | Site classification by the nature of identified field relics |
| zachovalost | Site preservation state |
#### 3.3.4 Component fields (only when *Načíst komponenty* is checked)
| Field | Description |
| --- | --- |
| komponenta | Component ID |
| komponenta\_areal | Activity area \[settlement/burial area/field/…\] |
| komponenta\_obdobi | Period \[Neolithic/High Middle Ages–Modern Period/…\] |
## 4. Technical Architecture
The plugin is developed in **Python 3** using the **PyQt5** framework for the GUI and the **Requests** library for HTTP communication.
The plugin is developed in **Python 3** using the **PyQt6** framework for the GUI and the **Requests** library for HTTP communication.
> **Note:** The `requests` library is bundled with the QGIS installers for Windows and macOS. On Linux (distribution packages), it may need to be installed separately (e.g. `python3-requests`).
### 4.1 File Structure
* `amcr_viewer.py`: Entry point; handles GUI integration and initialization.
* `amcr_dialog.py`: Manages the UI logic, including the custom `FilterableSelectionDialog` for handling large vocabularies.
* `amcr_tools.py`: Core logic module. Handles API requests, pagination, data parsing, and vector layer generation.
* `amcr_codelists.py`: Manages local caching of controlled vocabularies (`codelists/*.csv`).
* `amcr_viewer.py`: Entry point; handles GUI integration, toolbar/menu setup, and login flow.
* `amcr_dialog.py`: Manages the UI logic, including `AmcrFilterDialog`, `FilterableSelectionDialog`, and `LoginDialog`.
* `amcr_tools.py`: Core logic module. Handles authentication, API requests, pagination, data parsing, and vector layer generation.
* `amcr_codelists.py`: Manages local caching of controlled vocabularies (`codelists/heslar.csv`) downloaded via OAI-PMH.
### 4.2 Data Flow & API Integration
The plugin interacts with three primary endpoints of the AIS CR infrastructure:
The plugin interacts with the following endpoints:
1. **Search API (Solr):**
1. **Login API:**
* Endpoint: `https://digiarchiv.aiscr.cz/api/user/login`
* Method: `POST`
* Returns a session cookie used for subsequent authenticated requests.
* Credentials are stored in the QGIS Authentication Manager; the session is restored automatically if it expires mid-download.
2. **Search API (Solr):**
* Endpoint: `https://digiarchiv.aiscr.cz/api/search/query`
* Method: `GET`
* Parameters: `entity=akce`, `rows/page` (pagination).
* Logic: The plugin implements a `while True` loop to handle pagination, processing data in batches of 500 records to ensure stability.
* Parameters: `entity=akce|lokalita|pian`, `rows/page` (pagination), `mapa=true`.
* Logic: Paginated in batches of 500 records (metadata) and 200 records (geometries). A safety cap of 20 000 records is enforced.
2. **Translation API:**
3. **Translation API:**
* Endpoint: `https://digiarchiv.aiscr.cz/api/assets/i18n/cs.json`
* Function: Retrieves the mapping between system codes (e.g., `HES-xxxx`) and Czech labels. This dictionary is cached in memory during the session.
* Function: Retrieves the mapping between system codes (e.g. `HES-xxxx`) and Czech labels. Cached in memory for the session.
4. **Codelists API (OAI-PMH):**
* Endpoint: `https://api.aiscr.cz/2.2/oai`
* Used for downloading controlled vocabularies (periods, regions, organisations, etc.) on demand.
### 4.3 Data Persistence
* **Vocabularies:** Static vocabularies (e.g., Periods, Regions) are stored in `codelists/heslar.csv`.
* **Dynamic Data:** The list of researchers is downloaded on-demand and cached in `codelists/vedouci.csv`.
* **Vocabularies:** Stored in `codelists/heslar.csv`; updated on user request via the background task.
* **Layers:** Output layers are created as `memory` layers. They are non-persistent and will be lost if QGIS is closed without saving.
### 4.4 Constraints
* **Record Limit:** A safety cap of 20,000 records is enforced.
* **Batch Processing:** Geometry fetching is batched (50 IDs per request) to comply with URL length limitations and server load balancing.
* **Record Limit:** A safety cap of 20 000 records is enforced.
* **Batch Processing:** Geometry fetching is batched (200 IDs per request) to comply with URL length limitations and server load balancing.
* **Component duplication:** When components are loaded, each output feature corresponds to one component rather than one documentation unit. A single PIAN may therefore appear multiple times in the layer.
## 6. Links and resources
## 5. Links and resources
* [AMCR/Digiarchive Documentation](https://amcr-help.aiscr.cz/) (only in Czech).
* [AMCR Viewer tutorial](https://amcr-help.aiscr.cz/digiarchiv/qgis-viewer.html) (only in Czech).
* [Import/Export. Pluginy propojující QGIS s AMČR \[poster\]](https://zenodo.org/records/20504909) (only in Czech; valid for v1.3.2).
-1
View File
@@ -31,6 +31,5 @@ def classFactory(iface): # pylint: disable=invalid-name
:param iface: A QGIS interface instance.
:type iface: QgsInterface
"""
#
from .amcr_viewer import AmcrViewer
return AmcrViewer(iface)
Binary file not shown.

After

Width:  |  Height:  |  Size: 533 B

+266 -76
View File
@@ -1,19 +1,59 @@
# -*- coding: utf-8 -*-
import os
# -*- coding: utf-8 -*-
import csv
import os
import time
import xml.etree.ElementTree as ET # nosec
import requests
from qgis.core import Qgis, QgsMessageLog
# Define paths for the plugin and its codelists directory
PLUGIN_DIR = os.path.dirname(__file__)
CODELISTS_DIR = os.path.join(PLUGIN_DIR, 'codelists')
BASE_URL_AMCR = "https://api.aiscr.cz/2.2/oai"
BASE_URL_DA = "https://digiarchiv.aiscr.cz/api/search/query"
OUTPUT_FILE = os.path.join(CODELISTS_DIR, 'heslar.csv')
slovnicek = {
'obdobi': (BASE_URL_AMCR, 'heslo:obdobi'),
'typ_akce': (BASE_URL_AMCR, 'heslo:akce_typ'),
'areal': (BASE_URL_AMCR, 'heslo:areal'),
'kraj': (BASE_URL_AMCR, 'ruian_kraj'),
'organizace': (BASE_URL_AMCR, 'organizace'),
'okres': (BASE_URL_AMCR, 'ruian_okres'),
'katastr': (BASE_URL_AMCR, 'ruian_katastr'),
'pian_presnost': (BASE_URL_AMCR, 'heslo:pian_presnost'),
'typ_lokality': (BASE_URL_AMCR, 'heslo:lokalita_typ'),
'druh_lokality': (BASE_URL_AMCR, 'heslo:lokalita_druh'),
'jistota': (BASE_URL_AMCR, 'heslo:jistota_urceni'),
'lokalita_zachovalost': (BASE_URL_AMCR, 'heslo:stav_dochovani'),
'pristupnost': (BASE_URL_AMCR, 'heslo:pristupnost'),
'nalez_kategorie': (BASE_URL_AMCR, 'heslo:predmet_druh_kat'),
'druh_nalezu': (BASE_URL_AMCR, 'heslo:predmet_druh'),
'specifikace': (BASE_URL_AMCR, 'heslo:predmet_specifikace'),
'nalezove_okolnosti': (BASE_URL_AMCR, 'heslo:nalezove_okolnosti'),
'vedouci': (BASE_URL_DA, 'f_vedouci'),
'nalezce': (BASE_URL_DA, 'f_nalezce'),
}
NS = {
'oai': 'http://www.openarchives.org/OAI/2.0/',
'dc': 'http://purl.org/dc/elements/1.1/',
'oai_dc': 'http://www.openarchives.org/OAI/2.0/oai_dc/'
}
def ensure_codelists_dir():
"""Creates the codelists directory if it does not exist."""
if not os.path.exists(CODELISTS_DIR):
os.makedirs(CODELISTS_DIR)
def parse_codelist_file(filename, target_dict=None):
"""Reads a CSV codelist file and populates the target dictionary grouped by categories."""
"""
Reads a CSV codelist file and populates
the target dictionary grouped by categories.
"""
if target_dict is None:
target_dict = {}
@@ -39,108 +79,258 @@ def parse_codelist_file(filename, target_dict=None):
cat = row[2].strip()
clean = code if code else None
# Initialize a new dictionary for a category if encountered for the first time
# Initialize a new dictionary for a category if encountered
# for the first time
if cat not in target_dict:
target_dict[cat] = {}
# Assign the extracted code to the corresponding label within the category
# Assign the extracted code to the corresponding label
# within the category
target_dict[cat][label] = clean
except Exception as e:
print(f"AMČR Codelist Read Error for {filename}: {e}")
QgsMessageLog.logMessage(
f"AMČR Codelist Read Error for {filename}: {e}",
"AMČR", Qgis.MessageLevel.Critical)
return target_dict
def load_all_data():
"""Loads all static and dynamic codelists during plugin startup."""
"""Loads the codelist during plugin startup."""
ensure_codelists_dir()
# Initialize the base structure with empty dictionaries for all expected categories
categorized_data = {
'obdobi': {}, 'typ_akce': {}, 'areal': {},
'kraj': {}, 'organizace': {}, 'okres': {}, 'katastr': {},
'vedouci': {}, 'pian_presnost': {}, 'typ_lokality': {}, 'druh_lokality': {},
'jistota': {}, 'lokalita_zachovalost': {}
}
# Parse the default static codelist and the dynamically generated leaders codelist
categorized_data = {k: {} for k in slovnicek}
parse_codelist_file('heslar.csv', categorized_data)
parse_codelist_file('vedouci.csv', categorized_data)
return categorized_data
def download_vedouci():
"""Fetches the list of leaders from the AMČR API and saves it to a CSV file."""
ensure_codelists_dir()
# API endpoint for fetching facet data for leaders
url = "https://digiarchiv.aiscr.cz/api/search/query?entity=akce&sort=datestamp%20desc&page=0&onlyFacets=True&rows=0"
def fetch_set(base_url, internal_name, api_set, task=None):
dataset = []
params_amcr = {
"verb": "ListRecords",
"metadataPrefix": "oai_dc",
"set": api_set
}
params_da = {
"entity": "samostatny_nalez" if internal_name == "nalezce" else "akce",
"rows": 0,
"noFacets": "false",
"onlyFacets": "true"
}
while True:
# Check for cancellation at each iteration
if task and task.isCanceled():
return None
try:
# Execute the GET request with a 20-second timeout
r = requests.get(url, timeout=20)
r.raise_for_status()
data = r.json()
if "digiarchiv" not in base_url:
response = requests.get(
base_url, params=params_amcr, timeout=30
)
response.raise_for_status()
root = ET.fromstring(response.content) # nosec
# Extract the leaders list from the JSON response using safe dict getters
vedouci_list = data.get('facet_counts', {}).get('f_vedouci', [])
if not vedouci_list:
vedouci_list = data.get('facet_counts', {}).get('facet_fields', {}).get('f_vedouci', [])
records = root.findall('.//oai:record', NS)
for rec in records:
metadata = rec.find('.//oai_dc:dc', NS)
if metadata is not None:
# Code (identifier)
identifier_el = metadata.find('dc:identifier', NS)
kod = (
identifier_el.text
if identifier_el is not None
else ""
)
csv_path = os.path.join(CODELISTS_DIR, 'vedouci.csv')
# Title – filter out system labels "AMČR - ..."
titles = metadata.findall('dc:title', NS)
nazev = ""
for t in titles:
if (
t.text
and not t.text.startswith("AMČR -")
and not t.text.startswith(" AMČR -")
):
nazev = t.text
break
# If no title passed the filter, fall back
# to the first available one
if not nazev and titles:
nazev = titles[0].text
count = 0
specialni_pripady = ['okres', 'katastr']
# Open the target CSV file for writing without extra blank lines
with open(csv_path, 'w', encoding='utf-8', newline='') as f:
writer = csv.writer(f, delimiter=';')
if internal_name in specialni_pripady:
kod = nazev
# Write the standard header required by the parser function
writer.writerow(['Název', 'Kód', 'Kategorie'])
if internal_name == 'pristupnost':
kod = next(
(
t.text for t in titles
if t.text
and len(t.text) == 1
and t.text.isalpha()
),
None
)
# Skip records without a valid one-letter code –
# a None code would end up in the CSV and later
# in the API filter as the string "None"
if not kod:
continue
# Iterate through the API results and format them for the CSV
for item in vedouci_list:
name = None
if isinstance(item, dict):
name = item.get('name')
elif isinstance(item, str):
name = item
dataset.append({
'Název': nazev,
'Kód': kod,
'Kategorie': internal_name
})
# Ignore pure numbers (which are usually counts) and write valid names
if name and not str(name).isdigit():
writer.writerow([name, name, 'vedouci'])
count += 1
# Pagination
token = root.find('.//oai:resumptionToken', NS)
if token is not None and token.text:
params_amcr = {
"verb": "ListRecords",
"resumptionToken": token.text
}
time.sleep(0.5)
else:
break
return True, f"Staženo {count} jmen."
else:
response = requests.get(base_url, params=params_da, timeout=30)
response.raise_for_status()
data_json = response.json()
records = data_json['facet_counts']['facet_fields'][api_set]
for r in records:
nazev = r["name"]
dataset.append({
'Název': nazev,
'Kód': nazev,
'Kategorie': internal_name
})
break
except Exception as e:
return False, str(e)
QgsMessageLog.logMessage(
f"Chyba u setu {api_set}: {e}",
"AMČR", Qgis.MessageLevel.Warning)
break
# Initialize global codelist data when the module is imported
_DATA = load_all_data()
return dataset
# Safely extract individual categories into global variables for easy access across the plugin
OBDOBI = _DATA.get('obdobi', {})
TYP_AKCE = _DATA.get('typ_akce', {})
AREAL = _DATA.get('areal', {})
KRAJE = _DATA.get('kraj', {})
ORGANIZACE = _DATA.get('organizace', {})
OKRESY = _DATA.get('okres', {})
KATASTRY = _DATA.get('katastr', {})
VEDOUCI = _DATA.get('vedouci', {})
PIAN_PRESNOST = _DATA.get('pian_presnost', {})
TYP_LOKALITY = _DATA.get('typ_lokality', {})
DRUH_LOKALITY = _DATA.get('druh_lokality', {})
JISTOTA = _DATA.get('jistota', {})
LOKALITA_ZACHOVALOST = _DATA.get('lokalita_zachovalost', {})
def refresh_vedouci_cache():
"""Reloads only the 'vedouci.csv' file to quickly update the cache without full initialization."""
# Parse only the targeted file containing the updated leaders
temp_data = parse_codelist_file('vedouci.csv')
new_vedouci = temp_data.get('vedouci', {})
def download_heslare(task=None):
"""Fetches the codelists from the AMČR API and saves it to a CSV file."""
ensure_codelists_dir()
all_data = []
total_sets = len(slovnicek)
# index, (interni, api_nazev)
for index, (key, value) in enumerate(slovnicek.items()):
# Clear the existing global dictionary and update it with the fresh data
base_url = value[0]
interni = key
api_nazev = value[1]
# Check if the user cancelled the task via the QGIS taskbar
if task and task.isCanceled():
return False
QgsMessageLog.logMessage(
f"Zpracovávám kategorii: {interni}...",
"AMČR", Qgis.MessageLevel.Info)
# Pass the task correctly to the updated fetch function
data = fetch_set(base_url, interni, api_nazev, task=task)
if data is None:
return False # Cancelled mid-download
all_data.extend(data)
# Report progress (0-100)
if task:
progress = (index + 1) / total_sets * 100
task.setProgress(progress)
# Save to CSV
with open(OUTPUT_FILE, 'w', newline='', encoding='utf-8-sig') as f:
fieldnames = ['Název', 'Kód', 'Kategorie']
writer = csv.DictWriter(f, fieldnames=fieldnames, delimiter=';')
writer.writeheader()
writer.writerows(all_data)
return True
def refresh_globals():
"""Reloads data from files into the global variables."""
data = load_all_data()
OBDOBI.clear()
OBDOBI.update(data.get('obdobi', {}))
TYP_AKCE.clear()
TYP_AKCE.update(data.get('typ_akce', {}))
AREAL.clear()
AREAL.update(data.get('areal', {}))
KRAJE.clear()
KRAJE.update(data.get('kraj', {}))
ORGANIZACE.clear()
ORGANIZACE.update(data.get('organizace', {}))
OKRESY.clear()
OKRESY.update(data.get('okres', {}))
KATASTRY.clear()
KATASTRY.update(data.get('katastr', {}))
VEDOUCI.clear()
VEDOUCI.update(new_vedouci)
VEDOUCI.update(data.get('vedouci', {}))
PIAN_PRESNOST.clear()
PIAN_PRESNOST.update(data.get('pian_presnost', {}))
TYP_LOKALITY.clear()
TYP_LOKALITY.update(data.get('typ_lokality', {}))
DRUH_LOKALITY.clear()
DRUH_LOKALITY.update(data.get('druh_lokality', {}))
JISTOTA.clear()
JISTOTA.update(data.get('jistota', {}))
LOKALITA_ZACHOVALOST.clear()
LOKALITA_ZACHOVALOST.update(data.get('lokalita_zachovalost', {}))
PRISTUPNOST.clear()
PRISTUPNOST.update(data.get('pristupnost', {}))
NALEZ_KATEGORIE.clear()
NALEZ_KATEGORIE.update(data.get('nalez_kategorie', {}))
DRUH_NALEZU.clear()
DRUH_NALEZU.update(data.get('druh_nalezu', {}))
SPECIFIKACE.clear()
SPECIFIKACE.update(data.get('specifikace', {}))
NALEZOVE_OKOLNOSTI.clear()
NALEZOVE_OKOLNOSTI.update(data.get('nalezove_okolnosti', {}))
NALEZCE.clear()
NALEZCE.update(data.get('nalezce', {}))
return len(VEDOUCI)
# Initialize empty dicts that will be populated immediately below
OBDOBI = {}
TYP_AKCE = {}
AREAL = {}
KRAJE = {}
ORGANIZACE = {}
OKRESY = {}
KATASTRY = {}
VEDOUCI = {}
PIAN_PRESNOST = {}
TYP_LOKALITY = {}
DRUH_LOKALITY = {}
JISTOTA = {}
LOKALITA_ZACHOVALOST = {}
PRISTUPNOST = {}
NALEZ_KATEGORIE = {}
DRUH_NALEZU = {}
SPECIFIKACE = {}
NALEZOVE_OKOLNOSTI = {}
NALEZCE = {}
refresh_globals()
File diff suppressed because it is too large. Load diff
+992 -183
View File
File diff suppressed because it is too large. Load diff
+98 -22
View File
@@ -1,13 +1,15 @@
# -*- coding: utf-8 -*-
from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QMenu, QAction, QToolButton, QDialog
from .amcr_tools import load_amcr_data
from .amcr_dialog import AmcrFilterDialog
from .resources import *
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:
"""
Main plugin class that manages the GUI elements, menu entries,
@@ -22,14 +24,17 @@ 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',
'AmcrViewer_{}.qm'.format(locale))
f'AmcrViewer_{locale}.qm'
)
# Install the translator if a translation file for the current locale exists
# Install the translator if a translation file
# for the current locale exists
if os.path.exists(locale_path):
self.translator = QTranslator()
self.translator.load(locale_path)
@@ -37,11 +42,14 @@ class AmcrViewer:
# Initialize internal state
self.actions = []
self.menu = self.tr(u'&AMČR Viewer')
self.menu = self.tr('&AMČR Viewer')
self.first_start = None
def tr(self, message):
"""Helper method for translating strings within the AmcrViewer context."""
"""
Helper method for translating strings within
the AmcrViewer context.
"""
return QCoreApplication.translate('AmcrViewer', message)
def add_action(self, icon_path, text, callback, enabled_flag=True,
@@ -69,7 +77,8 @@ class AmcrViewer:
if add_to_menu:
self.iface.addPluginToMenu(self.menu, action)
# Store only actions that are directly attached to the QGIS UI for later cleanup
# Store only actions that are directly attached
# to the QGIS UI for later cleanup
if add_to_toolbar or add_to_menu:
self.actions.append(action)
@@ -82,16 +91,19 @@ class AmcrViewer:
"""
# Define paths for action-specific icons
icon_akce_path = os.path.join(self.plugin_dir, 'akce.png')
icon_pas_path = os.path.join(self.plugin_dir, 'sn.png')
icon_lokality_path = os.path.join(self.plugin_dir, 'lokality.png')
icon_amcr_help_path = os.path.join(self.plugin_dir, 'amcr-help.png')
# 1. Create a container menu for the plugin
self.plugin_menu = QMenu()
# 2. Create sub-actions (Download Projects / Download Sites)
# add_to_menu/toolbar is False because these go into our custom dropdown menu
# add_to_menu/toolbar is False because these go into our
# custom dropdown menu
self.action_download_akce = self.add_action(
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'),
parent=self.iface.mainWindow(),
add_to_menu=False,
@@ -99,9 +111,20 @@ class AmcrViewer:
)
self.plugin_menu.addAction(self.action_download_akce)
self.action_download_pas = self.add_action(
icon_path=icon_pas_path,
text=self.tr('Stáhnout data samostatných nálezů | AMČR Viewer'),
callback=lambda checked=False: self.run_download(
'samostatny_nalez'),
parent=self.iface.mainWindow(),
add_to_menu=False,
add_to_toolbar=False
)
self.plugin_menu.addAction(self.action_download_pas)
self.action_download_lokality = self.add_action(
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'),
parent=self.iface.mainWindow(),
add_to_menu=False,
@@ -109,9 +132,33 @@ class AmcrViewer:
)
self.plugin_menu.addAction(self.action_download_lokality)
self.action_login_dialog = self.add_action(
icon_path=icon_pas_path,
text=self.tr('Přihlásit se | AMČR Viewer'),
callback=lambda checked=False: self.login(),
parent=self.iface.mainWindow(),
add_to_menu=False,
add_to_toolbar=False
)
self.plugin_menu.addAction(self.action_login_dialog)
self.action_amcr_help = self.add_action(
icon_path=icon_amcr_help_path,
text=self.tr('Nápověda AMČR Help | AMČR Viewer'),
callback=lambda checked=False: self.open_help(),
parent=self.iface.mainWindow(),
add_to_menu=False,
add_to_toolbar=False
)
self.plugin_menu.addAction(self.action_amcr_help)
# 3. Create the main project action and attach the menu to it
main_icon = QIcon(icon_akce_path)
self.main_action = QAction(main_icon, 'AMČR Viewer', self.iface.mainWindow())
self.main_action = QAction(
main_icon,
'AMČR Viewer',
self.iface.mainWindow()
)
self.main_action.setMenu(self.plugin_menu)
self.iface.addPluginToMenu(self.menu, self.main_action)
@@ -120,9 +167,12 @@ class AmcrViewer:
self.tool_button = QToolButton()
self.tool_button.setMenu(self.plugin_menu)
self.tool_button.setDefaultAction(self.action_download_akce)
self.tool_button.setPopupMode(QToolButton.ToolButtonPopupMode.MenuButtonPopup)
self.tool_button.setPopupMode(
QToolButton.ToolButtonPopupMode.MenuButtonPopup
)
# Add the widget directly to the toolbar and store the reference for cleanup
# Add the widget directly to the toolbar
# and store the reference for cleanup
self.toolbar_action = self.iface.addToolBarWidget(self.tool_button)
self.first_start = True
@@ -160,12 +210,38 @@ class AmcrViewer:
dlg = AmcrFilterDialog(typ_dat)
result = dlg.exec()
# If user confirmed the dialog (OK button), gather filters and load data
# If user confirmed the dialog (OK button),
# gather filters and load data
if result == QDialog.DialogCode.Accepted:
filters = dlg.get_filters()
bbox = dlg.get_bbox()
komponenty = dlg.get_komponenty()
# Access the map canvas and start the fetch/render process from amcr_tools
# Access the map canvas and start
# the fetch/render process from amcr_tools
canvas = self.iface.mapCanvas()
load_amcr_data(canvas, bbox, filters, typ_dat, komponenty)
def login(self):
dlg = LoginDialog(parent=self.iface.mainWindow())
result = dlg.exec()
if result == QDialog.DialogCode.Accepted:
username, password = LoginDialog.get_credentials()
session = login_to_api(username, password)
if session:
self.iface.messageBar().pushMessage(
"AMČR",
"Přihlášení proběhlo úspěšně.",
level=Qgis.MessageLevel.Success
)
else:
self.iface.messageBar().pushMessage(
"AMČR",
"Přihlášení se nezdařilo – viz záložka AMČR login "
"v panelu Zprávy.",
level=Qgis.MessageLevel.Critical
)
def open_help(self):
help_url = "https://amcr-help.aiscr.cz/digiarchiv/qgis-viewer.html"
QDesktopServices.openUrl(QUrl(help_url))
+16820 -13604
View File
File diff suppressed because it is too large. Load diff
+37 -10
View File
@@ -5,14 +5,14 @@
[general]
name=AMČR Viewer
qgisMinimumVersion=3.4.0
qgisMaximumVersion=4.9.9
qgisMinimumVersion=3.44.0
qgisMaximumVersion=4.99.0
description=Viewing and downloading the AMČR data.
version=1.3.0
version=2.1.2
author=David Spáčil
email=spacil@arub.cz
about=This plugin is intended for downloading the data (Fieldwork events, Sites and their Components) from the Digiarchive of the Archaeological Map of the Czech Republic (https://digiarchiv.aiscr.cz/). As of now, only publicly accessible data can be downloaded.
about=This plugin is intended for downloading the data (Fieldwork events, Sites, and their Components) from the Digital archive of the Archaeological Map of the Czech Republic (https://digiarchiv.aiscr.cz/).
tracker=https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer/issues
repository=https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer
@@ -22,14 +22,44 @@ repository=https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer
hasProcessingProvider=no
# 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
v2.1.2 (2026-09-01)
* Qt6 compatibility
* Code clean-up
v2.1.1 (2026-09-01)
* Added download of Individual finds (PAS), including a dedicated menu entry
* Added filtering by date
* Added filtering of project fieldwork events and a Project column in the attribute table
* Codelists are now built from the Digiarchiv API as well, not only from OAI-PMH; persons come from its facets by role (finder, fieldwork leader)
* Updated the bundled codelist file
* Filter dialog is now scrollable
* Empty API results are now diagnosable from the Messages panel: the query URL and API errors are logged
* Code clean-up
v2.0.2 (2026-06-13)
* Plugin-wide fixes and optimalizations (details https://github.com/ARUP-CAS/aiscr-qgis-amcr-viewer/pull/49)
v2.0.1 (2026-06-10)
* Fixed QGIS minimum version
v2.0.0 (2026-06-05)
* Added warning regarding the feature duplication when loading components to the dialog
* Added Help button to the plugin menu
* Code clean-up
v2.0.0-alpha.4 (2026-06-03)
* Backend filtering of the results based on the component-related filters improvement (plugin not only loads the results from API, it filters them further)
v2.0.0-alpha.2–3 (2026-05-19)
* Security vulnerabilities fix
v2.0.0-alpha.1 (2026-05-19):
* Attribute fields renamed to be ASCII compliant
* Codelist update; codelist can be recompiled from AMČR API
* Base element changed from Documentation Unit to Component if user asks for components to simplify result filtering
* Plugin now supports logging with an AMČR account and enables the downloading of Events and Sites available to the roles Researcher and higher
# Tags are comma separated with spaces allowed
tags=python,AMCR,AIS CR,archaeology,PIAN,AMČR
tags=python,AMCR,AIS CR,archaeology,PIAN,AMČR,archeologie
homepage=https://amcr-help.aiscr.cz/digiarchiv/qgis-viewer.html
category=Vector
icon=download.png
icon=akce.png
# experimental flag
experimental=False
@@ -41,9 +71,6 @@ deprecated=False
# Check the documentation for more information.
# plugin_dependencies=
# Category of the plugin: Raster, Vector, Database or Web
# category=
# If the plugin can run on QGIS Server.
server=False
Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

+23 -7
View File
@@ -9,7 +9,7 @@
id="svg1"
xml:space="preserve"
sodipodi:docname="icon.svg"
inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
@@ -24,12 +24,12 @@
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="22.627417"
inkscape:cx="6.8059028"
inkscape:cy="14.606174"
inkscape:cx="0.57452426"
inkscape:cy="15.556349"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-height="1131"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" /><defs
id="defs1"><clipPath
@@ -96,4 +96,20 @@
d="M 3.3486328 2.4970052 L 3.3486328 3.8323242 L 2.7424683 3.8323242 L 4.2085286 5.738151 L 5.674589 3.8323242 L 5.0684245 3.8323242 L 5.0684245 2.4970052 L 3.3486328 2.4970052 z "
inkscape:export-filename="path32.png"
inkscape:export-xdpi="3000"
inkscape:export-ydpi="3000" /></g></svg>
inkscape:export-ydpi="3000" /><rect
style="opacity:1;fill:#85140e;fill-opacity:1;stroke:none;stroke-width:0.414999;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;paint-order:stroke fill markers"
id="rect1"
width="1.672105"
height="1.2511554"
x="-4.501821"
y="4.2814822" /><text
xml:space="preserve"
style="font-size:0.705556px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;opacity:1;fill:#85140e;fill-opacity:1;stroke:none;stroke-width:0.414999;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;paint-order:stroke fill markers"
x="-2.6360023"
y="5.1136947"
id="text1"><tspan
sodipodi:role="line"
id="tspan1"
style="font-size:0.705556px;fill:#85140e;fill-opacity:1;stroke-width:0.415"
x="-2.6360023"
y="5.1136947">lokality</tspan></text></g></svg>

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB