├── LICENSE ├── README.rdoc └── openlayers ├── Makefile ├── __init__.py ├── about_dialog.py ├── bindogr.py ├── help ├── Makefile ├── make.bat └── source │ ├── conf.py │ └── index.rst ├── i18n ├── openlayers_de.qm ├── openlayers_de.ts ├── openlayers_en.qm ├── openlayers_en.ts ├── openlayers_es.qm ├── openlayers_es.ts ├── openlayers_fr.qm ├── openlayers_fr.ts ├── openlayers_pt_BR.qm └── openlayers_pt_BR.ts ├── kml.png ├── mActionAddRasterLayer.png ├── mActionDraw.png ├── mActionSaveMapAsImage.png ├── metadata.txt ├── openlayers.png ├── openlayers_layer.py ├── openlayers_overview.py ├── openlayers_ovwidget.py ├── openlayers_plugin.py ├── openlayers_plugin_layer_type.py ├── plugin_upload.py ├── qgiscloud.png ├── resources.qrc ├── resources_rc.py ├── ui_about_dialog.py ├── ui_about_dialog.ui ├── ui_openlayers_ovwidget.py ├── ui_openlayers_ovwidget.ui ├── ui_openlayersplugin.ui ├── weblayers ├── __init__.py ├── apple_maps.py ├── bing_maps.py ├── google_maps.py ├── html │ ├── OlOverviewMarker.js │ ├── OpenLayers.js │ ├── apple.html │ ├── bing_aerial-labels.html │ ├── bing_aerial.html │ ├── bing_road.html │ ├── google.css │ ├── google_hybrid.html │ ├── google_physical.html │ ├── google_satellite.html │ ├── google_streets.html │ ├── osm.html │ ├── osm_hdm.html │ ├── osm_thunderforest.html │ ├── qgis.css │ ├── stamen_terrain.html │ ├── stamen_toner.html │ ├── stamen_toner_lite.html │ ├── stamen_watercolor.html │ ├── wikimedia.html │ └── wikimedia_nolabels.html ├── icons │ ├── apple_icon.png │ ├── bing_icon.png │ ├── google_icon.png │ ├── kml.png │ ├── osm_icon.png │ ├── stamen_icon.png │ └── wikimedia_icon.png ├── osm.py ├── osm_stamen.py ├── osm_thunderforest.py ├── weblayer.py ├── weblayer_registry.py └── wikimedia_maps.py └── x.png /LICENSE: -------------------------------------------------------------------------------- 1 |  GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | =qgis-openlayers-plugin 2 | 3 | qgis-openlayers-plugin is a QGIS[http://www.qgis.org/] plugin embedding OpenLayers functionality. 4 | 5 | It uses WebKit to render web based map services using their official Javascript API. 6 | 7 | ==Installation 8 | 9 | Use the QGIS Plugins menu to install the OpenLayers Plugin (see {QGIS manual}[http://docs.qgis.org/latest/en/docs/user_manual/plugins/plugins.html]). 10 | 11 | ==License 12 | 13 | qgis-openlayers-plugin 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. 14 | 15 | Copyright (c) 2010-2017 Pirmin Kalberer & Mathias Walker, Sourcepole AG 16 | -------------------------------------------------------------------------------- /openlayers/Makefile: -------------------------------------------------------------------------------- 1 | #/*************************************************************************** 2 | # OpenlayersPlugin 3 | # 4 | # OpenStreetMap, Google Maps, Bing Maps layers and more 5 | # ------------------- 6 | # begin : 2014-03-24 7 | # copyright : (C) 2014 by Sourcepole and contributors 8 | # email : pka@sourcepole.ch 9 | # ***************************************************************************/ 10 | # 11 | #/*************************************************************************** 12 | # * * 13 | # * This program is free software; you can redistribute it and/or modify * 14 | # * it under the terms of the GNU General Public License as published by * 15 | # * the Free Software Foundation; either version 2 of the License, or * 16 | # * (at your option) any later version. * 17 | # * * 18 | # ***************************************************************************/ 19 | 20 | # CONFIGURATION 21 | PLUGIN_UPLOAD = $(CURDIR)/plugin_upload.py 22 | 23 | QGISDIR=.qgis2 24 | 25 | # Makefile for a PyQGIS plugin 26 | 27 | # translation 28 | SOURCES = openlayers_plugin.py \ 29 | ui_about_dialog.py \ 30 | openlayers_ovwidget.py \ 31 | ui_openlayers_ovwidget.py 32 | 33 | TRANSLATIONS = i18n/openlayers_de.ts \ 34 | i18n/openlayers_en.ts \ 35 | i18n/openlayers_fr.ts \ 36 | i18n/openlayers_pt_BR.ts \ 37 | i18n/openlayers_es.ts 38 | 39 | # global 40 | 41 | PLUGINNAME = openlayers_plugin 42 | 43 | PY_FILES = __init__.py 44 | 45 | EXTRAS = openlayers.png 46 | 47 | UI_FILES = ui_about_dialog.py ui_openlayers_ovwidget.py 48 | 49 | RESOURCE_FILES = resources_rc.py 50 | 51 | HELP = help/build/html 52 | 53 | default: compile 54 | 55 | compile: $(UI_FILES) $(RESOURCE_FILES) 56 | 57 | %_rc.py : %.qrc 58 | pyrcc4 -o $*_rc.py $< 59 | 60 | %.py : %.ui 61 | pyuic4 -o $@ $< 62 | 63 | %.qm : %.ts 64 | /usr/lib/x86_64-linux-gnu/qt4/bin/lrelease $< 65 | 66 | # The deploy target only works on unix like operating system where 67 | # the Python plugin directory is located at: 68 | # $HOME/$(QGISDIR)/python/plugins 69 | deploy: compile doc transcompile 70 | mkdir -p $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) 71 | cp -vf $(PY_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) 72 | cp -vf $(UI_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) 73 | cp -vf $(RESOURCE_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) 74 | cp -vf $(EXTRAS) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) 75 | cp -vfr i18n $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) 76 | cp -vfr $(HELP) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)/help 77 | 78 | # The dclean target removes compiled python files from plugin directory 79 | # also delets any .svn entry 80 | dclean: 81 | find $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) -iname "*.pyc" -delete 82 | find $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) -iname ".svn" -prune -exec rm -Rf {} \; 83 | 84 | # The derase deletes deployed plugin 85 | derase: 86 | rm -Rf $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) 87 | 88 | # The zip target deploys the plugin and creates a zip file with the deployed 89 | # content. You can then upload the zip file on http://plugins.qgis.org 90 | zip: deploy dclean 91 | rm -f $(PLUGINNAME).zip 92 | cd $(HOME)/$(QGISDIR)/python/plugins; zip -9r $(CURDIR)/$(PLUGINNAME).zip $(PLUGINNAME) 93 | 94 | # Create a zip package of the plugin named $(PLUGINNAME).zip. 95 | # This requires use of git (your plugin development directory must be a 96 | # git repository). 97 | # To use, pass a valid commit or tag as follows: 98 | # make package VERSION=Version_0.3.2 99 | package: compile 100 | rm -f $(PLUGINNAME).zip 101 | git archive --prefix=$(PLUGINNAME)/ -o $(PLUGINNAME).zip $(VERSION) 102 | echo "Created package: $(PLUGINNAME).zip" 103 | 104 | upload: #zip 105 | $(PLUGIN_UPLOAD) $(PLUGINNAME).zip 106 | 107 | # transup 108 | # update .ts translation files 109 | transup: 110 | pylupdate4 Makefile 111 | 112 | # transcompile 113 | # compile translation files into .qm binary format 114 | transcompile: $(TRANSLATIONS:.ts=.qm) 115 | 116 | # transclean 117 | # deletes all .qm files 118 | transclean: 119 | rm -f i18n/*.qm 120 | 121 | clean: 122 | rm $(UI_FILES) $(RESOURCE_FILES) 123 | 124 | # build documentation with sphinx 125 | doc: 126 | cd help; make html 127 | 128 | # To plugins.qgis.org: 129 | # make package VERSION=master 130 | # make upload 131 | -------------------------------------------------------------------------------- /openlayers/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2009-11-30 9 | copyright : (C) 2009 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | This script initializes the plugin, making it known to QGIS. 22 | """ 23 | 24 | 25 | def classFactory(iface): 26 | from .openlayers_plugin import OpenlayersPlugin 27 | return OpenlayersPlugin(iface) 28 | -------------------------------------------------------------------------------- /openlayers/about_dialog.py: -------------------------------------------------------------------------------- 1 | from qgis.PyQt.QtWidgets import QDialog 2 | from .ui_about_dialog import Ui_dlgAbout 3 | 4 | 5 | class AboutDialog(QDialog, Ui_dlgAbout): 6 | def __init__(self): 7 | QDialog.__init__(self) 8 | # Set up the user interface from Designer. 9 | # After setupUI you can access any designer object by doing 10 | # self., and you can use autoconnect slots - see 11 | # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html 12 | # #widgets-and-dialogs-with-auto-connect 13 | self.setupUi(self) 14 | -------------------------------------------------------------------------------- /openlayers/bindogr.py: -------------------------------------------------------------------------------- 1 | from osgeo import ogr, osr 2 | 3 | 4 | def __getSpatialRefProj4(sProj4): 5 | sr = osr.SpatialReference() 6 | sr.ImportFromProj4(sProj4) 7 | return sr 8 | 9 | 10 | def initOgr(): 11 | ogr.RegisterAll() 12 | 13 | 14 | def exportKml(wkt, proj4): 15 | geom = ogr.CreateGeometryFromWkt(wkt) 16 | sr = __getSpatialRefProj4(proj4) 17 | geom.AssignSpatialReference(sr) 18 | return geom.ExportToKML() 19 | -------------------------------------------------------------------------------- /openlayers/help/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 14 | 15 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest 16 | 17 | help: 18 | @echo "Please use \`make ' where is one of" 19 | @echo " html to make standalone HTML files" 20 | @echo " dirhtml to make HTML files named index.html in directories" 21 | @echo " singlehtml to make a single large HTML file" 22 | @echo " pickle to make pickle files" 23 | @echo " json to make JSON files" 24 | @echo " htmlhelp to make HTML files and a HTML help project" 25 | @echo " qthelp to make HTML files and a qthelp project" 26 | @echo " devhelp to make HTML files and a Devhelp project" 27 | @echo " epub to make an epub" 28 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 29 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 30 | @echo " text to make text files" 31 | @echo " man to make manual pages" 32 | @echo " changes to make an overview of all changed/added/deprecated items" 33 | @echo " linkcheck to check all external links for integrity" 34 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 35 | 36 | clean: 37 | -rm -rf $(BUILDDIR)/* 38 | 39 | html: 40 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 41 | @echo 42 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 43 | 44 | dirhtml: 45 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 48 | 49 | singlehtml: 50 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 51 | @echo 52 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 53 | 54 | pickle: 55 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 56 | @echo 57 | @echo "Build finished; now you can process the pickle files." 58 | 59 | json: 60 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 61 | @echo 62 | @echo "Build finished; now you can process the JSON files." 63 | 64 | htmlhelp: 65 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 66 | @echo 67 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 68 | ".hhp project file in $(BUILDDIR)/htmlhelp." 69 | 70 | qthelp: 71 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 72 | @echo 73 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 74 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 75 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/templateclass.qhcp" 76 | @echo "To view the help file:" 77 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/templateclass.qhc" 78 | 79 | devhelp: 80 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 81 | @echo 82 | @echo "Build finished." 83 | @echo "To view the help file:" 84 | @echo "# mkdir -p $$HOME/.local/share/devhelp/templateclass" 85 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/templateclass" 86 | @echo "# devhelp" 87 | 88 | epub: 89 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 90 | @echo 91 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 92 | 93 | latex: 94 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 95 | @echo 96 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 97 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 98 | "(use \`make latexpdf' here to do that automatically)." 99 | 100 | latexpdf: 101 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 102 | @echo "Running LaTeX files through pdflatex..." 103 | make -C $(BUILDDIR)/latex all-pdf 104 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 105 | 106 | text: 107 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 108 | @echo 109 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 110 | 111 | man: 112 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 113 | @echo 114 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 115 | 116 | changes: 117 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 118 | @echo 119 | @echo "The overview file is in $(BUILDDIR)/changes." 120 | 121 | linkcheck: 122 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 123 | @echo 124 | @echo "Link check complete; look for any errors in the above output " \ 125 | "or in $(BUILDDIR)/linkcheck/output.txt." 126 | 127 | doctest: 128 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 129 | @echo "Testing of doctests in the sources finished, look at the " \ 130 | "results in $(BUILDDIR)/doctest/output.txt." 131 | -------------------------------------------------------------------------------- /openlayers/help/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 10 | if NOT "%PAPER%" == "" ( 11 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 12 | ) 13 | 14 | if "%1" == "" goto help 15 | 16 | if "%1" == "help" ( 17 | :help 18 | echo.Please use `make ^` where ^ is one of 19 | echo. html to make standalone HTML files 20 | echo. dirhtml to make HTML files named index.html in directories 21 | echo. singlehtml to make a single large HTML file 22 | echo. pickle to make pickle files 23 | echo. json to make JSON files 24 | echo. htmlhelp to make HTML files and a HTML help project 25 | echo. qthelp to make HTML files and a qthelp project 26 | echo. devhelp to make HTML files and a Devhelp project 27 | echo. epub to make an epub 28 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 29 | echo. text to make text files 30 | echo. man to make manual pages 31 | echo. changes to make an overview over all changed/added/deprecated items 32 | echo. linkcheck to check all external links for integrity 33 | echo. doctest to run all doctests embedded in the documentation if enabled 34 | goto end 35 | ) 36 | 37 | if "%1" == "clean" ( 38 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 39 | del /q /s %BUILDDIR%\* 40 | goto end 41 | ) 42 | 43 | if "%1" == "html" ( 44 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 45 | echo. 46 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 47 | goto end 48 | ) 49 | 50 | if "%1" == "dirhtml" ( 51 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 52 | echo. 53 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 54 | goto end 55 | ) 56 | 57 | if "%1" == "singlehtml" ( 58 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 59 | echo. 60 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 61 | goto end 62 | ) 63 | 64 | if "%1" == "pickle" ( 65 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 66 | echo. 67 | echo.Build finished; now you can process the pickle files. 68 | goto end 69 | ) 70 | 71 | if "%1" == "json" ( 72 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 73 | echo. 74 | echo.Build finished; now you can process the JSON files. 75 | goto end 76 | ) 77 | 78 | if "%1" == "htmlhelp" ( 79 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 80 | echo. 81 | echo.Build finished; now you can run HTML Help Workshop with the ^ 82 | .hhp project file in %BUILDDIR%/htmlhelp. 83 | goto end 84 | ) 85 | 86 | if "%1" == "qthelp" ( 87 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 88 | echo. 89 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 90 | .qhcp project file in %BUILDDIR%/qthelp, like this: 91 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\templateclass.qhcp 92 | echo.To view the help file: 93 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\templateclass.ghc 94 | goto end 95 | ) 96 | 97 | if "%1" == "devhelp" ( 98 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 99 | echo. 100 | echo.Build finished. 101 | goto end 102 | ) 103 | 104 | if "%1" == "epub" ( 105 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 106 | echo. 107 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 108 | goto end 109 | ) 110 | 111 | if "%1" == "latex" ( 112 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 113 | echo. 114 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 115 | goto end 116 | ) 117 | 118 | if "%1" == "text" ( 119 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 120 | echo. 121 | echo.Build finished. The text files are in %BUILDDIR%/text. 122 | goto end 123 | ) 124 | 125 | if "%1" == "man" ( 126 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 127 | echo. 128 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 129 | goto end 130 | ) 131 | 132 | if "%1" == "changes" ( 133 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 134 | echo. 135 | echo.The overview file is in %BUILDDIR%/changes. 136 | goto end 137 | ) 138 | 139 | if "%1" == "linkcheck" ( 140 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 141 | echo. 142 | echo.Link check complete; look for any errors in the above output ^ 143 | or in %BUILDDIR%/linkcheck/output.txt. 144 | goto end 145 | ) 146 | 147 | if "%1" == "doctest" ( 148 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 149 | echo. 150 | echo.Testing of doctests in the sources finished, look at the ^ 151 | results in %BUILDDIR%/doctest/output.txt. 152 | goto end 153 | ) 154 | 155 | :end 156 | -------------------------------------------------------------------------------- /openlayers/help/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # openlayersplugin documentation build configuration file, created by 4 | # sphinx-quickstart on Sun Feb 12 17:11:03 2012. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | #sys.path.insert(0, os.path.abspath('.')) 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # If your documentation needs a minimal Sphinx version, state it here. 24 | #needs_sphinx = '1.0' 25 | 26 | # Add any Sphinx extension module names here, as strings. They can be extensions 27 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 28 | extensions = ['sphinx.ext.todo', 'sphinx.ext.pngmath', 'sphinx.ext.viewcode'] 29 | 30 | # Add any paths that contain templates here, relative to this directory. 31 | templates_path = ['_templates'] 32 | 33 | # The suffix of source filenames. 34 | source_suffix = '.rst' 35 | 36 | # The encoding of source files. 37 | #source_encoding = 'utf-8-sig' 38 | 39 | # The master toctree document. 40 | master_doc = 'index' 41 | 42 | # General information about the project. 43 | project = u'openlayersplugin' 44 | copyright = u'2013, Sourcepole and contributors' 45 | 46 | # The version info for the project you're documenting, acts as replacement for 47 | # |version| and |release|, also used in various other places throughout the 48 | # built documents. 49 | # 50 | # The short X.Y version. 51 | version = '1.3' 52 | # The full version, including alpha/beta/rc tags. 53 | release = '1.3' 54 | 55 | # The language for content autogenerated by Sphinx. Refer to documentation 56 | # for a list of supported languages. 57 | #language = None 58 | 59 | # There are two options for replacing |today|: either, you set today to some 60 | # non-false value, then it is used: 61 | #today = '' 62 | # Else, today_fmt is used as the format for a strftime call. 63 | #today_fmt = '%B %d, %Y' 64 | 65 | # List of patterns, relative to source directory, that match files and 66 | # directories to ignore when looking for source files. 67 | exclude_patterns = [] 68 | 69 | # The reST default role (used for this markup: `text`) to use for all documents. 70 | #default_role = None 71 | 72 | # If true, '()' will be appended to :func: etc. cross-reference text. 73 | #add_function_parentheses = True 74 | 75 | # If true, the current module name will be prepended to all description 76 | # unit titles (such as .. function::). 77 | #add_module_names = True 78 | 79 | # If true, sectionauthor and moduleauthor directives will be shown in the 80 | # output. They are ignored by default. 81 | #show_authors = False 82 | 83 | # The name of the Pygments (syntax highlighting) style to use. 84 | pygments_style = 'sphinx' 85 | 86 | # A list of ignored prefixes for module index sorting. 87 | #modindex_common_prefix = [] 88 | 89 | 90 | # -- Options for HTML output --------------------------------------------------- 91 | 92 | # The theme to use for HTML and HTML Help pages. See the documentation for 93 | # a list of builtin themes. 94 | html_theme = 'default' 95 | 96 | # Theme options are theme-specific and customize the look and feel of a theme 97 | # further. For a list of options available for each theme, see the 98 | # documentation. 99 | #html_theme_options = {} 100 | 101 | # Add any paths that contain custom themes here, relative to this directory. 102 | #html_theme_path = [] 103 | 104 | # The name for this set of Sphinx documents. If None, it defaults to 105 | # " v documentation". 106 | #html_title = None 107 | 108 | # A shorter title for the navigation bar. Default is the same as html_title. 109 | #html_short_title = None 110 | 111 | # The name of an image file (relative to this directory) to place at the top 112 | # of the sidebar. 113 | #html_logo = None 114 | 115 | # The name of an image file (within the static path) to use as favicon of the 116 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 117 | # pixels large. 118 | #html_favicon = None 119 | 120 | # Add any paths that contain custom static files (such as style sheets) here, 121 | # relative to this directory. They are copied after the builtin static files, 122 | # so a file named "default.css" will overwrite the builtin "default.css". 123 | html_static_path = ['_static'] 124 | 125 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 126 | # using the given strftime format. 127 | #html_last_updated_fmt = '%b %d, %Y' 128 | 129 | # If true, SmartyPants will be used to convert quotes and dashes to 130 | # typographically correct entities. 131 | #html_use_smartypants = True 132 | 133 | # Custom sidebar templates, maps document names to template names. 134 | #html_sidebars = {} 135 | 136 | # Additional templates that should be rendered to pages, maps page names to 137 | # template names. 138 | #html_additional_pages = {} 139 | 140 | # If false, no module index is generated. 141 | #html_domain_indices = True 142 | 143 | # If false, no index is generated. 144 | #html_use_index = True 145 | 146 | # If true, the index is split into individual pages for each letter. 147 | #html_split_index = False 148 | 149 | # If true, links to the reST sources are added to the pages. 150 | #html_show_sourcelink = True 151 | 152 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 153 | #html_show_sphinx = True 154 | 155 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 156 | #html_show_copyright = True 157 | 158 | # If true, an OpenSearch description file will be output, and all pages will 159 | # contain a tag referring to it. The value of this option must be the 160 | # base URL from which the finished HTML is served. 161 | #html_use_opensearch = '' 162 | 163 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 164 | #html_file_suffix = None 165 | 166 | # Output file base name for HTML help builder. 167 | htmlhelp_basename = 'templateclassdoc' 168 | 169 | 170 | # -- Options for LaTeX output -------------------------------------------------- 171 | 172 | # The paper size ('letter' or 'a4'). 173 | #latex_paper_size = 'letter' 174 | 175 | # The font size ('10pt', '11pt' or '12pt'). 176 | #latex_font_size = '10pt' 177 | 178 | # Grouping the document tree into LaTeX files. List of tuples 179 | # (source start file, target name, title, author, documentclass [howto/manual]). 180 | latex_documents = [ 181 | ('index', 'openlayersplugin.tex', u'openlayersplugin Documentation', 182 | u'Sourcepole and contributors', 'manual'), 183 | ] 184 | 185 | # The name of an image file (relative to this directory) to place at the top of 186 | # the title page. 187 | #latex_logo = None 188 | 189 | # For "manual" documents, if this is true, then toplevel headings are parts, 190 | # not chapters. 191 | #latex_use_parts = False 192 | 193 | # If true, show page references after internal links. 194 | #latex_show_pagerefs = False 195 | 196 | # If true, show URL addresses after external links. 197 | #latex_show_urls = False 198 | 199 | # Additional stuff for the LaTeX preamble. 200 | #latex_preamble = '' 201 | 202 | # Documents to append as an appendix to all manuals. 203 | #latex_appendices = [] 204 | 205 | # If false, no module index is generated. 206 | #latex_domain_indices = True 207 | 208 | 209 | # -- Options for manual page output -------------------------------------------- 210 | 211 | # One entry per manual page. List of tuples 212 | # (source start file, name, description, authors, manual section). 213 | man_pages = [ 214 | ('index', 'templateclass', u'openlayersplugin Documentation', 215 | [u'Sourcepole and contributors'], 1) 216 | ] 217 | -------------------------------------------------------------------------------- /openlayers/help/source/index.rst: -------------------------------------------------------------------------------- 1 | .. openlayersplugin documentation master file, created by 2 | sphinx-quickstart on Sun Feb 12 17:11:03 2012. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to openlayersplugin's documentation! 7 | ============================================ 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | Indices and tables 15 | ================== 16 | 17 | * :ref:`genindex` 18 | * :ref:`modindex` 19 | * :ref:`search` 20 | 21 | -------------------------------------------------------------------------------- /openlayers/i18n/openlayers_de.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/i18n/openlayers_de.qm -------------------------------------------------------------------------------- /openlayers/i18n/openlayers_en.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/i18n/openlayers_en.qm -------------------------------------------------------------------------------- /openlayers/i18n/openlayers_es.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/i18n/openlayers_es.qm -------------------------------------------------------------------------------- /openlayers/i18n/openlayers_fr.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/i18n/openlayers_fr.qm -------------------------------------------------------------------------------- /openlayers/i18n/openlayers_pt_BR.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/i18n/openlayers_pt_BR.qm -------------------------------------------------------------------------------- /openlayers/kml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/kml.png -------------------------------------------------------------------------------- /openlayers/mActionAddRasterLayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/mActionAddRasterLayer.png -------------------------------------------------------------------------------- /openlayers/mActionDraw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/mActionDraw.png -------------------------------------------------------------------------------- /openlayers/mActionSaveMapAsImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/mActionSaveMapAsImage.png -------------------------------------------------------------------------------- /openlayers/metadata.txt: -------------------------------------------------------------------------------- 1 | [general] 2 | name=OpenLayers Plugin 3 | qgisMinimumVersion=3.0.1 4 | description=Google Maps, Bing Maps, OpenStreetMap layers and more 5 | about=Google Maps, Bing Maps, OpenStreetMap layers and more 6 | version=2.0.0 7 | author=Sourcepole and contributors 8 | email=pka@sourcepole.ch 9 | 10 | changelog=2.0.0 11 | - Port to QGIS 3 (Python 3 / QT 5) 12 | - Requires QT5 WebKit (Package python3-pyqt5.qtwebkit on Debian/Ubuntu) 13 | - Use XYZ Layers instead of GDAL TMS for non-Javascript service providers 14 | - Catch lat/lon transformation exceptions 15 | 1.4.7 16 | - Fix disappearance of previously loaded layers 17 | 1.4.6 18 | - Improved use of proxy settings for GDAL Layers (OSM, etc.) 19 | 1.4.5 20 | - Partial revert of new proxy method because of Windows crashes 21 | 1.4.4 22 | - Improved use of system proxy settings 23 | 1.4.3 24 | - Fix "No module named map_quest" 25 | 1.4.2 26 | - Thunderstorm OSM layers with API Key (OpenCycleMap, etc.) 27 | - Wikimedia Commons OpenStreetMap layers. Thanks to Henry Walshaw! 28 | - Discontinued MapQuest layers removed 29 | 1.4.1 30 | - Display warning for Google & Bing layers regarding printing and rotating 31 | - Fix UnicodeEncodeError at initialization 32 | - Spanish translation. Thanks to @ermati 33 | 1.4.0 34 | - Support printing and rotating of OpenStreetMap and OSM/Stamen layers 35 | - Update Google Maps layers and add configurable API key 36 | - Update to OpenLayers 2.14 37 | - Add Stamen Toner Lite layer. Thanks to Gerald Rich! 38 | 1.3.6 39 | - Fix zooming of Google Maps layers 40 | - Release sponsored by BLS Netz AG 41 | 1.3.5 42 | - Update to OpenLayers 2.13 to fix offset of Google Maps layers. Thanks to Guilhem Vellut! 43 | - Remove zoom limitations to allow zooming out to global scales. Thanks to Guilhem Vellut! 44 | 1.3.4 45 | - Add OpenStreetMap Humanitarian Data Model layer. Thanks to Vivien Deparday! 46 | - Add MapQuest layers 47 | - Remove obsolete Yahoo Maps layers 48 | - Translation to brazilian portuguese (pt_BR). Thanks to Marcelo Soares Souza! 49 | - Fix project loading. Thanks to Guilhem Vellut! 50 | - Fix enabling of on-the-fly CRS transformation 51 | - Fix menu icons 52 | 1.3.3 53 | - First release for QGIS 2.4 54 | - Save OL layer type in custom property 55 | - Fix initial map rendering 56 | - Fix HTML file path on Windows 57 | 1.3.2 58 | - Pre-release for QGIS 2.4 (Map rendering on Windows broken) 59 | - Omit maps with invalid extents, except initial map 60 | 1.3.1 61 | - Pre-release for QGIS 2.4 (Initial map rendering partially broken) 62 | - Image scaling fixed 63 | - Support for accented characters in home directory 64 | 1.3.0 65 | - Pre-release for QGIS 2.4 (Initial map rendering partially broken, printing not working yet) 66 | - Moved into Web menu 67 | - Support for multi-treaded rendering (QGIS 2.3/2.4) 68 | - Refactoring of OL layers and registry 69 | - Ready for supporting other CRS and initial extends 70 | - PEP8 conformance 71 | 1.1.2 72 | - Fix saving/loading on OSGeo4W 64bit and OS X. Thanks to Minoru Akagi! 73 | - Terms of Service/About dialog 74 | 1.1.1 75 | - Basic port to 2.0 API by Richard Duivenvoorde and Minpa Lee 76 | 1.1.0 77 | -Added Stamen OSM layers. Thanks to Nathaniel V. KELSO! 78 | -Fix for Python API breaks in master branch. Thanks to Salvatore Larosa! 79 | 80 | ; tags are in comma separated value format, spaces are allowed 81 | tags=openlayers,OSM,google,bing,stamen 82 | 83 | homepage=https://github.com/sourcepole/qgis-openlayers-plugin 84 | tracker=https://github.com/sourcepole/qgis-openlayers-plugin/issues 85 | repository=https://github.com/sourcepole/qgis-openlayers-plugin 86 | icon=openlayers.png 87 | 88 | experimental=True 89 | deprecated=False 90 | -------------------------------------------------------------------------------- /openlayers/openlayers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/openlayers.png -------------------------------------------------------------------------------- /openlayers/openlayers_layer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2010-02-03 9 | copyright : (C) 2010 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | """ 22 | 23 | from qgis.PyQt.QtCore import (QUrl, Qt, QMetaObject, QTimer, QEventLoop, 24 | QSize, QObject, pyqtSignal, qDebug, pyqtSlot) 25 | from qgis.PyQt.QtGui import QImage, QPainter 26 | from qgis.PyQt.QtWebKitWidgets import QWebPage 27 | from qgis.core import (QgsMapLayerRenderer, Qgis, QgsMessageLog, 28 | QgsPluginLayer, QgsRectangle) 29 | 30 | 31 | debuglevel = 4 # 0 (none) - 4 (all) 32 | 33 | 34 | def debug(msg, verbosity=1): 35 | if debuglevel >= verbosity: 36 | try: 37 | qDebug(msg) 38 | except Exception: 39 | pass 40 | 41 | 42 | class OLWebPage(QWebPage): 43 | def __init__(self, parent=None): 44 | QWebPage.__init__(self, parent) 45 | 46 | self.loaded = False 47 | 48 | self.extent = None 49 | self.olResolutions = None 50 | 51 | self.lastExtent = None 52 | self.lastViewPortSize = None 53 | self.lastLogicalDpi = None 54 | self.lastOutputDpi = None 55 | self.lastMapUnitsPerPixel = None 56 | 57 | def resolutions(self): 58 | if self.olResolutions is None: 59 | # get OpenLayers resolutions 60 | jsResolutions = self.mainFrame().evaluateJavaScript( 61 | "map.layers[0].resolutions") 62 | debug("Detected OpenLayers resolutions: %s" % jsResolutions) 63 | self.olResolutions = jsResolutions 64 | return self.olResolutions or [] 65 | 66 | def javaScriptConsoleMessage(self, message, lineNumber, sourceID): 67 | qDebug("%s[%d]: %s" % (sourceID, lineNumber, message)) 68 | 69 | 70 | class OpenlayersController(QObject): 71 | """ 72 | Helper class that deals with QWebPage. 73 | The object lives in GUI thread, its request() slot is asynchronously called 74 | from worker thread. 75 | See https://github.com/wonder-sk/qgis-mtr-example-plugin for basic example 76 | 1. Load Web Page with OpenLayers map 77 | 2. Update OL map extend according to QGIS canvas extent 78 | """ 79 | 80 | # signal that reports to the worker thread that the image is ready 81 | finished = pyqtSignal() 82 | 83 | def __init__(self, parent, context, webPage, layerType): 84 | QObject.__init__(self, parent) 85 | 86 | debug("OpenlayersController.__init__", 3) 87 | self.context = context 88 | self.layerType = layerType 89 | 90 | self.img = QImage() 91 | 92 | self.page = webPage 93 | self.page.loadFinished.connect(self.pageLoaded) 94 | # initial size for map 95 | self.page.setViewportSize(QSize(1, 1)) 96 | 97 | self.timerMapReady = QTimer() 98 | self.timerMapReady.setSingleShot(True) 99 | self.timerMapReady.setInterval(20) 100 | self.timerMapReady.timeout.connect(self.checkMapReady) 101 | 102 | self.timer = QTimer() 103 | self.timer.setInterval(100) 104 | self.timer.timeout.connect(self.checkMapUpdate) 105 | 106 | self.timerMax = QTimer() 107 | self.timerMax.setSingleShot(True) 108 | # TODO: different timeouts for map types 109 | self.timerMax.setInterval(5000) 110 | self.timerMax.timeout.connect(self.mapTimeout) 111 | 112 | @pyqtSlot() 113 | def request(self): 114 | debug("[GUI THREAD] Processing request", 3) 115 | self.cancelled = False 116 | 117 | if not self.page.loaded: 118 | self.init_page() 119 | else: 120 | self.setup_map() 121 | 122 | def init_page(self): 123 | url = self.layerType.html_url() 124 | debug("page file: %s" % url) 125 | self.page.mainFrame().load(QUrl(url)) 126 | # wait for page to finish loading 127 | debug("OpenlayersWorker waiting for page to load", 3) 128 | 129 | def pageLoaded(self): 130 | debug("[GUI THREAD] pageLoaded", 3) 131 | try: 132 | if self.cancelled: 133 | self.emitErrorImage() 134 | return 135 | except: 136 | # if you spam the addmap button in the overview then an error 137 | # appears where self.cancelled is not known/defined 138 | debug("Exception raised while adding too many OpenlayersLayer at the same time", 4) 139 | 140 | # wait until OpenLayers map is ready 141 | self.checkMapReady() 142 | 143 | def checkMapReady(self): 144 | debug("[GUI THREAD] checkMapReady", 3) 145 | if self.page.mainFrame().evaluateJavaScript("map != undefined"): 146 | # map ready 147 | self.page.loaded = True 148 | self.setup_map() 149 | else: 150 | # wait for map 151 | self.timerMapReady.start() 152 | 153 | def setup_map(self): 154 | rendererContext = self.context 155 | 156 | # FIXME: self.mapSettings.outputDpi() 157 | self.outputDpi = rendererContext.painter().device().logicalDpiX() 158 | debug(" extent: %s" % rendererContext.extent().toString(), 3) 159 | debug(" center: %lf, %lf" % (rendererContext.extent().center().x(), 160 | rendererContext.extent().center().y()), 3) 161 | debug(" size: %d, %d" % ( 162 | rendererContext.painter().viewport().size().width(), 163 | rendererContext.painter().viewport().size().height()), 3) 164 | debug(" logicalDpiX: %d" % rendererContext.painter(). 165 | device().logicalDpiX(), 3) 166 | debug(" outputDpi: %lf" % self.outputDpi) 167 | debug(" mapUnitsPerPixel: %f" % rendererContext.mapToPixel(). 168 | mapUnitsPerPixel(), 3) 169 | # debug(" rasterScaleFactor: %s" % str(rendererContext. 170 | # rasterScaleFactor()), 3) 171 | # debug(" outputSize: %d, %d" % (self.iface.mapCanvas().mapRenderer(). 172 | # outputSize().width(), 173 | # self.iface.mapCanvas().mapRenderer(). 174 | # outputSize().height()), 3) 175 | # debug(" scale: %lf" % self.iface.mapCanvas().mapRenderer().scale(), 176 | # 3) 177 | # 178 | # if (self.page.lastExtent == rendererContext.extent() 179 | # and self.page.lastViewPortSize == rendererContext.painter(). 180 | # viewport().size() 181 | # and self.page.lastLogicalDpi == rendererContext.painter(). 182 | # device().logicalDpiX() 183 | # and self.page.lastOutputDpi == self.outputDpi 184 | # and self.page.lastMapUnitsPerPixel == rendererContext. 185 | # mapToPixel().mapUnitsPerPixel()): 186 | # self.renderMap() 187 | # self.finished.emit() 188 | # return 189 | 190 | self.targetSize = rendererContext.painter().viewport().size() 191 | if rendererContext.painter().device().logicalDpiX() != int(self.outputDpi): 192 | # use screen dpi for printing 193 | sizeFact = self.outputDpi / 25.4 / rendererContext.mapToPixel().mapUnitsPerPixel() 194 | self.targetSize.setWidth( 195 | rendererContext.extent().width() * sizeFact) 196 | self.targetSize.setHeight( 197 | rendererContext.extent().height() * sizeFact) 198 | debug(" targetSize: %d, %d" % ( 199 | self.targetSize.width(), self.targetSize.height()), 3) 200 | 201 | # find matching OL resolution 202 | qgisRes = rendererContext.extent().width() / self.targetSize.width() 203 | olRes = None 204 | for res in self.page.resolutions(): 205 | if qgisRes >= res: 206 | olRes = res 207 | break 208 | if olRes is None: 209 | debug("No matching OL resolution found (QGIS resolution: %f)" % 210 | qgisRes) 211 | self.emitErrorImage() 212 | return 213 | 214 | # adjust OpenLayers viewport to match QGIS extent 215 | olWidth = rendererContext.extent().width() / olRes 216 | olHeight = rendererContext.extent().height() / olRes 217 | debug(" adjust viewport: %f -> %f: %f x %f" % (qgisRes, 218 | olRes, olWidth, 219 | olHeight), 3) 220 | olSize = QSize(int(olWidth), int(olHeight)) 221 | self.page.setViewportSize(olSize) 222 | self.page.mainFrame().evaluateJavaScript("map.updateSize();") 223 | self.img = QImage(olSize, QImage.Format_ARGB32_Premultiplied) 224 | 225 | self.page.extent = rendererContext.extent() 226 | debug("map.zoomToExtent (%f, %f, %f, %f)" % ( 227 | self.page.extent.xMinimum(), self.page.extent.yMinimum(), 228 | self.page.extent.xMaximum(), self.page.extent.yMaximum()), 3) 229 | self.page.mainFrame().evaluateJavaScript( 230 | "map.zoomToExtent(new OpenLayers.Bounds(%f, %f, %f, %f), true);" % 231 | (self.page.extent.xMinimum(), self.page.extent.yMinimum(), 232 | self.page.extent.xMaximum(), self.page.extent.yMaximum())) 233 | olextent = self.page.mainFrame().evaluateJavaScript("map.getExtent();") 234 | debug("Resulting OL extent: %s" % olextent, 3) 235 | if olextent is None or not hasattr(olextent, '__getitem__'): 236 | debug("map.zoomToExtent failed") 237 | # map.setCenter and other operations throw "undefined[0]: 238 | # TypeError: 'null' is not an object" on first page load 239 | # We ignore that and render the initial map with wrong extents 240 | # self.emitErrorImage() 241 | # return 242 | else: 243 | reloffset = abs((self.page.extent.yMaximum()-olextent[ 244 | "top"])/self.page.extent.xMinimum()) 245 | debug("relative offset yMaximum %f" % reloffset, 3) 246 | if reloffset > 0.1: 247 | debug("OL extent shift failure: %s" % reloffset) 248 | self.emitErrorImage() 249 | return 250 | self.mapFinished = False 251 | self.timer.start() 252 | self.timerMax.start() 253 | 254 | def checkMapUpdate(self): 255 | if self.layerType.emitsLoadEnd: 256 | # wait for OpenLayers to finish loading 257 | try: 258 | loadEndOL = self.page.mainFrame().evaluateJavaScript("loadEnd") 259 | debug("waiting for loadEnd: renderingStopped=%r loadEndOL=%r" % ( 260 | self.context.renderingStopped(), loadEndOL), 4) 261 | except: 262 | # Multi threading problem when deleting multiple Openlayers layers 263 | debug("Exception raised while deleting multiple Openlayers layers", 4) 264 | if loadEndOL is not None: 265 | self.mapFinished = loadEndOL 266 | else: 267 | debug("OpenlayersLayer Warning: Could not get loadEnd") 268 | 269 | if self.mapFinished: 270 | self.timerMax.stop() 271 | self.timer.stop() 272 | 273 | self.renderMap() 274 | 275 | self.finished.emit() 276 | 277 | def renderMap(self): 278 | rendererContext = self.context 279 | if rendererContext.painter().device().logicalDpiX() != int(self.outputDpi): 280 | printScale = 25.4 / self.outputDpi # OL DPI to printer pixels 281 | rendererContext.painter().scale(printScale, printScale) 282 | 283 | # render OpenLayers to image 284 | painter = QPainter(self.img) 285 | self.page.mainFrame().render(painter) 286 | painter.end() 287 | 288 | if self.img.size() != self.targetSize: 289 | targetWidth = self.targetSize.width() 290 | targetHeight = self.targetSize.height() 291 | # scale using QImage for better quality 292 | debug(" scale image: %i x %i -> %i x %i" % ( 293 | self.img.width(), self.img.height(), 294 | targetWidth, targetHeight), 3) 295 | self.img = self.img.scaled(targetWidth, targetHeight, 296 | Qt.KeepAspectRatio, 297 | Qt.SmoothTransformation) 298 | 299 | # save current state 300 | self.page.lastExtent = rendererContext.extent() 301 | self.page.lastViewPortSize = rendererContext.painter().viewport().size() 302 | self.page.lastLogicalDpi = rendererContext.painter().device().logicalDpiX() 303 | self.page.lastOutputDpi = self.outputDpi 304 | self.page.lastMapUnitsPerPixel = rendererContext.mapToPixel().mapUnitsPerPixel() 305 | 306 | def mapTimeout(self): 307 | debug("mapTimeout reached") 308 | self.timer.stop() 309 | # if not self.layerType.emitsLoadEnd: 310 | self.renderMap() 311 | self.finished.emit() 312 | 313 | def emitErrorImage(self): 314 | self.img = QImage() 315 | self.targetSize = self.img.size 316 | self.finished.emit() 317 | 318 | 319 | class OpenlayersRenderer(QgsMapLayerRenderer): 320 | def __init__(self, layer, context, webPage, layerType): 321 | """ Initialize the object. This function is still run in the GUI thread. 322 | Should refrain from doing any heavy work. 323 | """ 324 | QgsMapLayerRenderer.__init__(self, layer.id()) 325 | self.context = context 326 | self.controller = OpenlayersController(None, 327 | context, webPage, layerType) 328 | self.loop = None 329 | 330 | def render(self): 331 | """ do the rendering. This function is called in the worker thread """ 332 | 333 | debug("[WORKER THREAD] Calling request() asynchronously", 3) 334 | QMetaObject.invokeMethod(self.controller, "request") 335 | 336 | # setup a timer that checks whether the rendering has not been stopped 337 | # in the meanwhile 338 | timer = QTimer() 339 | timer.setInterval(50) 340 | timer.timeout.connect(self.onTimeout) 341 | timer.start() 342 | 343 | debug("[WORKER THREAD] Waiting for the async request to complete", 3) 344 | self.loop = QEventLoop() 345 | self.controller.finished.connect(self.loop.exit) 346 | self.loop.exec_() 347 | 348 | debug("[WORKER THREAD] Async request finished", 3) 349 | 350 | painter = self.context.painter() 351 | painter.drawImage(0, 0, self.controller.img) 352 | return True 353 | 354 | def onTimeout(self): 355 | """ periodically check whether the rendering should not be stopped """ 356 | if self.context.renderingStopped(): 357 | debug("[WORKER THREAD] Cancelling rendering", 3) 358 | self.loop.exit() 359 | 360 | 361 | class OpenlayersLayer(QgsPluginLayer): 362 | 363 | LAYER_TYPE = "openlayers" 364 | LAYER_PROPERTY = "ol_layer_type" 365 | MAX_ZOOM_LEVEL = 15 366 | SCALE_ON_MAX_ZOOM = 13540 # QGIS scale for 72 dpi 367 | 368 | def __init__(self, iface, olLayerTypeRegistry): 369 | QgsPluginLayer.__init__(self, 370 | OpenlayersLayer.LAYER_TYPE, 371 | "OpenLayers plugin layer") 372 | self.setValid(True) 373 | 374 | self.olLayerTypeRegistry = olLayerTypeRegistry 375 | self.layerType = None 376 | 377 | self.iface = iface 378 | self.olWebPage = OLWebPage(self) 379 | 380 | def readXml(self, node): 381 | # early read of custom properties 382 | self.readCustomProperties(node) 383 | 384 | # get layer type 385 | ol_layer_type = None 386 | ol_layer_type_name = self.customProperty( 387 | OpenlayersLayer.LAYER_PROPERTY, "") 388 | if ol_layer_type_name != "": 389 | ol_layer_type = self.olLayerTypeRegistry.getByName( 390 | ol_layer_type_name) 391 | else: 392 | # handle ol_layer_type idx stored in layer node 393 | # (OL plugin <= 1.1.2) 394 | ol_layer_type_idx = int(node.toElement().attribute( 395 | "ol_layer_type", "-1")) 396 | if ol_layer_type_idx != -1: 397 | ol_layer_type = self.olLayerTypeRegistry.getById( 398 | ol_layer_type_idx) 399 | 400 | if ol_layer_type is not None: 401 | self.setLayerType(ol_layer_type) 402 | else: 403 | # Set default layer type 404 | self.setLayerType( 405 | self.olLayerTypeRegistry.getByName("OpenStreetMap")) 406 | msg = "Obsolete or unknown layer type '%s', using OpenStreetMap\ 407 | instead" % ol_layer_type_name 408 | self.iface.messageBar().pushMessage("OpenLayers Plugin", msg, 409 | level=Qgis.MessageLevel(1)) 410 | QgsMessageLog.logMessage(msg, "OpenLayers Plugin", 411 | QgsMessageLog.WARNING) 412 | 413 | return True 414 | 415 | def writeXml(self, node, doc): 416 | element = node.toElement() 417 | # write plugin layer type to project 418 | # (essential to be read from project) 419 | element.setAttribute("type", "plugin") 420 | element.setAttribute("name", OpenlayersLayer.LAYER_TYPE) 421 | return True 422 | 423 | def setLayerType(self, layerType): 424 | qDebug(" setLayerType: %s" % layerType.layerTypeName) 425 | self.layerType = layerType 426 | self.setCustomProperty(OpenlayersLayer.LAYER_PROPERTY, 427 | layerType.layerTypeName) 428 | coordRefSys = self.layerType.coordRefSys(None) # FIXME 429 | self.setCrs(coordRefSys) 430 | # TODO: get extent from layer type 431 | self.setExtent(QgsRectangle(-20037508.34, 432 | -20037508.34, 20037508.34, 20037508.34)) 433 | 434 | def createMapRenderer(self, context): 435 | return OpenlayersRenderer(self, context, 436 | self.olWebPage, self.layerType) 437 | -------------------------------------------------------------------------------- /openlayers/openlayers_overview.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | Openlayers Overview - A QGIS plugin to show map in browser(google maps and others) 5 | ------------------- 6 | begin : 2011-03-01 7 | copyright : (C) 2011 by Luiz Motta 8 | author : Luiz P. Motta 9 | email : motta _dot_ luiz _at_ gmail.com 10 | ***************************************************************************/ 11 | 12 | /*************************************************************************** 13 | * * 14 | * This program is free software; you can redistribute it and/or modify * 15 | * it under the terms of the GNU General Public License as published by * 16 | * the Free Software Foundation; either version 2 of the License, or * 17 | * (at your option) any later version. * 18 | * * 19 | ***************************************************************************/ 20 | """ 21 | from qgis.PyQt.QtCore import Qt 22 | from qgis.PyQt.QtWidgets import QApplication, QDockWidget 23 | from .openlayers_ovwidget import OpenLayersOverviewWidget 24 | 25 | 26 | class OLOverview(object): 27 | 28 | def __init__(self, iface, olLayerTypeRegistry): 29 | self._iface = iface 30 | self._olLayerTypeRegistry = olLayerTypeRegistry 31 | self._dockwidget = None 32 | self._oloWidget = None 33 | 34 | # Private 35 | def _setDocWidget(self): 36 | self._dockwidget = QDockWidget(QApplication.translate( 37 | "OpenLayersOverviewWidget", "OpenLayers Overview"), 38 | self._iface.mainWindow()) 39 | self._dockwidget.setObjectName("dwOpenlayersOverview") 40 | self._oloWidget = OpenLayersOverviewWidget(self._iface, 41 | self._dockwidget, 42 | self._olLayerTypeRegistry) 43 | self._dockwidget.setWidget(self._oloWidget) 44 | 45 | def _initGui(self): 46 | self._setDocWidget() 47 | self._iface.addDockWidget(Qt.LeftDockWidgetArea, self._dockwidget) 48 | 49 | def _unload(self): 50 | self._dockwidget.close() 51 | self._iface.removeDockWidget(self._dockwidget) 52 | del self._oloWidget 53 | self._dockwidget = None 54 | 55 | # Public 56 | def setVisible(self, visible): 57 | if visible: 58 | if self._dockwidget is None: 59 | self._initGui() 60 | else: 61 | if self._dockwidget is not None: 62 | self._unload() 63 | -------------------------------------------------------------------------------- /openlayers/openlayers_ovwidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | Openlayers Overview - A QGIS plugin to show map in browser(google maps and others) 5 | ------------------- 6 | begin : 2011-03-01 7 | copyright : (C) 2011 by Luiz Motta 8 | author : Luiz P. Motta 9 | email : motta _dot_ luiz _at_ gmail.com 10 | ***************************************************************************/ 11 | 12 | /*************************************************************************** 13 | * * 14 | * This program is free software; you can redistribute it and/or modify * 15 | * it under the terms of the GNU General Public License as published by * 16 | * the Free Software Foundation; either version 2 of the License, or * 17 | * (at your option) any later version. * 18 | * * 19 | ***************************************************************************/ 20 | This script initializes the plugin, making it known to QGIS. 21 | """ 22 | import os.path 23 | 24 | from qgis.PyQt.QtCore import QObject, QTimer, Qt, QUrl, pyqtSlot 25 | from qgis.PyQt.QtWidgets import (QWidget, QMessageBox, QApplication, 26 | QFileDialog, QDockWidget) 27 | from qgis.PyQt.QtGui import QIcon, QPainter, QImage, QGuiApplication 28 | from qgis.core import (QgsGeometry, QgsPointXY, QgsRectangle, 29 | QgsCoordinateReferenceSystem, QgsCoordinateTransform, 30 | QgsProject, QgsLogger) 31 | from qgis.gui import QgsVertexMarker, QgsMapCanvas 32 | from . import bindogr 33 | 34 | from .ui_openlayers_ovwidget import Ui_Form 35 | 36 | 37 | class MarkerCursor(QObject): 38 | 39 | def __init__(self, mapCanvas, srsOL): 40 | QObject.__init__(self) 41 | self.__srsOL = srsOL 42 | self.__canvas = mapCanvas 43 | self.__marker = None 44 | self.__showMarker = True 45 | 46 | def __del__(self): 47 | self.reset() 48 | 49 | def __refresh(self, pointCenter): 50 | if self.__marker is not None: 51 | self.reset() 52 | self.__marker = QgsVertexMarker(self.__canvas) 53 | self.__marker.setCenter(pointCenter) 54 | self.__marker.setIconType(QgsVertexMarker.ICON_X) 55 | self.__marker.setPenWidth(4) 56 | 57 | def setVisible(self, visible): 58 | self.__showMarker = visible 59 | 60 | def reset(self): 61 | self.__canvas.scene().removeItem(self.__marker) 62 | del self.__marker 63 | self.__marker = None 64 | 65 | @pyqtSlot(str) 66 | def changeMarker(self, strListExtent): 67 | if not self.__showMarker: 68 | return 69 | # left, bottom, right, top 70 | left, bottom, right, top = [float(item) for item in 71 | strListExtent.split(',')] 72 | pointCenter = QgsRectangle(QgsPointXY(left, top), 73 | QgsPointXY(right, bottom)).center() 74 | crsCanvas = self.__canvas.mapSettings().destinationCrs() 75 | if self.__srsOL != crsCanvas: 76 | coodTrans = QgsCoordinateTransform(self.__srsOL, crsCanvas, 77 | QgsProject.instance()) 78 | pointCenter = coodTrans.transform( 79 | pointCenter, 80 | QgsCoordinateTransform.ForwardTransform) 81 | self.__refresh(pointCenter) 82 | 83 | 84 | class OpenLayersOverviewWidget(QWidget, Ui_Form): 85 | 86 | def __init__(self, iface, dockwidget, olLayerTypeRegistry): 87 | QWidget.__init__(self) 88 | Ui_Form.__init__(self) 89 | self.setupUi(self) 90 | self.__canvas = iface.mapCanvas() 91 | self.__dockwidget = dockwidget 92 | self.__olLayerTypeRegistry = olLayerTypeRegistry 93 | self.__initLayerOL = False 94 | self.__fileNameImg = '' 95 | self.__srsOL = QgsCoordinateReferenceSystem( 96 | 3857, QgsCoordinateReferenceSystem.EpsgCrsId) 97 | self.__marker = MarkerCursor(self.__canvas, self.__srsOL) 98 | self.__manager = None # Need persist for PROXY 99 | bindogr.initOgr() 100 | self.__init() 101 | 102 | def __init(self): 103 | self.checkBoxHideCross.setEnabled(False) 104 | self.__populateTypeMapGUI() 105 | self.__populateButtonBox() 106 | self.__registerObjJS() 107 | self.lbStatusRead.setVisible(False) 108 | self.__setConnections() 109 | 110 | self.__timerMapReady = QTimer() 111 | self.__timerMapReady.setSingleShot(True) 112 | self.__timerMapReady.setInterval(20) 113 | self.__timerMapReady.timeout.connect(self.__checkMapReady) 114 | 115 | def __del__(self): 116 | self.__marker.reset() 117 | # Disconnect Canvas 118 | # Canvas 119 | QgsMapCanvas.extentsChanged.disconnect(self.__canvas) 120 | # Doc WidgetparentWidget 121 | QDockWidget.visibilityChanged.disconnect(self.__dockwidget) 122 | 123 | def __populateButtonBox(self): 124 | pathPlugin = "%s%s%%s" % (os.path.dirname(__file__), os.path.sep) 125 | self.pbRefresh.setIcon(QIcon(pathPlugin % "mActionDraw.png")) 126 | self.pbRefresh.setEnabled(False) 127 | self.pbAddRaster.setIcon(QIcon(pathPlugin % 128 | "mActionAddRasterLayer.png")) 129 | self.pbAddRaster.setEnabled(False) 130 | self.pbCopyKml.setIcon(QIcon(pathPlugin % "kml.png")) 131 | self.pbCopyKml.setEnabled(False) 132 | self.pbSaveImg.setIcon(QIcon(pathPlugin % "mActionSaveMapAsImage.png")) 133 | self.pbSaveImg.setEnabled(False) 134 | 135 | def __populateTypeMapGUI(self): 136 | pathPlugin = "%s%s%%s" % (os.path.dirname(__file__), os.path.sep) 137 | totalLayers = len(self.__olLayerTypeRegistry.types()) 138 | for id in range(totalLayers): 139 | layer = self.__olLayerTypeRegistry.getById(id) 140 | name = str(layer.displayName) 141 | icon = QIcon(pathPlugin % layer.groupIcon) 142 | self.comboBoxTypeMap.addItem(icon, name, id) 143 | 144 | def __setConnections(self): 145 | # Check Box 146 | self.checkBoxEnableMap.stateChanged.connect( 147 | self.__signal_checkBoxEnableMap_stateChanged) 148 | self.checkBoxHideCross.stateChanged.connect( 149 | self.__signal_checkBoxHideCross_stateChanged) 150 | # comboBoxTypeMap 151 | self.comboBoxTypeMap.currentIndexChanged.connect( 152 | self.__signal_comboBoxTypeMap_currentIndexChanged) 153 | # Canvas 154 | self.__canvas.extentsChanged.connect( 155 | self.__signal_canvas_extentsChanged) 156 | # Doc WidgetparentWidget 157 | self.__dockwidget.visibilityChanged.connect( 158 | self.__signal_DocWidget_visibilityChanged) 159 | # WebView Map 160 | self.webViewMap.page().mainFrame().javaScriptWindowObjectCleared.connect( 161 | self.__registerObjJS) 162 | # Push Button 163 | self.pbRefresh.clicked.connect( 164 | self.__signal_pbRefresh_clicked) 165 | self.pbAddRaster.clicked.connect( 166 | self.__signal_pbAddRaster_clicked) 167 | self.pbCopyKml.clicked.connect( 168 | self.__signal_pbCopyKml_clicked) 169 | self.pbSaveImg.clicked.connect( 170 | self.__signal_pbSaveImg_clicked) 171 | 172 | def __registerObjJS(self): 173 | self.webViewMap.page().mainFrame().addToJavaScriptWindowObject( 174 | "MarkerCursorQGis", self.__marker) 175 | 176 | def __signal_checkBoxEnableMap_stateChanged(self, state): 177 | enable = False 178 | if state == Qt.Unchecked: 179 | self.__marker.reset() 180 | else: 181 | if self.__canvas.layerCount() == 0: 182 | QMessageBox.warning(self, QApplication.translate( 183 | "OpenLayersOverviewWidget", 184 | "OpenLayers Overview"), QApplication.translate( 185 | "OpenLayersOverviewWidget", 186 | "At least one layer in map canvas required")) 187 | self.checkBoxEnableMap.setCheckState(Qt.Unchecked) 188 | else: 189 | enable = True 190 | if not self.__initLayerOL: 191 | self.__initLayerOL = True 192 | self.__setWebViewMap(0) 193 | else: 194 | self.__refreshMapOL() 195 | # GUI 196 | if enable: 197 | self.lbStatusRead.setVisible(False) 198 | self.webViewMap.setVisible(True) 199 | else: 200 | self.lbStatusRead.setText("") 201 | self.lbStatusRead.setVisible(True) 202 | self.webViewMap.setVisible(False) 203 | self.webViewMap.setEnabled(enable) 204 | self.comboBoxTypeMap.setEnabled(enable) 205 | self.pbRefresh.setEnabled(enable) 206 | self.pbAddRaster.setEnabled(enable) 207 | self.pbCopyKml.setEnabled(enable) 208 | self.pbSaveImg.setEnabled(enable) 209 | self.checkBoxHideCross.setEnabled(enable) 210 | 211 | def __signal_checkBoxHideCross_stateChanged(self, state): 212 | if state == Qt.Checked: 213 | self.__marker.reset() 214 | self.__marker.setVisible(False) 215 | else: 216 | self.__marker.setVisible(True) 217 | self.__refreshMapOL() 218 | 219 | def __signal_DocWidget_visibilityChanged(self, visible): 220 | if self.__canvas.layerCount() == 0: 221 | return 222 | self.checkBoxEnableMap.setCheckState(Qt.Unchecked) 223 | self.__signal_checkBoxEnableMap_stateChanged(Qt.Unchecked) 224 | 225 | def __signal_comboBoxTypeMap_currentIndexChanged(self, index): 226 | self.__setWebViewMap(index) 227 | 228 | def __signal_canvas_extentsChanged(self): 229 | if self.__canvas.layerCount() == 0 or not self.webViewMap.isVisible(): 230 | return 231 | if self.checkBoxEnableMap.checkState() == Qt.Checked: 232 | self.__refreshMapOL() 233 | 234 | def __signal_pbRefresh_clicked(self, checked): 235 | index = self.comboBoxTypeMap.currentIndex() 236 | self.__setWebViewMap(index) 237 | 238 | def __signal_pbAddRaster_clicked(self, checked): 239 | index = self.comboBoxTypeMap.currentIndex() 240 | layer = self.__olLayerTypeRegistry.getById(index) 241 | QGuiApplication.setOverrideCursor(Qt.WaitCursor) 242 | layer.addLayer() 243 | QGuiApplication.restoreOverrideCursor() 244 | 245 | def __signal_pbCopyKml_clicked(self, cheked): 246 | # Extent Openlayers 247 | action = "map.getExtent().toGeometry().toString();" 248 | wkt = self.webViewMap.page().mainFrame().evaluateJavaScript(action) 249 | rect = QgsGeometry.fromWkt(wkt).boundingBox() 250 | srsGE = QgsCoordinateReferenceSystem( 251 | 4326, QgsCoordinateReferenceSystem.EpsgCrsId) 252 | coodTrans = QgsCoordinateTransform(self.__srsOL, srsGE, 253 | QgsProject.instance()) 254 | rect = coodTrans.transform( 255 | rect, QgsCoordinateTransform.ForwardTransform) 256 | line = QgsGeometry.fromRect(rect).asPolygon()[0] 257 | wkt = str(QgsGeometry.fromPolylineXY(line).asWkt()) 258 | # Kml 259 | proj4 = str(srsGE.toProj4()) 260 | kmlLine = bindogr.exportKml(wkt, proj4) 261 | kml = ""\ 262 | "" \ 266 | "" \ 267 | "KML from Plugin Openlayers Overview for QGIS" \ 268 | "Extent of openlayers map from Plugin Openlayers \ 269 | Overview for QGIS"\ 270 | "%s" \ 271 | "" % kmlLine 272 | clipBoard = QApplication.clipboard() 273 | clipBoard.setText(kml) 274 | 275 | def __signal_pbSaveImg_clicked(self, cheked): 276 | if type(self.__fileNameImg) == tuple: 277 | self.__fileNameImg = self.__fileNameImg[0] 278 | fileName = QFileDialog.getSaveFileName(self, 279 | QApplication.translate( 280 | "OpenLayersOverviewWidget", 281 | "Save image"), 282 | self.__fileNameImg, 283 | QApplication.translate( 284 | "OpenLayersOverviewWidget", 285 | "Image(*.jpg)")) 286 | if not fileName == '': 287 | self.__fileNameImg = fileName 288 | else: 289 | return 290 | img = QImage(self.webViewMap.page().mainFrame().contentsSize(), 291 | QImage.Format_ARGB32_Premultiplied) 292 | imgPainter = QPainter() 293 | imgPainter.begin(img) 294 | self.webViewMap.page().mainFrame().render(imgPainter) 295 | imgPainter.end() 296 | img.save(fileName[0], "JPEG") 297 | 298 | def __signal_webViewMap_loadFinished(self, ok): 299 | if ok is False: 300 | QMessageBox.warning(self, QApplication.translate( 301 | "OpenLayersOverviewWidget", "OpenLayers Overview"), 302 | QApplication.translate( 303 | "OpenLayersOverviewWidget", 304 | "Error loading page!")) 305 | else: 306 | # wait until OpenLayers map is ready 307 | self.__checkMapReady() 308 | self.lbStatusRead.setVisible(False) 309 | self.webViewMap.setVisible(True) 310 | self.webViewMap.page().mainFrame().loadFinished.disconnect( 311 | self.__signal_webViewMap_loadFinished) 312 | 313 | def __setWebViewMap(self, id): 314 | layer = self.__olLayerTypeRegistry.getById(id) 315 | self.lbStatusRead.setText("Loading " + layer.displayName + " ...") 316 | self.lbStatusRead.setVisible(True) 317 | self.webViewMap.setVisible(False) 318 | self.webViewMap.page().mainFrame().loadFinished.connect( 319 | self.__signal_webViewMap_loadFinished) 320 | url = layer.html_url() 321 | self.webViewMap.page().mainFrame().load(QUrl(url)) 322 | 323 | def __checkMapReady(self): 324 | if self.webViewMap.page().mainFrame().evaluateJavaScript( 325 | "map != undefined"): 326 | # map ready 327 | self.__refreshMapOL() 328 | else: 329 | # wait for map 330 | self.__timerMapReady.start() 331 | 332 | def __refreshMapOL(self): 333 | # catch Exception where lat/long exceed limit of the loaded layer 334 | # the Exception name is unknown 335 | latlon = None 336 | try: 337 | latlon = self.__getCenterLongLat2OL() 338 | except Exception as e: 339 | QgsLogger().warning(e.args[0]) 340 | 341 | if latlon: 342 | action = "map.setCenter(new OpenLayers.LonLat(%f, %f));" % (latlon) 343 | self.webViewMap.page().mainFrame().evaluateJavaScript(action) 344 | action = "map.zoomToScale(%f);" % self.__canvas.scale() 345 | self.webViewMap.page().mainFrame().evaluateJavaScript(action) 346 | self.webViewMap.page().mainFrame().evaluateJavaScript( 347 | "oloMarker.changeMarker();") 348 | 349 | def __getCenterLongLat2OL(self): 350 | pntCenter = self.__canvas.extent().center() 351 | crsCanvas = self.__canvas.mapSettings().destinationCrs() 352 | if crsCanvas != self.__srsOL: 353 | coodTrans = QgsCoordinateTransform(crsCanvas, self.__srsOL, 354 | QgsProject.instance()) 355 | pntCenter = coodTrans.transform( 356 | pntCenter, QgsCoordinateTransform.ForwardTransform) 357 | return tuple([pntCenter.x(), pntCenter.y()]) 358 | -------------------------------------------------------------------------------- /openlayers/openlayers_plugin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2009-11-30 9 | copyright : (C) 2009 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | """ 22 | # Import the PyQt and QGIS libraries 23 | from qgis.PyQt.QtCore import (QSettings, QTranslator) 24 | from qgis.PyQt.QtWidgets import (QApplication, QLineEdit, QInputDialog, 25 | QAction, QMenu) 26 | from qgis.PyQt.QtGui import QIcon 27 | from qgis.core import (QgsCoordinateTransform, Qgis, QgsProject, 28 | QgsPluginLayerRegistry, QgsLayerTree, QgsMapLayer, 29 | QgsRasterLayer, QgsMessageLog) 30 | 31 | from . import resources_rc 32 | from .about_dialog import AboutDialog 33 | from .openlayers_overview import OLOverview 34 | from .openlayers_layer import OpenlayersLayer 35 | from .openlayers_plugin_layer_type import OpenlayersPluginLayerType 36 | from .weblayers.weblayer_registry import WebLayerTypeRegistry 37 | from .weblayers.google_maps import (OlGooglePhysicalLayer, 38 | OlGoogleStreetsLayer, OlGoogleHybridLayer, 39 | OlGoogleSatelliteLayer) 40 | from .weblayers.osm import (OlOpenStreetMapLayer, 41 | OlOSMHumanitarianDataModelLayer) 42 | from .weblayers.osm_thunderforest import (OlOpenCycleMapLayer, 43 | OlOCMLandscapeLayer, 44 | OlOCMPublicTransportLayer, 45 | OlOCMOutdoorstLayer, 46 | OlOCMTransportDarkLayer, 47 | OlOCMSpinalMapLayer, 48 | OlOCMPioneerLayer, 49 | OlOCMMobileAtlasLayer, 50 | OlOCMNeighbourhoodLayer) 51 | from .weblayers.bing_maps import (OlBingRoadLayer, OlBingAerialLayer, 52 | OlBingAerialLabelledLayer) 53 | from .weblayers.apple_maps import OlAppleiPhotoMapLayer 54 | from .weblayers.osm_stamen import (OlOSMStamenTonerLayer, 55 | OlOSMStamenTonerLiteLayer, 56 | OlOSMStamenWatercolorLayer, 57 | OlOSMStamenTerrainLayer) 58 | from .weblayers.wikimedia_maps import (WikimediaLabelledLayer, 59 | WikimediaUnLabelledLayer) 60 | import os.path 61 | import time 62 | 63 | 64 | class OpenlayersPlugin: 65 | 66 | def __init__(self, iface): 67 | # Save reference to the QGIS interface 68 | self.iface = iface 69 | # initialize plugin directory 70 | self.plugin_dir = os.path.dirname(__file__) 71 | # Keep a reference to all OL layers to avoid GC 72 | self._ol_layers = [] 73 | # initialize locale 74 | locale = QSettings().value("locale/userLocale")[0:2] 75 | localePath = os.path.join(self.plugin_dir, "i18n", 76 | "openlayers_{}.qm".format(locale)) 77 | 78 | if os.path.exists(localePath): 79 | self.translator = QTranslator() 80 | self.translator.load(localePath) 81 | 82 | self._olLayerTypeRegistry = WebLayerTypeRegistry(self) 83 | self.olOverview = OLOverview(iface, self._olLayerTypeRegistry) 84 | self.dlgAbout = AboutDialog() 85 | self.pluginLayerRegistry = QgsPluginLayerRegistry() 86 | 87 | def initGui(self): 88 | self._olMenu = QMenu("OpenLayers plugin") 89 | self._olMenu.setIcon(QIcon(":/plugins/openlayers/openlayers.png")) 90 | 91 | # Overview 92 | self.overviewAddAction = QAction(QApplication.translate( 93 | "OpenlayersPlugin", "OpenLayers Overview"), 94 | self.iface.mainWindow()) 95 | self.overviewAddAction.setCheckable(True) 96 | self.overviewAddAction.setChecked(False) 97 | self.overviewAddAction.toggled.connect(self.olOverview.setVisible) 98 | self._olMenu.addAction(self.overviewAddAction) 99 | 100 | self._actionAbout = QAction("Terms of Service / About", 101 | self.iface.mainWindow()) 102 | self._actionAbout.triggered.connect(self.dlgAbout.show) 103 | self._olMenu.addAction(self._actionAbout) 104 | self.dlgAbout.finished.connect(self._publicationInfoClosed) 105 | 106 | self._olLayerTypeRegistry.register(OlGooglePhysicalLayer()) 107 | self._olLayerTypeRegistry.register(OlGoogleStreetsLayer()) 108 | self._olLayerTypeRegistry.register(OlGoogleHybridLayer()) 109 | self._olLayerTypeRegistry.register(OlGoogleSatelliteLayer()) 110 | 111 | self._olLayerTypeRegistry.register(OlOpenStreetMapLayer()) 112 | self._olLayerTypeRegistry.register(OlOpenCycleMapLayer()) 113 | self._olLayerTypeRegistry.register(OlOCMLandscapeLayer()) 114 | self._olLayerTypeRegistry.register(OlOCMPublicTransportLayer()) 115 | 116 | # ID 8-10 was Yahoo 117 | self._olLayerTypeRegistry.register(OlOSMHumanitarianDataModelLayer()) 118 | 119 | self._olLayerTypeRegistry.register(OlOCMOutdoorstLayer()) 120 | self._olLayerTypeRegistry.register(OlOCMTransportDarkLayer()) 121 | 122 | self._olLayerTypeRegistry.register(OlBingRoadLayer()) 123 | self._olLayerTypeRegistry.register(OlBingAerialLayer()) 124 | self._olLayerTypeRegistry.register(OlBingAerialLabelledLayer()) 125 | 126 | # Order from here on is free. Layers 0-14 should keep order for 127 | # compatibility with OL Plugin < 2.3 128 | 129 | self._olLayerTypeRegistry.register(OlOCMSpinalMapLayer()) 130 | self._olLayerTypeRegistry.register(OlOCMPioneerLayer()) 131 | self._olLayerTypeRegistry.register(OlOCMMobileAtlasLayer()) 132 | self._olLayerTypeRegistry.register(OlOCMNeighbourhoodLayer()) 133 | 134 | self._olLayerTypeRegistry.register(OlOSMStamenTonerLayer()) 135 | self._olLayerTypeRegistry.register(OlOSMStamenTonerLiteLayer()) 136 | self._olLayerTypeRegistry.register(OlOSMStamenWatercolorLayer()) 137 | self._olLayerTypeRegistry.register(OlOSMStamenTerrainLayer()) 138 | 139 | self._olLayerTypeRegistry.register(OlAppleiPhotoMapLayer()) 140 | 141 | self._olLayerTypeRegistry.register(WikimediaLabelledLayer()) 142 | self._olLayerTypeRegistry.register(WikimediaUnLabelledLayer()) 143 | 144 | for group in self._olLayerTypeRegistry.groups(): 145 | groupMenu = group.menu() 146 | for layer in self._olLayerTypeRegistry.groupLayerTypes(group): 147 | layer.addMenuEntry(groupMenu, self.iface.mainWindow()) 148 | self._olMenu.addMenu(groupMenu) 149 | 150 | # add action for API key dialogs 151 | for action in self._olMenu.actions(): 152 | if action.text() == "Google Maps": 153 | self._actionGoogleMapsApiKey = QAction( 154 | "Set API key", self.iface.mainWindow()) 155 | self._actionGoogleMapsApiKey.triggered.connect( 156 | self.showGoogleMapsApiKeyDialog) 157 | action.menu().addAction(self._actionGoogleMapsApiKey) 158 | if action.text() == "OSM/Thunderforest": 159 | self._actionThunderforestApiKey = QAction( 160 | "Set API key", self.iface.mainWindow()) 161 | self._actionThunderforestApiKey.triggered.connect( 162 | self.showThunderforestApiKeyDialog) 163 | action.menu().addAction(self._actionThunderforestApiKey) 164 | 165 | # Create Web menu, if it doesn't exist yet 166 | self.iface.addPluginToWebMenu("_tmp", self._actionAbout) 167 | self._menu = self.iface.webMenu() 168 | self._menu.addMenu(self._olMenu) 169 | self.iface.removePluginWebMenu("_tmp", self._actionAbout) 170 | 171 | # Register plugin layer type 172 | self.pluginLayerType = OpenlayersPluginLayerType( 173 | self.iface, self.setReferenceLayer, self._olLayerTypeRegistry) 174 | 175 | self.pluginLayerRegistry.addPluginLayerType( 176 | self.pluginLayerType) 177 | 178 | QgsProject.instance().readProject.connect(self.projectLoaded) 179 | QgsProject.instance().projectSaved.connect(self.projectSaved) 180 | 181 | def unload(self): 182 | self.iface.webMenu().removeAction(self._olMenu.menuAction()) 183 | 184 | self.olOverview.setVisible(False) 185 | del self.olOverview 186 | 187 | # Unregister plugin layer type 188 | self.pluginLayerRegistry.removePluginLayerType( 189 | OpenlayersLayer.LAYER_TYPE) 190 | 191 | QgsProject.instance().readProject.disconnect(self.projectLoaded) 192 | QgsProject.instance().projectSaved.disconnect(self.projectSaved) 193 | 194 | def addLayer(self, layerType): 195 | if layerType.hasXYZUrl(): 196 | # create XYZ layer 197 | layer, url = self.createXYZLayer(layerType, 198 | layerType.displayName) 199 | else: 200 | # create OpenlayersLayer 201 | layer = OpenlayersLayer(self.iface, self._olLayerTypeRegistry) 202 | layer.setName(layerType.displayName) 203 | layer.setLayerType(layerType) 204 | 205 | if layer.isValid(): 206 | coordRefSys = layerType.coordRefSys(self.canvasCrs()) 207 | self.setMapCrs(coordRefSys) 208 | QgsProject.instance().addMapLayer(layer) 209 | 210 | # store xyz config into qgis settings 211 | if layerType.hasXYZUrl(): 212 | settings = QSettings() 213 | settings.beginGroup('qgis/connections-xyz') 214 | settings.setValue("%s/authcfg" % (layer.name()), '') 215 | settings.setValue("%s/password" % (layer.name()), '') 216 | settings.setValue("%s/referer" % (layer.name()), '') 217 | settings.setValue("%s/url" % (layer.name()), url) 218 | settings.setValue("%s/username" % (layer.name()), '') 219 | # specify max/min or else only a picture of the map is saved 220 | # in settings 221 | settings.setValue("%s/zmax" % (layer.name()), '18') 222 | settings.setValue("%s/zmin" % (layer.name()), '0') 223 | settings.endGroup() 224 | # reload connections to update Browser Panel content 225 | self.iface.reloadConnections() 226 | 227 | self._ol_layers += [layer] 228 | 229 | # last added layer is new reference 230 | self.setReferenceLayer(layer) 231 | 232 | if not layerType.hasXYZUrl(): 233 | msg = "Printing and rotating of Javascript API " \ 234 | "based layers is currently not supported!" 235 | self.iface.messageBar().pushMessage( 236 | "OpenLayers Plugin", msg, level=Qgis.MessageLevel(1), 237 | duration=5) 238 | 239 | def setReferenceLayer(self, layer): 240 | self.layer = layer 241 | 242 | def removeLayer(self, layerId): 243 | if self.layer is not None: 244 | if self.layer.id() == layerId: 245 | self.layer = None 246 | # TODO: switch to next available OpenLayers layer? 247 | 248 | def canvasCrs(self): 249 | mapCanvas = self.iface.mapCanvas() 250 | crs = mapCanvas.mapSettings().destinationCrs() 251 | return crs 252 | 253 | def setMapCrs(self, coordRefSys): 254 | mapCanvas = self.iface.mapCanvas() 255 | # On the fly 256 | canvasCrs = self.canvasCrs() 257 | if canvasCrs != coordRefSys: 258 | coordTrans = QgsCoordinateTransform(canvasCrs, coordRefSys, 259 | QgsProject.instance()) 260 | extMap = mapCanvas.extent() 261 | extMap = coordTrans.transform( 262 | extMap, QgsCoordinateTransform.ForwardTransform) 263 | mapCanvas.setDestinationCrs(coordRefSys) 264 | mapCanvas.freeze(False) 265 | mapCanvas.setExtent(extMap) 266 | 267 | def projectLoaded(self): 268 | # replace old OpenlayersLayer with XYZ layer(OL plugin <= 1.3.6) 269 | rootGroup = self.iface.layerTreeView().layerTreeModel().rootGroup() 270 | for layer in QgsProject.instance().mapLayers().values(): 271 | if layer.type() == QgsMapLayer.PluginLayer and layer.pluginLayerType() == OpenlayersLayer.LAYER_TYPE: 272 | if layer.layerType.hasXYZUrl(): 273 | # replace layer 274 | xyzLayer, url = self.createXYZLayer(layer.layerType, 275 | layer.name()) 276 | if xyzLayer.isValid(): 277 | self.replaceLayer(rootGroup, layer, xyzLayer) 278 | 279 | def _hasOlLayer(self): 280 | for layer in QgsProject.instance().mapLayers().values(): 281 | if layer.customProperty('ol_layer_type'): 282 | return True 283 | return False 284 | 285 | def _publicationInfo(self): 286 | cloud_info_off = QSettings().value("Plugin-OpenLayers/cloud_info_off", 287 | defaultValue=False, type=bool) 288 | day = 3600*24 289 | now = time.time() 290 | lastInfo = QSettings().value("Plugin-OpenLayers/cloud_info_ts", 291 | defaultValue=0.0, type=float) 292 | if lastInfo == 0.0: 293 | lastInfo = now-20*day # Show first time after 10 days 294 | QSettings().setValue("Plugin-OpenLayers/cloud_info_ts", lastInfo) 295 | days = (now-lastInfo)/day 296 | if days >= 30 and not cloud_info_off: 297 | self.dlgAbout.tabWidget.setCurrentWidget( 298 | self.dlgAbout.tab_publishing) 299 | self.dlgAbout.show() 300 | QSettings().setValue("Plugin-OpenLayers/cloud_info_ts", now) 301 | 302 | def _publicationInfoClosed(self): 303 | QSettings().setValue("Plugin-OpenLayers/cloud_info_off", 304 | self.dlgAbout.cb_publishing.isChecked()) 305 | 306 | def projectSaved(self): 307 | if self._hasOlLayer(): 308 | self._publicationInfo() 309 | 310 | def createXYZLayer(self, layerType, name): 311 | # create XYZ layer with tms url as uri 312 | provider = 'wms' 313 | url = "type=xyz&url=" + layerType.xyzUrlConfig() 314 | layer = QgsRasterLayer(url, name, provider, 315 | QgsRasterLayer.LayerOptions()) 316 | layer.setCustomProperty('ol_layer_type', layerType.layerTypeName) 317 | return layer, layerType.xyzUrlConfig() 318 | 319 | def replaceLayer(self, group, oldLayer, newLayer): 320 | index = 0 321 | for child in group.children(): 322 | if QgsLayerTree.isLayer(child): 323 | if child.layerId() == oldLayer.id(): 324 | # insert new layer 325 | QgsProject.instance().addMapLayer(newLayer, False) 326 | newLayerNode = group.insertLayer(index, newLayer) 327 | newLayerNode.setVisible(child.isVisible()) 328 | 329 | # remove old layer 330 | QgsProject.instance().removeMapLayer( 331 | oldLayer.id()) 332 | 333 | msg = "Updated layer '%s' from old \ 334 | OpenLayers Plugin version" % newLayer.name() 335 | self.iface.messageBar().pushMessage( 336 | "OpenLayers Plugin", msg, level=Qgis.MessageLevel(0)) 337 | QgsMessageLog.logMessage( 338 | msg, "OpenLayers Plugin", QgsMessageLog.INFO) 339 | 340 | # layer replaced 341 | return True 342 | else: 343 | if self.replaceLayer(child, oldLayer, newLayer): 344 | # layer replaced in child group 345 | return True 346 | 347 | index += 1 348 | 349 | # layer not in this group 350 | return False 351 | 352 | def showGoogleMapsApiKeyDialog(self): 353 | apiKey = QSettings().value("Plugin-OpenLayers/googleMapsApiKey") 354 | newApiKey, ok = QInputDialog.getText( 355 | self.iface.mainWindow(), "API key", 356 | "Enter your Google Maps API key", QLineEdit.Normal, apiKey) 357 | if ok: 358 | QSettings().setValue("Plugin-OpenLayers/googleMapsApiKey", 359 | newApiKey) 360 | 361 | def showThunderforestApiKeyDialog(self): 362 | apiKey = QSettings().value("Plugin-OpenLayers/thunderforestApiKey") 363 | newApiKey, ok = QInputDialog.getText( 364 | self.iface.mainWindow(), "API key", 365 | "Enter your API key (https://thunderforest.com)", QLineEdit.Normal, apiKey) 366 | if ok: 367 | QSettings().setValue("Plugin-OpenLayers/thunderforestApiKey", 368 | newApiKey) 369 | -------------------------------------------------------------------------------- /openlayers/openlayers_plugin_layer_type.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2010-02-03 9 | copyright : (C) 2010 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | """ 22 | from qgis.core import QgsPluginLayerType 23 | from .openlayers_layer import OpenlayersLayer 24 | 25 | 26 | class OpenlayersPluginLayerType(QgsPluginLayerType): 27 | 28 | def __init__(self, iface, add_callback, olLayerTypeRegistry): 29 | QgsPluginLayerType.__init__(self, OpenlayersLayer.LAYER_TYPE) 30 | self.iface = iface 31 | self.add_callback = add_callback 32 | self.olLayerTypeRegistry = olLayerTypeRegistry 33 | 34 | def createLayer(self): 35 | layer = OpenlayersLayer(self.iface, self.olLayerTypeRegistry) 36 | self.add_callback(layer) 37 | return layer 38 | 39 | def showLayerProperties(self, layer): 40 | return False 41 | -------------------------------------------------------------------------------- /openlayers/plugin_upload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # This script uploads a plugin package on the server 3 | # 4 | # Author: A. Pasotti, V. Picavet 5 | 6 | import xmlrpclib, sys, os 7 | import getpass 8 | from optparse import OptionParser 9 | 10 | # Configuration 11 | PROTOCOL='https' 12 | SERVER='plugins.qgis.org' 13 | PORT='443' 14 | ENDPOINT='/plugins/RPC2/' 15 | VERBOSE=False 16 | 17 | def main(options, args): 18 | address = "%s://%s:%s@%s:%s%s" % (PROTOCOL, options.username, options.password, 19 | options.server, options.port, ENDPOINT) 20 | print "Connecting to: %s" % hidepassword(address) 21 | 22 | server = xmlrpclib.ServerProxy(address, verbose=VERBOSE) 23 | 24 | try: 25 | plugin_id, version_id = server.plugin.upload(xmlrpclib.Binary(open(args[0]).read())) 26 | print "Plugin ID: %s" % plugin_id 27 | print "Version ID: %s" % version_id 28 | except xmlrpclib.ProtocolError, err: 29 | print "A protocol error occurred" 30 | print "URL: %s" % hidepassword(err.url, 0) 31 | print "HTTP/HTTPS headers: %s" % err.headers 32 | print "Error code: %d" % err.errcode 33 | print "Error message: %s" % err.errmsg 34 | except xmlrpclib.Fault, err: 35 | print "A fault occurred" 36 | print "Fault code: %d" % err.faultCode 37 | print "Fault string: %s" % err.faultString 38 | 39 | def hidepassword(url, start = 6): 40 | """Returns the http url with password part replaced with '*'.""" 41 | passdeb = url.find(':', start) + 1 42 | passend = url.find('@') 43 | return "%s%s%s" % (url[:passdeb], '*' * (passend - passdeb), url[passend:]) 44 | 45 | 46 | if __name__ == "__main__": 47 | parser = OptionParser(usage="%prog [options] plugin.zip") 48 | parser.add_option("-w", "--password", dest="password", 49 | help="Password for plugin site", metavar="******") 50 | parser.add_option("-u", "--username", dest="username", 51 | help="Username of plugin site", metavar="user") 52 | parser.add_option("-p", "--port", dest="port", 53 | help="Server port to connect to", metavar="80") 54 | parser.add_option("-s", "--server", dest="server", 55 | help="Specify server name", metavar="plugins.qgis.org") 56 | (options, args) = parser.parse_args() 57 | if len(args) != 1: 58 | print "Please specify zip file.\n" 59 | parser.print_help() 60 | sys.exit(1) 61 | if not options.server: 62 | options.server = SERVER 63 | if not options.port: 64 | options.port = PORT 65 | if not options.username: 66 | # interactive mode 67 | username = getpass.getuser() 68 | print "Please enter user name [%s] :"%username, 69 | res = raw_input() 70 | if res != "": 71 | options.username = res 72 | else: 73 | options.username = username 74 | if not options.password: 75 | # interactive mode 76 | options.password = getpass.getpass() 77 | main(options, args) 78 | -------------------------------------------------------------------------------- /openlayers/qgiscloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/qgiscloud.png -------------------------------------------------------------------------------- /openlayers/resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | openlayers.png 4 | qgiscloud.png 5 | weblayers/icons/apple_icon.png 6 | weblayers/icons/bing_icon.png 7 | weblayers/icons/google_icon.png 8 | weblayers/icons/osm_icon.png 9 | weblayers/icons/stamen_icon.png 10 | weblayers/icons/wikimedia_icon.png 11 | 12 | 13 | -------------------------------------------------------------------------------- /openlayers/ui_about_dialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'ui_about_dialog.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.1 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_dlgAbout(object): 12 | def setupUi(self, dlgAbout): 13 | dlgAbout.setObjectName("dlgAbout") 14 | dlgAbout.resize(466, 412) 15 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(dlgAbout) 16 | self.verticalLayout_3.setObjectName("verticalLayout_3") 17 | self.tabWidget = QtWidgets.QTabWidget(dlgAbout) 18 | self.tabWidget.setObjectName("tabWidget") 19 | self.tab_terms = QtWidgets.QWidget() 20 | self.tab_terms.setObjectName("tab_terms") 21 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab_terms) 22 | self.verticalLayout_2.setObjectName("verticalLayout_2") 23 | self.textBrowser = QtWidgets.QTextBrowser(self.tab_terms) 24 | self.textBrowser.setUndoRedoEnabled(False) 25 | self.textBrowser.setReadOnly(True) 26 | self.textBrowser.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) 27 | self.textBrowser.setOpenExternalLinks(True) 28 | self.textBrowser.setObjectName("textBrowser") 29 | self.verticalLayout_2.addWidget(self.textBrowser) 30 | self.tabWidget.addTab(self.tab_terms, "") 31 | self.tab_about = QtWidgets.QWidget() 32 | self.tab_about.setObjectName("tab_about") 33 | self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.tab_about) 34 | self.verticalLayout_4.setObjectName("verticalLayout_4") 35 | self.textBrowser_2 = QtWidgets.QTextBrowser(self.tab_about) 36 | self.textBrowser_2.setUndoRedoEnabled(False) 37 | self.textBrowser_2.setReadOnly(True) 38 | self.textBrowser_2.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) 39 | self.textBrowser_2.setOpenExternalLinks(True) 40 | self.textBrowser_2.setObjectName("textBrowser_2") 41 | self.verticalLayout_4.addWidget(self.textBrowser_2) 42 | self.tabWidget.addTab(self.tab_about, "") 43 | self.tab_publishing = QtWidgets.QWidget() 44 | self.tab_publishing.setObjectName("tab_publishing") 45 | self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.tab_publishing) 46 | self.verticalLayout_5.setObjectName("verticalLayout_5") 47 | self.logo = QtWidgets.QLabel(self.tab_publishing) 48 | self.logo.setAutoFillBackground(False) 49 | self.logo.setPixmap(QtGui.QPixmap(":/plugins/openlayers/qgiscloud.png")) 50 | self.logo.setScaledContents(False) 51 | self.logo.setAlignment(QtCore.Qt.AlignCenter) 52 | self.logo.setObjectName("logo") 53 | self.verticalLayout_5.addWidget(self.logo) 54 | self.textBrowser1 = QtWidgets.QTextBrowser(self.tab_publishing) 55 | self.textBrowser1.setAcceptDrops(False) 56 | self.textBrowser1.setReadOnly(True) 57 | self.textBrowser1.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction) 58 | self.textBrowser1.setOpenExternalLinks(True) 59 | self.textBrowser1.setObjectName("textBrowser1") 60 | self.verticalLayout_5.addWidget(self.textBrowser1) 61 | self.cb_publishing = QtWidgets.QCheckBox(self.tab_publishing) 62 | self.cb_publishing.setObjectName("cb_publishing") 63 | self.verticalLayout_5.addWidget(self.cb_publishing) 64 | self.tabWidget.addTab(self.tab_publishing, "") 65 | self.verticalLayout_3.addWidget(self.tabWidget) 66 | self.widget = QtWidgets.QWidget(dlgAbout) 67 | self.widget.setMinimumSize(QtCore.QSize(0, 0)) 68 | self.widget.setMaximumSize(QtCore.QSize(180, 16777215)) 69 | self.widget.setObjectName("widget") 70 | self.verticalLayout = QtWidgets.QVBoxLayout(self.widget) 71 | self.verticalLayout.setObjectName("verticalLayout") 72 | self.verticalLayout_3.addWidget(self.widget) 73 | self.buttonBox = QtWidgets.QDialogButtonBox(dlgAbout) 74 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal) 75 | self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close) 76 | self.buttonBox.setCenterButtons(True) 77 | self.buttonBox.setObjectName("buttonBox") 78 | self.verticalLayout_3.addWidget(self.buttonBox) 79 | self.widget.raise_() 80 | self.tabWidget.raise_() 81 | self.buttonBox.raise_() 82 | 83 | self.retranslateUi(dlgAbout) 84 | self.tabWidget.setCurrentIndex(0) 85 | self.buttonBox.accepted.connect(dlgAbout.accept) 86 | self.buttonBox.rejected.connect(dlgAbout.reject) 87 | QtCore.QMetaObject.connectSlotsByName(dlgAbout) 88 | 89 | def retranslateUi(self, dlgAbout): 90 | _translate = QtCore.QCoreApplication.translate 91 | dlgAbout.setWindowTitle(_translate("dlgAbout", "About OpenLayers Plugin")) 92 | self.textBrowser.setHtml(_translate("dlgAbout", "\n" 93 | "\n" 96 | "

The terms of service of the used map providers apply!

\n" 97 | "


\n" 98 | "

Selected links:

\n" 99 | "

OpenStreetMap (Tile Usage)

\n" 100 | "

Google Maps

\n" 101 | "

Microsoft® Bing™ Maps

\n" 102 | "


\n" 103 | "


\n" 104 | "

License

\n" 105 | "


\n" 106 | "

qgis-openlayers-plugin 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.

\n" 107 | "


\n" 108 | "

Copyright (c) 2010-2017 Pirmin Kalberer & Mathias Walker, Sourcepole AG

")) 109 | self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_terms), _translate("dlgAbout", "Terms of Service")) 110 | self.textBrowser_2.setHtml(_translate("dlgAbout", "\n" 111 | "\n" 114 | "

Development/Support:

\n" 115 | "


\n" 116 | "

QGIS OpenLayers plugin is developed and maintained by

\n" 117 | "

@PirminKalberer & Mathias Walker, Sourcepole, Switzerland

\n" 118 | "


\n" 119 | "

Support is available as part of QGIS Enterprise

\n" 120 | "


\n" 121 | "


\n" 122 | "

Contributions:

\n" 123 | "


\n" 124 | "

OpenLayers Overview by Luiz Motta

\n" 125 | "


\n" 126 | "

Other contributions by:

\n" 127 | "

-Etienne Tourigny

\n" 128 | "

-Minoru Akagi

\n" 129 | "

-Minpa Lee

\n" 130 | "

-Richard Duivenvoorde

\n" 131 | "

-Nathaniel V. Kelso

\n" 132 | "

-Salvatore Larosa

\n" 133 | "

-Jürgen E. Fischer

\n" 134 | "

-Fkili Mohamed

\n" 135 | "

-Morten Agerlin

\n" 136 | "

-Guilhem Vellut

\n" 137 | "

-Vivien Deparday

\n" 138 | "

-Marcelo Soares Souza

\n" 139 | "

-Gerald Rich

\n" 140 | "

-Henry Walshaw

\n" 141 | "


\n" 142 | "

Sponsors:

\n" 143 | "


\n" 144 | "

-BLS Netz AG

\n" 145 | "

-Cooperativa Colonizadora Multiactiva Fernheim Ltda.

")) 146 | self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_about), _translate("dlgAbout", "About")) 147 | self.textBrowser1.setHtml(_translate("dlgAbout", "\n" 148 | "\n" 151 | "


\n" 152 | "

Want to publish this map to the Web?

\n" 153 | "


\n" 154 | "

Install the QGIS Cloud plugin and publish your map

\n" 155 | "

on QGIS Cloud with a few mouse clicks!

")) 156 | self.cb_publishing.setText(_translate("dlgAbout", "Don\'t show again")) 157 | self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_publishing), _translate("dlgAbout", "Publishing")) 158 | 159 | from . import resources_rc 160 | -------------------------------------------------------------------------------- /openlayers/ui_openlayers_ovwidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'ui_openlayers_ovwidget.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.1 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_Form(object): 12 | def setupUi(self, Form): 13 | Form.setObjectName("Form") 14 | Form.resize(457, 467) 15 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(Form) 16 | self.verticalLayout_2.setObjectName("verticalLayout_2") 17 | self.lytEnableMap = QtWidgets.QHBoxLayout() 18 | self.lytEnableMap.setObjectName("lytEnableMap") 19 | self.checkBoxEnableMap = QtWidgets.QCheckBox(Form) 20 | self.checkBoxEnableMap.setChecked(False) 21 | self.checkBoxEnableMap.setObjectName("checkBoxEnableMap") 22 | self.lytEnableMap.addWidget(self.checkBoxEnableMap) 23 | self.comboBoxTypeMap = QtWidgets.QComboBox(Form) 24 | self.comboBoxTypeMap.setObjectName("comboBoxTypeMap") 25 | self.lytEnableMap.addWidget(self.comboBoxTypeMap) 26 | self.pbAddRaster = QtWidgets.QPushButton(Form) 27 | self.pbAddRaster.setText("") 28 | self.pbAddRaster.setObjectName("pbAddRaster") 29 | self.lytEnableMap.addWidget(self.pbAddRaster) 30 | spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 31 | self.lytEnableMap.addItem(spacerItem) 32 | self.verticalLayout_2.addLayout(self.lytEnableMap) 33 | self.lbStatusRead = QtWidgets.QLabel(Form) 34 | self.lbStatusRead.setText("") 35 | self.lbStatusRead.setTextFormat(QtCore.Qt.PlainText) 36 | self.lbStatusRead.setObjectName("lbStatusRead") 37 | self.verticalLayout_2.addWidget(self.lbStatusRead) 38 | self.webViewMap = QtWebKitWidgets.QWebView(Form) 39 | self.webViewMap.setObjectName("webViewMap") 40 | self.verticalLayout_2.addWidget(self.webViewMap) 41 | self.lytHideCross = QtWidgets.QHBoxLayout() 42 | self.lytHideCross.setObjectName("lytHideCross") 43 | self.checkBoxHideCross = QtWidgets.QCheckBox(Form) 44 | self.checkBoxHideCross.setObjectName("checkBoxHideCross") 45 | self.lytHideCross.addWidget(self.checkBoxHideCross) 46 | self.pbRefresh = QtWidgets.QPushButton(Form) 47 | self.pbRefresh.setText("") 48 | self.pbRefresh.setObjectName("pbRefresh") 49 | self.lytHideCross.addWidget(self.pbRefresh) 50 | self.pbSaveImg = QtWidgets.QPushButton(Form) 51 | self.pbSaveImg.setText("") 52 | self.pbSaveImg.setObjectName("pbSaveImg") 53 | self.lytHideCross.addWidget(self.pbSaveImg) 54 | self.pbCopyKml = QtWidgets.QPushButton(Form) 55 | self.pbCopyKml.setText("") 56 | self.pbCopyKml.setObjectName("pbCopyKml") 57 | self.lytHideCross.addWidget(self.pbCopyKml) 58 | spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 59 | self.lytHideCross.addItem(spacerItem1) 60 | self.verticalLayout_2.addLayout(self.lytHideCross) 61 | 62 | self.retranslateUi(Form) 63 | QtCore.QMetaObject.connectSlotsByName(Form) 64 | 65 | def retranslateUi(self, Form): 66 | _translate = QtCore.QCoreApplication.translate 67 | Form.setWindowTitle(_translate("Form", "Form")) 68 | self.checkBoxEnableMap.setText(_translate("Form", "Enable map")) 69 | self.pbAddRaster.setToolTip(_translate("Form", "Add map")) 70 | self.checkBoxHideCross.setText(_translate("Form", "Hide cross in map")) 71 | self.pbRefresh.setToolTip(_translate("Form", "Refresh map")) 72 | self.pbSaveImg.setToolTip(_translate("Form", "Save this image")) 73 | self.pbCopyKml.setToolTip(_translate("Form", "Copy rectangle (KML) of map to clipboard")) 74 | 75 | from PyQt5 import QtWebKitWidgets 76 | -------------------------------------------------------------------------------- /openlayers/ui_openlayers_ovwidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 457 10 | 467 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Enable map 23 | 24 | 25 | false 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | Add map 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | Qt::Horizontal 46 | 47 | 48 | 49 | 40 50 | 20 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | Qt::PlainText 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Hide cross in map 76 | 77 | 78 | 79 | 80 | 81 | 82 | Refresh map 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | Save this image 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | Copy rectangle (KML) of map to clipboard 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | Qt::Horizontal 113 | 114 | 115 | 116 | 40 117 | 20 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | QWebView 129 | QWidget 130 |
QtWebKit/QWebView
131 |
132 |
133 | 134 | 135 | 136 | activeCatalog() 137 | 138 |
139 | -------------------------------------------------------------------------------- /openlayers/ui_openlayersplugin.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenlayersPlugin 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | OpenlayersPlugin 15 | 16 | 17 | 18 | 19 | 30 20 | 240 21 | 341 22 | 32 23 | 24 | 25 | 26 | Qt::Horizontal 27 | 28 | 29 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 30 | 31 | 32 | 33 | 34 | 35 | 36 | buttonBox 37 | accepted() 38 | OpenlayersPlugin 39 | accept() 40 | 41 | 42 | 248 43 | 254 44 | 45 | 46 | 157 47 | 274 48 | 49 | 50 | 51 | 52 | buttonBox 53 | rejected() 54 | OpenlayersPlugin 55 | reject() 56 | 57 | 58 | 316 59 | 260 60 | 61 | 62 | 286 63 | 274 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /openlayers/weblayers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/weblayers/__init__.py -------------------------------------------------------------------------------- /openlayers/weblayers/apple_maps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2009-11-30 9 | copyright : (C) 2009 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | """ 22 | 23 | from .weblayer import WebLayer3857 24 | 25 | 26 | class OlAppleiPhotoMapLayer(WebLayer3857): 27 | 28 | emitsLoadEnd = True 29 | 30 | def __init__(self): 31 | WebLayer3857.__init__(self, groupName="Apple Maps", 32 | groupIcon="apple_icon.png", 33 | name='Apple iPhoto map', html='apple.html') 34 | -------------------------------------------------------------------------------- /openlayers/weblayers/bing_maps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2009-11-30 9 | copyright : (C) 2009 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | """ 22 | 23 | from .weblayer import WebLayer3857 24 | 25 | 26 | class OlBingMapsLayer(WebLayer3857): 27 | 28 | emitsLoadEnd = True 29 | 30 | def __init__(self, name, html): 31 | WebLayer3857.__init__(self, groupName="Bing Maps", 32 | groupIcon="bing_icon.png", name=name, html=html) 33 | 34 | 35 | class OlBingRoadLayer(OlBingMapsLayer): 36 | 37 | def __init__(self): 38 | OlBingMapsLayer.__init__(self, name='Bing Road', html='bing_road.html') 39 | 40 | 41 | class OlBingAerialLayer(OlBingMapsLayer): 42 | 43 | def __init__(self): 44 | OlBingMapsLayer.__init__(self, name='Bing Aerial', 45 | html='bing_aerial.html') 46 | 47 | 48 | class OlBingAerialLabelledLayer(OlBingMapsLayer): 49 | 50 | def __init__(self): 51 | OlBingMapsLayer.__init__(self, name='Bing Aerial with labels', 52 | html='bing_aerial-labels.html') 53 | -------------------------------------------------------------------------------- /openlayers/weblayers/google_maps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2009-11-30 9 | copyright : (C) 2009 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | """ 22 | 23 | from qgis.PyQt.QtCore import QSettings 24 | from .weblayer import WebLayer3857 25 | 26 | 27 | class OlGoogleMapsLayer(WebLayer3857): 28 | 29 | emitsLoadEnd = True 30 | 31 | def __init__(self, name, html): 32 | WebLayer3857.__init__(self, groupName="Google Maps", 33 | groupIcon="google_icon.png", name=name, 34 | html=html) 35 | 36 | def html_url(self): 37 | url = WebLayer3857.html_url(self) 38 | apiKey = QSettings().value("Plugin-OpenLayers/googleMapsApiKey") 39 | if apiKey is not None and bool(apiKey.strip()): 40 | url += "?key=%s" % apiKey 41 | return url 42 | 43 | 44 | class OlGooglePhysicalLayer(OlGoogleMapsLayer): 45 | 46 | def __init__(self): 47 | OlGoogleMapsLayer.__init__(self, name="Google Physical", 48 | html="google_physical.html") 49 | 50 | 51 | class OlGoogleStreetsLayer(OlGoogleMapsLayer): 52 | 53 | def __init__(self): 54 | OlGoogleMapsLayer.__init__(self, name='Google Streets', 55 | html='google_streets.html') 56 | 57 | 58 | class OlGoogleHybridLayer(OlGoogleMapsLayer): 59 | 60 | def __init__(self): 61 | OlGoogleMapsLayer.__init__(self, name='Google Hybrid', 62 | html='google_hybrid.html') 63 | 64 | 65 | class OlGoogleSatelliteLayer(OlGoogleMapsLayer): 66 | 67 | def __init__(self): 68 | OlGoogleMapsLayer.__init__(self, name='Google Satellite', 69 | html='google_satellite.html') 70 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/OlOverviewMarker.js: -------------------------------------------------------------------------------- 1 | /* 2 | **************************************************************************** 3 | Operlayer Overview Marker 4 | ------------------- 5 | begin : 2010-03-03 6 | copyright : (C) 2010 by Luiz Motta 7 | email : motta.luiz at gamil.com 8 | **************************************************************************** 9 | 10 | **************************************************************************** 11 | * * 12 | * This program is free software; you can redistribute it and/or modify * 13 | * it under the terms of the GNU General Public License as published by * 14 | * the Free Software Foundation; either version 2 of the License, or * 15 | * (at your option) any later version. * 16 | * * 17 | *************************************************************************** 18 | 19 | Dependences: 20 | Libray: OpenLayers.js and MarkerCursorQGis(Python binding - @QtCore.pyqtSlot(str) ) 21 | 22 | Usage: 23 | Inside HTML: 24 | var oloMarker; 25 | // Inside init function by HTML() 26 | oloMarker = OlOverviewMarker(map, getPathUpper(document.URL) + '/x.png') // x.png in upper directory of HTML 27 | Inside Python: 28 | evaluateJavaScript("oloMarker.changeMarker();") 29 | 30 | *****************************************************************************/ 31 | 32 | function getPathUpper(url) 33 | { 34 | var paths = new Array(); 35 | paths = document.URL.split('/'); 36 | paths.pop();paths.pop(); 37 | return paths.join('/'); 38 | } 39 | 40 | function OlOverviewMarker(map, urlIcon) { 41 | //Private 42 | function __createMarker(urlIcon) 43 | { 44 | var size = new OpenLayers.Size(16,16); 45 | var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); 46 | var icon = new OpenLayers.Icon(urlIcon, size, offset); 47 | marker = new OpenLayers.Marker(new OpenLayers.LonLat(0,0), icon); 48 | marker.display(false); 49 | } 50 | //Public CTRL+Q 51 | this.changeMarker = function() { 52 | this.lyrMarker.removeMarker(marker); 53 | var extent = this.map.getExtent(); 54 | marker.lonlat = extent.getCenterLonLat(); 55 | marker.display(true); 56 | this.lyrMarker.addMarker(marker); 57 | MarkerCursorQGis.changeMarker(extent.toArray().toString()); 58 | }; 59 | this.map = map; 60 | var marker; 61 | __createMarker(urlIcon); 62 | this.lyrMarker = new OpenLayers.Layer.Markers("Marker Overview"); 63 | this.lyrMarker.addMarker(marker); 64 | map.addLayer(this.lyrMarker); 65 | } 66 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/apple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Apple iPhoto map Layer 4 | 5 | 6 | 7 | 53 | 54 | 55 |
56 | 57 | 58 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/bing_aerial-labels.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Bing Aerial with labels Layer 4 | 5 | 6 | 7 | 8 | 50 | 51 | 52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/bing_aerial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Bing Aerial Layer 4 | 5 | 6 | 7 | 8 | 50 | 51 | 52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/bing_road.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Bing Road Layer 4 | 5 | 6 | 7 | 8 | 50 | 51 | 52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/google.css: -------------------------------------------------------------------------------- 1 | .olLayerGoogleCopyright { 2 | right: 3px; 3 | bottom: 2px; 4 | left: auto; 5 | } 6 | .olLayerGoogleV3.olLayerGoogleCopyright { 7 | bottom: 0px; 8 | right: 0px !important; 9 | } 10 | .olLayerGooglePoweredBy { 11 | left: 2px; 12 | bottom: 2px; 13 | } 14 | .olLayerGoogleV3.olLayerGooglePoweredBy { 15 | bottom: 0px !important; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/google_hybrid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Google Hybrid Layer 4 | 5 | 6 | 7 | 8 | 57 | 58 | 59 |
60 | 61 | 62 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/google_physical.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Google Physical Layer 4 | 5 | 6 | 7 | 8 | 54 | 55 | 56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/google_satellite.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Google Satellite Layer 4 | 5 | 6 | 7 | 8 | 57 | 58 | 59 |
60 | 61 | 62 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/google_streets.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Google Streets Layer 4 | 5 | 6 | 7 | 8 | 55 | 56 | 57 |
58 | 59 | 60 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/osm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers OpenStreetMap Layer 4 | 5 | 6 | 7 | 48 | 49 | 50 |
51 | 52 | 53 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/osm_hdm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers OpenStreetMap Layer 4 | 5 | 6 | 7 | 50 | 51 | 52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/osm_thunderforest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers OpenStreetMap Layer 4 | 5 | 6 | 7 | 64 | 65 | 66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/qgis.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | #map { 5 | width: 100%; 6 | height: 100%; 7 | } 8 | .olControlAttribution { 9 | font-size: smaller; 10 | right: 3px; 11 | bottom: 0.5em; 12 | position: absolute; 13 | display: block; 14 | } 15 | /* avoid pink tiles */ 16 | .olImageLoadError { 17 | background-color: transparent !important; 18 | } 19 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/stamen_terrain.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Stamen Terrain/OSM map Layer 4 | 5 | 6 | 7 | 53 | 54 | 55 |
56 | 57 | 58 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/stamen_toner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Stamen Toner/OSM map Layer 4 | 5 | 6 | 7 | 53 | 54 | 55 |
56 | 57 | 58 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/stamen_toner_lite.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Stamen Toner/OSM map Layer 4 | 5 | 6 | 7 | 53 | 54 | 55 |
56 | 57 | 58 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/stamen_watercolor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Stamen Terrain/OSM map Layer 4 | 5 | 6 | 7 | 53 | 54 | 55 |
56 | 57 | 58 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/wikimedia.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Wikimedia Labelled Layer 4 | 5 | 6 | 7 | 48 | 49 | 50 |
51 | 52 | 53 | -------------------------------------------------------------------------------- /openlayers/weblayers/html/wikimedia_nolabels.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | OpenLayers Wikimedia Unlabelled Layer 4 | 5 | 6 | 7 | 48 | 49 | 50 |
51 | 52 | 53 | -------------------------------------------------------------------------------- /openlayers/weblayers/icons/apple_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/weblayers/icons/apple_icon.png -------------------------------------------------------------------------------- /openlayers/weblayers/icons/bing_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/weblayers/icons/bing_icon.png -------------------------------------------------------------------------------- /openlayers/weblayers/icons/google_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/weblayers/icons/google_icon.png -------------------------------------------------------------------------------- /openlayers/weblayers/icons/kml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/weblayers/icons/kml.png -------------------------------------------------------------------------------- /openlayers/weblayers/icons/osm_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/weblayers/icons/osm_icon.png -------------------------------------------------------------------------------- /openlayers/weblayers/icons/stamen_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/weblayers/icons/stamen_icon.png -------------------------------------------------------------------------------- /openlayers/weblayers/icons/wikimedia_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/weblayers/icons/wikimedia_icon.png -------------------------------------------------------------------------------- /openlayers/weblayers/osm.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2009-11-30 9 | copyright : (C) 2009 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | """ 22 | 23 | from .weblayer import WebLayer3857 24 | 25 | 26 | class OlOSMLayer(WebLayer3857): 27 | 28 | emitsLoadEnd = True 29 | 30 | def __init__(self, name, html, xyzUrl=None): 31 | WebLayer3857.__init__(self, groupName="OpenStreetMap", 32 | groupIcon="osm_icon.png", 33 | name=name, html=html, xyzUrl=xyzUrl) 34 | 35 | 36 | class OlOpenStreetMapLayer(OlOSMLayer): 37 | 38 | def __init__(self): 39 | tmsUrl = 'http://tile.openstreetmap.org/{z}/{x}/{y}.png' 40 | OlOSMLayer.__init__(self, name='OpenStreetMap', html='osm.html', 41 | xyzUrl=tmsUrl) 42 | 43 | 44 | class OlOSMHumanitarianDataModelLayer(OlOSMLayer): 45 | 46 | def __init__(self): 47 | tmsUrl = 'http://a.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png' 48 | OlOSMLayer.__init__(self, name='OSM Humanitarian Data Model', 49 | html='osm_hdm.html', xyzUrl=tmsUrl) 50 | -------------------------------------------------------------------------------- /openlayers/weblayers/osm_stamen.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2009-11-30 9 | copyright : (C) 2009 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | """ 22 | 23 | from .weblayer import WebLayer3857 24 | 25 | 26 | class OlOSMStamenLayer(WebLayer3857): 27 | 28 | emitsLoadEnd = True 29 | 30 | def __init__(self, name, html, xyzUrl=None): 31 | WebLayer3857.__init__(self, groupName="OSM/Stamen", 32 | groupIcon="stamen_icon.png", name=name, 33 | html=html, xyzUrl=xyzUrl) 34 | 35 | 36 | class OlOSMStamenTonerLayer(OlOSMStamenLayer): 37 | 38 | def __init__(self): 39 | tmsUrl = 'http://tile.stamen.com/toner/{z}/{x}/{y}.png' 40 | OlOSMStamenLayer.__init__(self, name='Stamen Toner/OSM', 41 | html='stamen_toner.html', 42 | xyzUrl=tmsUrl) 43 | 44 | 45 | class OlOSMStamenTonerLiteLayer(OlOSMStamenLayer): 46 | 47 | def __init__(self): 48 | tmsUrl = 'http://tile.stamen.com/toner-lite/{z}/{x}/{y}.png' 49 | OlOSMStamenLayer.__init__(self, name='Stamen Toner Lite/OSM', 50 | html='stamen_toner_lite.html', 51 | xyzUrl=tmsUrl) 52 | 53 | 54 | class OlOSMStamenWatercolorLayer(OlOSMStamenLayer): 55 | 56 | def __init__(self): 57 | tmsUrl = 'http://tile.stamen.com/watercolor/{z}/{x}/{y}.jpg' 58 | OlOSMStamenLayer.__init__(self, name='Stamen Watercolor/OSM', 59 | html='stamen_watercolor.html', 60 | xyzUrl=tmsUrl) 61 | 62 | 63 | class OlOSMStamenTerrainLayer(OlOSMStamenLayer): 64 | 65 | def __init__(self): 66 | tmsUrl = 'http://tile.stamen.com/terrain/{z}/{x}/{y}.png' 67 | OlOSMStamenLayer.__init__(self, name='Stamen Terrain-USA/OSM', 68 | html='stamen_terrain.html', 69 | xyzUrl=tmsUrl) 70 | -------------------------------------------------------------------------------- /openlayers/weblayers/osm_thunderforest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2009-11-30 9 | copyright : (C) 2009 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | """ 22 | 23 | from .weblayer import WebLayer3857 24 | from qgis.PyQt.QtCore import QSettings 25 | 26 | 27 | class OlOSMThunderforest(WebLayer3857): 28 | 29 | emitsLoadEnd = True 30 | 31 | def __init__(self, name, layer): 32 | WebLayer3857.__init__(self, groupName="OSM/Thunderforest", 33 | groupIcon="osm_icon.png", 34 | name=name, html='osm_thunderforest.html', 35 | xyzUrl='inline') 36 | self._layer = layer 37 | 38 | def apiKey(self): 39 | return QSettings().value("Plugin-OpenLayers/thunderforestApiKey") 40 | 41 | def html_url(self): 42 | url = WebLayer3857.html_url(self) 43 | url += "?layer=%s" % self._layer 44 | if self.apiKey(): 45 | url += "&key=%s" % self.apiKey().strip() 46 | return url 47 | 48 | def xyzUrlConfig(self): 49 | if self.apiKey(): 50 | keyarg = self.apiKey().strip() 51 | return 'https://tile.thunderforest.com/%s/{z}/{x}/{y}.png?apikey=%s' % (self._layer, keyarg) 52 | else: 53 | return 'https://tile.thunderforest.com/%s/{z}/{x}/{y}.png' % (self._layer) 54 | 55 | 56 | class OlOpenCycleMapLayer(OlOSMThunderforest): 57 | 58 | def __init__(self): 59 | OlOSMThunderforest.__init__(self, name='OpenCycleMap', layer='cycle') 60 | 61 | 62 | class OlOCMLandscapeLayer(OlOSMThunderforest): 63 | 64 | def __init__(self): 65 | OlOSMThunderforest.__init__(self, name='OCM Landscape', 66 | layer='landscape') 67 | 68 | 69 | class OlOCMPublicTransportLayer(OlOSMThunderforest): 70 | 71 | def __init__(self): 72 | OlOSMThunderforest.__init__(self, name='OCM Public Transport', 73 | layer='transport') 74 | 75 | 76 | class OlOCMOutdoorstLayer(OlOSMThunderforest): 77 | 78 | def __init__(self): 79 | OlOSMThunderforest.__init__(self, name='Outdoors', layer='outdoors') 80 | 81 | 82 | class OlOCMTransportDarkLayer(OlOSMThunderforest): 83 | 84 | def __init__(self): 85 | OlOSMThunderforest.__init__(self, name='Transport Dark', 86 | layer='transport-dark') 87 | 88 | 89 | class OlOCMSpinalMapLayer(OlOSMThunderforest): 90 | 91 | def __init__(self): 92 | OlOSMThunderforest.__init__(self, name='Spinal Map', 93 | layer='spinal-map') 94 | 95 | 96 | class OlOCMPioneerLayer(OlOSMThunderforest): 97 | 98 | def __init__(self): 99 | OlOSMThunderforest.__init__(self, name='Pioneer', layer='pioneer') 100 | 101 | 102 | class OlOCMMobileAtlasLayer(OlOSMThunderforest): 103 | 104 | def __init__(self): 105 | OlOSMThunderforest.__init__(self, name='Mobile Atlas', 106 | layer='mobile-atlas') 107 | 108 | 109 | class OlOCMNeighbourhoodLayer(OlOSMThunderforest): 110 | 111 | def __init__(self): 112 | OlOSMThunderforest.__init__(self, name='Neighbourhood', 113 | layer='neighbourhood') 114 | -------------------------------------------------------------------------------- /openlayers/weblayers/weblayer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2009-11-30 9 | copyright : (C) 2009 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | """ 22 | 23 | from qgis.PyQt.QtGui import QIcon 24 | from qgis.PyQt.QtWidgets import QAction, QMenu 25 | from qgis.core import Qgis as QGis, QgsCoordinateReferenceSystem 26 | import os 27 | 28 | 29 | class WebLayerGroup: 30 | """Group in menu""" 31 | 32 | def __init__(self, name, icon): 33 | self._menu = QMenu(name) 34 | self._menu.setIcon(QIcon(os.path.join( 35 | ":/plugins/openlayers/weblayers/icons", icon))) 36 | 37 | def menu(self): 38 | return self._menu 39 | 40 | 41 | class WebLayer: 42 | """Base class for OpenLayers layers""" 43 | 44 | displayName = None 45 | """Layer type name in menu""" 46 | 47 | layerTypeName = None 48 | """Layer type identificator used to store in project""" 49 | 50 | layerTypeId = None 51 | """Numerical ID used in versions < 2.3""" 52 | # GOOGLE_TERRAIN => 0, 53 | # GOOGLE_ROADMAP => 1, 54 | # GOOGLE_HYBRID => 2, 55 | # GOOGLE_SATELLITE => 3, 56 | # OSM => 4, 57 | # OCM => 5, 58 | # OCM_LANDSCAPE => 6, 59 | # OCM_PUBLIC_TRANSPORT => 7, 60 | # YAHOO_STREET => 8, 61 | # YAHOO_HYBRID => 9, 62 | # YAHOO_SATELLITE => 10, 63 | # BING_ROAD => 11, 64 | # BING_AERIAL => 12, 65 | # BING_AERIAL_WITH_LABELS => 13, 66 | # APPLE_IPHOTO => 14 67 | 68 | groupName = None 69 | """Group in menu""" 70 | 71 | groupIcon = None 72 | """Group icon in menu""" 73 | 74 | epsgList = [] 75 | """Supported EPSG projections, ordered by preference""" 76 | 77 | fullExtent = [-180.0, -90.0, 180.0, 90.0] 78 | """WGS84 bounds""" 79 | 80 | emitsLoadEnd = True 81 | 82 | def __init__(self, groupName, groupIcon, name, html, xyzUrl=None): 83 | self.groupName = groupName 84 | self.groupIcon = groupIcon 85 | self.displayName = name 86 | self.layerTypeName = name 87 | self._html = html 88 | # optional GDAL TMS config to use as layer instead of an 89 | # OpenlayersLayer 90 | # the OpenlayersLayer is still used in the OpenLayers Overview 91 | self._xyzUrl = xyzUrl 92 | 93 | def addMenuEntry(self, groupMenu, parent): 94 | self._actionAddLayer = QAction(self.displayName, parent) 95 | self._actionAddLayer.triggered.connect(self.addLayer) 96 | groupMenu.addAction(self._actionAddLayer) 97 | 98 | def setAddLayerCallback(self, addLayerCallback): 99 | self._addLayerCallback = addLayerCallback 100 | 101 | def addLayer(self): 102 | self._addLayerCallback(self) 103 | 104 | def html_url(self): 105 | dir = os.path.dirname(__file__) 106 | url = "file:///%s/html/%s" % (dir.replace("\\", "/"), self._html) 107 | return url 108 | 109 | def hasXYZUrl(self): 110 | return self._xyzUrl is not None 111 | 112 | def xyzUrlConfig(self): 113 | if self._xyzUrl is not None: 114 | return self._xyzUrl 115 | else: 116 | return None 117 | 118 | def coordRefSys(self, mapCoordSys): 119 | epsg = self.epsgList[0] # TODO: look for matching coord 120 | coordRefSys = QgsCoordinateReferenceSystem() 121 | createCrs = coordRefSys.createFromOgcWmsCrs("EPSG:%d" % epsg) 122 | if not createCrs: 123 | return None 124 | return coordRefSys 125 | 126 | 127 | class WebLayer3857(WebLayer): 128 | 129 | epsgList = [3857] 130 | 131 | MAX_ZOOM_LEVEL = 15 132 | SCALE_ON_MAX_ZOOM = 13540 # QGIS scale for 72 dpi 133 | 134 | def coordRefSys(self, mapCoordSys): 135 | epsg = self.epsgList[0] 136 | coordRefSys = QgsCoordinateReferenceSystem() 137 | if QGis.QGIS_VERSION_INT >= 10900: 138 | idEpsgRSGoogle = "EPSG:%d" % epsg 139 | createCrs = coordRefSys.createFromOgcWmsCrs(idEpsgRSGoogle) 140 | else: 141 | idEpsgRSGoogle = epsg 142 | createCrs = coordRefSys.createFromEpsg(idEpsgRSGoogle) 143 | if not createCrs: 144 | google_proj_def = "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +\ 145 | lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 " 146 | google_proj_def += "+units=m +nadgrids=@null +wktext +no_defs" 147 | isOk = coordRefSys.createFromProj4(google_proj_def) 148 | if not isOk: 149 | return None 150 | return coordRefSys 151 | -------------------------------------------------------------------------------- /openlayers/weblayers/weblayer_registry.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2009-11-30 9 | copyright : (C) 2009 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | """ 22 | 23 | from .weblayer import WebLayerGroup 24 | 25 | 26 | class WebLayerTypeRegistry: 27 | """Registry of OL web Layers""" 28 | def __init__(self, plugin): 29 | self._plugin = plugin 30 | self._groups = {} 31 | self._olLayerTypes = {} 32 | self._layerTypeId = 0 # Sequence for ID 33 | self._olLayerTypeNames = {} 34 | 35 | def group(self, name, icon): 36 | """Create group and register in registry""" 37 | if name not in self._groups: 38 | self._groups[name] = WebLayerGroup(name, icon) 39 | return self._groups[name] 40 | 41 | def groups(self): 42 | return self._groups.values() 43 | 44 | def register(self, layerType): 45 | layerType.group = self.group(layerType.groupName, layerType.groupIcon) 46 | layerType.setAddLayerCallback(self._plugin.addLayer) 47 | layerType.layerTypeId = self._layerTypeId 48 | self._olLayerTypes[self._layerTypeId] = layerType 49 | self._layerTypeId += 1 50 | self._olLayerTypeNames[layerType.layerTypeName] = layerType 51 | 52 | def types(self): 53 | return self._olLayerTypes.values() 54 | 55 | def getById(self, id): 56 | if id in self._olLayerTypes: 57 | return self._olLayerTypes[id] 58 | else: 59 | return None 60 | 61 | def getByName(self, name): 62 | if name in self._olLayerTypeNames: 63 | return self._olLayerTypeNames[name] 64 | else: 65 | return None 66 | 67 | def groupLayerTypes(self, group): 68 | lst = [] 69 | for lyr in self.types(): 70 | if lyr.group == group: 71 | lst.append(lyr) 72 | return lst 73 | -------------------------------------------------------------------------------- /openlayers/weblayers/wikimedia_maps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | OpenLayers Plugin 5 | A QGIS plugin 6 | 7 | ------------------- 8 | begin : 2009-11-30 9 | copyright : (C) 2009 by Pirmin Kalberer, Sourcepole 10 | email : pka at sourcepole.ch 11 | ***************************************************************************/ 12 | 13 | /*************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | ***************************************************************************/ 21 | """ 22 | 23 | from .weblayer import WebLayer3857 24 | 25 | 26 | class WikimediaLayer(WebLayer3857): 27 | 28 | emitsLoadEnd = True 29 | 30 | def __init__(self, name, html, xyzUrl=None): 31 | WebLayer3857.__init__(self, groupName="Wikimedia Maps", 32 | groupIcon="wikimedia_icon.png", 33 | name=name, html=html, xyzUrl=xyzUrl) 34 | 35 | 36 | class WikimediaLabelledLayer(WikimediaLayer): 37 | 38 | def __init__(self): 39 | tmsUrl = 'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png' 40 | WikimediaLayer.__init__(self, name='Wikimedia labelled layer', 41 | html='wikimedia.html', xyzUrl=tmsUrl) 42 | 43 | 44 | class WikimediaUnLabelledLayer(WikimediaLayer): 45 | 46 | def __init__(self): 47 | tmsUrl = 'https://maps.wikimedia.org/osm/{z}/{x}/{y}.png' 48 | WikimediaLayer.__init__(self, name='Wikimedia unlabelled layer', 49 | html='wikimedia_nolabels.html', 50 | xyzUrl=tmsUrl) 51 | -------------------------------------------------------------------------------- /openlayers/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sourcepole/qgis-openlayers-plugin/63f05b1087507ac8ecb2b71b35073bee5ec371b4/openlayers/x.png --------------------------------------------------------------------------------