├── .gitignore
├── LICENSE
├── README.md
├── __init__.py
├── add_connection_dialog.py
├── add_connection_dialog_base.ui
├── browser_mapitem.py
├── browser_root_collection.py
├── configure_dialog.py
├── configure_dialog_base.ui
├── data
├── background.geojson
├── icons
│ ├── bright
│ │ ├── road_1.svg
│ │ ├── road_2.svg
│ │ ├── road_3.svg
│ │ ├── road_4.svg
│ │ ├── road_5.svg
│ │ ├── road_6.svg
│ │ ├── us-highway_1.svg
│ │ ├── us-highway_2.svg
│ │ ├── us-highway_3.svg
│ │ ├── us-interstate_1.svg
│ │ ├── us-interstate_2.svg
│ │ ├── us-interstate_3.svg
│ │ ├── us-interstate_4.svg
│ │ ├── us-interstate_5.svg
│ │ ├── us-state_1.svg
│ │ ├── us-state_2.svg
│ │ ├── us-state_3.svg
│ │ ├── us-state_4.svg
│ │ ├── us-state_5.svg
│ │ └── us-state_6.svg
│ ├── default_1.svg
│ ├── default_2.svg
│ ├── default_3.svg
│ ├── default_4.svg
│ ├── default_5.svg
│ ├── default_6.svg
│ ├── road_1.svg
│ ├── road_2.svg
│ ├── road_3.svg
│ ├── road_4.svg
│ ├── road_5.svg
│ ├── road_6.svg
│ ├── road_motorway.svg
│ ├── road_primary.svg
│ ├── road_secondary.svg
│ ├── road_tertiary.svg
│ ├── us-highway_1.svg
│ ├── us-highway_2.svg
│ ├── us-highway_3.svg
│ ├── us-interstate_1.svg
│ ├── us-interstate_2.svg
│ ├── us-interstate_3.svg
│ ├── us-interstate_4.svg
│ ├── us-interstate_5.svg
│ ├── us-state_1.svg
│ ├── us-state_2.svg
│ ├── us-state_3.svg
│ ├── us-state_4.svg
│ ├── us-state_5.svg
│ └── us-state_6.svg
├── ocean-color-ramp.txt
└── terrain-color-ramp.txt
├── edit_connection_dialog.py
├── edit_connection_dialog_base.ui
├── geocoder.py
├── gl2qgis
├── __init__.py
├── converter.py
└── gl2qgis.py
├── imgs
├── icon_account_dark.svg
├── icon_account_light.svg
├── icon_maps_dark.svg
├── icon_maps_light.svg
├── icon_maptiler.svg
├── logo_maptiler_dark.svg
├── logo_maptiler_light.svg
├── readme_01.png
├── readme_02.png
├── readme_03.png
├── readme_04.png
├── readme_06.png
├── readme_07.png
├── readme_08.png
├── readme_09.png
├── readme_10.gif
├── readme_11.png
├── readme_12.png
├── readme_13.gif
└── readme_14.png
├── mapdatasets.py
├── maptiler.py
├── metadata.txt
├── settings_manager.py
└── utils.py
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 | .DS_Store
3 | gl2qgis/sprites/
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | /***************************************************************************
4 | MapTiler
5 | A QGIS plugin
6 | Show MapTiler cloud maps.
7 | Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
8 | -------------------
9 | begin : 2020-04-02
10 | copyright : (C) 2020 by MapTiler AG
11 | email : sales@maptiler.com
12 | git sha : $Format:%H$
13 | ***************************************************************************/
14 |
15 | /***************************************************************************
16 | * *
17 | * This program is free software; you can redistribute it and/or modify *
18 | * it under the terms of the GNU General Public License as published by *
19 | * the Free Software Foundation; either version 2 of the License, or *
20 | * (at your option) any later version. *
21 | * *
22 | ***************************************************************************/
23 | This script initializes the plugin, making it known to QGIS.
24 | """
25 |
26 |
27 | # noinspection PyPep8Naming
28 | def classFactory(iface): # pylint: disable=invalid-name
29 | """Load MapTiler class from file MapTiler.
30 |
31 | :param iface: A QGIS interface instance.
32 | :type iface: QgsInterface
33 | """
34 | #
35 | from .maptiler import MapTiler
36 | return MapTiler(iface)
37 |
--------------------------------------------------------------------------------
/add_connection_dialog.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from qgis.PyQt import uic, QtWidgets, QtCore
4 | import os
5 |
6 | from .settings_manager import SettingsManager
7 | from . import mapdatasets
8 |
9 |
10 | class AddConnectionDialog(QtWidgets.QDialog):
11 |
12 | STANDARD_DATASET = mapdatasets.STANDARD_DATASET
13 | LOCAL_JP_DATASET = mapdatasets.LOCAL_JP_DATASET
14 | LOCAL_NL_DATASET = mapdatasets.LOCAL_NL_DATASET
15 | LOCAL_UK_DATASET = mapdatasets.LOCAL_UK_DATASET
16 |
17 | def __init__(self):
18 | super().__init__()
19 | self.ui = uic.loadUi(os.path.join(os.path.dirname(
20 | __file__), 'add_connection_dialog_base.ui'), self)
21 |
22 | self._init_list()
23 | self.ui.button_box.accepted.connect(self._accepted)
24 | self.ui.button_box.rejected.connect(self._rejected)
25 |
26 | def _init_list(self):
27 | # support multiple selection
28 | self.ui.listWidget.setSelectionMode(
29 | QtWidgets.QAbstractItemView.ExtendedSelection)
30 |
31 | DATASETS = dict(**self.STANDARD_DATASET,
32 | **self.LOCAL_JP_DATASET,
33 | **self.LOCAL_NL_DATASET,
34 | **self.LOCAL_UK_DATASET
35 | )
36 |
37 | smanager = SettingsManager()
38 | selectedmaps = smanager.get_setting('selectedmaps')
39 | for key in DATASETS:
40 | if key in selectedmaps:
41 | continue
42 | self.ui.listWidget.addItem(key)
43 |
44 | def _maptiler_tab_action(self):
45 | selecteditems = self.ui.listWidget.selectedItems()
46 |
47 | smanager = SettingsManager()
48 | selectedmaps = smanager.get_setting('selectedmaps')
49 |
50 | for item in selecteditems:
51 | # this lines is not runned in normal
52 | if item.text() in selectedmaps:
53 | print('Selected map already exist in Browser')
54 | return
55 |
56 | selectedmaps.append(item.text())
57 | smanager.store_setting('selectedmaps', selectedmaps)
58 |
59 | def _custom_tab_action(self):
60 | name = self.ui.nameLineEdit.text()
61 | json_url = self.ui.jsonLineEdit.text()
62 |
63 | smanager = SettingsManager()
64 | if self._has_error():
65 | return
66 |
67 | custommaps = smanager.get_setting('custommaps')
68 | custommaps[name] = {
69 | 'custom': json_url
70 | }
71 | smanager.store_setting('custommaps', custommaps)
72 |
73 | def _accepted(self):
74 | if self.ui.tabWidget.currentIndex() == 0:
75 | self._maptiler_tab_action()
76 | else:
77 | self._custom_tab_action()
78 | self.close()
79 |
80 | def _rejected(self):
81 | self.close()
82 |
83 | def _has_error(self):
84 | name = self.ui.nameLineEdit.text()
85 | json_url = self.ui.jsonLineEdit.text()
86 |
87 | is_empty_name = False
88 | is_empty_url = False
89 | is_existing_name = False
90 | error_message = ''
91 |
92 | if name == '':
93 | is_empty_name = True
94 | error_message += 'Name is empty, please input.\n'
95 |
96 | if json_url == '':
97 | is_empty_url = True
98 | error_message += 'Url to map is empty, please input.\n'
99 |
100 | smanager = SettingsManager()
101 | custommaps = smanager.get_setting('custommaps')
102 | if name in custommaps:
103 | is_existing_name = True
104 | error_message += str('"' + name + '"' +
105 | ' already exists, please input other name.\n')
106 |
107 | if is_empty_name or is_empty_url or is_existing_name:
108 | QtWidgets.QMessageBox.warning(None, 'Error', error_message)
109 | return True
110 |
--------------------------------------------------------------------------------
/add_connection_dialog_base.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | newConnectionDialogBase
4 |
5 |
6 |
7 | 0
8 | 0
9 | 500
10 | 500
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 |
21 | 500
22 | 500
23 |
24 |
25 |
26 |
27 | 500
28 | 500
29 |
30 |
31 |
32 | Add a new map...
33 |
34 |
35 | -
36 |
37 |
38 |
39 | 0
40 | 0
41 |
42 |
43 |
44 |
45 | 0
46 | 0
47 |
48 |
49 |
50 | 0
51 |
52 |
53 |
54 | MapTiler Cloud
55 |
56 |
57 |
-
58 |
59 |
60 |
61 | 0
62 | 0
63 |
64 |
65 |
66 |
67 | 0
68 | 0
69 |
70 |
71 |
72 |
73 | 50
74 | false
75 |
76 |
77 |
78 | Select a map from MapTiler Cloud.
79 |
80 |
81 |
82 | -
83 |
84 |
85 |
86 |
87 |
88 |
89 | From URL
90 |
91 |
92 | -
93 |
94 |
95 | Name
96 |
97 |
98 |
99 | -
100 |
101 |
102 | 50
103 |
104 |
105 |
106 | -
107 |
108 |
109 |
110 | 0
111 | 0
112 |
113 |
114 |
115 |
116 | 0
117 | 0
118 |
119 |
120 |
121 | Add a link to vector style (GL JSON format) or raster TileJSON.
122 |
123 |
124 | true
125 |
126 |
127 |
128 | -
129 |
130 |
131 | 200
132 |
133 |
134 |
135 | -
136 |
137 |
138 | JSON URL
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 | -
147 |
148 |
149 | Qt::Horizontal
150 |
151 |
152 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------
/browser_root_collection.py:
--------------------------------------------------------------------------------
1 | import os
2 | from qgis.PyQt import sip
3 | from qgis.PyQt.QtGui import QIcon
4 | from qgis.PyQt.QtWidgets import QAction
5 | from qgis.core import *
6 |
7 | from .browser_mapitem import MapDataItem
8 | from .add_connection_dialog import AddConnectionDialog
9 | from .configure_dialog import ConfigureDialog
10 | from .settings_manager import SettingsManager
11 | from . import mapdatasets
12 |
13 | IMGS_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "imgs")
14 |
15 |
16 | class DataItemProvider(QgsDataItemProvider):
17 | def __init__(self):
18 | QgsDataItemProvider.__init__(self)
19 |
20 | def name(self):
21 | return "MapTilerProvider"
22 |
23 | def capabilities(self):
24 | return QgsDataProvider.Net
25 |
26 | def createDataItem(self, path, parentItem):
27 | root = RootCollection()
28 | sip.transferto(root, None)
29 | return root
30 |
31 |
32 | class RootCollection(QgsDataCollectionItem):
33 | STANDARD_DATASET = mapdatasets.STANDARD_DATASET
34 | LOCAL_JP_DATASET = mapdatasets.LOCAL_JP_DATASET
35 | LOCAL_NL_DATASET = mapdatasets.LOCAL_NL_DATASET
36 | LOCAL_UK_DATASET = mapdatasets.LOCAL_UK_DATASET
37 |
38 | def __init__(self):
39 | QgsDataCollectionItem.__init__(self, None, "MapTiler", "/MapTiler")
40 |
41 | self.setIcon(QIcon(os.path.join(IMGS_PATH, "icon_maptiler.svg")))
42 |
43 | def createChildren(self):
44 | children = []
45 |
46 | DATASETS = dict(**self.STANDARD_DATASET,
47 | **self.LOCAL_JP_DATASET,
48 | **self.LOCAL_NL_DATASET,
49 | **self.LOCAL_UK_DATASET,
50 | )
51 | smanager = SettingsManager()
52 | selectedmaps = smanager.get_setting('selectedmaps')
53 |
54 | for key in DATASETS:
55 | if not key in selectedmaps:
56 | continue
57 | md_item = MapDataItem(self, key, DATASETS[key])
58 | sip.transferto(md_item, self)
59 | children.append(md_item)
60 |
61 | custommaps = smanager.get_setting('custommaps')
62 | for key in custommaps:
63 | md_item = MapDataItem(self, key,
64 | custommaps[key], editable=True)
65 | sip.transferto(md_item, self)
66 | children.append(md_item)
67 |
68 | return children
69 |
70 | def actions(self, parent):
71 | actions = []
72 |
73 | add_action = QAction(QIcon(), 'Add a new map...', parent)
74 | add_action.triggered.connect(self._open_add_dialog)
75 | actions.append(add_action)
76 |
77 | configure_action = QAction(QIcon(), 'Account...', parent)
78 | configure_action.triggered.connect(self._open_configure_dialog)
79 | actions.append(configure_action)
80 |
81 | return actions
82 |
83 | def _open_add_dialog(self):
84 | add_dialog = AddConnectionDialog()
85 | add_dialog.exec()
86 | self.refreshConnections()
87 |
88 | def _open_configure_dialog(self):
89 | configure_dialog = ConfigureDialog()
90 | configure_dialog.exec()
91 | self.refreshConnections()
92 |
--------------------------------------------------------------------------------
/configure_dialog.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import os
4 |
5 | from qgis.PyQt import uic, QtWidgets, QtGui
6 | from qgis.core import Qgis, QgsAuthMethodConfig, QgsApplication
7 | from qgis.PyQt.QtWidgets import QMessageBox
8 |
9 | from .settings_manager import SettingsManager
10 | from . import utils
11 |
12 |
13 | def _token_format_valid(token):
14 | if "_" in token:
15 | parts = token.split("_")
16 | if len(parts) == 2:
17 | if len(parts[0]) == 32 and len(parts[1]) >= 64:
18 | return True
19 | return False
20 |
21 |
22 | class ConfigureDialog(QtWidgets.QDialog):
23 | def __init__(self):
24 | super().__init__()
25 |
26 | self.ui = uic.loadUi(os.path.join(os.path.dirname(
27 | __file__), 'configure_dialog_base.ui'), self)
28 |
29 | self.ui.button_box.accepted.connect(self._accepted)
30 | self.ui.button_box.rejected.connect(self._rejected)
31 |
32 | # Load saved token
33 | smanager = SettingsManager()
34 | auth_cfg_id = smanager.get_setting('auth_cfg_id')
35 | if auth_cfg_id:
36 | am = QgsApplication.authManager()
37 | cfg = QgsAuthMethodConfig()
38 | am.loadAuthenticationConfig(auth_cfg_id, cfg, True)
39 | token = cfg.configMap().get("token")
40 | self.ui.token_txt.setText(token)
41 |
42 | # e.g. QGIS3.10.4 -> 31004
43 | qgis_version_str = str(Qgis.QGIS_VERSION_INT)
44 | #major_ver = int(qgis_version_str[0])
45 | minor_ver = int(qgis_version_str[1:3])
46 | #micro_ver = int(qgis_version_str[3:])
47 |
48 | # Checkbox are available only when on QGIS version having feature of Vectortile
49 | if minor_ver > 12:
50 | self.ui.vtileCheckBox.setEnabled(True)
51 | prefervector = bool(int(smanager.get_setting('prefervector')))
52 | self.ui.vtileCheckBox.setChecked(prefervector)
53 |
54 | # when OS in darkmode change icon to darkmode one
55 | if utils.is_in_darkmode():
56 | darkmode_icon_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
57 | "imgs",
58 | "logo_maptiler_dark.svg")
59 | pixmap = QtGui.QPixmap(darkmode_icon_path)
60 | self.ui.label_2.setPixmap(pixmap)
61 |
62 | def _accepted(self):
63 | # get and store UI values
64 | token = self.ui.token_txt.text()
65 | if token:
66 | cfg = QgsAuthMethodConfig('MapTilerHmacSha256')
67 | if _token_format_valid(token):
68 | smanager = SettingsManager()
69 | am = QgsApplication.authManager()
70 | auth_cfg_id = smanager.get_setting('auth_cfg_id')
71 | if auth_cfg_id:
72 | (res, cfg) = am.loadAuthenticationConfig(auth_cfg_id, cfg, True)
73 | if res:
74 | saved_token = cfg.configMap().get("token")
75 | if not saved_token == token:
76 | cfg.setConfigMap({'token': token})
77 | (res, cfg) = am.storeAuthenticationConfig(cfg, True)
78 | if res:
79 | smanager.store_setting('auth_cfg_id', cfg.id())
80 | else:
81 | cfg.setName('qgis-maptiler-plugin')
82 | cfg.setConfigMap({'token': token})
83 | (res, cfg) = am.storeAuthenticationConfig(cfg, True)
84 | if res:
85 | smanager.store_setting('auth_cfg_id', cfg.id())
86 | else:
87 | cfg.setName('qgis-maptiler-plugin')
88 | cfg.setConfigMap({'token': token})
89 | (res, cfg) = am.storeAuthenticationConfig(cfg, True)
90 | if res:
91 | smanager.store_setting('auth_cfg_id', cfg.id())
92 | prefervector = str(int(self.ui.vtileCheckBox.isChecked()))
93 | smanager.store_setting('prefervector', prefervector)
94 | self.close()
95 | else:
96 | self.ui.label_6.setText(f"Not a valid token format. (Use token, not API key.)")
97 | else:
98 | self.ui.label_6.setText(f"Token is required.")
99 |
100 | def _rejected(self):
101 | self.close()
102 |
--------------------------------------------------------------------------------
/configure_dialog_base.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MapTilerConfigureDialogBase
4 |
5 |
6 |
7 | 0
8 | 0
9 | 300
10 | 226
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 |
21 | 0
22 | 0
23 |
24 |
25 |
26 |
27 | 300
28 | 226
29 |
30 |
31 |
32 | MapTiler Account
33 |
34 |
35 | -
36 |
37 |
38 |
39 | 0
40 | 0
41 |
42 |
43 |
44 |
45 | 300
46 | 80
47 |
48 |
49 |
50 |
51 |
52 |
53 | Qt::RichText
54 |
55 |
56 | imgs/logo_maptiler_light.svg
57 |
58 |
59 | true
60 |
61 |
62 |
63 | -
64 |
65 |
66 | Account Settings
67 |
68 |
69 |
70 | -
71 |
72 |
-
73 |
74 |
75 | Token
76 |
77 |
78 |
79 | -
80 |
81 |
82 | true
83 |
84 |
85 | 100
86 |
87 |
88 |
89 |
90 |
91 | -
92 |
93 |
94 |
95 |
96 |
97 |
98 | -
99 |
100 |
101 | Get FREE credentials at:
102 |
103 |
104 |
105 | -
106 |
107 |
108 | <a href="https://maptiler.link/qgiscredentials"><span style=" text-decoration: underline; color:#419cff;">https://cloud.maptiler.com/account/credentials/</span></a></p></body></html>
109 |
110 |
111 | Qt::RichText
112 |
113 |
114 | true
115 |
116 |
117 |
118 | -
119 |
120 |
121 | false
122 |
123 |
124 | Use vector tiles by default (requires QGIS 3.14+)
125 |
126 |
127 |
128 | -
129 |
130 |
131 | <html><head/><body><p>Read more <a href="https://maptiler.link/qgisplugin"><span style=" text-decoration: underline; color:#419cff;">about this plugin.</span></a></p></body></html>
132 |
133 |
134 | true
135 |
136 |
137 |
138 | -
139 |
140 |
141 | Qt::Horizontal
142 |
143 |
144 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/data/background.geojson:
--------------------------------------------------------------------------------
1 | {
2 | "type": "FeatureCollection",
3 | "name": "background",
4 | "crs": {
5 | "type": "name",
6 | "properties": {
7 | "name": "urn:ogc:def:crs:EPSG::3857"
8 | }
9 | },
10 | "features": [
11 | {
12 | "type": "Feature",
13 | "properties": {
14 | "fid": 1
15 | },
16 | "geometry": {
17 | "type": "Polygon",
18 | "coordinates": [
19 | [
20 | [
21 | -20037508.342789243906736,
22 | 20048966.104014594107866
23 | ],
24 | [
25 | -20037508.342789243906736,
26 | -20048966.104014601558447
27 | ],
28 | [
29 | 20037508.342789243906736,
30 | -20048966.104014601558447
31 | ],
32 | [
33 | 20037508.342789243906736,
34 | 20048966.104014594107866
35 | ],
36 | [
37 | -20037508.342789243906736,
38 | 20048966.104014594107866
39 | ]
40 | ]
41 | ]
42 | }
43 | }
44 | ]
45 | }
46 |
--------------------------------------------------------------------------------
/data/icons/bright/road_1.svg:
--------------------------------------------------------------------------------
1 |
2 |
83 |
--------------------------------------------------------------------------------
/data/icons/bright/road_2.svg:
--------------------------------------------------------------------------------
1 |
2 |
83 |
--------------------------------------------------------------------------------
/data/icons/bright/road_3.svg:
--------------------------------------------------------------------------------
1 |
2 |
82 |
--------------------------------------------------------------------------------
/data/icons/bright/road_4.svg:
--------------------------------------------------------------------------------
1 |
2 |
82 |
--------------------------------------------------------------------------------
/data/icons/bright/road_5.svg:
--------------------------------------------------------------------------------
1 |
2 |
82 |
--------------------------------------------------------------------------------
/data/icons/bright/road_6.svg:
--------------------------------------------------------------------------------
1 |
2 |
85 |
--------------------------------------------------------------------------------
/data/icons/bright/us-highway_1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
88 |
--------------------------------------------------------------------------------
/data/icons/bright/us-highway_2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
88 |
--------------------------------------------------------------------------------
/data/icons/bright/us-highway_3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
90 |
--------------------------------------------------------------------------------
/data/icons/bright/us-interstate_1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
91 |
--------------------------------------------------------------------------------
/data/icons/bright/us-interstate_2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
91 |
--------------------------------------------------------------------------------
/data/icons/bright/us-interstate_3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
103 |
--------------------------------------------------------------------------------
/data/icons/bright/us-interstate_4.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
103 |
--------------------------------------------------------------------------------
/data/icons/bright/us-interstate_5.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
103 |
--------------------------------------------------------------------------------
/data/icons/bright/us-state_1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
86 |
--------------------------------------------------------------------------------
/data/icons/bright/us-state_2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
86 |
--------------------------------------------------------------------------------
/data/icons/bright/us-state_3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
86 |
--------------------------------------------------------------------------------
/data/icons/bright/us-state_4.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
97 |
--------------------------------------------------------------------------------
/data/icons/bright/us-state_5.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
97 |
--------------------------------------------------------------------------------
/data/icons/bright/us-state_6.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
97 |
--------------------------------------------------------------------------------
/data/icons/default_1.svg:
--------------------------------------------------------------------------------
1 |
2 |
83 |
--------------------------------------------------------------------------------
/data/icons/default_2.svg:
--------------------------------------------------------------------------------
1 |
2 |
83 |
--------------------------------------------------------------------------------
/data/icons/default_3.svg:
--------------------------------------------------------------------------------
1 |
2 |
82 |
--------------------------------------------------------------------------------
/data/icons/default_4.svg:
--------------------------------------------------------------------------------
1 |
2 |
82 |
--------------------------------------------------------------------------------
/data/icons/default_5.svg:
--------------------------------------------------------------------------------
1 |
2 |
82 |
--------------------------------------------------------------------------------
/data/icons/default_6.svg:
--------------------------------------------------------------------------------
1 |
2 |
85 |
--------------------------------------------------------------------------------
/data/icons/road_1.svg:
--------------------------------------------------------------------------------
1 |
2 |
83 |
--------------------------------------------------------------------------------
/data/icons/road_2.svg:
--------------------------------------------------------------------------------
1 |
2 |
83 |
--------------------------------------------------------------------------------
/data/icons/road_3.svg:
--------------------------------------------------------------------------------
1 |
2 |
82 |
--------------------------------------------------------------------------------
/data/icons/road_4.svg:
--------------------------------------------------------------------------------
1 |
2 |
82 |
--------------------------------------------------------------------------------
/data/icons/road_5.svg:
--------------------------------------------------------------------------------
1 |
2 |
82 |
--------------------------------------------------------------------------------
/data/icons/road_6.svg:
--------------------------------------------------------------------------------
1 |
2 |
85 |
--------------------------------------------------------------------------------
/data/icons/road_motorway.svg:
--------------------------------------------------------------------------------
1 |
2 |
69 |
--------------------------------------------------------------------------------
/data/icons/us-highway_1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
88 |
--------------------------------------------------------------------------------
/data/icons/us-highway_2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
88 |
--------------------------------------------------------------------------------
/data/icons/us-highway_3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
90 |
--------------------------------------------------------------------------------
/data/icons/us-interstate_1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
--------------------------------------------------------------------------------
/data/icons/us-interstate_2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
--------------------------------------------------------------------------------
/data/icons/us-interstate_3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
--------------------------------------------------------------------------------
/data/icons/us-interstate_4.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
--------------------------------------------------------------------------------
/data/icons/us-interstate_5.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
--------------------------------------------------------------------------------
/data/icons/us-state_1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
86 |
--------------------------------------------------------------------------------
/data/icons/us-state_2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
86 |
--------------------------------------------------------------------------------
/data/icons/us-state_3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
86 |
--------------------------------------------------------------------------------
/data/icons/us-state_4.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
97 |
--------------------------------------------------------------------------------
/data/icons/us-state_5.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
97 |
--------------------------------------------------------------------------------
/data/icons/us-state_6.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
97 |
--------------------------------------------------------------------------------
/data/ocean-color-ramp.txt:
--------------------------------------------------------------------------------
1 | # QGIS Generated Color Map Export File
2 | INTERPOLATION:INTERPOLATED
3 | -12000,8,48,107,255,-12000
4 | -11500,8,62,128,255,-11500
5 | -11000,8,76,148,255,-11000
6 | -10500,13,88,161,255,-10500
7 | -10000,22,98,170,255,-10000
8 | -9500,30,110,178,255,-9500
9 | -9000,40,120,185,255,-9000
10 | -8500,51,131,190,255,-8500
11 | -8000,62,142,196,255,-8000
12 | -7500,74,151,201,255,-7500
13 | -7000,87,161,206,255,-7000
14 | -6500,100,169,211,255,-6500
15 | -6000,115,179,216,255,-6000
16 | -5500,131,187,219,255,-5500
17 | -5000,148,196,223,255,-5000
18 | -4500,159,203,226,255,-4500
19 | -4000,162,207,230,255,-4000
20 | -3500,164,211,234,255,-3500
21 | -3000,169,214,237,255,-3000
22 | -2500,177,220,240,255,-2500
23 | -2000,185,225,243,255,-2000
24 | -1500,193,231,247,255,-1500
25 | -1000,199,235,250,255,-1000
26 | -500,200,238,252,255,-500
27 | -0.1,214,246,255,255,-0
28 | 0,214,246,255,1,0
29 |
--------------------------------------------------------------------------------
/data/terrain-color-ramp.txt:
--------------------------------------------------------------------------------
1 | # QGIS Generated Color Map Export File
2 | INTERPOLATION:INTERPOLATED
3 | 0,86,162,21,0,0
4 | 0.1,86,162,21,255,0
5 | 100,106,173,30,255,100
6 | 200,126,183,40,255,200
7 | 300,146,194,50,255,300
8 | 400,166,204,60,255,400
9 | 500,186,215,70,255,500
10 | 600,206,225,80,255,600
11 | 700,226,236,90,255,700
12 | 800,246,245,99,255,800
13 | 900,255,247,101,255,900
14 | 1000,255,242,96,255,1000
15 | 1100,255,237,91,255,1100
16 | 1200,255,232,86,255,1200
17 | 1300,255,226,81,255,1300
18 | 1400,255,221,76,255,1400
19 | 1500,255,217,72,255,1500
20 | 1600,255,211,68,255,1600
21 | 1700,255,206,63,255,1700
22 | 1800,255,201,58,255,1800
23 | 1900,255,195,53,255,1900
24 | 2000,255,190,48,255,2000
25 | 2100,255,185,43,255,2100
26 | 2200,254,180,39,255,2200
27 | 2300,251,176,37,255,2300
28 | 2400,246,173,37,255,2400
29 | 2500,241,169,37,255,2500
30 | 2600,237,165,36,255,2600
31 | 2700,232,162,36,255,2700
32 | 2800,227,158,36,255,2800
33 | 2900,222,155,35,255,2900
34 | 3000,217,152,35,255,3000
35 | 3100,212,148,35,255,3100
36 | 3200,207,144,34,255,3200
37 | 3300,203,141,34,255,3300
38 | 3400,198,137,33,255,3400
39 | 3500,193,134,33,255,3500
40 | 3600,188,131,33,255,3600
41 | 3700,183,127,32,255,3700
42 | 3800,178,123,32,255,3800
43 | 3900,173,120,32,255,3900
44 | 4000,168,117,31,255,4000
45 | 4100,164,113,31,255,4100
46 | 4200,159,109,30,255,4200
47 | 4300,154,106,30,255,4300
48 | 4400,149,102,30,255,4400
49 | 4500,147,101,31,255,4500
50 | 4600,149,104,36,255,4600
51 | 4700,151,108,41,255,4700
52 | 4800,154,111,46,255,4800
53 | 4900,156,114,51,255,4900
54 | 5000,159,118,56,255,5000
55 | 5100,161,122,61,255,5100
56 | 5200,164,125,66,255,5200
57 | 5300,166,128,71,255,5300
58 | 5400,168,132,76,255,5400
59 | 5500,171,135,81,255,5500
60 | 5600,173,138,86,255,5600
61 | 5700,176,142,91,255,5700
62 | 5800,178,146,96,255,5800
63 | 5900,181,149,101,255,5900
64 | 6000,183,153,106,255,6000
65 | 6100,185,156,111,255,6100
66 | 6200,188,159,116,255,6200
67 | 6300,190,163,121,255,6300
68 | 6400,193,166,126,255,6400
69 | 6500,195,169,131,255,6500
70 | 6600,198,174,136,255,6600
71 | 6700,200,177,141,255,6700
72 | 6800,203,180,146,255,6800
73 | 6900,204,183,151,255,6900
74 | 7000,207,187,156,255,7000
75 | 7100,210,190,161,255,7100
76 | 7200,212,193,166,255,7200
77 | 7300,215,197,171,255,7300
78 | 7400,217,200,176,255,7400
79 | 7500,219,204,181,255,7500
80 | 7600,222,208,185,255,7600
81 | 7700,224,211,190,255,7700
82 | 7800,226,214,195,255,7800
83 | 7900,229,218,200,255,7900
84 | 8000,231,221,205,255,8000
85 | 8100,234,224,210,255,8100
86 | 8200,236,228,215,255,8200
87 | 8300,238,232,220,255,8300
88 | 8400,241,235,225,255,8400
89 | 8500,243,238,230,255,8500
90 | 8600,246,242,235,255,8600
91 | 8700,248,245,240,255,8700
92 | 8800,251,248,245,255,8800
93 | 8900,253,252,250,255,8900
94 | 9000,255,255,255,255,9000
95 |
--------------------------------------------------------------------------------
/edit_connection_dialog.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from qgis.PyQt import uic, QtWidgets
4 | import os
5 |
6 | from .settings_manager import SettingsManager
7 |
8 |
9 | class EditConnectionDialog(QtWidgets.QDialog):
10 | def __init__(self, current_name):
11 | super().__init__()
12 | self.ui = uic.loadUi(os.path.join(os.path.dirname(
13 | __file__), 'edit_connection_dialog_base.ui'), self)
14 | self.ui.button_box.accepted.connect(self._accepted)
15 | self.ui.button_box.rejected.connect(self._rejected)
16 |
17 | self._current_name = current_name
18 | smanager = SettingsManager()
19 | custommaps = smanager.get_setting('custommaps')
20 | self._current_data = custommaps[self._current_name]
21 |
22 | self.ui.nameLineEdit.setText(self._current_name)
23 | self.ui.jsonLineEdit.setText(self._current_data['custom'])
24 |
25 | def _accepted(self):
26 | name = self.ui.nameLineEdit.text()
27 | json_url = self.ui.jsonLineEdit.text()
28 | smanager = SettingsManager()
29 |
30 | if self._has_error():
31 | return
32 |
33 | custommaps = smanager.get_setting('custommaps')
34 | del custommaps[self._current_name]
35 | custommaps[name] = {
36 | 'custom': json_url,
37 | }
38 | smanager.store_setting('custommaps', custommaps)
39 | self.close()
40 |
41 | def _rejected(self):
42 | self.close()
43 |
44 | def _has_error(self):
45 | name = self.ui.nameLineEdit.text()
46 | json_url = self.ui.jsonLineEdit.text()
47 |
48 | is_empty_name = False
49 | is_empty_url = False
50 | is_existing_name = False
51 | error_message = ''
52 |
53 | if name == '':
54 | is_empty_name = True
55 | error_message += 'Name is empty, please input.\n'
56 |
57 | if json_url == '':
58 | is_empty_url = True
59 | error_message += 'Url to map is empty, please input.\n'
60 |
61 | smanager = SettingsManager()
62 | custommaps = smanager.get_setting('custommaps')
63 | if not name == self._current_name and name in custommaps:
64 | is_existing_name = True
65 | error_message += str('"' + name + '"' +
66 | ' already exists, please input other name.\n')
67 |
68 | if is_empty_name or is_empty_url or is_existing_name:
69 | QtWidgets.QMessageBox.warning(None, 'Error', error_message)
70 | return True
71 |
--------------------------------------------------------------------------------
/edit_connection_dialog_base.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | editConnectionDialogBase
4 |
5 |
6 |
7 | 0
8 | 0
9 | 506
10 | 191
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 |
21 | 0
22 | 0
23 |
24 |
25 |
26 |
27 | 16777215
28 | 16777215
29 |
30 |
31 |
32 | Edit Connection
33 |
34 |
35 | -
36 |
37 |
38 |
39 | 0
40 | 0
41 |
42 |
43 |
44 |
45 | 0
46 | 25
47 |
48 |
49 |
50 | Load map from MapTiler Cloud. Add url to style for map or TileJSON url for raster mode of a plugin.
51 |
52 |
53 | true
54 |
55 |
56 |
57 | -
58 |
59 |
-
60 |
61 |
62 |
63 | 0
64 | 0
65 |
66 |
67 |
68 | Name
69 |
70 |
71 |
72 | -
73 |
74 |
75 | true
76 |
77 |
78 |
79 | 0
80 | 0
81 |
82 |
83 |
84 | URL to map
85 |
86 |
87 |
88 | -
89 |
90 |
91 | true
92 |
93 |
94 |
95 | 0
96 | 0
97 |
98 |
99 |
100 |
101 | 400
102 | 0
103 |
104 |
105 |
106 |
107 | 16777215
108 | 16777215
109 |
110 |
111 |
112 | 200
113 |
114 |
115 |
116 | -
117 |
118 |
119 | true
120 |
121 |
122 |
123 | 0
124 | 0
125 |
126 |
127 |
128 |
129 | 400
130 | 0
131 |
132 |
133 |
134 |
135 | 16777215
136 | 16777215
137 |
138 |
139 |
140 |
141 |
142 |
143 | 200
144 |
145 |
146 |
147 |
148 |
149 | -
150 |
151 |
152 | Qt::Horizontal
153 |
154 |
155 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
--------------------------------------------------------------------------------
/geocoder.py:
--------------------------------------------------------------------------------
1 | import json
2 | import urllib
3 |
4 |
5 | from qgis.PyQt.QtCore import Qt, QModelIndex, QSettings
6 | from qgis.PyQt.QtWidgets import QCompleter, QLineEdit, QMessageBox
7 | from qgis.core import *
8 |
9 | from .configure_dialog import ConfigureDialog
10 | from .settings_manager import SettingsManager
11 | from . import utils
12 |
13 |
14 | class MapTilerGeocoder:
15 | def __init__(self, language='en'):
16 | self._language = language
17 |
18 | def geocoding(self, searchword, center_lonlat):
19 | if not utils.validate_credentials():
20 | QMessageBox.warning(None, 'Access Error', '\nAccess error occurred. \nPlease Confirm your Credentials.')
21 | self._openConfigureDialog()
22 | return
23 |
24 | proximity = '%s,%s' % (str(center_lonlat[0]), str(center_lonlat[1]))
25 | params = {
26 | 'proximity': proximity,
27 | 'language': self._language
28 | }
29 | p = urllib.parse.urlencode(params, safe=',')
30 | query = urllib.parse.quote(searchword)
31 | url = f"https://api.maptiler.com/geocoding/{query}.json?{p}"
32 | geojson_dict = utils.qgis_request_json(url)
33 |
34 | return geojson_dict
35 |
36 | def _openConfigureDialog(self):
37 | configure_dialog = ConfigureDialog()
38 | configure_dialog.exec()
39 |
40 |
41 | class MapTilerGeocoderToolbar:
42 | def __init__(self, iface):
43 | # TODO: We are going to let the user set this up in a future iteration
44 | self.iface = iface
45 | self.proj = QgsProject.instance()
46 | self.toolbar = self.iface.addToolBar(u'MapTiler')
47 | self.toolbar.setObjectName(u'MapTiler')
48 |
49 | # init QCompleter
50 | self.completer = QCompleter([])
51 | self.completer.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
52 | self.completer.setMaxVisibleItems(30)
53 | self.completer.setModelSorting(QCompleter.ModelSorting.UnsortedModel)
54 | self.completer.setCompletionMode(QCompleter.CompletionMode.UnfilteredPopupCompletion)
55 | self.completer.activated[QModelIndex].connect(self.on_result_clicked)
56 |
57 | # init LineEdit of searchword
58 | self.search_line_edit = QLineEdit()
59 | self.search_line_edit.setPlaceholderText('MapTiler Geocoding API')
60 | self.search_line_edit.setMaximumWidth(300)
61 | self.search_line_edit.setClearButtonEnabled(True)
62 | self.search_line_edit.setCompleter(self.completer)
63 | self.search_line_edit.textEdited.connect(self.on_searchword_edited)
64 | self.search_line_edit.returnPressed.connect(
65 | self.on_searchword_returned)
66 | self.toolbar.addWidget(self.search_line_edit)
67 |
68 | # LineEdit edited event
69 | def on_searchword_edited(self):
70 | model = self.completer.model()
71 | model.setStringList([])
72 | self.completer.complete()
73 |
74 | # LineEdit returned event
75 | def on_searchword_returned(self):
76 | searchword = self.search_line_edit.text()
77 | geojson_dict = self._fetch_geocoding_api(searchword)
78 |
79 | # always dict is None when apikey invalid
80 | if geojson_dict is None:
81 | return
82 |
83 | self.result_features = geojson_dict['features']
84 |
85 | result_list = []
86 | for feature in self.result_features:
87 | result_list.append('%s:%s' %
88 | (feature['text'], feature['place_name']))
89 |
90 | model = self.completer.model()
91 | model.setStringList(result_list)
92 | self.completer.complete()
93 |
94 | def _fetch_geocoding_api(self, searchword):
95 | # get a center point of MapCanvas
96 | center = self.iface.mapCanvas().center()
97 | center_as_qgspoint = QgsPoint(center.x(), center.y())
98 |
99 | # transform the center point to EPSG:4326
100 | target_crs = QgsCoordinateReferenceSystem('EPSG:4326')
101 | transform = QgsCoordinateTransform(
102 | self.proj.crs(), target_crs, self.proj)
103 | center_as_qgspoint.transform(transform)
104 | center_lonlat = [center_as_qgspoint.x(), center_as_qgspoint.y()]
105 |
106 | # start Geocoding
107 | locale = 'en'
108 | global_locale = QSettings().value('locale/globalLocale')
109 | if global_locale:
110 | locale = global_locale[0:2]
111 | else:
112 | user_locale = QSettings().value('locale/userLocale')
113 | if user_locale:
114 | locale = user_locale[0:2]
115 |
116 | geocoder = MapTilerGeocoder(locale)
117 | geojson_dict = geocoder.geocoding(searchword, center_lonlat)
118 | return geojson_dict
119 |
120 | def on_result_clicked(self, result_index):
121 | # add selected feature to Project
122 | selected_feature = self.result_features[result_index.row()]
123 |
124 | extent_rect = QgsRectangle()
125 | current_crs = QgsCoordinateReferenceSystem()
126 |
127 | bbox = selected_feature.get("bbox")
128 | geometry_type = selected_feature.get("geometry", {}).get("type")
129 |
130 | if bbox:
131 | extent_rect = QgsRectangle(bbox[0], bbox[1], bbox[2], bbox[3])
132 | current_crs = QgsCoordinateReferenceSystem("EPSG:4326")
133 | elif geometry_type == "GeometryCollection":
134 | geometries = selected_feature.get("geometries")
135 | if geometries is None:
136 | print("invalid GeoJSON")
137 | return
138 | tmp_geojson = {
139 | "type": "Feature",
140 | "geometry": geometries[0]
141 | }
142 | geojson_str = json.dumps(tmp_geojson)
143 | vlayer = QgsVectorLayer(geojson_str, 'tmp', 'ogr')
144 | extent_rect = vlayer.extent()
145 | current_crs = vlayer.sourceCrs()
146 | else:
147 | geojson_str = json.dumps(selected_feature)
148 | vlayer = QgsVectorLayer(geojson_str, 'tmp', 'ogr')
149 | extent_rect = vlayer.extent()
150 | current_crs = vlayer.sourceCrs()
151 |
152 | extent_leftbottom = QgsPoint(
153 | extent_rect.xMinimum(), extent_rect.yMinimum())
154 | extent_righttop = QgsPoint(
155 | extent_rect.xMaximum(), extent_rect.yMaximum())
156 |
157 | # transform 2points to project CRS
158 | target_crs = self.proj.crs()
159 | transform = QgsCoordinateTransform(current_crs, target_crs, self.proj)
160 | extent_leftbottom.transform(transform)
161 | extent_righttop.transform(transform)
162 |
163 | # make rectangle same to new extent by transformed 2points
164 | extent_rect = QgsRectangle(extent_leftbottom.x(), extent_leftbottom.y(),
165 | extent_righttop.x(), extent_righttop.y())
166 |
167 | self.iface.mapCanvas().zoomToFeatureExtent(extent_rect)
168 |
--------------------------------------------------------------------------------
/gl2qgis/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/gl2qgis/__init__.py
--------------------------------------------------------------------------------
/imgs/icon_account_dark.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/imgs/icon_account_light.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/imgs/icon_maps_dark.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/imgs/icon_maps_light.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/imgs/icon_maptiler.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/imgs/logo_maptiler_dark.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/imgs/logo_maptiler_light.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/imgs/readme_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_01.png
--------------------------------------------------------------------------------
/imgs/readme_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_02.png
--------------------------------------------------------------------------------
/imgs/readme_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_03.png
--------------------------------------------------------------------------------
/imgs/readme_04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_04.png
--------------------------------------------------------------------------------
/imgs/readme_06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_06.png
--------------------------------------------------------------------------------
/imgs/readme_07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_07.png
--------------------------------------------------------------------------------
/imgs/readme_08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_08.png
--------------------------------------------------------------------------------
/imgs/readme_09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_09.png
--------------------------------------------------------------------------------
/imgs/readme_10.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_10.gif
--------------------------------------------------------------------------------
/imgs/readme_11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_11.png
--------------------------------------------------------------------------------
/imgs/readme_12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_12.png
--------------------------------------------------------------------------------
/imgs/readme_13.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_13.gif
--------------------------------------------------------------------------------
/imgs/readme_14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maptiler/qgis-maptiler-plugin/db79cf1b6cb496a3586f2d40b489f446ed19af79/imgs/readme_14.png
--------------------------------------------------------------------------------
/mapdatasets.py:
--------------------------------------------------------------------------------
1 | STANDARD_DATASET = {
2 | 'Basic': {
3 | 'raster': r'https://api.maptiler.com/maps/basic/256/tiles.json',
4 | 'vector': r'https://api.maptiler.com/maps/basic/style.json',
5 | 'customize_url': r'https://maptiler.link/qgisbasic'
6 | },
7 | 'Bright': {
8 | 'raster': r'https://api.maptiler.com/maps/bright/256/tiles.json',
9 | 'vector': r'https://api.maptiler.com/maps/bright/style.json',
10 | 'customize_url': r'https://maptiler.link/qgisbright'
11 | },
12 | 'Cadastre': {
13 | 'raster': r'https://api.maptiler.com/maps/cadastre/256/tiles.json',
14 | 'vector': r'https://api.maptiler.com/maps/cadastre/style.json',
15 | 'customize_url': r'https://maptiler.link/qgiscadastre'
16 | },
17 | 'Cadastre Satellite': {
18 | 'raster': r'https://api.maptiler.com/maps/cadastre-satellite/256/tiles.json',
19 | 'vector': r'https://api.maptiler.com/maps/cadastre-satellite/style.json',
20 | 'customize_url': r'https://maptiler.link/qgiscadsatellite'
21 | },
22 | 'Dark Matter': {
23 | 'raster': r'https://api.maptiler.com/maps/darkmatter/256/tiles.json',
24 | 'vector': r'https://api.maptiler.com/maps/darkmatter/style.json',
25 | 'customize_url': r'https://maptiler.link/qgisdarkmatter'
26 | },
27 | 'Dataviz': {
28 | 'raster': r'https://api.maptiler.com/maps/dataviz/256/tiles.json',
29 | 'vector': r'https://api.maptiler.com/maps/dataviz/style.json',
30 | 'customize_url': r'https://maptiler.link/qgisdataviz'
31 | },
32 | 'Dataviz Dark': {
33 | 'raster': r'https://api.maptiler.com/maps/dataviz-dark/256/tiles.json',
34 | 'vector': r'https://api.maptiler.com/maps/dataviz-dark/style.json',
35 | 'customize_url': r'https://maptiler.link/qgisdatavizdark'
36 | },
37 | 'Dataviz Light': {
38 | 'raster': r'https://api.maptiler.com/maps/dataviz-light/256/tiles.json',
39 | 'vector': r'https://api.maptiler.com/maps/dataviz-light/style.json',
40 | 'customize_url': r'https://maptiler.link/qgisdatavizlight'
41 | },
42 | 'Ocean RGB': {
43 | 'raster-dem': r'https://api.maptiler.com/tiles/ocean-rgb/tiles.json'
44 | },
45 | 'OpenStreetMap': {
46 | 'raster': r'https://api.maptiler.com/maps/openstreetmap/256/tiles.json',
47 | 'vector': r'https://api.maptiler.com/maps/openstreetmap/style.json',
48 | 'customize_url': r'https://maptiler.link/qgisosm'
49 | },
50 | 'Outdoor': {
51 | 'raster': r'https://api.maptiler.com/maps/outdoor/256/tiles.json',
52 | 'vector': r'https://api.maptiler.com/maps/outdoor/style.json',
53 | 'customize_url': r'https://maptiler.link/qgisoutdoor'
54 | },
55 | 'Pastel': {
56 | 'raster': r'https://api.maptiler.com/maps/pastel/256/tiles.json',
57 | 'vector': r'https://api.maptiler.com/maps/pastel/style.json',
58 | 'customize_url': r'https://maptiler.link/qgispastel'
59 | },
60 | 'Positron': {
61 | 'raster': r'https://api.maptiler.com/maps/positron/256/tiles.json',
62 | 'vector': r'https://api.maptiler.com/maps/positron/style.json',
63 | 'customize_url': r'https://maptiler.link/qgispositron'
64 | },
65 | 'Satellite': {
66 | 'raster': r'https://api.maptiler.com/tiles/satellite-v2/tiles.json'
67 | },
68 | 'Satellite Hybrid': {
69 | 'raster': r'https://api.maptiler.com/maps/hybrid/256/tiles.json',
70 | 'vector': r'https://api.maptiler.com/maps/hybrid/style.json',
71 | 'customize_url': r'https://maptiler.link/qgishybrid'
72 | },
73 | 'Streets': {
74 | 'raster': r'https://api.maptiler.com/maps/streets/256/tiles.json',
75 | 'vector': r'https://api.maptiler.com/maps/streets/style.json',
76 | 'customize_url': r'https://maptiler.link/qgisstreets'
77 | },
78 | 'Terrain': {
79 | 'terrain-group': [
80 | r'https://api.maptiler.com/tiles/terrain-rgb-v2/tiles.json',
81 | r'https://api.maptiler.com/tiles/ocean-rgb/tiles.json'
82 | ]
83 | },
84 | 'Terrain RGB': {
85 | 'raster-dem': r'https://api.maptiler.com/tiles/terrain-rgb-v2/tiles.json'
86 | },
87 | 'Toner': {
88 | 'raster': r'https://api.maptiler.com/maps/toner/256/tiles.json',
89 | 'vector': r'https://api.maptiler.com/maps/toner/style.json',
90 | 'customize_url': r'https://maptiler.link/qgistoner'
91 | },
92 | 'Topo': {
93 | 'raster': r'https://api.maptiler.com/maps/topo/256/tiles.json',
94 | 'vector': r'https://api.maptiler.com/maps/topo/style.json',
95 | 'customize_url': r'https://maptiler.link/qgistopo'
96 | },
97 | 'Topographique': {
98 | 'raster': r'https://api.maptiler.com/maps/topographique/256/tiles.json',
99 | 'vector': r'https://api.maptiler.com/maps/topographique/style.json',
100 | 'customize_url': r'https://maptiler.link/qgistopographique'
101 | },
102 | 'Voyager': {
103 | 'raster': r'https://api.maptiler.com/maps/voyager/256/tiles.json',
104 | 'vector': r'https://api.maptiler.com/maps/voyager/style.json',
105 | 'customize_url': r'https://maptiler.link/qgisvoyager'
106 | },
107 | 'Winter': {
108 | 'raster': r'https://api.maptiler.com/maps/winter/256/tiles.json',
109 | 'vector': r'https://api.maptiler.com/maps/winter/style.json',
110 | 'customize_url': r'https://maptiler.link/qgiswinter'
111 | }
112 | }
113 |
114 | LOCAL_JP_DATASET = {
115 | 'JP MIERUNE Streets': {
116 | 'raster': r'https://api.maptiler.com/maps/jp-mierune-streets/256/tiles.json',
117 | 'vector': r'https://api.maptiler.com/maps/jp-mierune-streets/style.json',
118 | 'customize_url': r'https://maptiler.link/qgisjpstreets'
119 | },
120 | 'JP MIERUNE Dark': {
121 | 'raster': r'https://api.maptiler.com/maps/jp-mierune-dark/256/tiles.json',
122 | 'vector': r'https://api.maptiler.com/maps/jp-mierune-dark/style.json',
123 | 'customize_url': r'https://maptiler.link/qgisjpdark'
124 | },
125 | 'JP MIERUNE Gray': {
126 | 'raster': r'https://api.maptiler.com/maps/jp-mierune-gray/256/tiles.json',
127 | 'vector': r'https://api.maptiler.com/maps/jp-mierune-gray/style.json',
128 | 'customize_url': r'https://maptiler.link/qgisjpgray'
129 | }
130 | }
131 |
132 | LOCAL_NL_DATASET = {
133 | 'NL Cartiqo Dark': {
134 | 'raster': r'https://api.maptiler.com/maps/nl-cartiqo-dark/256/tiles.json',
135 | 'vector': r'https://api.maptiler.com/maps/nl-cartiqo-dark/style.json',
136 | 'customize_url': r'https://maptiler.link/qgisnldark'
137 | },
138 | 'NL Cartiqo Light': {
139 | 'raster': r'https://api.maptiler.com/maps/nl-cartiqo-light/256/tiles.json',
140 | 'vector': r'https://api.maptiler.com/maps/nl-cartiqo-light/style.json',
141 | 'customize_url': r'https://maptiler.link/qgisnllight'
142 | },
143 | 'NL Cartiqo Topo': {
144 | 'raster': r'https://api.maptiler.com/maps/nl-cartiqo-topo/256/tiles.json',
145 | 'vector': r'https://api.maptiler.com/maps/nl-cartiqo-topo/style.json',
146 | 'customize_url': r'https://maptiler.link/qgisnltopo'
147 | }
148 | }
149 |
150 | LOCAL_UK_DATASET = {
151 | 'UK OS Open Zoomstack Light': {
152 | 'raster': r'https://api.maptiler.com/maps/uk-openzoomstack-light/256/tiles.json',
153 | 'vector': r'https://api.maptiler.com/maps/uk-openzoomstack-light/style.json',
154 | 'customize_url': r'https://maptiler.link/qgislight'
155 | },
156 | 'UK OS Open Zoomstack Night': {
157 | 'raster': r'https://api.maptiler.com/maps/uk-openzoomstack-night/256/tiles.json',
158 | 'vector': r'https://api.maptiler.com/maps/uk-openzoomstack-night/style.json',
159 | 'customize_url': r'https://maptiler.link/qgisosnight'
160 | },
161 | 'UK OS Open Zoomstack Outdoor': {
162 | 'raster': r'https://api.maptiler.com/maps/uk-openzoomstack-outdoor/256/tiles.json',
163 | 'vector': r'https://api.maptiler.com/maps/uk-openzoomstack-outdoor/style.json',
164 | 'customize_url': r'https://maptiler.link/qgisosoutdoor'
165 | },
166 | 'UK OS Open Zoomstack Road': {
167 | 'raster': r'https://api.maptiler.com/maps/uk-openzoomstack-road/256/tiles.json',
168 | 'vector': r'https://api.maptiler.com/maps/uk-openzoomstack-road/style.json',
169 | 'customize_url': r'https://maptiler.link/qgisosroad'
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/metadata.txt:
--------------------------------------------------------------------------------
1 | # This file contains metadata for your plugin.
2 |
3 | # This file should be included when you package your plugin.# Mandatory items:
4 |
5 | [general]
6 | name=MapTiler
7 | qgisMinimumVersion=3.24
8 | supportsQt6=yes
9 | description=Street and satellite base maps with vector tiles
10 | version=3.4.2
11 | author=MapTiler
12 | email=info@maptiler.com
13 |
14 | about=- Beautiful base maps using OpenStreetMap data powered by vector tiles - served from MapTiler Cloud.
15 |
16 | - Satellite map of the entire world, outdoor map, hillshading and landcover, Ordnance Survey Open ZoomStack, Dutch Kadaster via Cartiqo, or GSI data in Japan - or your own datasets!
17 |
18 | - Global digital elevation model (DEM) for the entire planet.
19 |
20 | - Customize language & colors of your map with a few clicks!
21 |
22 | - Import your own Mapbox GL JSON style or TileJSON from any URL - even hosted on your own server.
23 |
24 | - Print the maps using vector PDF. (It might cause spikes in Cloud export requests.)
25 |
26 | tracker=https://github.com/maptiler/qgis-maptiler-plugin/issues
27 | repository=https://github.com/maptiler/qgis-maptiler-plugin
28 | # End of mandatory metadata
29 |
30 | # Recommended items:
31 |
32 | hasProcessingProvider=no
33 | # Uncomment the following line and add your changelog:
34 | # changelog=
35 |
36 | # Tags are comma separated with spaces allowed
37 | tags=maptiler, open, map, maps, tiles, openmaptiles, osm, openstreetmap, raster, vector, wmts, tilejson, mapbox, gl, style, styles, geocoding, basemaps, quickmapservices, vector-tiles, geojson, reader, xyz, print, ordnance survey, zoomstack, kadaster, cartiqo, gsi, japan, outdoor, carto, dem, digital, elevation, model, cadastre, cadastral, hillshade, terrain, ocean, rgb, dataviz, customize
38 |
39 | homepage=https://maptiler.link/qgisplugin
40 | category=Web
41 | icon=./imgs/icon_maptiler.svg
42 | # experimental flag
43 | experimental=False
44 |
--------------------------------------------------------------------------------
/settings_manager.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtCore import QSettings
2 |
3 | # QSettings holds variables as list or dict or str.
4 | # if int or bool value is set, they are converted to str in the Class.
5 | # In particular, isVectorEnabled is treated as bool by cast str '0' or '1' to int(bool).
6 |
7 |
8 | class SettingsManager:
9 | SETTING_GROUP = '/maptiler'
10 |
11 | def __init__(self):
12 | self._settings = {
13 | 'selectedmaps': ['Basic', 'Bright', 'Dataviz', 'Outdoor', 'OpenStreetMap', 'Satellite', 'Streets',
14 | 'Terrain', 'Toner', 'Topo', 'Voyager'],
15 | 'prefervector': '1',
16 | 'custommaps': {},
17 | 'auth_cfg_id': ''
18 | }
19 | self.load_settings()
20 |
21 | def load_setting(self, key):
22 | qsettings = QSettings()
23 | qsettings.beginGroup(self.SETTING_GROUP)
24 | value = qsettings.value(key)
25 | qsettings.endGroup()
26 | if value:
27 | self._settings[key] = value
28 |
29 | def load_settings(self):
30 | for key in self._settings:
31 | self.load_setting(key)
32 |
33 | def store_setting(self, key, value):
34 | if key == "auth_cfg_id":
35 | value = value.strip()
36 | qsettings = QSettings()
37 | qsettings.beginGroup(self.SETTING_GROUP)
38 | qsettings.setValue(key, value)
39 | qsettings.endGroup()
40 |
41 | self.load_settings()
42 |
43 | def get_setting(self, key):
44 | return self._settings[key]
45 |
46 | def get_settings(self):
47 | return self._settings
48 |
--------------------------------------------------------------------------------
/utils.py:
--------------------------------------------------------------------------------
1 | from qgis.PyQt.QtWidgets import QMessageBox
2 | from qgis.core import Qgis, QgsColorRampShader, QgsNetworkAccessManager, QgsApplication, QgsAuthMethodConfig
3 | from qgis.PyQt.QtGui import QColor
4 | from qgis.PyQt.QtNetwork import QNetworkRequest, QNetworkReply
5 | from qgis.PyQt.QtCore import QUrl
6 |
7 | import ssl
8 | import json
9 |
10 | from .settings_manager import SettingsManager
11 | ssl._create_default_https_context = ssl._create_unverified_context
12 |
13 |
14 | def validate_credentials() -> bool:
15 | testurl = 'https://api.maptiler.com/maps/basic/style.json'
16 | smanager = SettingsManager()
17 | auth_cfg_id = smanager.get_setting('auth_cfg_id')
18 | if auth_cfg_id:
19 | am = QgsApplication.authManager()
20 | cfg = QgsAuthMethodConfig()
21 | (res, cfg) = am.loadAuthenticationConfig(auth_cfg_id, cfg, True)
22 | if res:
23 | token = cfg.configMap().get("token")
24 | if token and len(token) > 33 and "_" in token:
25 | request = QNetworkRequest(QUrl(testurl))
26 | reply_content = QgsNetworkAccessManager.instance().blockingGet(request, auth_cfg_id)
27 | if reply_content.error() == QNetworkReply.NetworkError.NoError:
28 | return True
29 | return False
30 |
31 |
32 | def is_qgs_vectortile_api_enable():
33 | # judge vtile is available or not
34 | # e.g. QGIS3.10.4 -> 31004
35 | qgis_version_str = str(Qgis.QGIS_VERSION_INT)
36 | minor_ver = int(qgis_version_str[1:3])
37 | return minor_ver >= 13
38 |
39 |
40 | def is_qgs_early_resampling_enabled():
41 | qgis_version_str = str(Qgis.QGIS_VERSION_INT)
42 | minor_ver = int(qgis_version_str[1:3])
43 | return minor_ver >= 25
44 |
45 |
46 | def is_in_darkmode(threshold=383):
47 | """detect the Qt in Darkmode or not
48 |
49 | This function has a dependancy on PyQt, QMessageBox.
50 | Although Qt has no API to detect running in Darkmode or not,
51 | it is able to get RGB value of widgets, including UI parts of them.
52 | This function detect Darkmode by evaluating a sum of RGB value of the widget with threshold.
53 |
54 | Args:
55 | threshold (int, optional): a sum of RGB value (each 0-255, sum 0-765). Default to 383, is just median.
56 | Returns:
57 | bool: True means in Darkmode, False in not.
58 | """
59 | # generate empty QMessageBox to detect
60 | # generated widgets has default color palette in the OS
61 | empty_mbox = QMessageBox()
62 |
63 | # get a background color of the widget
64 | red = empty_mbox.palette().window().color().red()
65 | green = empty_mbox.palette().window().color().green()
66 | blue = empty_mbox.palette().window().color().blue()
67 |
68 | sum_rgb_value = red + green + blue
69 | return sum_rgb_value < threshold
70 |
71 |
72 | def load_color_ramp_from_file(fp: str) -> list:
73 | with open(fp, 'r') as f:
74 | lines = f.readlines()[2:] # get rid of header
75 | ramp_items = [[float(line.rstrip("\n").split(',')[0])] + list(map(int, line.rstrip("\n").split(',')[1:5])) for line in lines]
76 | ramp_lst = [QgsColorRampShader.ColorRampItem(ramp_item[0], QColor(ramp_item[1], ramp_item[2], ramp_item[3], ramp_item[4])) for ramp_item in ramp_items]
77 | min_ramp_value = ramp_items[0][0]
78 | max_ramp_value = ramp_items[-1][0]
79 | return min_ramp_value, max_ramp_value, ramp_lst
80 |
81 |
82 | class MapTilerApiException(Exception):
83 | def __init__(self, message, content):
84 | self.message = message
85 | self.content = content
86 | super().__init__(self.message)
87 |
88 |
89 | def _qgis_request(url: str):
90 | smanager = SettingsManager()
91 | auth_cfg_id = smanager.get_setting('auth_cfg_id')
92 | if "https://api.maptiler.com" in url:
93 | if "key=" in url:
94 | url = url.split("key=")[0]
95 | request = QNetworkRequest(QUrl(url))
96 | reply_content = QgsNetworkAccessManager.instance().blockingGet(request, auth_cfg_id)
97 | else:
98 | request = QNetworkRequest(QUrl(url))
99 | reply_content = QgsNetworkAccessManager.instance().blockingGet(request)
100 |
101 | if not reply_content.error():
102 | return reply_content
103 | else:
104 | error_msg = ""
105 | error_content = ""
106 | if reply_content.errorString():
107 | error_msg = f"{reply_content.errorString()}"
108 | if reply_content.content():
109 | error_content = f"{str(reply_content.content(), 'utf-8')}"
110 | raise MapTilerApiException(error_msg, error_content)
111 |
112 |
113 | def qgis_request_json(url: str) -> dict:
114 | reply_content = _qgis_request(url)
115 | if not reply_content.error():
116 | json_data = json.loads(reply_content.content().data().decode())
117 | return json_data
118 | else:
119 | return None
120 |
121 |
122 | def qgis_request_data(url: str) -> bytes:
123 | reply_content = _qgis_request(url)
124 | return reply_content.content().data()
125 |
126 |
127 | if __name__ == "__main__":
128 | validate_credentials()
129 |
--------------------------------------------------------------------------------