From 9a5f6d8b5fbfc588362c7957cb7a96ec6a166271 Mon Sep 17 00:00:00 2001 From: Luiz Cortinhas Date: Wed, 25 Nov 2020 18:32:55 -0300 Subject: [PATCH 1/3] feat(main): wms service correction and dynamic sld Signed-off-by: Luiz Cortinhas --- __init__.py | 13 +++-- create_zip_plugin.sh | 5 +- mapbiomascollection.py | 93 ++++++++++++++++++++++++++++++---- mapbiomascollection_en_US.json | 4 +- mapbiomascollection_pt_BR.json | 6 +-- metadata.txt | 9 ++-- 6 files changed, 101 insertions(+), 29 deletions(-) diff --git a/__init__.py b/__init__.py index 0c01001..3457be3 100644 --- a/__init__.py +++ b/__init__.py @@ -3,9 +3,9 @@ /*************************************************************************** Name : MapBiomas Collection Description : This plugin lets you get collection of mapping from MapBiomas Project(http://mapbiomas.org/). -Date : August, 2019 -copyright : (C) 2019 by Luiz Motta -email : motta.luiz@gmail.com +Date : August, 2020 +copyright : (C) 2019 by Luiz Motta, Updated by Luiz Cortinhas (2020) +email : motta.luiz@gmail.com, luiz.cortinhas@solved.eco.br ***************************************************************************/ @@ -18,12 +18,11 @@ * * ***************************************************************************/ """ -__author__ = 'Luiz Motta' -__date__ = '2019-08-28' -__copyright__ = '(C) 2019, Luiz Motta' +__author__ = 'Luiz Cortinhas, Luiz Motta' +__date__ = '2020-10-28' +__copyright__ = '(C) 2020, Luiz Cortinhas (Fork: 2019, Luiz Motta)' __revision__ = '$Format:%H$' - import os from qgis.PyQt.QtCore import QObject, pyqtSlot diff --git a/create_zip_plugin.sh b/create_zip_plugin.sh index 87e2dde..9c6c689 100755 --- a/create_zip_plugin.sh +++ b/create_zip_plugin.sh @@ -1,5 +1,4 @@ -#!/bin/bash -plugin_dir=$( basename $( pwd ) ) +plugin_dir=$( basename $( pwd ) ) if [ -f "./$plugin_dir.zip" ]; then rm "./$plugin_dir.zip" fi @@ -8,5 +7,3 @@ cp *.py "./$plugin_dir" for item in metadata.txt LICENSE mapbiomas.svg *.json; do cp "./$item" "./$plugin_dir"; done zip -r $plugin_dir $plugin_dir rm -r $plugin_dir -# -kdialog --msgbox "Zip file created: "$plugin_dir".zip" diff --git a/mapbiomascollection.py b/mapbiomascollection.py index 1382443..6fd13e1 100644 --- a/mapbiomascollection.py +++ b/mapbiomascollection.py @@ -1,6 +1,6 @@ import os, time, json import urllib.parse - +import warnings from osgeo import gdal from qgis.PyQt.QtCore import ( @@ -24,23 +24,88 @@ ) from qgis.gui import QgsGui, QgsMessageBar, QgsLayerTreeEmbeddedWidgetProvider - +#https://production.mapserver.mapbiomas.org/wms/coverage.map?service=WMS&request=GetMap&layers=coverage&styles=&format=image%2Fpng&transparent=true&version=1.3.0&territory_ids=96&year=2019&class_tree_node_ids=28%2C36%2C50%2C51%2C52%2C35%2C29%2C37%2C38%2C41%2C40%2C39%2C30%2C43%2C42%2C54%2C56%2C55%2C57%2C53%2C44%2C31%2C45%2C46%2C47%2C34%2C32%2C49%2C48%2C33&width=256&height=256&srs=EPSG%3A3857&maxZoom=19&minZoom=4&bbox=-5635549.221409475,-1252344.2714243263,-5009377.085697311,-626172.1357121632 class MapBiomasCollectionWidget(QWidget): + classRef = {1:{'color':'129912','parent':0,'status':False}, + 2:{'color':'1F4423','parent':1,'status':False}, + 3:{'color':'006400','parent':2,'status':False}, + 4:{'color':'32CD32','parent':2,'status':False}, + 5:{'color':'687537','parent':2,'status':False}, + 6:{'color':'000000','parent':0,'status':False}, + 7:{'color':'000000','parent':0,'status':False}, + 8:{'color':'000000','parent':0,'status':False}, + 9:{'color':'935132','parent':1,'status':False}, + 10:{'color':'BBFCAC','parent':0,'status':False}, + 11:{'color':'45C2A5','parent':10,'status':False}, + 12:{'color':'B8AF4F','parent':10,'status':False}, + 13:{'color':'BDB76B','parent':10,'status':False}, + 14:{'color':'FFFFB2','parent':0,'status':False}, + 15:{'color':'FFD966','parent':14,'status':False}, + 16:{'color':'000000','parent':0,'status':False}, + 17:{'color':'000000','parent':0,'status':False}, + 18:{'color':'E974ED','parent':14,'status':False}, + 19:{'color':'D5A6BD','parent':18,'status':False}, + 20:{'color':'C27BA0','parent':18,'status':False}, + 21:{'color':'FFEFC3','parent':14,'status':False}, + 22:{'color':'EA9999','parent':0,'status':False}, + 23:{'color':'DD7E6B','parent':22,'status':False}, + 24:{'color':'af2a2a','parent':22,'status':False}, + 25:{'color':'FF99FF','parent':22,'status':False}, + 26:{'color':'0000FF','parent':0,'status':False}, + 27:{'color':'D5D5E5','parent':0,'status':False}, + 28:{'color': '000000','parent':0,'status':False}, + 29:{'color':'FF8C00','parent':10,'status':False}, + 30:{'color':'8A2BE2','parent':22,'status':False}, + 31:{'color':'29EEE4','parent':26,'status':False}, + 32:{'color':'968c46','parent':10,'status':False}, + 33:{'color':'0000FF','parent':26,'status':False}, + 34:{'color':'000000','parent':0,'status':False}, + 35:{'color':'000000','parent':0,'status':False}, + 36:{'color':'f3b4f1','parent':0,'status':False}, + 37:{'color':'000000','parent':0,'status':False}, + 38:{'color':'000000','parent':0,'status':False}, + 39:{'color':'c59ff4','parent':0,'status':False}, + 40:{'color':'000000','parent':0,'status':False}, + 41:{'color':'e787f8','parent':0,'status':False}} + @staticmethod + def getParentColor(item): + if item['parent'] == 0 and item['status'] == False: + return 'FFFFFF' + if item['status']: + return item['color'] + else: + return MapBiomasCollectionWidget.getParentColor(MapBiomasCollectionWidget.classRef[item['parent']]) + @staticmethod def getUrl(url, version, year, l_class_id): l_strClass = [ str(item) for item in l_class_id ] - paramsWms = 'IgnoreGetFeatureInfoUrl=1&IgnoreGetMapUrl=1&crs=EPSG:3857&dpiMode=7&format=image/png&layers=coverage&styles=' - paramsQuote = f"map=wms/v/{version}/classification/coverage.map" - paramsQuote = f"{paramsQuote}&layers=coverage&transparent=true&version=1.1.1&territory_id=10" - paramsQuote = urllib.parse.quote( f"{paramsQuote}&year={year}&classification_ids=" ) + for item in MapBiomasCollectionWidget.classRef.keys(): + MapBiomasCollectionWidget.classRef[item]['status'] = False + for item in l_class_id: + MapBiomasCollectionWidget.classRef[item]['status'] = True + #ENV Percorredor! + env = 'env=' + for item in MapBiomasCollectionWidget.classRef.keys(): + classID = item + color = MapBiomasCollectionWidget.getParentColor(MapBiomasCollectionWidget.classRef[item]) + env = env + f'{classID}:{color};' + #env=1:00FF00;2:triangle;3:12 + #crs=EPSG:3857&dpiMode=7&format=image/png&layers=mapbiomas&styles&url=http://azure.solved.eco.br:8080/geoserver/solved/wms + paramsWms = f'IgnoreGetFeatureInfoUrl=1&IgnoreGetMapUrl=1&service=WMS&styles=solved:mapbiomas_legend&request=GetMap&format=image/png8&layers=mapbiomas_{year}&crs=EPSG:4326' + #'IgnoreGetFeatureInfoUrl=1&IgnoreGetMapUrl=1&crs=EPSG:3857&dpiMode=7&format=image/png&layers=coverage&styles=' + paramsQuote = f"" + paramsQuote = f"{paramsQuote}&transparent=true&version=1.1.1" + paramsQuote = urllib.parse.quote( f"{paramsQuote}&exceptions=application/vnd.ogc.se_inimage&years={year}&{env}&classification_ids=" )# a ordem importa paramClassification = ','.join( l_strClass ) + msg = f"{paramsWms}&url={url}?{paramsQuote}{paramClassification}" + warnings.warn(msg) return f"{paramsWms}&url={url}?{paramsQuote}{paramClassification}" def __init__(self, layer, data): def getYearClasses(): def getYear(): - values = [ item for item in paramsSource if item.find('year=') > -1 ] + values = [ item for item in paramsSource if item.find('years=') > -1] return self.maxYear if not len( values ) == 1 else int( values[0].split('=')[1] ) def getClasses(): @@ -183,7 +248,11 @@ def createItem(itemRoot, name, class_id, flags, icon): def _uploadSource(self): def checkDataSource(): url = self.getUrl( self.url, self.version, self.year, self.l_class_id ) + print('URL:') + print(url) name = f"Collection {self.version} - {self.year}" + print('name:') + print(name) args = [ url, name, self.layer.providerType() ] layer = QgsRasterLayer( *args ) if not layer.isValid(): @@ -233,6 +302,7 @@ def on_limitYear(self, checked): @pyqtSlot(QTreeWidgetItem, int) def on_classChanged(self, item, column): value = item.data( column, Qt.UserRole) + color = item.data( column, Qt.UserRole) status = item.checkState( column ) == Qt.Checked f = self.l_class_id.append if status else self.l_class_id.remove f( value ) @@ -257,7 +327,10 @@ def supportsLayer(self, layer): if not layer.providerType() == 'wms': return False source = urllib.parse.unquote( layer.source() ).split('&') + print('Here') host = f"url={self.data['url']}?map=wms/v/{self.data['version']}/classification/coverage.map" + print(host) + warnings.warn(host) l_url = [ item for item in source if item.find( host ) > -1 ] return len( l_url ) > 0 @@ -305,7 +378,9 @@ def register(self): def run(self): def createLayer(task, year, l_class_id): args = ( self.data['url'], self.data['version'], year, l_class_id ) + warnings.warn( self.data['url']) url = MapBiomasCollectionWidget.getUrl( *args ) + warnings.warn(url) return ( url, f"Collection {self.data['version']} - {year}", 'wms' ) def finished(exception, result=None): @@ -318,7 +393,7 @@ def finished(exception, result=None): if not layer.isValid(): source = urllib.parse.unquote( layer.source() ).split('&') url = [ v for v in source if v.split('=')[0] == 'url' ][0] - msg = f"Error server: Get {url}" + msg = f"!!!Error server: Get {url}" self.msgBar.pushCritical( self.MODULE, msg ) return @@ -338,7 +413,7 @@ def finished(exception, result=None): args = { 'description': self.MODULE, 'function': createLayer, - 'year': 2018, + 'year': 2017, 'l_class_id': [1, 10, 14, 22, 26, 27], 'on_finished': finished } diff --git a/mapbiomascollection_en_US.json b/mapbiomascollection_en_US.json index 9aa37d4..96db85d 100644 --- a/mapbiomascollection_en_US.json +++ b/mapbiomascollection_en_US.json @@ -1,7 +1,7 @@ { "version": "4.1", - "url": "http://workspace.mapbiomas.org/wms", - "years": { "min": 1985, "max": 2018}, + "url": "http://azure.solved.eco.br:8080/geoserver/solved/wms", + "years": { "min": 1985, "max": 2017}, "classes": { "Florestry": { "id": 1, "color": { "r": 18, "g": 153, "b": 18 }, diff --git a/mapbiomascollection_pt_BR.json b/mapbiomascollection_pt_BR.json index ce1c686..f4e49ea 100644 --- a/mapbiomascollection_pt_BR.json +++ b/mapbiomascollection_pt_BR.json @@ -1,7 +1,7 @@ { - "version": "4.1", - "url": "http://workspace.mapbiomas.org/wms", - "years": { "min": 1985, "max": 2018}, + "version": "5.0", + "url": "http://azure.solved.eco.br:8080/geoserver/solved/wms", + "years": { "min": 1985, "max": 2017}, "classes": { "Floresta": { "id": 1, "color": { "r": 18, "g": 153, "b": 18 }, diff --git a/metadata.txt b/metadata.txt index 8fd49bf..370e35b 100644 --- a/metadata.txt +++ b/metadata.txt @@ -3,11 +3,11 @@ name: MapBiomas Collection description: This plugin lets you get collection of mapping from MapBiomas Project(http://mapbiomas.org/). about:This plugin add layers(WMS) of collection from MapBiomas. -version:1.0 +version:1.1 qgisMinimumVersion:3.10 -author:Luiz Motta -email:motta.luiz@gmail.com +author:Luiz Motta, Luiz Cortinhas +email:motta.luiz@gmail.com, luiz.cortinhas@solved.eco.br category:Web @@ -22,7 +22,8 @@ icon:mapbiomas.svg experimental:False deprecated:False -changelog: 1.0(2020-03-25) +changelog: - 1.1(2020-10-28) Mapbiomas changed from Geoserver to MapServer + - 1.0(2020-03-25) Changed Docwidget to WidgetProvider(legend) - 0.3(2019-09-05) Add set for collection layer From ea3a7aa9534c48a2ede591709ea97ab39dc4a9df Mon Sep 17 00:00:00 2001 From: Luiz Cortinhas Date: Thu, 26 Nov 2020 10:31:03 -0300 Subject: [PATCH 2/3] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 97ff18d..efa165b 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,11 @@ This plugin lets you get collection of mapping from MapBiomas Project. ## Author -Luiz Motta +Luiz Motta, Luiz Cortinhas ## Changelog +- 2020-11-26 +Updated to new Map Server and SLD style - 2020-03-25 Changed Docwidget to WidgetProvider(legend) - 2019-09-05 From 8b85055a4346c3d99cd68bdd4404f9acee8c5cd8 Mon Sep 17 00:00:00 2001 From: Luiz Neto Date: Thu, 11 Feb 2021 15:50:13 -0300 Subject: [PATCH 3/3] fix: last years + unexpected close --- .gitignore | 16 +- LICENSE | 680 +++++++++++++------------- README.md | 48 +- __init__.py | 136 +++--- create_zip_plugin.sh | 19 +- mapbiomas.svg | 118 ++--- mapbiomascollection.py | 844 +++++++++++++++++---------------- mapbiomascollection_en_US.json | 131 ++--- mapbiomascollection_pt_BR.json | 130 ++--- metadata.txt | 67 +-- 10 files changed, 1103 insertions(+), 1086 deletions(-) diff --git a/.gitignore b/.gitignore index b137d67..568c479 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ -# Ignore -.directory -*.pyc -*.zip -*.sh -# Not Ignore -!create_zip_plugin.sh - +# Ignore +.directory +*.pyc +*.zip +*.sh +# Not Ignore +!create_zip_plugin.sh + diff --git a/LICENSE b/LICENSE index d6a9326..c0f8284 100644 --- a/LICENSE +++ b/LICENSE @@ -1,340 +1,340 @@ -GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {description} - Copyright (C) {year} {fullname} - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - {signature of Ty Coon}, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. - +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + diff --git a/README.md b/README.md index efa165b..29b83cd 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,24 @@ - -[mapbiomas_logo]: https://k6f2r3a6.stackpathcdn.com/wp-content/uploads/2018/04/C%C3%B3pia-de-mapbiomas_IV%C6%92_a-01.png - -![][mapbiomas_logo] -[MapBiomas](http://mapbiomas.org/) - -# MapBiomas Collection Plugin QGIS - -This plugin lets you get collection of mapping from MapBiomas Project. - -## Author -Luiz Motta, Luiz Cortinhas - -## Changelog -- 2020-11-26 -Updated to new Map Server and SLD style -- 2020-03-25 -Changed Docwidget to WidgetProvider(legend) -- 2019-09-05 -Add set for collection layer -- 2019-08-30 -Update metadata and added collection number -- 2019-08-29 -Start of plugin + +[mapbiomas_logo]: https://k6f2r3a6.stackpathcdn.com/wp-content/uploads/2018/04/C%C3%B3pia-de-mapbiomas_IV%C6%92_a-01.png + +![][mapbiomas_logo] +[MapBiomas](http://mapbiomas.org/) + +# MapBiomas Collection Plugin QGIS + +This plugin lets you get collection of mapping from MapBiomas Project. + +## Author +Luiz Motta, Luiz Cortinhas + +## Changelog +- 2020-11-26 +Updated to new Map Server and SLD style +- 2020-03-25 +Changed Docwidget to WidgetProvider(legend) +- 2019-09-05 +Add set for collection layer +- 2019-08-30 +Update metadata and added collection number +- 2019-08-29 +Start of plugin diff --git a/__init__.py b/__init__.py index 3457be3..b1be37d 100644 --- a/__init__.py +++ b/__init__.py @@ -1,69 +1,69 @@ -# -*- coding: utf-8 -*- -""" -/*************************************************************************** -Name : MapBiomas Collection -Description : This plugin lets you get collection of mapping from MapBiomas Project(http://mapbiomas.org/). -Date : August, 2020 -copyright : (C) 2019 by Luiz Motta, Updated by Luiz Cortinhas (2020) -email : motta.luiz@gmail.com, luiz.cortinhas@solved.eco.br - - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ -""" -__author__ = 'Luiz Cortinhas, Luiz Motta' -__date__ = '2020-10-28' -__copyright__ = '(C) 2020, Luiz Cortinhas (Fork: 2019, Luiz Motta)' -__revision__ = '$Format:%H$' - -import os - -from qgis.PyQt.QtCore import QObject, pyqtSlot -from qgis.PyQt.QtGui import QIcon -from qgis.PyQt.QtWidgets import QAction - -from .mapbiomascollection import MapBiomasCollection - -def classFactory(iface): - return MapbiomasCollectionPlugin( iface ) - -class MapbiomasCollectionPlugin(QObject): - def __init__(self, iface=None): - super().__init__() - self.iface = iface - self.name = u"&MapbiomasCollection" - self.mbc = MapBiomasCollection( iface ) - - def initGui(self): - name = "Mapbiomas Collection" - about = 'Add a MapBiomas collection' - icon = QIcon( os.path.join( os.path.dirname(__file__), 'mapbiomas.svg' ) ) - self.action = QAction( icon, name, self.iface.mainWindow() ) - self.action.setObjectName( name.replace(' ', '') ) - self.action.setWhatsThis( about ) - self.action.setStatusTip( about ) - self.action.triggered.connect( self.run ) - - self.iface.addToolBarIcon( self.action ) - self.iface.addPluginToMenu( self.name, self.action ) - - self.mbc.register() - - def unload(self): - self.iface.removeToolBarIcon( self.action ) - self.iface.removePluginMenu( self.name, self.action ) - del self.action - if not self.mbc: - del self.mbc - - @pyqtSlot() - def run(self): - self.mbc.run() +# -*- coding: utf-8 -*- +""" +/*************************************************************************** +Name : MapBiomas Collection +Description : This plugin lets you get collection of mapping from MapBiomas Project(http://mapbiomas.org/). +Date : August, 2020 +copyright : (C) 2019 by Luiz Motta, Updated by Luiz Cortinhas (2020) +email : motta.luiz@gmail.com, luiz.cortinhas@solved.eco.br + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +""" +__author__ = 'Luiz Cortinhas, Luiz Motta' +__date__ = '2021-02-11' +__copyright__ = '(C) 2021, Luiz Cortinhas (Fork: 2019, Luiz Motta)' +__revision__ = '$Format:%H$' + +import os + +from qgis.PyQt.QtCore import QObject, pyqtSlot +from qgis.PyQt.QtGui import QIcon +from qgis.PyQt.QtWidgets import QAction + +from .mapbiomascollection import MapBiomasCollection + +def classFactory(iface): + return MapbiomasCollectionPlugin( iface ) + +class MapbiomasCollectionPlugin(QObject): + def __init__(self, iface=None): + super().__init__() + self.iface = iface + self.name = u"&MapbiomasCollection" + self.mbc = MapBiomasCollection( iface ) + + def initGui(self): + name = "Mapbiomas Collection" + about = 'Add a MapBiomas collection' + icon = QIcon( os.path.join( os.path.dirname(__file__), 'mapbiomas.svg' ) ) + self.action = QAction( icon, name, self.iface.mainWindow() ) + self.action.setObjectName( name.replace(' ', '') ) + self.action.setWhatsThis( about ) + self.action.setStatusTip( about ) + self.action.triggered.connect( self.run ) + + self.iface.addToolBarIcon( self.action ) + self.iface.addPluginToMenu( self.name, self.action ) + + self.mbc.register() + + def unload(self): + self.iface.removeToolBarIcon( self.action ) + self.iface.removePluginMenu( self.name, self.action ) + del self.action + if not self.mbc: + del self.mbc + + @pyqtSlot() + def run(self): + self.mbc.run() \ No newline at end of file diff --git a/create_zip_plugin.sh b/create_zip_plugin.sh index 9c6c689..c014263 100755 --- a/create_zip_plugin.sh +++ b/create_zip_plugin.sh @@ -1,9 +1,10 @@ -plugin_dir=$( basename $( pwd ) ) -if [ -f "./$plugin_dir.zip" ]; then - rm "./$plugin_dir.zip" -fi -mkdir "./$plugin_dir" -cp *.py "./$plugin_dir" -for item in metadata.txt LICENSE mapbiomas.svg *.json; do cp "./$item" "./$plugin_dir"; done -zip -r $plugin_dir $plugin_dir -rm -r $plugin_dir +#/bin/bash +plugin_dir=$( basename $( pwd ) ) +if [ -f "./$plugin_dir.zip" ]; then + rm "./$plugin_dir.zip" +fi +mkdir "./$plugin_dir" +cp *.py "./$plugin_dir" +for item in metadata.txt LICENSE mapbiomas.svg *.json; do cp "./$item" "./$plugin_dir"; done +zip -r $plugin_dir $plugin_dir +rm -r $plugin_dir \ No newline at end of file diff --git a/mapbiomas.svg b/mapbiomas.svg index df304f3..54c39d9 100644 --- a/mapbiomas.svg +++ b/mapbiomas.svg @@ -1,59 +1,59 @@ - - - - - - image/svg+xml - - - - - - - - + + + + + + image/svg+xml + + + + + + + + diff --git a/mapbiomascollection.py b/mapbiomascollection.py index 6fd13e1..9228f15 100644 --- a/mapbiomascollection.py +++ b/mapbiomascollection.py @@ -1,421 +1,423 @@ -import os, time, json -import urllib.parse -import warnings -from osgeo import gdal - -from qgis.PyQt.QtCore import ( - Qt, QSettings, QLocale, - QObject, pyqtSlot, pyqtSignal -) -from qgis.PyQt.QtWidgets import ( - QWidget, QPushButton, - QSlider, QLabel, - QTreeWidget, QTreeWidgetItem, - QVBoxLayout, QHBoxLayout -) -from qgis.PyQt.QtGui import ( - QColor, QPixmap, QIcon -) - -from qgis.core import ( - QgsApplication, Qgis, QgsProject, - QgsRasterLayer, - QgsTask - -) -from qgis.gui import QgsGui, QgsMessageBar, QgsLayerTreeEmbeddedWidgetProvider -#https://production.mapserver.mapbiomas.org/wms/coverage.map?service=WMS&request=GetMap&layers=coverage&styles=&format=image%2Fpng&transparent=true&version=1.3.0&territory_ids=96&year=2019&class_tree_node_ids=28%2C36%2C50%2C51%2C52%2C35%2C29%2C37%2C38%2C41%2C40%2C39%2C30%2C43%2C42%2C54%2C56%2C55%2C57%2C53%2C44%2C31%2C45%2C46%2C47%2C34%2C32%2C49%2C48%2C33&width=256&height=256&srs=EPSG%3A3857&maxZoom=19&minZoom=4&bbox=-5635549.221409475,-1252344.2714243263,-5009377.085697311,-626172.1357121632 - -class MapBiomasCollectionWidget(QWidget): - classRef = {1:{'color':'129912','parent':0,'status':False}, - 2:{'color':'1F4423','parent':1,'status':False}, - 3:{'color':'006400','parent':2,'status':False}, - 4:{'color':'32CD32','parent':2,'status':False}, - 5:{'color':'687537','parent':2,'status':False}, - 6:{'color':'000000','parent':0,'status':False}, - 7:{'color':'000000','parent':0,'status':False}, - 8:{'color':'000000','parent':0,'status':False}, - 9:{'color':'935132','parent':1,'status':False}, - 10:{'color':'BBFCAC','parent':0,'status':False}, - 11:{'color':'45C2A5','parent':10,'status':False}, - 12:{'color':'B8AF4F','parent':10,'status':False}, - 13:{'color':'BDB76B','parent':10,'status':False}, - 14:{'color':'FFFFB2','parent':0,'status':False}, - 15:{'color':'FFD966','parent':14,'status':False}, - 16:{'color':'000000','parent':0,'status':False}, - 17:{'color':'000000','parent':0,'status':False}, - 18:{'color':'E974ED','parent':14,'status':False}, - 19:{'color':'D5A6BD','parent':18,'status':False}, - 20:{'color':'C27BA0','parent':18,'status':False}, - 21:{'color':'FFEFC3','parent':14,'status':False}, - 22:{'color':'EA9999','parent':0,'status':False}, - 23:{'color':'DD7E6B','parent':22,'status':False}, - 24:{'color':'af2a2a','parent':22,'status':False}, - 25:{'color':'FF99FF','parent':22,'status':False}, - 26:{'color':'0000FF','parent':0,'status':False}, - 27:{'color':'D5D5E5','parent':0,'status':False}, - 28:{'color': '000000','parent':0,'status':False}, - 29:{'color':'FF8C00','parent':10,'status':False}, - 30:{'color':'8A2BE2','parent':22,'status':False}, - 31:{'color':'29EEE4','parent':26,'status':False}, - 32:{'color':'968c46','parent':10,'status':False}, - 33:{'color':'0000FF','parent':26,'status':False}, - 34:{'color':'000000','parent':0,'status':False}, - 35:{'color':'000000','parent':0,'status':False}, - 36:{'color':'f3b4f1','parent':0,'status':False}, - 37:{'color':'000000','parent':0,'status':False}, - 38:{'color':'000000','parent':0,'status':False}, - 39:{'color':'c59ff4','parent':0,'status':False}, - 40:{'color':'000000','parent':0,'status':False}, - 41:{'color':'e787f8','parent':0,'status':False}} - @staticmethod - def getParentColor(item): - if item['parent'] == 0 and item['status'] == False: - return 'FFFFFF' - if item['status']: - return item['color'] - else: - return MapBiomasCollectionWidget.getParentColor(MapBiomasCollectionWidget.classRef[item['parent']]) - - @staticmethod - def getUrl(url, version, year, l_class_id): - l_strClass = [ str(item) for item in l_class_id ] - for item in MapBiomasCollectionWidget.classRef.keys(): - MapBiomasCollectionWidget.classRef[item]['status'] = False - for item in l_class_id: - MapBiomasCollectionWidget.classRef[item]['status'] = True - #ENV Percorredor! - env = 'env=' - for item in MapBiomasCollectionWidget.classRef.keys(): - classID = item - color = MapBiomasCollectionWidget.getParentColor(MapBiomasCollectionWidget.classRef[item]) - env = env + f'{classID}:{color};' - #env=1:00FF00;2:triangle;3:12 - #crs=EPSG:3857&dpiMode=7&format=image/png&layers=mapbiomas&styles&url=http://azure.solved.eco.br:8080/geoserver/solved/wms - paramsWms = f'IgnoreGetFeatureInfoUrl=1&IgnoreGetMapUrl=1&service=WMS&styles=solved:mapbiomas_legend&request=GetMap&format=image/png8&layers=mapbiomas_{year}&crs=EPSG:4326' - #'IgnoreGetFeatureInfoUrl=1&IgnoreGetMapUrl=1&crs=EPSG:3857&dpiMode=7&format=image/png&layers=coverage&styles=' - paramsQuote = f"" - paramsQuote = f"{paramsQuote}&transparent=true&version=1.1.1" - paramsQuote = urllib.parse.quote( f"{paramsQuote}&exceptions=application/vnd.ogc.se_inimage&years={year}&{env}&classification_ids=" )# a ordem importa - paramClassification = ','.join( l_strClass ) - msg = f"{paramsWms}&url={url}?{paramsQuote}{paramClassification}" - warnings.warn(msg) - return f"{paramsWms}&url={url}?{paramsQuote}{paramClassification}" - - def __init__(self, layer, data): - def getYearClasses(): - def getYear(): - values = [ item for item in paramsSource if item.find('years=') > -1] - return self.maxYear if not len( values ) == 1 else int( values[0].split('=')[1] ) - - def getClasses(): - values = [ item for item in paramsSource if item.find('classification_ids=') > -1 ] - return [1,10,14,22,26,27] \ - if not len( values ) == 1 \ - else [ int( item ) for item in values[0].split('=')[1].split(',') ] - - paramsSource = urllib.parse.unquote( self.layer.source() ).split('&') - return getYear(), getClasses() - - def setGui(classes): - def createLayoutYear(): - lytYear = QHBoxLayout() - lblTitleYear = QLabel( 'Year:', self ) - lblYear = QLabel( str( self.year ), self ) - lytYear.addWidget( lblTitleYear ) - lytYear.addWidget( lblYear ) - return lytYear, lblYear - - def createLayoutSlider(): - def createButtonLimit(limitYear, sFormat, objectName): - label = sFormat.format( limitYear ) - pb = QPushButton( label, self ) - width = pb.fontMetrics().boundingRect( label ).width() + 7 - pb.setMaximumWidth( width ) - pb.setObjectName( objectName ) - return pb - - def createSlider(): - slider = QSlider( Qt.Horizontal, self ) - #slider.setTracking( False ) # Value changed only released mouse - slider.setMinimum( self.minYear ) - slider.setMaximum( self.maxYear ) - slider.setSingleStep(1) - slider.setValue( self.year ) - interval = int( ( self.maxYear - self.minYear) / 10 ) - slider.setTickInterval( interval ) - slider.setPageStep( interval) - slider.setTickPosition( QSlider.TicksBelow ) - return slider - - lytSlider = QHBoxLayout() - pbMin = createButtonLimit( self.minYear, "{} <<", 'minYear' ) - lytSlider.addWidget( pbMin ) - slider = createSlider() - lytSlider.addWidget( slider ) - pbMax = createButtonLimit( self.maxYear, ">> {}", 'maxYear' ) - lytSlider.addWidget( pbMax ) - return lytSlider, slider, pbMin, pbMax - - def createTree(classes): - def populateTreeJson(classes, itemRoot): - def createIcon(color): - color = QColor( color['r'], color['g'], color['b'] ) - pix = QPixmap(16, 16) - pix.fill( color ) - return QIcon( pix ) - - def createItem(itemRoot, name, class_id, flags, icon): - # WidgetItem - item = QTreeWidgetItem( itemRoot ) - item.setText(0, name ) - item.setData(0, Qt.UserRole, class_id ) - checkState = Qt.Checked if class_id in self.l_class_id else Qt.Unchecked - item.setCheckState(0, checkState ) - item.setFlags( flags ) - item.setIcon(0, icon ) - return item - - flags = itemRoot.flags() | Qt.ItemIsUserCheckable - for k in classes: - class_id = classes[ k ]['id'] - icon = createIcon( classes[ k ]['color'] ) - itemClass = createItem( itemRoot, k, class_id, flags, icon ) - if 'classes' in classes[ k ]: - populateTreeJson( classes[ k ]['classes'], itemClass ) - - tree = QTreeWidget( self ) - tree.setSelectionMode( tree.NoSelection ) - tree.setHeaderHidden( True ) - itemRoot = QTreeWidgetItem( tree ) - itemRoot.setText(0, 'Classes') - populateTreeJson( classes, itemRoot ) - return tree, itemRoot - - lytYear, lblYear = createLayoutYear() - lytSlider, slider, pbMin, pbMax = createLayoutSlider( ) - tree, itemClasses = createTree( classes ) - itemClasses.setExpanded( True ) - # Layout - lyt = QVBoxLayout() - lyt.addLayout( lytYear ) - lyt.addLayout( lytSlider ) - lyt.addWidget( tree ) - msgBar = QgsMessageBar(self) - lyt.addWidget( msgBar ) - self.setLayout( lyt ) - - - return { - 'msgBar': msgBar, - 'lblYear': lblYear, - 'slider': slider, - 'pbMin': pbMin, - 'pbMax': pbMax, - 'tree': tree, - 'itemClasses': itemClasses - } - - super().__init__() - self.layer = layer - self.version = data['version'] - self.url = data['url'] - self.minYear = data['years']['min'] - self.maxYear = data['years']['max'] - - self.project = QgsProject.instance() - self.root = self.project.layerTreeRoot() - - self.year, self.l_class_id = getYearClasses() # Depend self.maxYear - self.valueYearLayer = self.year - - r = setGui( data['classes'] ) - self.msgBar = r['msgBar'] - self.lblYear = r['lblYear'] - self.slider = r['slider'] - self.pbMin = r['pbMin'] - self.pbMax = r['pbMax'] - self.tree = r['tree'] - self.itemClasses = r['itemClasses'] - - # Connections - self.slider.valueChanged.connect( self.on_yearChanged ) - self.slider.sliderReleased.connect( self.on_released ) - self.pbMin.clicked.connect( self.on_limitYear ) - self.pbMax.clicked.connect( self.on_limitYear ) - self.tree.itemChanged.connect( self.on_classChanged ) - - def _uploadSource(self): - def checkDataSource(): - url = self.getUrl( self.url, self.version, self.year, self.l_class_id ) - print('URL:') - print(url) - name = f"Collection {self.version} - {self.year}" - print('name:') - print(name) - args = [ url, name, self.layer.providerType() ] - layer = QgsRasterLayer( *args ) - if not layer.isValid(): - msg = f"Error server {self.url}" - return { 'isOk': False, 'message': msg } - args += [ self.layer.dataProvider().ProviderOptions() ] - return { 'isOk': True, 'args': args } - - self.setEnabled( False ) - r = checkDataSource() - if not r['isOk']: - self.msgBar.pushMessage( r['message'], Qgis.Critical, 4 ) - self.setEnabled( True ) - return - self.layer.setDataSource( *r['args'] ) # The Widget will be create agai - - @pyqtSlot() - def on_released(self): - if self.valueYearLayer == self.year: - return - - self._uploadSource() - - @pyqtSlot(int) - def on_yearChanged(self, value): - if value == self.year: - return - - self.yearChanged = True - self.year = value - self.lblYear.setText( str( value ) ) - if not self.slider.isSliderDown(): # Keyboard - self.valueYearLayer = self.year - self._uploadSource() - - @pyqtSlot(bool) - def on_limitYear(self, checked): - year = self.maxYear if self.sender().objectName() == 'maxYear' else self.minYear - if year == self.year: - return - - self.year = year - self.lblYear.setText( str( self.year ) ) - self.valueYearLayer = self.year - self._uploadSource() - - @pyqtSlot(QTreeWidgetItem, int) - def on_classChanged(self, item, column): - value = item.data( column, Qt.UserRole) - color = item.data( column, Qt.UserRole) - status = item.checkState( column ) == Qt.Checked - f = self.l_class_id.append if status else self.l_class_id.remove - f( value ) - self._uploadSource() - - -class LayerMapBiomasCollectionWidgetProvider(QgsLayerTreeEmbeddedWidgetProvider): - def __init__(self, data): - super().__init__() - self.data = data - - def id(self): - return 'mapbiomascollection' - - def name(self): - return "Layer MapBiomas Collection" - - def createWidget(self, layer, widgetIndex): - return MapBiomasCollectionWidget( layer, self.data ) - - def supportsLayer(self, layer): - if not layer.providerType() == 'wms': - return False - source = urllib.parse.unquote( layer.source() ).split('&') - print('Here') - host = f"url={self.data['url']}?map=wms/v/{self.data['version']}/classification/coverage.map" - print(host) - warnings.warn(host) - l_url = [ item for item in source if item.find( host ) > -1 ] - return len( l_url ) > 0 - - -class MapBiomasCollection(QObject): - MODULE = 'MapBiomasCollection' - def __init__(self, iface): - def getConfig(): - def existLocaleConfig(): - overrideLocale = QSettings().value('locale/overrideFlag', False, type=bool) - locale = QLocale.system().name() if not overrideLocale else QSettings().value('locale/userLocale', '') - name = f_name.format( locale=locale ) - fileConfig = os.path.join( dirname, name ) - if os.path.exists( fileConfig ): - return { 'isOk': True, 'fileConfig': fileConfig } - return { 'isOk': False } - - f_name = "mapbiomascollection_{locale}.json" - dirname = os.path.dirname(__file__) - r = existLocaleConfig() - if r['isOk']: - fileConfig = r['fileConfig'] - else: - name = f_name.format( locale='en_US') - fileConfig = os.path.join( dirname, name ) - - with open(fileConfig) as json_file: - data = json.load(json_file) - return data - - super().__init__() - self.msgBar = iface.messageBar() - self.root = QgsProject.instance().layerTreeRoot() - self.taskManager = QgsApplication.taskManager() - self.data = getConfig() - self.widgetProvider = None - - def register(self): - self.widgetProvider = LayerMapBiomasCollectionWidgetProvider( self.data ) - registry = QgsGui.layerTreeEmbeddedWidgetRegistry() - if not registry.provider( self.widgetProvider.id() ) is None: - registry.removeProvider( self.widgetProvider.id() ) - registry.addProvider( self.widgetProvider ) - - def run(self): - def createLayer(task, year, l_class_id): - args = ( self.data['url'], self.data['version'], year, l_class_id ) - warnings.warn( self.data['url']) - url = MapBiomasCollectionWidget.getUrl( *args ) - warnings.warn(url) - return ( url, f"Collection {self.data['version']} - {year}", 'wms' ) - - def finished(exception, result=None): - self.msgBar.clearWidgets() - if not exception is None: - msg = f"Error: Exception: {exception}" - self.msgBar.pushMessage( self.MODULE, msg, Qgis.Critical, 4 ) - return - layer = QgsRasterLayer( *result ) - if not layer.isValid(): - source = urllib.parse.unquote( layer.source() ).split('&') - url = [ v for v in source if v.split('=')[0] == 'url' ][0] - msg = f"!!!Error server: Get {url}" - self.msgBar.pushCritical( self.MODULE, msg ) - return - - project = QgsProject.instance() - totalEW = int( layer.customProperty('embeddedWidgets/count', 0) ) - layer.setCustomProperty('embeddedWidgets/count', totalEW + 1 ) - layer.setCustomProperty(f"embeddedWidgets/{totalEW}/id", self.widgetProvider.id() ) - project.addMapLayer( layer ) - root = project.layerTreeRoot() - ltl = root.findLayer( layer ) - ltl.setExpanded(True) - - msg = f"Adding layer collection from {self.data['url']}" - msg = f"{msg}(version {self.data['version']})..." - self.msgBar.pushMessage( self.MODULE, msg, Qgis.Info, 0 ) - # Task - args = { - 'description': self.MODULE, - 'function': createLayer, - 'year': 2017, - 'l_class_id': [1, 10, 14, 22, 26, 27], - 'on_finished': finished - } - task = QgsTask.fromFunction( **args ) - self.taskManager.addTask( task ) +import os, time, json +import urllib.parse +import warnings +from osgeo import gdal + +from qgis.PyQt.QtCore import ( + Qt, QSettings, QLocale, + QObject, pyqtSlot, pyqtSignal +) +from qgis.PyQt.QtWidgets import ( + QWidget, QPushButton, + QSlider, QLabel, + QTreeWidget, QTreeWidgetItem, + QVBoxLayout, QHBoxLayout +) +from qgis.PyQt.QtGui import ( + QColor, QPixmap, QIcon +) + +from qgis.core import ( + QgsApplication, Qgis, QgsProject, + QgsRasterLayer, + QgsTask + +) +from qgis.gui import QgsGui, QgsMessageBar, QgsLayerTreeEmbeddedWidgetProvider +#https://production.mapserver.mapbiomas.org/wms/coverage.map?service=WMS&request=GetMap&layers=coverage&styles=&format=image%2Fpng&transparent=true&version=1.3.0&territory_ids=96&year=2019&class_tree_node_ids=28%2C36%2C50%2C51%2C52%2C35%2C29%2C37%2C38%2C41%2C40%2C39%2C30%2C43%2C42%2C54%2C56%2C55%2C57%2C53%2C44%2C31%2C45%2C46%2C47%2C34%2C32%2C49%2C48%2C33&width=256&height=256&srs=EPSG%3A3857&maxZoom=19&minZoom=4&bbox=-5635549.221409475,-1252344.2714243263,-5009377.085697311,-626172.1357121632 + +class MapBiomasCollectionWidget(QWidget): + classRef = {1:{'color':'129912','parent':0,'status':False}, + 2:{'color':'1F4423','parent':1,'status':False}, + 3:{'color':'006400','parent':2,'status':False}, + 4:{'color':'32CD32','parent':2,'status':False}, + 5:{'color':'687537','parent':2,'status':False}, + 6:{'color':'000000','parent':0,'status':False}, + 7:{'color':'000000','parent':0,'status':False}, + 8:{'color':'000000','parent':0,'status':False}, + 9:{'color':'935132','parent':1,'status':False}, + 10:{'color':'BBFCAC','parent':0,'status':False}, + 11:{'color':'45C2A5','parent':10,'status':False}, + 12:{'color':'B8AF4F','parent':10,'status':False}, + 13:{'color':'BDB76B','parent':10,'status':False}, + 14:{'color':'FFFFB2','parent':0,'status':False}, + 15:{'color':'FFD966','parent':14,'status':False}, + 16:{'color':'000000','parent':0,'status':False}, + 17:{'color':'000000','parent':0,'status':False}, + 18:{'color':'E974ED','parent':14,'status':False}, + 19:{'color':'D5A6BD','parent':18,'status':False}, + 20:{'color':'C27BA0','parent':19,'status':False}, + 21:{'color':'FFEFC3','parent':14,'status':False}, + 22:{'color':'EA9999','parent':0,'status':False}, + 23:{'color':'DD7E6B','parent':22,'status':False}, + 24:{'color':'af2a2a','parent':22,'status':False}, + 25:{'color':'FF99FF','parent':22,'status':False}, + 26:{'color':'0000FF','parent':0,'status':False}, + 27:{'color':'D5D5E5','parent':0,'status':False}, + 28:{'color': '000000','parent':0,'status':False}, + 29:{'color':'FF8C00','parent':10,'status':False}, + 30:{'color':'8A2BE2','parent':22,'status':False}, + 31:{'color':'29EEE4','parent':26,'status':False}, + 32:{'color':'968c46','parent':10,'status':False}, + 33:{'color':'0000FF','parent':26,'status':False}, + 34:{'color':'000000','parent':0,'status':False}, + 35:{'color':'000000','parent':0,'status':False}, + 36:{'color':'f3b4f1','parent':18,'status':False}, + 37:{'color':'000000','parent':0,'status':False}, + 38:{'color':'000000','parent':0,'status':False}, + 39:{'color':'c59ff4','parent':19,'status':False}, + 40:{'color':'000000','parent':0,'status':False}, + 41:{'color':'e787f8','parent':19,'status':False}} + @staticmethod + def getParentColor(item): + if item['parent'] == 0 and item['status'] == False: + return 'FFFFFF' + if item['status']: + return item['color'] + else: + return MapBiomasCollectionWidget.getParentColor(MapBiomasCollectionWidget.classRef[item['parent']]) + + @staticmethod + def getUrl(url, version, year, l_class_id): + l_strClass = [ str(item) for item in l_class_id ] + for item in MapBiomasCollectionWidget.classRef.keys(): + MapBiomasCollectionWidget.classRef[item]['status'] = False + for item in l_class_id: + MapBiomasCollectionWidget.classRef[item]['status'] = True + #ENV Percorredor! + env = 'env=' + for item in MapBiomasCollectionWidget.classRef.keys(): + classID = item + color = MapBiomasCollectionWidget.getParentColor(MapBiomasCollectionWidget.classRef[item]) + env = env + f'{classID}:{color};' + #env=1:00FF00;2:triangle;3:12 + #crs=EPSG:3857&dpiMode=7&format=image/png&layers=mapbiomas&styles&url=http://azure.solved.eco.br:8080/geoserver/solved/wms + paramsWms = f'IgnoreGetFeatureInfoUrl=1&IgnoreGetMapUrl=1&service=WMS&styles=solved:mapbiomas_legend&request=GetMap&format=image/png8&layers=mapbiomas_{year}&crs=EPSG:4326' + #'IgnoreGetFeatureInfoUrl=1&IgnoreGetMapUrl=1&crs=EPSG:3857&dpiMode=7&format=image/png&layers=coverage&styles=' + paramsQuote = f"" + paramsQuote = f"{paramsQuote}&transparent=true&version=1.1.1" + paramsQuote = urllib.parse.quote( f"{paramsQuote}&exceptions=application/vnd.ogc.se_inimage&years={year}&{env}&classification_ids=" )# a ordem importa + paramClassification = ','.join( l_strClass ) + msg = f"{paramsWms}&url={url}?{paramsQuote}{paramClassification}" + #warnings.warn(msg) + return f"{paramsWms}&url={url}?{paramsQuote}{paramClassification}" + + def __init__(self, layer, data): + def getYearClasses(): + def getYear(): + values = [ item for item in paramsSource if item.find('years=') > -1] + return self.maxYear if not len( values ) == 1 else int( values[0].split('=')[1] ) + + def getClasses(): + values = [ item for item in paramsSource if item.find('classification_ids=') > -1 ] + warnings.warn(str(values)) + if (not len( values ) == 1) or (values[0] == 'classification_ids='): + return [] + else : + return [ int( item ) for item in values[0].split('=')[1].split(',') ] + + paramsSource = urllib.parse.unquote( self.layer.source() ).split('&') + return getYear(), getClasses() + + def setGui(classes): + def createLayoutYear(): + lytYear = QHBoxLayout() + lblTitleYear = QLabel( 'Year:', self ) + lblYear = QLabel( str( self.year ), self ) + lytYear.addWidget( lblTitleYear ) + lytYear.addWidget( lblYear ) + return lytYear, lblYear + + def createLayoutSlider(): + def createButtonLimit(limitYear, sFormat, objectName): + label = sFormat.format( limitYear ) + pb = QPushButton( label, self ) + width = pb.fontMetrics().boundingRect( label ).width() + 7 + pb.setMaximumWidth( width ) + pb.setObjectName( objectName ) + return pb + + def createSlider(): + slider = QSlider( Qt.Horizontal, self ) + #slider.setTracking( False ) # Value changed only released mouse + slider.setMinimum( self.minYear ) + slider.setMaximum( self.maxYear ) + slider.setSingleStep(1) + slider.setValue( self.year ) + interval = int( ( self.maxYear - self.minYear) / 10 ) + slider.setTickInterval( interval ) + slider.setPageStep( interval) + slider.setTickPosition( QSlider.TicksBelow ) + return slider + + lytSlider = QHBoxLayout() + pbMin = createButtonLimit( self.minYear, "{} <<", 'minYear' ) + lytSlider.addWidget( pbMin ) + slider = createSlider() + lytSlider.addWidget( slider ) + pbMax = createButtonLimit( self.maxYear, ">> {}", 'maxYear' ) + lytSlider.addWidget( pbMax ) + return lytSlider, slider, pbMin, pbMax + + def createTree(classes): + def populateTreeJson(classes, itemRoot): + def createIcon(color): + color = QColor( color['r'], color['g'], color['b'] ) + pix = QPixmap(16, 16) + pix.fill( color ) + return QIcon( pix ) + + def createItem(itemRoot, name, class_id, flags, icon): + # WidgetItem + item = QTreeWidgetItem( itemRoot ) + item.setText(0, name ) + item.setData(0, Qt.UserRole, class_id ) + checkState = Qt.Checked if class_id in self.l_class_id else Qt.Unchecked + item.setCheckState(0, checkState ) + item.setFlags( flags ) + item.setIcon(0, icon ) + return item + + flags = itemRoot.flags() | Qt.ItemIsUserCheckable + for k in classes: + class_id = classes[ k ]['id'] + icon = createIcon( classes[ k ]['color'] ) + itemClass = createItem( itemRoot, k, class_id, flags, icon ) + if 'classes' in classes[ k ]: + populateTreeJson( classes[ k ]['classes'], itemClass ) + + tree = QTreeWidget( self ) + tree.setSelectionMode( tree.NoSelection ) + tree.setHeaderHidden( True ) + itemRoot = QTreeWidgetItem( tree ) + itemRoot.setText(0, 'Classes') + populateTreeJson( classes, itemRoot ) + return tree, itemRoot + + lytYear, lblYear = createLayoutYear() + lytSlider, slider, pbMin, pbMax = createLayoutSlider( ) + tree, itemClasses = createTree( classes ) + itemClasses.setExpanded( True ) + # Layout + lyt = QVBoxLayout() + lyt.addLayout( lytYear ) + lyt.addLayout( lytSlider ) + lyt.addWidget( tree ) + msgBar = QgsMessageBar(self) + lyt.addWidget( msgBar ) + self.setLayout( lyt ) + + + return { + 'msgBar': msgBar, + 'lblYear': lblYear, + 'slider': slider, + 'pbMin': pbMin, + 'pbMax': pbMax, + 'tree': tree, + 'itemClasses': itemClasses + } + + super().__init__() + self.layer = layer + self.version = data['version'] + self.url = data['url'] + self.minYear = data['years']['min'] + self.maxYear = data['years']['max'] + + self.project = QgsProject.instance() + self.root = self.project.layerTreeRoot() + + self.year, self.l_class_id = getYearClasses() # Depend self.maxYear + self.valueYearLayer = self.year + + r = setGui( data['classes'] ) + self.msgBar = r['msgBar'] + self.lblYear = r['lblYear'] + self.slider = r['slider'] + self.pbMin = r['pbMin'] + self.pbMax = r['pbMax'] + self.tree = r['tree'] + self.itemClasses = r['itemClasses'] + + # Connections + self.slider.valueChanged.connect( self.on_yearChanged ) + self.slider.sliderReleased.connect( self.on_released ) + self.pbMin.clicked.connect( self.on_limitYear ) + self.pbMax.clicked.connect( self.on_limitYear ) + self.tree.itemChanged.connect( self.on_classChanged ) + + def _uploadSource(self): + def checkDataSource(): + url = self.getUrl( self.url, self.version, self.year, self.l_class_id ) + print('URL:') + print(url) + name = f"Collection {self.version} - {self.year}" + print('name:') + print(name) + args = [ url, name, self.layer.providerType() ] + layer = QgsRasterLayer( *args ) + if not layer.isValid(): + msg = f"Error server {self.url}" + return { 'isOk': False, 'message': msg } + args += [ self.layer.dataProvider().ProviderOptions() ] + return { 'isOk': True, 'args': args } + + self.setEnabled( False ) + r = checkDataSource() + if not r['isOk']: + self.msgBar.pushMessage( r['message'], Qgis.Critical, 4 ) + self.setEnabled( True ) + return + self.layer.setDataSource( *r['args'] ) # The Widget will be create agai + + @pyqtSlot() + def on_released(self): + if self.valueYearLayer == self.year: + return + + self._uploadSource() + + @pyqtSlot(int) + def on_yearChanged(self, value): + if value == self.year: + return + + self.yearChanged = True + self.year = value + self.lblYear.setText( str( value ) ) + if not self.slider.isSliderDown(): # Keyboard + self.valueYearLayer = self.year + self._uploadSource() + + @pyqtSlot(bool) + def on_limitYear(self, checked): + year = self.maxYear if self.sender().objectName() == 'maxYear' else self.minYear + if year == self.year: + return + + self.year = year + self.lblYear.setText( str( self.year ) ) + self.valueYearLayer = self.year + self._uploadSource() + + @pyqtSlot(QTreeWidgetItem, int) + def on_classChanged(self, item, column): + value = item.data( column, Qt.UserRole) + color = item.data( column, Qt.UserRole) + status = item.checkState( column ) == Qt.Checked + f = self.l_class_id.append if status else self.l_class_id.remove + f( value ) + self._uploadSource() + + +class LayerMapBiomasCollectionWidgetProvider(QgsLayerTreeEmbeddedWidgetProvider): + def __init__(self, data): + super().__init__() + self.data = data + + def id(self): + return 'mapbiomascollection' + + def name(self): + return "Layer MapBiomas Collection" + + def createWidget(self, layer, widgetIndex): + return MapBiomasCollectionWidget( layer, self.data ) + + def supportsLayer(self, layer): + if not layer.providerType() == 'wms': + return False + source = urllib.parse.unquote( layer.source() ).split('&') + print('Here') + host = f"url={self.data['url']}?map=wms/v/{self.data['version']}/classification/coverage.map" + print(host) + #warnings.warn(host) + l_url = [ item for item in source if item.find( host ) > -1 ] + return len( l_url ) > 0 + + +class MapBiomasCollection(QObject): + MODULE = 'MapBiomasCollection' + def __init__(self, iface): + def getConfig(): + def existLocaleConfig(): + overrideLocale = QSettings().value('locale/overrideFlag', False, type=bool) + locale = QLocale.system().name() if not overrideLocale else QSettings().value('locale/userLocale', '') + name = f_name.format( locale=locale ) + fileConfig = os.path.join( dirname, name ) + if os.path.exists( fileConfig ): + return { 'isOk': True, 'fileConfig': fileConfig } + return { 'isOk': False } + + f_name = "mapbiomascollection_{locale}.json" + dirname = os.path.dirname(__file__) + r = existLocaleConfig() + if r['isOk']: + fileConfig = r['fileConfig'] + else: + name = f_name.format( locale='en_US') + fileConfig = os.path.join( dirname, name ) + + with open(fileConfig) as json_file: + data = json.load(json_file) + return data + + super().__init__() + self.msgBar = iface.messageBar() + self.root = QgsProject.instance().layerTreeRoot() + self.taskManager = QgsApplication.taskManager() + self.data = getConfig() + self.widgetProvider = None + + def register(self): + self.widgetProvider = LayerMapBiomasCollectionWidgetProvider( self.data ) + registry = QgsGui.layerTreeEmbeddedWidgetRegistry() + if not registry.provider( self.widgetProvider.id() ) is None: + registry.removeProvider( self.widgetProvider.id() ) + registry.addProvider( self.widgetProvider ) + + def run(self): + def createLayer(task, year, l_class_id): + args = ( self.data['url'], self.data['version'], year, l_class_id ) + #warnings.warn( self.data['url']) + url = MapBiomasCollectionWidget.getUrl( *args ) + #warnings.warn(url) + return ( url, f"Collection {self.data['version']} - {year}", 'wms' ) + + def finished(exception, result=None): + self.msgBar.clearWidgets() + if not exception is None: + msg = f"Error: Exception: {exception}" + self.msgBar.pushMessage( self.MODULE, msg, Qgis.Critical, 4 ) + return + layer = QgsRasterLayer( *result ) + if not layer.isValid(): + source = urllib.parse.unquote( layer.source() ).split('&') + url = [ v for v in source if v.split('=')[0] == 'url' ][0] + msg = f"!!!Error server: Get {url}" + self.msgBar.pushCritical( self.MODULE, msg ) + return + + project = QgsProject.instance() + totalEW = int( layer.customProperty('embeddedWidgets/count', 0) ) + layer.setCustomProperty('embeddedWidgets/count', totalEW + 1 ) + layer.setCustomProperty(f"embeddedWidgets/{totalEW}/id", self.widgetProvider.id() ) + project.addMapLayer( layer ) + root = project.layerTreeRoot() + ltl = root.findLayer( layer ) + ltl.setExpanded(True) + + msg = f"Adding layer collection from {self.data['url']}" + msg = f"{msg}(version {self.data['version']})..." + self.msgBar.pushMessage( self.MODULE, msg, Qgis.Info, 0 ) + # Task + args = { + 'description': self.MODULE, + 'function': createLayer, + 'year': 2017, + 'l_class_id': [1, 10, 14, 22, 26, 27], + 'on_finished': finished + } + task = QgsTask.fromFunction( **args ) + self.taskManager.addTask( task ) diff --git a/mapbiomascollection_en_US.json b/mapbiomascollection_en_US.json index 96db85d..091c5bc 100644 --- a/mapbiomascollection_en_US.json +++ b/mapbiomascollection_en_US.json @@ -1,62 +1,69 @@ -{ - "version": "4.1", - "url": "http://azure.solved.eco.br:8080/geoserver/solved/wms", - "years": { "min": 1985, "max": 2017}, - "classes": { - "Florestry": { - "id": 1, "color": { "r": 18, "g": 153, "b": 18 }, - "classes": { - "Natural Forest": { - "id": 2, "color": { "r": 31, "g": 68, "b": 35 }, - "classes": { - "Forest Formation": { "id": 3, "color": { "r": 39, "g": 78, "b": 19 } }, - "Savanna Formation ": { "id": 4, "color": { "r": 50, "g": 205, "b": 50 } }, - "Mangrove": { "id": 5, "color": { "r": 104, "g": 117, "b": 55 } } - } - }, - "Forest Plantation": { "id": 9, "color": { "r": 147, "g": 81, "b": 50 } } - } - }, - "Non Forest Natural Formation": { - "id": 10, "color": { "r": 187, "g": 252, "b": 172 }, - "classes": { - "Wetland": { "id": 11, "color": { "r": 69, "g": 194, "b": 165 } }, - "Grassland": { "id": 12, "color": { "r": 184, "g": 175, "b": 79 } }, - "Salt Flat": { "id": 32, "color": { "r": 150, "g": 140, "b": 70 } }, - " Rocky Outcrop": { "id": 29, "color": { "r": 255, "g": 140, "b": 0 } }, - " Other Non Forest Natural Formation": { "id": 13, "color": { "r": 189, "g": 183, "b": 107 } } - } - }, - "Farming": { - "id": 14, "color": { "r": 255, "g": 255, "b": 178 }, - "classes": { - "Pasture": { "id": 15, "color": { "r": 255, "g": 217, "b": 102 } }, - "Agriculture": { - "id": 18, "color": { "r": 233, "g": 116, "b": 237 }, - "classes": { - "Annual and Perennial Crop": { "id": 19, "color": { "r": 213, "g": 166, "b": 189 } }, - "Semi-perennial Crop": { "id": 20, "color": { "r": 194, "g": 123, "b": 160 } } - } - }, - "Mosaic of Agriculture and Pasture": { "id": 21, "color": { "r": 255, "g": 239, "b": 195 } } - } - }, - "Non vegetated area": { - "id": 22, "color": { "r": 234, "g": 153, "b": 153 }, - "classes": { - "Beach and Dune": { "id": 23, "color": { "r": 221, "g": 126, "b": 107 } }, - "Urban Infrastructure": { "id": 24, "color": { "r": 175, "g": 42, "b": 42 } }, - "Mining": { "id": 30, "color": { "r": 138, "g": 43, "b": 226 } }, - "Other Non Vegetated Area": { "id": 25, "color": { "r": 255, "g": 153, "b": 255 } } - } - }, - "Water": { - "id": 26, "color": { "r": 0, "g": 0, "b": 255 }, - "classes": { - " River, Lake and Ocean": { "id": 33, "color": { "r": 0, "g": 0, "b": 255 } }, - "Aquaculture": { "id": 31, "color": { "r": 41, "g": 238, "b": 228 } } - } - }, - "Non Observed": { "id": 27, "color": { "r": 213, "g": 213, "b": 229 } } - } -} +{ + "version": "4.1", + "url": "http://azure.solved.eco.br:8080/geoserver/solved/wms", + "years": { "min": 1985, "max": 2019}, + "classes": { + "Florestry": { + "id": 1, "color": { "r": 18, "g": 153, "b": 18 }, + "classes": { + "Natural Forest": { + "id": 2, "color": { "r": 31, "g": 68, "b": 35 }, + "classes": { + "Forest Formation": { "id": 3, "color": { "r": 39, "g": 78, "b": 19 } }, + "Savanna Formation ": { "id": 4, "color": { "r": 50, "g": 205, "b": 50 } }, + "Mangrove": { "id": 5, "color": { "r": 104, "g": 117, "b": 55 } } + } + }, + "Forest Plantation": { "id": 9, "color": { "r": 147, "g": 81, "b": 50 } } + } + }, + "Non Forest Natural Formation": { + "id": 10, "color": { "r": 187, "g": 252, "b": 172 }, + "classes": { + "Wetland": { "id": 11, "color": { "r": 69, "g": 194, "b": 165 } }, + "Grassland": { "id": 12, "color": { "r": 184, "g": 175, "b": 79 } }, + "Salt Flat": { "id": 32, "color": { "r": 150, "g": 140, "b": 70 } }, + " Rocky Outcrop": { "id": 29, "color": { "r": 255, "g": 140, "b": 0 } }, + " Other Non Forest Natural Formation": { "id": 13, "color": { "r": 189, "g": 183, "b": 107 } } + } + }, + "Farming": { + "id": 14, "color": { "r": 255, "g": 255, "b": 178 }, + "classes": { + "Pasture": { "id": 15, "color": { "r": 255, "g": 217, "b": 102 } }, + "Agriculture": { + "id": 18, "color": { "r": 233, "g": 116, "b": 237 }, + "classes": { + "Temporary Crop ": { + "id": 19, "color": { "r": 213, "g": 166, "b": 189 }, + "classes": { + "Soybean": { "id": 39, "color": { "r": 197, "g": 159, "b": 244 }}, + "Suggar Cane": { "id": 20, "color": { "r": 194, "g": 123, "b": 160 }}, + "Other Temporary Crops ": { "id": 41, "color": { "r": 231, "g": 135, "b": 248 }} + } + }, + "Perennial Crop": { "id": 36, "color": { "r": 243, "g": 180, "b": 241 } } + } + }, + "Mosaic of Agriculture and Pasture": { "id": 21, "color": { "r": 255, "g": 239, "b": 195 } } + } + }, + "Non vegetated area": { + "id": 22, "color": { "r": 234, "g": 153, "b": 153 }, + "classes": { + "Beach and Dune": { "id": 23, "color": { "r": 221, "g": 126, "b": 107 } }, + "Urban Infrastructure": { "id": 24, "color": { "r": 175, "g": 42, "b": 42 } }, + "Mining": { "id": 30, "color": { "r": 138, "g": 43, "b": 226 } }, + "Other Non Vegetated Area": { "id": 25, "color": { "r": 255, "g": 153, "b": 255 } } + } + }, + "Water": { + "id": 26, "color": { "r": 0, "g": 0, "b": 255 }, + "classes": { + " River, Lake and Ocean": { "id": 33, "color": { "r": 0, "g": 0, "b": 255 } }, + "Aquaculture": { "id": 31, "color": { "r": 41, "g": 238, "b": 228 } } + } + }, + "Non Observed": { "id": 27, "color": { "r": 213, "g": 213, "b": 229 } } + } +} diff --git a/mapbiomascollection_pt_BR.json b/mapbiomascollection_pt_BR.json index f4e49ea..9c5bce5 100644 --- a/mapbiomascollection_pt_BR.json +++ b/mapbiomascollection_pt_BR.json @@ -1,62 +1,68 @@ -{ - "version": "5.0", - "url": "http://azure.solved.eco.br:8080/geoserver/solved/wms", - "years": { "min": 1985, "max": 2017}, - "classes": { - "Floresta": { - "id": 1, "color": { "r": 18, "g": 153, "b": 18 }, - "classes": { - "Floresta Natural": { - "id": 2, "color": { "r": 31, "g": 68, "b": 35 }, - "classes": { - "Formação Florestal": { "id": 3, "color": { "r": 39, "g": 78, "b": 19 } }, - "Formação Savanica": { "id": 4, "color": { "r": 50, "g": 205, "b": 50 } }, - "Mangue": { "id": 5, "color": { "r": 104, "g": 117, "b": 55 } } - } - }, - "Floresta Plantada": { "id": 9, "color": { "r": 147, "g": 81, "b": 50 } } - } - }, - "Formação Natural não Florestal": { - "id": 10, "color": { "r": 187, "g": 252, "b": 172 }, - "classes": { - "Área Úmida Natural não Florestal": { "id": 11, "color": { "r": 69, "g": 194, "b": 165 } }, - "Formação Campestre": { "id": 12, "color": { "r": 184, "g": 175, "b": 79 } }, - "Apicum": { "id": 32, "color": { "r": 150, "g": 140, "b": 70 } }, - "Afloramento Rochoso": { "id": 29, "color": { "r": 255, "g": 140, "b": 0 } }, - "Outra Formação Natural não Florestal": { "id": 13, "color": { "r": 189, "g": 183, "b": 107 } } - } - }, - "Agropecuária": { - "id": 14, "color": { "r": 255, "g": 255, "b": 178 }, - "classes": { - "Pastagem": { "id": 15, "color": { "r": 255, "g": 217, "b": 102 } }, - "Agricultura": { - "id": 18, "color": { "r": 233, "g": 116, "b": 237 }, - "classes": { - "Cultura Anual e Perene": { "id": 19, "color": { "r": 213, "g": 166, "b": 189 } }, - "Cultura Semi-Perene": { "id": 20, "color": { "r": 194, "g": 123, "b": 160 } } - } - }, - "Mosaico de Agricultura e Pastagem": { "id": 21, "color": { "r": 255, "g": 239, "b": 195 } } - } - }, - "Área não vegetada": { - "id": 22, "color": { "r": 234, "g": 153, "b": 153 }, - "classes": { - "Praia e Duna": { "id": 23, "color": { "r": 221, "g": 126, "b": 107 } }, - "Infraestrutura Urbana": { "id": 24, "color": { "r": 175, "g": 42, "b": 42 } }, - "Mineração": { "id": 30, "color": { "r": 138, "g": 43, "b": 226 } }, - "Outra Área não Vegetada": { "id": 25, "color": { "r": 255, "g": 153, "b": 255 } } - } - }, - "Corpos D'água": { - "id": 26, "color": { "r": 0, "g": 0, "b": 255 }, - "classes": { - "Rio, Lago e Oceano": { "id": 33, "color": { "r": 0, "g": 0, "b": 255 } }, - "Aquicultura": { "id": 31, "color": { "r": 41, "g": 238, "b": 228 } } - } - }, - "Não observado": { "id": 27, "color": { "r": 213, "g": 213, "b": 229 } } - } -} +{ + "version": "5.0", + "url": "http://azure.solved.eco.br:8080/geoserver/solved/wms", + "years": { "min": 1985, "max": 2019}, + "classes": { + "Floresta": { + "id": 1, "color": { "r": 18, "g": 153, "b": 18 }, + "classes": { + "Floresta Natural": { + "id": 2, "color": { "r": 31, "g": 68, "b": 35 }, + "classes": { + "Formação Florestal": { "id": 3, "color": { "r": 39, "g": 78, "b": 19 } }, + "Formação Savanica": { "id": 4, "color": { "r": 50, "g": 205, "b": 50 } }, + "Mangue": { "id": 5, "color": { "r": 104, "g": 117, "b": 55 } } + } + }, + "Floresta Plantada": { "id": 9, "color": { "r": 147, "g": 81, "b": 50 } } + } + }, + "Formação Natural não Florestal": { + "id": 10, "color": { "r": 187, "g": 252, "b": 172 }, + "classes": { + "Área Úmida Natural não Florestal": { "id": 11, "color": { "r": 69, "g": 194, "b": 165 } }, + "Formação Campestre": { "id": 12, "color": { "r": 184, "g": 175, "b": 79 } }, + "Apicum": { "id": 32, "color": { "r": 150, "g": 140, "b": 70 } }, + "Afloramento Rochoso": { "id": 29, "color": { "r": 255, "g": 140, "b": 0 } }, + "Outra Formação Natural não Florestal": { "id": 13, "color": { "r": 189, "g": 183, "b": 107 } } + } + }, + "Agropecuária": { + "id": 14, "color": { "r": 255, "g": 255, "b": 178 }, + "classes": { + "Pastagem": { "id": 15, "color": { "r": 255, "g": 217, "b": 102 } }, + "Agricultura": { + "id": 18, "color": { "r": 233, "g": 116, "b": 237 }, + "classes": { + "Lavoura Temporária ": { + "id": 19, "color": { "r": 213, "g": 166, "b": 189 }, + "classes": { + "Soja": { "id": 39, "color": { "r": 197, "g": 159, "b": 244 }}, + "Cana": { "id": 20, "color": { "r": 194, "g": 123, "b": 160 }}, + "Outras Lavouras Temporárias": { "id": 41, "color": { "r": 231, "g": 135, "b": 248 }} + } + } + }}, + "Lavoura Perene": { "id": 36, "color": { "r": 243, "g": 180, "b": 241 } }, + "Mosaico de Agricultura e Pastagem": { "id": 21, "color": { "r": 255, "g": 239, "b": 195 } } + } + }, + "Área não vegetada": { + "id": 22, "color": { "r": 234, "g": 153, "b": 153 }, + "classes": { + "Praia e Duna": { "id": 23, "color": { "r": 221, "g": 126, "b": 107 } }, + "Infraestrutura Urbana": { "id": 24, "color": { "r": 175, "g": 42, "b": 42 } }, + "Mineração": { "id": 30, "color": { "r": 138, "g": 43, "b": 226 } }, + "Outra Área não Vegetada": { "id": 25, "color": { "r": 255, "g": 153, "b": 255 } } + } + }, + "Corpos D'água": { + "id": 26, "color": { "r": 0, "g": 0, "b": 255 }, + "classes": { + "Rio, Lago e Oceano": { "id": 33, "color": { "r": 0, "g": 0, "b": 255 } }, + "Aquicultura": { "id": 31, "color": { "r": 41, "g": 238, "b": 228 } } + } + }, + "Não observado": { "id": 27, "color": { "r": 213, "g": 213, "b": 229 } } + } +} diff --git a/metadata.txt b/metadata.txt index 370e35b..2e714bd 100644 --- a/metadata.txt +++ b/metadata.txt @@ -1,33 +1,34 @@ -[general] -name: MapBiomas Collection -description: This plugin lets you get collection of mapping from MapBiomas Project(http://mapbiomas.org/). -about:This plugin add layers(WMS) of collection from MapBiomas. - -version:1.1 -qgisMinimumVersion:3.10 - -author:Luiz Motta, Luiz Cortinhas -email:motta.luiz@gmail.com, luiz.cortinhas@solved.eco.br - -category:Web - -tags:MapBiomas - -homepage:https://github.com/lmotta/mapbiomascollection/wiki -tracker:https://github.com/lmotta/mapbiomascollection/issues -repository:https://github.com/lmotta/mapbiomascollection - -icon:mapbiomas.svg - -experimental:False -deprecated:False - -changelog: - 1.1(2020-10-28) Mapbiomas changed from Geoserver to MapServer - - 1.0(2020-03-25) - Changed Docwidget to WidgetProvider(legend) - - 0.3(2019-09-05) - Add set for collection layer - - 0.2(2019-08-30) - Update metadata and added collection number - - 0.1(2019-08-29) - Start of plugin +[general] +name: MapBiomas Collection +description: This plugin lets you get collection of mapping from MapBiomas Project(http://mapbiomas.org/). +about:This plugin add layers(WMS) of collection from MapBiomas. + +version:1.1 +qgisMinimumVersion:3.10 + +author:Luiz Motta, Luiz Cortinhas +email:motta.luiz@gmail.com, luiz.cortinhas@solved.eco.br + +category:Web + +tags:MapBiomas + +homepage:https://github.com/lmotta/mapbiomascollection/wiki +tracker:https://github.com/lmotta/mapbiomascollection/issues +repository:https://github.com/lmotta/mapbiomascollection + +icon:mapbiomas.svg + +experimental:False +deprecated:False + +changelog: - 1.2(2020-10-28) added 2018 and 2019 + - 1.1(2020-10-28) Mapbiomas changed from Geoserver to MapServer + - 1.0(2020-03-25) + Changed Docwidget to WidgetProvider(legend) + - 0.3(2019-09-05) + Add set for collection layer + - 0.2(2019-08-30) + Update metadata and added collection number + - 0.1(2019-08-29) + Start of plugin