From f639aee47ed45611f70e127981982092b6343d86 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste DESBAS Date: Wed, 26 Jul 2023 15:07:54 +0200 Subject: [PATCH 1/7] dl files in separate threads after iface loading --- plugin/idg/plugin_main.py | 11 ++-- plugin/idg/toolbelt/__init__.py | 1 + plugin/idg/toolbelt/network_manager.py | 83 ++++++++++++++++++++++++ plugin/idg/toolbelt/tree_node_factory.py | 43 +++++------- 4 files changed, 106 insertions(+), 32 deletions(-) create mode 100644 plugin/idg/toolbelt/network_manager.py diff --git a/plugin/idg/plugin_main.py b/plugin/idg/plugin_main.py index eedd333..a41b56b 100644 --- a/plugin/idg/plugin_main.py +++ b/plugin/idg/plugin_main.py @@ -58,12 +58,11 @@ def __init__(self, iface: QgisInterface): config_struct = None config_string = "" - # Download the config if needed - #if self.need_download_tree_config_file(): - # download_tree_config_file(PluginGlobals.instance().CONFIG_FILE_URLS[0]) - - # Read the resources tree file and update the GUI - #self.ressources_tree = TreeNodeFactory(PluginGlobals.instance().config_file_path).root_node # dev + self.iface.initializationCompleted.connect(self.post_ui_init) + + + def post_ui_init(self): + """Run after plugin's UI has been initialized.""" download_default_idg_list() download_all_config_files(RemotePlatforms().stock_idgs) diff --git a/plugin/idg/toolbelt/__init__.py b/plugin/idg/toolbelt/__init__.py index 8b65702..0b0b401 100644 --- a/plugin/idg/toolbelt/__init__.py +++ b/plugin/idg/toolbelt/__init__.py @@ -7,3 +7,4 @@ from .singleton import Singleton from .browser import IdgProvider from .remote_platforms import RemotePlatforms +from .network_manager import NetworkRequestsManager # noqa: F401 diff --git a/plugin/idg/toolbelt/network_manager.py b/plugin/idg/toolbelt/network_manager.py new file mode 100644 index 0000000..1569d45 --- /dev/null +++ b/plugin/idg/toolbelt/network_manager.py @@ -0,0 +1,83 @@ +#! python3 # noqa: E265 + +""" + Perform network request. + (from https://github.com/geotribu/qtribu/blob/main/qtribu/toolbelt/network_manager.py) +""" + +# ############################################################################ +# ########## Imports ############### +# ################################## + +# Standard library +import logging + +# PyQGIS +from qgis.core import QgsBlockingNetworkRequest, QgsFileDownloader +from qgis.PyQt.QtCore import QByteArray, QCoreApplication, QEventLoop, QUrl + +# project +from idg.toolbelt.log_handler import PlgLogger + + +# ############################################################################ +# ########## Globals ############### +# ################################## + +logger = logging.getLogger(__name__) + +# ############################################################################ +# ########## Classes ############### +# ################################## + + +class NetworkRequestsManager: + """Helper on network operations. + + :param tr: method to translate + :type tr: func + """ + + def __init__(self): + """Initialization.""" + self.log = PlgLogger().log + self.ntwk_requester = QgsBlockingNetworkRequest() + + def tr(self, message: str) -> str: + """Get the translation for a string using Qt translation API. + + :param message: string to be translated. + :type message: str + + :returns: Translated version of message. + :rtype: str + """ + return QCoreApplication.translate(self.__class__.__name__, message) + + + def download_file(self, remote_url: str, local_path: str) -> str: + """Download a file from a remote web server accessible through HTTP. + + :param remote_url: remote URL + :type remote_url: str + :param local_path: path to the local file + :type local_path: str + :return: output path + :rtype: str + """ + self.log( + message=f"Downloading file from {remote_url} to {local_path}", log_level=4 + ) + # download it + loop = QEventLoop() + file_downloader = QgsFileDownloader( + url=QUrl(remote_url), outputFileName=local_path, delayStart=True + ) + file_downloader.downloadExited.connect(loop.quit) + file_downloader.startDownload() + loop.exec_() + + self.log( + message=f"Download of {remote_url} to {local_path} succeedeed", log_level=3 + ) + return local_path diff --git a/plugin/idg/toolbelt/tree_node_factory.py b/plugin/idg/toolbelt/tree_node_factory.py index 351dad1..cfb16eb 100644 --- a/plugin/idg/toolbelt/tree_node_factory.py +++ b/plugin/idg/toolbelt/tree_node_factory.py @@ -11,11 +11,13 @@ QgsProject, QgsNetworkAccessManager, QgsNetworkReplyContent, + QgsFileDownloader ) from qgis.PyQt.QtNetwork import QNetworkRequest, QNetworkReply -from qgis.PyQt.QtCore import QUrl +from qgis.PyQt.QtCore import QUrl, QEventLoop from idg.toolbelt import PluginGlobals +from .network_manager import NetworkRequestsManager from .nodes import WmsLayerTreeNode, WmsStyleLayerTreeNode, WmtsLayerTreeNode, WfsFeatureTypeTreeNode from .nodes import WfsFeatureTypeFilterTreeNode, GdalWmsConfigFileTreeNode, FolderTreeNode @@ -28,14 +30,16 @@ def download_default_idg_list(url='https://raw.githubusercontent.com/geo2france/ response: QgsNetworkReplyContent = manager.blockingGet( request, forceRefresh=True ) - if response.error() == QNetworkReply.NoError: - try: - os.remove(local_file) - except OSError: - pass - with open(local_file, "wb") as local_config_file: - local_config_file.write(response.content()) - return json.loads(bytes(response.content()).decode()) + qntwk = NetworkRequestsManager() + local_file_name = qntwk.download_file(url, os.path.join(PluginGlobals.instance().config_dir_path, 'default_idg.json')) + if local_file_name is not None: + #try: + # os.remove(local_file) + #except OSError: + # pass + with open(local_file, "r") as local_config_file: + out = json.load(local_config_file) + return out #TOD gérer les erreur (garder le fichier précédent + avertissement) def download_all_config_files(idgs): #remplacer la list par un dict ({idg_id:url}) @@ -47,6 +51,7 @@ def download_all_config_files(idgs): #remplacer la list par un dict ({idg_id:url key = IDG_id, value = url rename local file """ + qntwk = NetworkRequestsManager() for idg_id, url in idgs.items(): idg_id = str(idg_id) request = QNetworkRequest(QUrl(url)) @@ -55,23 +60,8 @@ def download_all_config_files(idgs): #remplacer la list par un dict ({idg_id:url request, forceRefresh=True ) suffix = os.path.splitext(os.path.basename(url))[-1] - local_file_name = os.path.join(PluginGlobals.instance().config_dir_path, idg_id + suffix) - if response.error() == QNetworkReply.NoError: - # Creer le dossier si non existant - try: - os.makedirs(os.path.join(PluginGlobals.instance().config_dir_path)) - except OSError: - if not os.path.isdir(os.path.join(PluginGlobals.instance().config_dir_path)): - raise - # Supprimer le fichier si existant - try : - os.remove(os.path.join(PluginGlobals.instance().config_dir_path, idg_id + '.qgz') ) - except OSError: - pass - try : - os.remove(os.path.join(PluginGlobals.instance().config_dir_path, idg_id + '.qgs') ) - except OSError: - pass + local_file_name = qntwk.download_file(url, os.path.join(PluginGlobals.instance().config_dir_path, idg_id + suffix)) + if local_file_name : with open(local_file_name, "wb") as local_config_file: local_config_file.write(response.content()) # Download icon if custom TODO a factoriser @@ -101,6 +91,7 @@ def download_all_config_files(idgs): #remplacer la list par un dict ({idg_id:url "Erreur", short_message, level=Qgis.Warning ) + def download_tree_config_file(file_url): """ Download the resources tree file From 42c9b937e6354418df7e6ffc7dd0762156aeb322 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste DESBAS Date: Fri, 28 Jul 2023 09:55:47 +0200 Subject: [PATCH 2/7] use QgsFileDownloader for dl icon --- plugin/idg/toolbelt/tree_node_factory.py | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/plugin/idg/toolbelt/tree_node_factory.py b/plugin/idg/toolbelt/tree_node_factory.py index cfb16eb..be9513d 100644 --- a/plugin/idg/toolbelt/tree_node_factory.py +++ b/plugin/idg/toolbelt/tree_node_factory.py @@ -51,8 +51,10 @@ def download_all_config_files(idgs): #remplacer la list par un dict ({idg_id:url key = IDG_id, value = url rename local file """ + #TODO a passer dans RemotePlatforms qntwk = NetworkRequestsManager() for idg_id, url in idgs.items(): + #continue si l'IDG est masquée idg_id = str(idg_id) request = QNetworkRequest(QUrl(url)) manager = QgsNetworkAccessManager.instance() @@ -69,20 +71,8 @@ def download_all_config_files(idgs): #remplacer la list par un dict ({idg_id:url project.read(local_file_name, QgsProject.ReadFlags()|QgsProject.FlagDontResolveLayers|QgsProject.FlagDontLoadLayouts) for l in project.metadata().links(): if l.name.lower().strip() == 'icon': - request = QNetworkRequest(QUrl(l.url)) - manager = QgsNetworkAccessManager.instance() suffix = os.path.splitext(os.path.basename(l.url))[-1] - response: QgsNetworkReplyContent = manager.blockingGet( - request, forceRefresh=True - ) - if response.error() == QNetworkReply.NoError: - local_icon_file_name = os.path.join(PluginGlobals.instance().config_dir_path, idg_id + suffix) #TODO : vérifier qu'il s'agit d'un type image - try: - os.remove(local_icon_file_name) - except OSError: - pass - with open(local_icon_file_name, "wb") as icon_file: - icon_file.write(response.content()) + qntwk.download_file(l.url, os.path.join(PluginGlobals.instance().config_dir_path, idg_id + suffix) ) break else : From 85fcb7fd77f941c4857f2d495af43ee91d8263d2 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste DESBAS Date: Fri, 28 Jul 2023 09:56:35 +0200 Subject: [PATCH 3/7] file download : log errors --- plugin/idg/toolbelt/network_manager.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugin/idg/toolbelt/network_manager.py b/plugin/idg/toolbelt/network_manager.py index 1569d45..0ece4d3 100644 --- a/plugin/idg/toolbelt/network_manager.py +++ b/plugin/idg/toolbelt/network_manager.py @@ -71,13 +71,17 @@ def download_file(self, remote_url: str, local_path: str) -> str: # download it loop = QEventLoop() file_downloader = QgsFileDownloader( - url=QUrl(remote_url), outputFileName=local_path, delayStart=True + url=QUrl(remote_url ), outputFileName=local_path, delayStart=True ) file_downloader.downloadExited.connect(loop.quit) + file_downloader.downloadCompleted.connect( + lambda : self.log(message=f"Download of {remote_url} to {local_path} succeedeed", log_level=3) + ) + file_downloader.downloadError.connect( + lambda e : self.log(message=f"Download of {remote_url} to {local_path} error {e}", log_level=1) + ) file_downloader.startDownload() loop.exec_() - self.log( - message=f"Download of {remote_url} to {local_path} succeedeed", log_level=3 - ) + return local_path From d2f3c7ed5ced2441a1f3cfc11046324a205fff55 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste DESBAS Date: Fri, 28 Jul 2023 11:14:46 +0200 Subject: [PATCH 4/7] async download project file --- plugin/idg/plugin_main.py | 13 ++++++----- plugin/idg/toolbelt/network_manager.py | 17 +++++++++----- plugin/idg/toolbelt/tree_node_factory.py | 28 +++++++++++++++++++++++- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/plugin/idg/plugin_main.py b/plugin/idg/plugin_main.py index a41b56b..495fea6 100644 --- a/plugin/idg/plugin_main.py +++ b/plugin/idg/plugin_main.py @@ -23,7 +23,7 @@ from idg.gui.dock import DockWidget from idg.gui.about_box import AboutBox from idg.gui.param_box import ParamBox -from idg.toolbelt.tree_node_factory import TreeNodeFactory, download_tree_config_file, download_all_config_files, download_default_idg_list +from idg.toolbelt.tree_node_factory import TreeNodeFactory, download_tree_config_file, download_all_config_files, download_default_idg_list, DownloadAllConfigFilesAsync import os import json @@ -63,8 +63,10 @@ def __init__(self, iface: QgisInterface): def post_ui_init(self): """Run after plugin's UI has been initialized.""" - download_default_idg_list() - download_all_config_files(RemotePlatforms().stock_idgs) + download_default_idg_list() # TODO a passer en asynchrone aussi ? + self.task = DownloadAllConfigFilesAsync(RemotePlatforms().stock_idgs) + self.task.finished.connect(self.add_browser_provider) + self.task.start() def need_download_tree_config_file(self): """ @@ -116,8 +118,9 @@ def initGui(self): #self.dock.set_tree_content(self.ressources_tree) #self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock) # dev - # Add browser provider - self.registry = QgsApplication.dataItemProviderRegistry() + + def add_browser_provider(self): + self.registry = QgsApplication.dataItemProviderRegistry() self.provider = IdgProvider(self.iface) self.registry.addProvider(self.provider) diff --git a/plugin/idg/toolbelt/network_manager.py b/plugin/idg/toolbelt/network_manager.py index 0ece4d3..ccdfdc8 100644 --- a/plugin/idg/toolbelt/network_manager.py +++ b/plugin/idg/toolbelt/network_manager.py @@ -11,7 +11,8 @@ # Standard library import logging - +from os import remove, path +from shutil import copy # PyQGIS from qgis.core import QgsBlockingNetworkRequest, QgsFileDownloader from qgis.PyQt.QtCore import QByteArray, QCoreApplication, QEventLoop, QUrl @@ -65,21 +66,25 @@ def download_file(self, remote_url: str, local_path: str) -> str: :return: output path :rtype: str """ + + def dlCompleted(): + self.log(message=f"Download of {remote_url} to {local_path} succeedeed", log_level=3) + copy(local_path+'_tmp', local_path) + remove(local_path+'_tmp') + self.log( message=f"Downloading file from {remote_url} to {local_path}", log_level=4 ) # download it loop = QEventLoop() file_downloader = QgsFileDownloader( - url=QUrl(remote_url ), outputFileName=local_path, delayStart=True - ) - file_downloader.downloadExited.connect(loop.quit) - file_downloader.downloadCompleted.connect( - lambda : self.log(message=f"Download of {remote_url} to {local_path} succeedeed", log_level=3) + url = QUrl(remote_url ), outputFileName=local_path+'_tmp', delayStart=True # Le téléchargement se fait dans un fichier temporaire, pour garder l'ancien fichier en cas d'échec ) + file_downloader.downloadCompleted.connect(dlCompleted) file_downloader.downloadError.connect( lambda e : self.log(message=f"Download of {remote_url} to {local_path} error {e}", log_level=1) ) + file_downloader.downloadExited.connect(loop.quit) file_downloader.startDownload() loop.exec_() diff --git a/plugin/idg/toolbelt/tree_node_factory.py b/plugin/idg/toolbelt/tree_node_factory.py index be9513d..24ae26b 100644 --- a/plugin/idg/toolbelt/tree_node_factory.py +++ b/plugin/idg/toolbelt/tree_node_factory.py @@ -14,7 +14,7 @@ QgsFileDownloader ) from qgis.PyQt.QtNetwork import QNetworkRequest, QNetworkReply -from qgis.PyQt.QtCore import QUrl, QEventLoop +from qgis.PyQt.QtCore import QUrl, QThread, pyqtSignal from idg.toolbelt import PluginGlobals from .network_manager import NetworkRequestsManager @@ -81,6 +81,32 @@ def download_all_config_files(idgs): #remplacer la list par un dict ({idg_id:url "Erreur", short_message, level=Qgis.Warning ) +class DownloadAllConfigFilesAsync(QThread): + finished = pyqtSignal() + def __init__(self, idgs): + super(QThread, self).__init__() + self.idgs=idgs + def run(self): + qntwk = NetworkRequestsManager() + + for idg_id, url in self.idgs.items(): + # continue si l'IDG est masquée + idg_id = str(idg_id) + suffix = os.path.splitext(os.path.basename(url))[-1] + local_file_name = qntwk.download_file(url, os.path.join(PluginGlobals.instance().config_dir_path, + idg_id + suffix)) + if local_file_name: + project = QgsProject() + project.read(local_file_name, + QgsProject.ReadFlags() | QgsProject.FlagDontResolveLayers | QgsProject.FlagDontLoadLayouts) + for l in project.metadata().links(): + if l.name.lower().strip() == 'icon': + suffix = os.path.splitext(os.path.basename(l.url))[-1] + qntwk.download_file(l.url, + os.path.join(PluginGlobals.instance().config_dir_path, idg_id + suffix)) + break + self.finished.emit() + def download_tree_config_file(file_url): """ From d6de63b0ad5475ed6e32d88dcbc49f81a8426259 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste DESBAS Date: Fri, 28 Jul 2023 13:51:43 +0200 Subject: [PATCH 5/7] IDG provider populating state --- plugin/idg/gui/dlg_settings.py | 5 +++-- plugin/idg/plugin_main.py | 16 ++++++++++------ plugin/idg/toolbelt/browser.py | 27 ++++++++++++++++++--------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/plugin/idg/gui/dlg_settings.py b/plugin/idg/gui/dlg_settings.py index d18e7e0..354f333 100644 --- a/plugin/idg/gui/dlg_settings.py +++ b/plugin/idg/gui/dlg_settings.py @@ -135,8 +135,9 @@ def apply(self): # dump new settings into QgsSettings self.plg_settings.save_from_object(settings) #Les variables globales ne sont peut être pas MAJ ici - iface.mainWindow().findChildren(QWidget, 'Browser')[0].refresh() # refresh browser (supprimer et recreer le registre IDG plutôt ?) - + registry = QgsApplication.dataItemProviderRegistry() + provider = registry.provider('IDG Provider') + provider.root.repopulate() if __debug__: self.log( message="DEBUG - Settings successfully saved.", diff --git a/plugin/idg/plugin_main.py b/plugin/idg/plugin_main.py index 495fea6..c658ea0 100644 --- a/plugin/idg/plugin_main.py +++ b/plugin/idg/plugin_main.py @@ -57,7 +57,10 @@ def __init__(self, iface: QgisInterface): config_struct = None config_string = "" - + + self.registry = QgsApplication.dataItemProviderRegistry() + self.provider = IdgProvider(self.iface) + self.iface.initializationCompleted.connect(self.post_ui_init) @@ -65,7 +68,7 @@ def post_ui_init(self): """Run after plugin's UI has been initialized.""" download_default_idg_list() # TODO a passer en asynchrone aussi ? self.task = DownloadAllConfigFilesAsync(RemotePlatforms().stock_idgs) - self.task.finished.connect(self.add_browser_provider) + self.task.finished.connect(self.populate_browser) self.task.start() def need_download_tree_config_file(self): @@ -113,16 +116,17 @@ def initGui(self): # Create a menu self.createPluginMenu() + # Add browser IDG provider + self.registry.addProvider(self.provider) + # Create a dockable panel with a tree of resources #self.dock = DockWidget() #self.dock.set_tree_content(self.ressources_tree) #self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock) # dev - def add_browser_provider(self): - self.registry = QgsApplication.dataItemProviderRegistry() - self.provider = IdgProvider(self.iface) - self.registry.addProvider(self.provider) + def populate_browser(self): + self.provider.root.repopulate() def unload(self): """Cleans up when plugin is disabled/uninstalled.""" diff --git a/plugin/idg/toolbelt/browser.py b/plugin/idg/toolbelt/browser.py index e57b18e..fdaa1d0 100644 --- a/plugin/idg/toolbelt/browser.py +++ b/plugin/idg/toolbelt/browser.py @@ -1,4 +1,4 @@ -from qgis.core import QgsDataItemProvider, QgsDataCollectionItem, QgsDataItem, QgsDataProvider, QgsProject, \ +from qgis.core import Qgis, QgsDataItemProvider, QgsDataCollectionItem, QgsDataItem, QgsDataProvider, QgsProject, \ QgsLayerTreeLayer, QgsLayerTreeGroup, QgsMimeDataUtils, QgsAbstractMetadataBase, QgsApplication, QgsIconUtils from qgis.gui import QgisInterface from qgis.PyQt.QtGui import QIcon @@ -8,7 +8,6 @@ from idg.__about__ import __title__ from qgis.PyQt.QtWidgets import QAction, QMenu from qgis.utils import iface - import os.path import json import webbrowser @@ -40,8 +39,8 @@ def capabilities(self): return QgsDataProvider.Net def createDataItem(self, path, parentItem): - root = RootCollection(self.iface) - return root + self.root = RootCollection(self.iface) + return self.root class RootCollection(QgsDataCollectionItem): @@ -49,6 +48,7 @@ def __init__(self, iface: QgisInterface): self.iface = iface QgsDataCollectionItem.__init__(self, None, "IDG", "/IDG") self.setIcon(QIcon(PluginGlobals.instance().plugin_path+'/resources/images/layers-svgrepo-com.svg')) + self.setState(Qgis.BrowserItemState.Populating) def actions(self, parent): actions = list() @@ -71,15 +71,24 @@ def menus(self, parent): menu.addSeparator() menu.addAction(QAction(self.tr('Add URL'), menu, )) # TODO Liens vers le panneau Options de QGIS return [menu] - - def createChildren(self): - children = [] + + def repopulate(self): + self.refresh() for pf in RemotePlatforms().plateforms : if pf.is_hidden() : continue pf_collection = PlatformCollection(plateform=pf) - children.append(pf_collection) - return children + self.addChildItem(pf_collection, refresh=True) + self.setState(Qgis.BrowserItemState.Populated) + + #def createChildren(self): + # children = [] + # for pf in RemotePlatforms().plateforms : + # if pf.is_hidden() : + # continue + # pf_collection = PlatformCollection(plateform=pf) + # children.append(pf_collection) + # return children class PlatformCollection(QgsDataCollectionItem): From f4ce43fe8e78e54dc7b876af0aa1d7d62cb9ae06 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste DESBAS Date: Fri, 28 Jul 2023 14:08:17 +0200 Subject: [PATCH 6/7] remove useless --- plugin/idg/toolbelt/browser.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/plugin/idg/toolbelt/browser.py b/plugin/idg/toolbelt/browser.py index fdaa1d0..4cd67d6 100644 --- a/plugin/idg/toolbelt/browser.py +++ b/plugin/idg/toolbelt/browser.py @@ -9,7 +9,6 @@ from qgis.PyQt.QtWidgets import QAction, QMenu from qgis.utils import iface import os.path -import json import webbrowser @@ -81,15 +80,6 @@ def repopulate(self): self.addChildItem(pf_collection, refresh=True) self.setState(Qgis.BrowserItemState.Populated) - #def createChildren(self): - # children = [] - # for pf in RemotePlatforms().plateforms : - # if pf.is_hidden() : - # continue - # pf_collection = PlatformCollection(plateform=pf) - # children.append(pf_collection) - # return children - class PlatformCollection(QgsDataCollectionItem): def __init__(self, plateform, parent=None): From 42bd5e35d240fd46e4c15430adac96aab439809a Mon Sep 17 00:00:00 2001 From: Jean-Baptiste DESBAS Date: Fri, 28 Jul 2023 14:16:17 +0200 Subject: [PATCH 7/7] 0.2.2 --- plugin/idg/metadata.txt | 8 ++++---- repo/plugins-dev.xml | 23 ----------------------- 2 files changed, 4 insertions(+), 27 deletions(-) delete mode 100644 repo/plugins-dev.xml diff --git a/plugin/idg/metadata.txt b/plugin/idg/metadata.txt index cec88de..ce6836e 100644 --- a/plugin/idg/metadata.txt +++ b/plugin/idg/metadata.txt @@ -7,8 +7,8 @@ description[fr]=Plugin fournissant un accès simple aux données de différentes about=Plugin providing easy access to data from different Spatial Data Infrastructures about[fr]=Plugin fournissant un accès simple aux données de différentes Infrastructures de Données Géographiques DataGrandEst, Géo2France, GeoBretagne et OPenIG icon=resources/images/layers-svgrepo-com.svg -tags=opendata,sdi,DataGrandEst,Géo2France,GéoBretagne,OPenIG -tags[fr]=opendata,idg,DataGrandEst,Géo2France,GéoBretagne,OPenIG +tags=opendata,sdi,DataGrandEst,Géo2France,GéoBretagne,OPenIG, crige +tags[fr]=opendata,idg,DataGrandEst,Géo2France,GéoBretagne,OPenIG,crige # credits and contact author=Benjamin CHARTIER, Jean-Baptiste DESBAS @@ -24,5 +24,5 @@ qgisMinimumVersion=3.00 qgisMaximumVersion=3.99 # versioning -version=0.2.1 -changelog= +version=0.2.2 +changelog=Amélioration performance et stabilité diff --git a/repo/plugins-dev.xml b/repo/plugins-dev.xml deleted file mode 100644 index 9004987..0000000 --- a/repo/plugins-dev.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - Version de développement. - 0.2.1 - 3.0.0 - 3.99.0 - https://github.com/geo2france/idg-qgis-plugin/ - idg.zip - Benjamin Chartier, Jean-Baptiste Desbas - https://github.com/geo2france/idg-qgis-plugin/releases/download/v0.2.1/idg.zip - Jean-Baptiste Desbas - 2023-04-13 - 2023-07-19 - True - False - - https://github.com/geo2france/idg-qgis-plugin/ - - -