# -*- 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 class AmcrViewer: """ Main plugin class that manages the GUI elements, menu entries, and coordinates the flow between user input and data processing. """ def __init__(self, iface): """ Constructor initializes the connection to QGIS interface and sets up internationalization (i18n). """ self.iface = iface self.plugin_dir = os.path.dirname(__file__) # 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) ) # 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) QCoreApplication.installTranslator(self.translator) # Initialize internal state self.actions = [] self.menu = self.tr(u'&AMČR Viewer') self.first_start = None def tr(self, message): """ 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, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """ Helper method to create QActions and automatically register them into the QGIS Menu and Toolbar. """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) # Standard QGIS API for adding icons and menu items if add_to_toolbar: self.iface.addToolBarIcon(action) if add_to_menu: self.iface.addPluginToMenu(self.menu, action) # 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) return action def initGui(self): """ Called when the plugin is loaded. Creates the menu structure, sub-actions, and the dropdown tool button in the toolbar. """ # Define paths for action-specific icons icon_akce_path = os.path.join(self.plugin_dir, 'akce.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 self.action_download_akce = self.add_action( icon_path=icon_akce_path, text=self.tr(u'Stáhnout data akcí | AMČR Viewer'), callback=lambda checked=False: self.run_download('akce'), parent=self.iface.mainWindow(), add_to_menu=False, add_to_toolbar=False ) self.plugin_menu.addAction(self.action_download_akce) self.action_download_lokality = self.add_action( icon_path=icon_lokality_path, text=self.tr(u'Stáhnout data lokalit | AMČR Viewer'), callback=lambda checked=False: self.run_download('lokalita'), parent=self.iface.mainWindow(), add_to_menu=False, add_to_toolbar=False ) self.plugin_menu.addAction(self.action_download_lokality) self.action_login_dialog = self.add_action( icon_path=icon_akce_path, text=self.tr(u'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(u'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.setMenu(self.plugin_menu) self.iface.addPluginToMenu(self.menu, self.main_action) # 4. Create and configure a QToolButton for the QGIS Toolbar # This button acts as a dropdown menu button (MenuButtonPopup) 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 ) # 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 def unload(self): """ Called when the plugin is disabled or removed. Ensures all GUI elements are removed from QGIS to avoid ghost icons. """ # 1. Remove the custom entry from the main 'Plugins' menu if hasattr(self, 'main_action'): self.iface.removePluginMenu(self.menu, self.main_action) # 2. Remove the custom QToolButton from the toolbar if hasattr(self, 'toolbar_action'): self.iface.removeToolBarIcon(self.toolbar_action) # 3. Clean up any remaining actions registered in self.actions for action in self.actions: self.iface.removePluginMenu(self.menu, action) self.iface.removeToolBarIcon(action) self.actions.clear() # 4. Reset map tools if currently active if hasattr(self, 'tool'): self.iface.mapCanvas().unsetMapTool(self.tool) # --- Data downloading --- def run_download(self, typ_dat): """ Triggered by menu/toolbar actions. Opens the filter dialog and hands off the parameters to the data loader. """ # Open the specific filter dialog (Projects vs Sites) dlg = AmcrFilterDialog(typ_dat) result = dlg.exec() # 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 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))