diff --git a/COMPONENTS b/COMPONENTS
index 25160dd..14a5e2a 100644
--- a/COMPONENTS
+++ b/COMPONENTS
@@ -1,3 +1 @@
-
-
Python tile layer: TileLayer Plugin by Minoru Akagi
Some icons from QGIS: QGIS GitHub
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 66dd2b2..4477f82 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -19,7 +19,6 @@ ui-files = [
"src/quick_map_services/gui/*.ui",
"src/quick_map_services/scales.xml",
"src/quick_map_services/*.ui",
- "src/quick_map_services/py_tiled_layer/*.ui",
]
compile = false
diff --git a/src/quick_map_services/compat2qgis.py b/src/quick_map_services/compat2qgis.py
deleted file mode 100644
index f69546e..0000000
--- a/src/quick_map_services/compat2qgis.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-/***************************************************************************
- QuickMapServices
- A QGIS plugin
- Collection of internet map services
- -------------------
- begin : 2014-11-21
- git sha : $Format:%H$
- copyright : (C) 2014 by NextGIS
- email : info@nextgis.com
- ***************************************************************************/
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
-"""
-
-import os
-import sys
-
-from qgis import core
-from qgis.PyQt.QtWidgets import QFileDialog
-
-if hasattr(core, "QGis"):
- from qgis.core import QGis
-else:
- from qgis.core import Qgis as QGis
-
-
-if QGis.QGIS_VERSION_INT >= 30000:
- getQGisUserDatabaseFilePath = core.QgsApplication.qgisUserDatabaseFilePath
-
- addMapLayer = core.QgsProject.instance().addMapLayer
-
- message_log_levels = {
- "Info": QGis.Info,
- "Warning": QGis.Warning,
- "Critical": QGis.Critical,
- }
- message_bar_levels = message_log_levels
-
- geometry_types = {
- "Point": core.QgsWkbTypes.PointGeometry,
- }
-
- qgisRegistryInstance = core.QgsApplication.pluginLayerRegistry()
-
- imageActionShowAllLayers = (
- ":/images/themes/default/mActionShowAllLayers.svg"
- )
- imageActionHideAllLayers = (
- ":images/themes/default/mActionHideAllLayers.svg"
- )
-else:
- getQGisUserDatabaseFilePath = core.QgsApplication.qgisUserDbFilePath
-
- addMapLayer = core.QgsMapLayerRegistry.instance().addMapLayer
-
- from qgis.core import QgsMessageLog
- from qgis.gui import QgsMessageBar
-
- message_log_levels = {
- "Info": QgsMessageLog.INFO,
- "Warning": QgsMessageLog.WARNING,
- "Critical": QgsMessageLog.CRITICAL,
- }
- message_bar_levels = {
- "Info": QgsMessageBar.INFO,
- "Warning": QgsMessageBar.WARNING,
- "Critical": QgsMessageBar.CRITICAL,
- }
-
- geometry_types = {
- "Point": QGis.Point,
- }
-
- qgisRegistryInstance = core.QgsPluginLayerRegistry.instance()
-
- imageActionShowAllLayers = (
- ":/images/themes/default/mActionShowAllLayers.png"
- )
- imageActionHideAllLayers = (
- ":images/themes/default/mActionHideAllLayers.png"
- )
-
-QGisMessageLogLevel = type("QGisMessageLogLevel", (), (message_log_levels))
-QGisMessageBarLevel = type("QGisMessageBarLevel", (), (message_bar_levels))
-QGisGeometryType = type("QGisGeometryType", (), (geometry_types))
-
-
-def getCanvasDestinationCrs(iface):
- if QGis.QGIS_VERSION_INT >= 30000:
- return iface.mapCanvas().mapSettings().destinationCrs()
- else:
- return iface.mapCanvas().mapRenderer().destinationCrs()
-
-
-class QgsCoordinateTransform(core.QgsCoordinateTransform):
- def __init__(self, src_crs, dst_crs):
- super(QgsCoordinateTransform, self).__init__()
-
- self.setSourceCrs(src_crs)
- self.setDestinationCrs(dst_crs)
-
- def setDestinationCrs(self, dst_crs):
- if QGis.QGIS_VERSION_INT >= 30000:
- super(QgsCoordinateTransform, self).setDestinationCrs(dst_crs)
- else:
- self.setDestCRS(dst_crs)
-
-
-def getOpenFileName(parent, caption, filedir, search_filter):
- result = QFileDialog.getOpenFileName(
- parent, caption, filedir, search_filter
- )
-
- if isinstance(result, tuple):
- return result[0]
- return result
-
-
-class QgsCoordinateReferenceSystem(core.QgsCoordinateReferenceSystem):
- def __init__(self, id, type):
- if QGis.QGIS_VERSION_INT >= 30000:
- super(QgsCoordinateReferenceSystem, self).__init__(
- core.QgsCoordinateReferenceSystem.fromEpsgId(id)
- )
- else:
- super(QgsCoordinateReferenceSystem, self).__init__(id, type)
-
- @staticmethod
- def fromEpsgId(id):
- if QGis.QGIS_VERSION_INT >= 30000:
- return core.QgsCoordinateReferenceSystem.fromEpsgId(id)
- else:
- return core.QgsCoordinateReferenceSystem(id)
diff --git a/src/quick_map_services/data_sources_list.py b/src/quick_map_services/data_sources_list.py
index 6dbcd2b..3d247b1 100644
--- a/src/quick_map_services/data_sources_list.py
+++ b/src/quick_map_services/data_sources_list.py
@@ -25,13 +25,12 @@
import os
import sys
-from qgis.core import QgsMessageLog
+from qgis.core import Qgis, QgsMessageLog
from qgis.PyQt.QtCore import QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction
from . import extra_sources
-from .compat2qgis import message_log_levels
from .config_reader_helper import ConfigReaderHelper
from .custom_translator import CustomTranslator
from .data_source_info import DataSourceCategory, DataSourceInfo
@@ -96,10 +95,10 @@ def _fill_data_sources_list(self):
except Exception as e:
error_message = (
- "INI file can't be parsed: " + e.message
+ "INI file can't be parsed: " + str(e)
)
QgsMessageLog.logMessage(
- error_message, level=message_log_levels["Critical"]
+ error_message, level=Qgis.Critical
)
# noinspection PyMethodMayBeStatic
diff --git a/src/quick_map_services/ds_edit_dialog.py b/src/quick_map_services/ds_edit_dialog.py
index f706d54..db964d9 100644
--- a/src/quick_map_services/ds_edit_dialog.py
+++ b/src/quick_map_services/ds_edit_dialog.py
@@ -4,10 +4,9 @@
from qgis.PyQt import uic
from qgis.PyQt.QtGui import QIcon, QPixmap
-from qgis.PyQt.QtWidgets import QDialog, QMessageBox
+from qgis.PyQt.QtWidgets import QDialog, QFileDialog, QMessageBox
from . import extra_sources
-from .compat2qgis import getOpenFileName
from .data_source_info import DataSourceInfo
from .data_source_serializer import DataSourceSerializer
from .data_sources_list import DataSourcesList
@@ -112,7 +111,7 @@ def fill_ds_info(self, ds_info):
self.feel_specific_fields()
def choose_icon(self):
- icon_path = getOpenFileName(
+ icon_path = QFileDialog.getOpenFileName(
self,
self.tr("Select icon for data source"),
PluginSettings.get_default_user_icon_path(),
diff --git a/src/quick_map_services/extra_sources.py b/src/quick_map_services/extra_sources.py
index 6a94a4f..067315d 100644
--- a/src/quick_map_services/extra_sources.py
+++ b/src/quick_map_services/extra_sources.py
@@ -27,15 +27,14 @@
import tempfile
from zipfile import ZipFile
-from qgis.core import QgsNetworkAccessManager
+from qgis.core import QgsApplication, QgsNetworkAccessManager
from qgis.PyQt.QtCore import QEventLoop, QFile, QUrl
from qgis.PyQt.QtNetwork import QNetworkReply, QNetworkRequest
from .compat import OpenModeFlag
-from .compat2qgis import getQGisUserDatabaseFilePath
from .plugin_settings import PluginSettings
-LOCAL_SETTINGS_PATH = os.path.dirname(getQGisUserDatabaseFilePath())
+LOCAL_SETTINGS_PATH = os.path.dirname(QgsApplication.qgisUserDatabaseFilePath())
PLUGIN_SETTINGS_PATH = os.path.join(
LOCAL_SETTINGS_PATH, PluginSettings.product_name()
)
diff --git a/src/quick_map_services/file_selection_widget.py b/src/quick_map_services/file_selection_widget.py
index 67d6e38..bd70780 100644
--- a/src/quick_map_services/file_selection_widget.py
+++ b/src/quick_map_services/file_selection_widget.py
@@ -39,8 +39,6 @@
QWidget,
)
-from .compat2qgis import getOpenFileName
-
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
@@ -79,7 +77,7 @@ def show_selection_dialog(self):
self.leText.setText(folder)
PluginSettings.set_last_icon_path(os.path.dirname(folder))
else:
- filename = getOpenFileName(self, self.dialog_title, path, self.ext)
+ filename = QFileDialog.getOpenFileName(self, self.dialog_title, path, self.ext)
if filename:
self.leText.setText(filename)
PluginSettings.set_last_icon_path(os.path.dirname(filename))
@@ -97,7 +95,7 @@ def set_dialog_ext(self, ext):
self.ext = ext
def set_dialog_title(self, title):
- self.dialog_titledialog_title = title
+ self.dialog_title = title
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
diff --git a/src/quick_map_services/group_edit_dialog.py b/src/quick_map_services/group_edit_dialog.py
index d6838ea..dcc3c29 100644
--- a/src/quick_map_services/group_edit_dialog.py
+++ b/src/quick_map_services/group_edit_dialog.py
@@ -5,10 +5,9 @@
from qgis.PyQt import uic
from qgis.PyQt.QtGui import QPixmap
-from qgis.PyQt.QtWidgets import QDialog, QMessageBox
+from qgis.PyQt.QtWidgets import QDialog, QFileDialog, QMessageBox
from . import extra_sources
-from .compat2qgis import getOpenFileName
from .fixed_config_parser import FixedConfigParser
from .groups_list import GroupsList
from .gui.line_edit_color_validator import LineEditColorValidator
@@ -73,8 +72,16 @@ def fill_group_info(self, group_info):
self.set_icon(self.group_info.icon)
def choose_icon(self):
+ """
+ Opens a file dialog to select an icon for the group and sets it.
+
+ The selected icon path is stored using PluginSettings and applied
+ via `set_icon()`. If no icon is selected, the method exits silently.
+ """
print(PluginSettings.get_default_user_icon_path())
- icon_path = getOpenFileName(
+
+ # Open a file dialog to choose an icon
+ icon_path, _ = QFileDialog.getOpenFileName(
self,
self.tr("Select icon for group"),
PluginSettings.get_default_user_icon_path(),
@@ -84,6 +91,8 @@ def choose_icon(self):
)
print(icon_path)
+
+ # If a file was selected, update the default path and apply the icon
if icon_path != "":
PluginSettings.set_default_user_icon_path(icon_path)
self.set_icon(icon_path)
diff --git a/src/quick_map_services/groups_list.py b/src/quick_map_services/groups_list.py
index ded36a6..1f2354c 100644
--- a/src/quick_map_services/groups_list.py
+++ b/src/quick_map_services/groups_list.py
@@ -26,13 +26,12 @@
import os
import sys
-from qgis.core import QgsMessageLog
+from qgis.core import Qgis, QgsMessageLog
from qgis.PyQt.QtCore import QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QMenu
from . import extra_sources
-from .compat2qgis import message_log_levels
from .config_reader_helper import ConfigReaderHelper
from .custom_translator import CustomTranslator
from .group_info import GroupCategory, GroupInfo
@@ -123,10 +122,10 @@ def _read_ini_file(self, root, ini_file_path, category):
)
except Exception as e:
error_message = (
- self.tr("Group INI file can't be parsed: ") + e.message
+ self.tr("Group INI file can't be parsed: ") + str(e)
)
QgsMessageLog.logMessage(
- error_message, level=message_log_levels["Critical"]
+ error_message, level=Qgis.Critical
)
def get_group_menu(self, group_id):
diff --git a/src/quick_map_services/i18n/QuickMapServices_ru.ts b/src/quick_map_services/i18n/QuickMapServices_ru.ts
index 41185bd..42f3932 100644
--- a/src/quick_map_services/i18n/QuickMapServices_ru.ts
+++ b/src/quick_map_services/i18n/QuickMapServices_ru.ts
@@ -4,12 +4,12 @@
@default
-
+
Layer %s can't be added to the map!
Слой %s невозможно добавить на карту!
-
+
Error
Ошибка
@@ -150,77 +150,27 @@ p, li { white-space: pre-wrap; }
Лицензия
-
- Properties
- Свойства
-
-
-
- Style
- Стиль
-
-
-
- Transparency
- Прозрачность
-
-
-
- Brightness
- Яркость
-
-
-
- Blending mode
- Режим наложения
-
-
-
- (Default: SourceOver)
- (По умолчанию: SourceOver)
-
-
-
- Contrast
- Контраст
-
-
-
- Grayscale
- Оттенки серого
-
-
-
- Smoothing
- Сглаживание
-
-
-
- Place the credit on the bottom right corner
- Поместить авторство в нижнем правом углу
-
-
-
+
Dialog
Диалог
-
+
General
Общие
-
+
ID
ID
-
+
Alias
Алиас
-
+
Icon
Иконка
@@ -255,7 +205,7 @@ p, li { white-space: pre-wrap; }
Условия использования
-
+
Choose
Выбрать
@@ -263,67 +213,67 @@ p, li { white-space: pre-wrap; }
DsEditDialog
-
+
Select icon for data source
Выберите иконку для источника данных
-
+
Any text
Любой текст
-
+
Error on save group
Ошибка при сохранении группы
-
+
Data source with such id already exists! Select new id for data source!
Источник данных с таким id уже существует! Выберите новый id!
-
+
Error on save data source
Ошибка при сохранении источника данных
-
+
Icons (*.ico *.jpg *.jpeg *.png *.svg);;All files (*.*)
Икоки (*.ico *.jpg *.jpeg *.png *.svg);;Все файлы (*.*)
-
+
Please, enter data source id
Пожалуйста введите id источника данных
-
+
Please, enter data source alias
Пожалуйста введите алиас источника данных
-
+
Please, select icon for data source
Пожалуйста, выберите иконку для источника данных
-
+
Please, select group for data source
Пожалуйста, выберите группу для источника данных
-
+
Please, select type for data source
Пожалуйста, выберите тип для источника данных
-
+
Please, enter correct value for data source id
Пожалуйста введите корректное значение id для источника данных
-
+
Please, enter correct value for data source alias
Пожалуйста введите корректное значение для алиаса источника данных
@@ -441,12 +391,12 @@ p, li { white-space: pre-wrap; }
FileSelectionWidget
-
+
Select folder
Выберите директорию
-
+
...
...
@@ -454,7 +404,7 @@ p, li { white-space: pre-wrap; }
Form
-
+
Form
Форма
@@ -464,7 +414,7 @@ p, li { white-space: pre-wrap; }
Файл GDAL
-
+
URL
URL
@@ -522,42 +472,42 @@ p, li { white-space: pre-wrap; }
GroupEditDialog
-
+
Select icon for group
Выберите иконку для группы
-
+
Any text
Любой текст
-
+
Error on save group
Ошибка при сохранении группы
-
+
Please, enter group id
Пожалуйста введите id группы
-
+
Group with such id already exists! Select new id for group!
Группа с таким id уже существует! Выберите новый id!
-
+
All icon files (*.ico *.jpg *.jpeg *.png *.svg);;All files (*.*)
Икоки (*.ico *.jpg *.jpeg *.png *.svg);;Все файлы (*.*)
-
+
Please, enter group alias
Пожалуйста введите алиас группы
-
+
Please, select icon for group
Выберите иконку для группы
@@ -565,7 +515,7 @@ p, li { white-space: pre-wrap; }
GroupsList
-
+
Group INI file can't be parsed:
INI файл группы не может быть разобран:
@@ -669,28 +619,20 @@ p, li { white-space: pre-wrap; }
(QGIS 2.18.8 и выше):
-
- PropertiesDialog
-
-
- Layer Properties
- Свойства слоя
-
-
QmsSearchResultItemWidget
-
+
details
подробнее
-
+
report a problem
сообщить о проблеме
-
+
Add
Добавить
@@ -698,22 +640,22 @@ p, li { white-space: pre-wrap; }
QmsServiceToolbox
-
+
Search string...
Поиск геосервиса...
-
+
Searching...
Поиск...
-
+
No results!
Нет результатов!
-
+
Last used:
Недавно использованы:
@@ -728,12 +670,12 @@ p, li { white-space: pre-wrap; }
Введите часть имени сервиса
-
+
No results.
Ничего не найдено.
-
+
You can add a service to become searchable. Start <a href='{}'>here</a>.
Вы можете <a href='{}'>добавить сервис</a> самостоятельно, и он станет доступен через поиск.
@@ -743,22 +685,22 @@ p, li { white-space: pre-wrap; }
Фильтр по охвату
-
+
All
Все
-
+
Error
Ошибка
-
+
Valid
Рабочие
-
+
Need at least 3 symbols to start searching...
Для поиска нужно минимум 3 символа...
@@ -766,52 +708,52 @@ p, li { white-space: pre-wrap; }
QuickMapServices
-
+
QuickMapServices
QuickMapServices
-
+
Set proper scale
Ближайший масштаб
-
+
Set SlippyMap scales
Установить масштабы SlippyMap
-
+
Settings
Настройки
-
+
About QMS
О QMS
-
+
Error
Ошибка
-
+
Extra dirs for %s can't be created: %s %s
Невозможно создать дополнительные директории для %s: %s %s
-
+
Search QMS
Поиск в QMS
-
+
Add to Search
Добавить в Поиск
-
+
Set SlippyMap scales for current project?
The previous settings will be overwritten!
Установить масштабы мозаичной карты для текущего проекта?
@@ -821,21 +763,21 @@ The previous settings will be overwritten!
SearchThread
-
+
Network error!
{0}
Сетевая ошибка!
{0}
-
+
Error of processing!
{0}: {1}
Ошибка обработки!
{0}: {1}
-
+
Network error: {0}
Сетевая ошибка
@@ -843,104 +785,26 @@ The previous settings will be overwritten!
SettingsDialog
-
+
Last version of contrib pack was downloaded!
Последняя версия пакета с источниками данных была успешно загружена!
-
+
Show all
Показать все
-
+
Hide all
Скрыть все
-
+
Error on getting contrib pack: %s
Ошибка при получении источников данных: %s
-
- TileLayer
-
-
- Current zoom level ({0}) is smaller than zmin ({1}): {2}
- Текущий уровень масштабирования ({0}) меньше чем zmin ({1}): {2}
-
-
-
- Tile count is over limit ({0}, max={1})
- Количество тайлов превысило лимит ({0}, max={1})
-
-
-
- Download Timeout - {}
- Время ожидания скачивания - {}
-
-
-
- {} files failed.
- {} файла(ов) не скачано.
-
-
-
- Failed to download all {0} files. - {1}
- Не удалось загрузить все {0} файла(ов). - {1}
-
-
-
- Reprojection requires python-gdal
- Перепроецирование требует наличие python-gdal
-
-
-
- {0} of {1} files downloaded.
- {0} из {1} файлов скачано.
-
-
-
- Title
- Заголовок
-
-
-
- Credit
- Авторство
-
-
-
- URL
- URL
-
-
-
- yOrigin
- yOrigin
-
-
-
- Not set
- Не установлено
-
-
-
- Zoom range
- Диапазон масштабирования
-
-
-
- Layer Extent
- Границы слоя
-
-
-
- {0} files downloaded. {1} cache hits.
- {0} файлов скачано. {1} попаданий кэша.
-
-
UserGroupsBox
diff --git a/src/quick_map_services/plugin_settings.py b/src/quick_map_services/plugin_settings.py
index 97ef342..fffb4f0 100644
--- a/src/quick_map_services/plugin_settings.py
+++ b/src/quick_map_services/plugin_settings.py
@@ -25,8 +25,6 @@
from qgis.PyQt.QtCore import QByteArray, QDir, QSettings, Qt
-from .compat2qgis import QGis
-
class PluginSettings(object):
_company_name = "NextGIS"
@@ -151,21 +149,4 @@ def set_last_used_services(cls, services):
settings.remove("last_used_services")
settings.beginGroup("last_used_services")
for geoservice in services:
- geoservice.saveSelf(settings)
-
- @classmethod
- def use_native_tms(cls):
- if QGis.QGIS_VERSION_INT >= 30000:
- return True
- elif QGis.QGIS_VERSION_INT >= 21808:
- return cls.get_settings().value(
- "tile_layer/use_native_tms", True, bool
- )
- else:
- return False
-
- @classmethod
- def set_use_native_tms(cls, bool_val):
- return cls.get_settings().setValue(
- "tile_layer/use_native_tms", bool_val
- )
+ geoservice.saveSelf(settings)
\ No newline at end of file
diff --git a/src/quick_map_services/py_tiled_layer/__init__.py b/src/quick_map_services/py_tiled_layer/__init__.py
deleted file mode 100644
index 906f671..0000000
--- a/src/quick_map_services/py_tiled_layer/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-__author__ = "yellow"
-__license__ = ""
-__date__ = "2014"
diff --git a/src/quick_map_services/py_tiled_layer/downloader.py b/src/quick_map_services/py_tiled_layer/downloader.py
deleted file mode 100644
index 8b8d1c0..0000000
--- a/src/quick_map_services/py_tiled_layer/downloader.py
+++ /dev/null
@@ -1,253 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-/***************************************************************************
- TileLayer Plugin
- A QGIS plugin
- Plugin layer for Tile Maps
- -------------------
- begin : 2012-12-16
- copyright : (C) 2013 by Minoru Akagi
- email : akaginch@gmail.com
- ***************************************************************************/
-
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
-"""
-
-import threading
-
-from qgis.core import QgsNetworkAccessManager
-from qgis.PyQt.QtCore import (
- QDateTime,
- QEventLoop,
- QObject,
- QTimer,
- QUrl,
- pyqtSignal,
- qDebug,
-)
-from qgis.PyQt.QtNetwork import QNetworkReply, QNetworkRequest
-
-debug_mode = 0
-
-
-class Downloader(QObject):
- NOT_FOUND = 0
- NO_ERROR = 0
- TIMEOUT_ERROR = 4
- UNKNOWN_ERROR = -1
-
- replyFinished = pyqtSignal(str, int, int)
-
- def __init__(self, parent=None):
- QObject.__init__(self, parent)
- self.queue = []
- self.redirected_urls = {}
- self.requestingUrls = []
- self.replies = []
-
- self.eventLoop = QEventLoop()
- self.sync = False
- self.fetchedFiles = {}
- self.clearCounts()
-
- self.timer = QTimer()
- self.timer.setSingleShot(True)
- self.timer.timeout.connect(self.fetchTimedOut)
-
- # network settings
- self.userAgent = "QuickMapServices tile layer (+https://github.com/nextgis/quickmapservices)"
- self.max_connection = 4
- self.default_cache_expiration = 24
- self.errorStatus = Downloader.NO_ERROR
-
- def clearCounts(self):
- self.fetchSuccesses = 0
- self.fetchErrors = 0
- self.cacheHits = 0
-
- def fetchTimedOut(self):
- self.log("Downloader.timeOut()")
- self.abort()
- self.errorStatus = Downloader.TIMEOUT_ERROR
-
- def abort(self):
- # clear queue and abort sent requests
- self.queue = []
- self.timer.stop()
- for reply in self.replies:
- reply.abort()
- self.errorStatus = Downloader.UNKNOWN_ERROR
-
- def replyFinishedSlot(self):
- reply = self.sender()
- url = reply.request().url().toString()
- self.log("replyFinishedSlot: %s" % url)
- if not url in self.fetchedFiles:
- self.fetchedFiles[url] = None
- self.requestingUrls.remove(url)
- self.replies.remove(reply)
- isFromCache = 0
- httpStatusCode = reply.attribute(
- QNetworkRequest.Attribute.HttpStatusCodeAttribute
- )
- if reply.error() == QNetworkReply.NetworkError.NoError:
- if httpStatusCode == 301:
- new_url = str(reply.rawHeader("Location"))
- self.addToQueue(new_url, url)
- else:
- self.fetchSuccesses += 1
- if reply.attribute(
- QNetworkRequest.Attribute.SourceIsFromCacheAttribute
- ):
- self.cacheHits += 1
- isFromCache = 1
- elif not reply.hasRawHeader("Cache-Control"):
- cache = QgsNetworkAccessManager.instance().cache()
- if cache:
- metadata = cache.metaData(reply.request().url())
- # self.log("Expiration date: " + metadata.expirationDate().toString().encode("utf-8"))
- if metadata.expirationDate().isNull():
- metadata.setExpirationDate(
- QDateTime.currentDateTime().addSecs(
- self.default_cache_expiration * 60 * 60
- )
- )
- cache.updateMetaData(metadata)
- self.log(
- "Default expiration date has been set: %s (%d h)"
- % (url, self.default_cache_expiration)
- )
-
- if reply.isReadable():
- data = reply.readAll()
- if url in self.redirected_urls:
- url = self.redirected_urls[url]
-
- self.fetchedFiles[url] = data
- else:
- qDebug("http status code: " + str(httpStatusCode))
-
- # self.emit(SIGNAL('replyFinished(QString, int, int)'), url, reply.error(), isFromCache)
- self.replyFinished.emit(url, reply.error(), isFromCache)
- else:
- if self.sync and httpStatusCode == 404:
- self.fetchedFiles[url] = self.NOT_FOUND
- self.fetchErrors += 1
- if self.errorStatus == self.NO_ERROR:
- self.errorStatus = self.UNKNOWN_ERROR
-
- reply.deleteLater()
-
- if debug_mode:
- qDebug(
- "queue: %d, requesting: %d"
- % (len(self.queue), len(self.requestingUrls))
- )
-
- if len(self.queue) + len(self.requestingUrls) == 0:
- # all replies have been received
- if self.sync:
- self.logT("eventLoop.quit()")
- self.eventLoop.quit()
- else:
- self.timer.stop()
- elif len(self.queue) > 0:
- # start fetching the next file
- self.fetchNext()
- self.log("replyFinishedSlot End: %s" % url)
-
- def fetchNext(self):
- if len(self.queue) == 0:
- return
- url = self.queue.pop(0)
- self.log("fetchNext: %s" % url)
-
- request = QNetworkRequest(QUrl(url))
- request.setRawHeader("User-Agent", self.userAgent)
- reply = QgsNetworkAccessManager.instance().get(request)
- reply.finished.connect(self.replyFinishedSlot)
- self.requestingUrls.append(url)
- self.replies.append(reply)
- return reply
-
- def fetchFiles(self, urlList, timeout_ms=0):
- self.log("fetchFiles()")
- self.sync = True
- self.queue = []
- self.redirected_urls = {}
- self.clearCounts()
- self.errorStatus = Downloader.NO_ERROR
- self.fetchedFiles = {}
-
- if len(urlList) == 0:
- return self.fetchedFiles
-
- for url in urlList:
- self.addToQueue(url)
-
- for i in range(self.max_connection):
- self.fetchNext()
-
- if timeout_ms > 0:
- self.timer.setInterval(timeout_ms)
- self.timer.start()
-
- self.logT("eventLoop.exec(): " + str(self.eventLoop))
- self.eventLoop.exec()
- self.log("fetchFiles() End: %d" % self.errorStatus)
- if timeout_ms > 0:
- self.timer.stop()
- return self.fetchedFiles
-
- def addToQueue(self, url, redirected_from=None):
- if url in self.queue:
- return False
- self.queue.append(url)
- if redirected_from is not None:
- self.redirected_urls[url] = redirected_from
- return True
-
- def queueCount(self):
- return len(self.queue)
-
- def finishedCount(self):
- return len(self.fetchedFiles)
-
- def unfinishedCount(self):
- return len(self.queue) + len(self.requestingUrls)
-
- def log(self, msg):
- if debug_mode:
- qDebug(msg)
-
- def logT(self, msg):
- if debug_mode:
- qDebug("%s: %s" % (str(threading.current_thread()), msg))
-
- def fetchFilesAsync(self, urlList, timeout_ms=0):
- self.log("fetchFilesAsync()")
- self.sync = False
- self.queue = []
- self.clearCounts()
- self.errorStatus = Downloader.NO_ERROR
- self.fetchedFiles = {}
-
- if len(urlList) == 0:
- return self.fetchedFiles
-
- for url in urlList:
- self.addToQueue(url)
-
- for i in range(self.max_connection):
- self.fetchNext()
-
- if timeout_ms > 0:
- self.timer.setInterval(timeout_ms)
- self.timer.start()
diff --git a/src/quick_map_services/py_tiled_layer/propertiesdialog.py b/src/quick_map_services/py_tiled_layer/propertiesdialog.py
deleted file mode 100644
index 052e8a7..0000000
--- a/src/quick_map_services/py_tiled_layer/propertiesdialog.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-/***************************************************************************
- TileLayer Plugin
- A QGIS plugin
- Plugin layer for Tile Maps
- -------------------
- begin : 2012-12-16
- copyright : (C) 2013 by Minoru Akagi
- email : akaginch@gmail.com
- ***************************************************************************/
-
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
-"""
-
-import os
-
-from qgis.PyQt import uic
-from qgis.PyQt.QtCore import QObject, pyqtSignal
-from qgis.PyQt.QtGui import QDialog, QDialogButtonBox, QPainter
-
-CURR_PATH = os.path.dirname(__file__)
-FORM_CLASS, _ = uic.loadUiType(
- os.path.join(CURR_PATH, "propertiesdialog_base.ui")
-)
-
-
-class PropertiesDialog(QDialog):
- applyClicked = pyqtSignal()
-
- def __init__(self, layer):
- QDialog.__init__(self)
- # set up the user interface
- self.ui = FORM_CLASS()
- self.ui.setupUi(self)
- self.setWindowTitle(
- "%s - %s" % (self.tr("Layer Properties"), layer.name())
- )
-
- self.layer = layer
- # signals
- self.ui.horizontalSlider_Transparency.valueChanged.connect(
- self.ui.spinBox_Transparency.setValue
- )
- self.ui.spinBox_Transparency.valueChanged.connect(
- self.ui.horizontalSlider_Transparency.setValue
- )
- self.ui.horizontalSlider_Brightness.valueChanged.connect(
- self.ui.spinBox_Brightness.setValue
- )
- self.ui.spinBox_Brightness.valueChanged.connect(
- self.ui.horizontalSlider_Brightness.setValue
- )
- self.ui.horizontalSlider_Contrast.valueChanged.connect(
- lambda x: self.ui.doubleSpinBox_Contrast.setValue(x / 100.0)
- )
- self.ui.doubleSpinBox_Contrast.valueChanged.connect(
- lambda x: self.ui.horizontalSlider_Contrast.setValue(x * 100)
- )
-
- self.ui.buttonBox.button(QDialogButtonBox.Apply).clicked.connect(
- self.applyClicked.emit
- )
-
- # set init values
- self.initBlendingCombo()
- self.ui.textEdit_Properties.setText(layer.metadata())
- self.ui.spinBox_Transparency.setValue(layer.transparency)
- self.ui.spinBox_Brightness.setValue(layer.brigthness)
- self.ui.doubleSpinBox_Contrast.setValue(layer.contrast)
- i = self.ui.comboBox_BlendingMode.findText(layer.blendModeName)
- if i != -1:
- self.ui.comboBox_BlendingMode.setCurrentIndex(i)
-
- self.ui.checkBox_SmoothRender.setChecked(layer.smoothRender)
- self.ui.checkBox_CreditVisibility.setChecked(layer.creditVisibility)
- self.ui.checkBox_Grayscale.setChecked(layer.grayscaleRender)
-
- def initBlendingCombo(self):
- attrs = dir(QPainter)
- for attr in attrs:
- if attr.startswith("CompositionMode_"):
- self.ui.comboBox_BlendingMode.addItem(attr[16:])
diff --git a/src/quick_map_services/py_tiled_layer/propertiesdialog_base.ui b/src/quick_map_services/py_tiled_layer/propertiesdialog_base.ui
deleted file mode 100644
index 549c8ab..0000000
--- a/src/quick_map_services/py_tiled_layer/propertiesdialog_base.ui
+++ /dev/null
@@ -1,262 +0,0 @@
-
-
- Dialog
-
-
-
- 0
- 0
- 438
- 428
-
-
-
- Properties
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Style
-
-
-
- QLayout::SetDefaultConstraint
-
-
-
-
-
- QFormLayout::ExpandingFieldsGrow
-
-
-
-
-
- Transparency
-
-
-
- -
-
-
-
-
-
- 100
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- 100
-
-
-
-
-
- -
-
-
- Brightness
-
-
-
- -
-
-
- Blending mode
-
-
-
- -
-
-
-
-
-
- -
-
-
- (Default: SourceOver)
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
-
-
- -
-
-
-
-
-
- -255
-
-
- 255
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- -255
-
-
- 255
-
-
-
-
-
- -
-
-
- Contrast
-
-
-
- -
-
-
-
-
-
- 1000
-
-
- 10
-
-
- 100
-
-
- 100
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- 10.000000000000000
-
-
- 0.010000000000000
-
-
- 1.000000000000000
-
-
-
-
-
-
-
- -
-
-
- Grayscale
-
-
-
- -
-
-
- Smoothing
-
-
-
- -
-
-
- Place the credit on the bottom right corner
-
-
-
-
-
-
- -
-
-
- Properties
-
-
-
-
-
-
- true
-
-
- 80
-
-
-
-
-
-
-
-
-
-
-
-
-
- buttonBox
- accepted()
- Dialog
- accept()
-
-
- 248
- 254
-
-
- 157
- 274
-
-
-
-
- buttonBox
- rejected()
- Dialog
- reject()
-
-
- 316
- 260
-
-
- 286
- 274
-
-
-
-
-
diff --git a/src/quick_map_services/py_tiled_layer/tilelayer.py b/src/quick_map_services/py_tiled_layer/tilelayer.py
deleted file mode 100644
index 927f0af..0000000
--- a/src/quick_map_services/py_tiled_layer/tilelayer.py
+++ /dev/null
@@ -1,1087 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-/***************************************************************************
- TileLayer Plugin
- A QGIS plugin
- Plugin layer for Tile Maps
- -------------------
- begin : 2012-12-16
- copyright : (C) 2013 by Minoru Akagi
- email : akaginch@gmail.com
- ***************************************************************************/
-
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
-"""
-
-# Import the PyQt and QGIS libraries
-import os
-import threading
-
-from qgis.core import QgsImageOperation, QgsPluginLayer, QgsPluginLayerType
-from qgis.gui import QgsMessageBar
-from qgis.PyQt.QtCore import (
- QEventLoop,
- QFile,
- QObject,
- QPoint,
- QPointF,
- QRectF,
- Qt,
- QTimer,
- pyqtSignal,
- qDebug,
-)
-from qgis.PyQt.QtGui import QBrush, QColor, QFont
-from qgis.utils import iface
-
-from ..compat2qgis import QGisMessageBarLevel, QgsCoordinateReferenceSystem
-from ..plugin_settings import PluginSettings
-from ..qgis_proj_helper import ProjectionHelper
-from ..qgis_settings import QGISSettings
-from .downloader import Downloader
-from .tiles import *
-
-try:
- from osgeo import gdal
-
- hasGdal = True
-except:
- hasGdal = False
-
-debug_mode = 0
-
-
-class LayerDefaultSettings(object):
- TRANSPARENCY = 0
- BLEND_MODE = "SourceOver"
- SMOOTH_RENDER = True
- GRAYSCALE_RENDER = False
- BRIGTNESS = 0
- CONTRAST = 1.0
-
-
-class TileLayer(QgsPluginLayer):
- CRS_ID_3857 = 3857
- CRS_3857 = QgsCoordinateReferenceSystem.fromEpsgId(CRS_ID_3857)
-
- LAYER_TYPE = "PyTiledLayer"
- MAX_TILE_COUNT = 256
- CHANGE_SCALE_VALUE = 0.30
-
- fetchRequest = pyqtSignal(list)
- showMessage = pyqtSignal(str, int)
- showBarMessage = pyqtSignal(str, str, int, int)
- allRepliesFinished = pyqtSignal()
-
- def __init__(self, layerDef, creditVisibility=1):
- QgsPluginLayer.__init__(self, TileLayer.LAYER_TYPE, layerDef.title)
-
- self.iface = iface
- self.layerDef = layerDef
- self.creditVisibility = 1 if creditVisibility else 0
-
- # set custom properties
- self.setCustomProperty("title", layerDef.title)
- self.setCustomProperty(
- "credit", layerDef.credit
- ) # TODO: need to remove
- self.setCustomProperty("serviceUrl", layerDef.serviceUrl)
- self.setCustomProperty("yOriginTop", layerDef.yOriginTop)
- self.setCustomProperty("zmin", layerDef.zmin)
- self.setCustomProperty("zmax", layerDef.zmax)
- if layerDef.bbox:
- self.setCustomProperty("bbox", layerDef.bbox.toString())
- self.setCustomProperty("creditVisibility", self.creditVisibility)
-
- # set standard/custom crs
- ProjectionHelper.set_tile_layer_proj(
- self,
- layerDef.epsg_crs_id,
- layerDef.postgis_crs_id,
- layerDef.custom_proj,
- )
-
- if layerDef.bbox:
- self.setExtent(
- BoundingBox.degreesToMercatorMeters(
- layerDef.bbox
- ).toQgsRectangle()
- )
- else:
- if self.layerDef.tile_ranges is not None:
- zmin = sorted(self.layerDef.tile_ranges.keys())[0]
- tbbox = self.layerDef.tile_ranges[zmin]
-
- size = self.layerDef.tsize1 / 2 ** (zmin - 1)
- xmin = self.layerDef.originX + tbbox[0] * size
- xmax = self.layerDef.originX + (tbbox[1] + 1) * size
- ymin = self.layerDef.originY - (tbbox[3] + 1) * size
- ymax = self.layerDef.originY - tbbox[2] * size
- else:
- xmin = -layerDef.tsize1
- ymin = -layerDef.tsize1
- xmax = layerDef.tsize1
- ymax = layerDef.tsize1
-
- self.setExtent(
- QgsRectangle(
- xmin,
- ymin,
- xmax,
- ymax,
- )
- )
-
- self.setValid(True)
- self.tiles = None
- self.useLastZoomForPrint = False
- self.canvasLastZoom = 0
- self.setTransparency(LayerDefaultSettings.TRANSPARENCY)
- self.setBlendModeByName(LayerDefaultSettings.BLEND_MODE)
- self.setSmoothRender(LayerDefaultSettings.SMOOTH_RENDER)
- self.setGrayscaleRender(LayerDefaultSettings.GRAYSCALE_RENDER)
- self.setBrigthness(LayerDefaultSettings.BRIGTNESS)
- self.setContrast(LayerDefaultSettings.CONTRAST)
-
- # downloader
- self.downloader = Downloader(self)
- self.downloader.userAgent = QGISSettings.get_default_user_agent()
- self.downloader.default_cache_expiration = (
- QGISSettings.get_default_tile_expiry()
- )
- self.downloader.max_connection = (
- PluginSettings.default_tile_layer_conn_count()
- ) # TODO: Move to INI files
- self.downloader.replyFinished.connect(self.networkReplyFinished)
- # QObject.connect(self.downloader, SIGNAL("replyFinished(QString, int, int)"), self.networkReplyFinished)
-
- # network
- self.downloadTimeout = QGISSettings.get_default_network_timeout()
-
- # multi-thread rendering
- self.eventLoop = None
-
- self.fetchRequest.connect(self.fetchRequestSlot)
- # QObject.connect(self, SIGNAL("fetchRequest(QStringList)"), self.fetchRequest)
- if self.iface:
- # QObject.connect(self, SIGNAL("showMessage(QString, int)"), self.showStatusMessageSlot)
- # QObject.connect(self, SIGNAL("showBarMessage(QString, QString, int, int)"), self.showBarMessageSlot)
- self.showMessage.connect(self.showStatusMessageSlot)
- self.showBarMessage.connect(self.showBarMessageSlot)
-
- def setBlendModeByName(self, modeName):
- self.blendModeName = modeName
- blendMode = getattr(QPainter, "CompositionMode_" + modeName, 0)
- self.setBlendMode(blendMode)
- self.setCustomProperty("blendMode", modeName)
-
- def setTransparency(self, transparency):
- self.transparency = transparency
- self.setCustomProperty("transparency", transparency)
-
- def setSmoothRender(self, isSmooth):
- self.smoothRender = isSmooth
- self.setCustomProperty("smoothRender", 1 if isSmooth else 0)
-
- def setCreditVisibility(self, visible):
- self.creditVisibility = visible
- self.setCustomProperty("creditVisibility", 1 if visible else 0)
-
- def setGrayscaleRender(self, isGrayscale):
- self.grayscaleRender = isGrayscale
- self.setCustomProperty("grayscaleRender", 1 if isGrayscale else 0)
-
- def setBrigthness(self, brigthness):
- self.brigthness = brigthness
- self.setCustomProperty("brigthness", brigthness)
-
- def setContrast(self, contrast):
- self.contrast = contrast
- self.setCustomProperty("contrast", contrast)
-
- def draw(self, renderContext):
- self.renderContext = renderContext
- extent = renderContext.extent()
- if extent.isEmpty() or extent.width() == float("inf"):
- qDebug("Drawing is skipped because map extent is empty or inf.")
- return True
-
- mapSettings = self.iface.mapCanvas().mapSettings()
- painter = renderContext.painter()
- isDpiEqualToCanvas = (
- painter.device().logicalDpiX() == mapSettings.outputDpi()
- )
- if isDpiEqualToCanvas or not self.useLastZoomForPrint:
- # calculate zoom level
- tile_mpp1 = (
- self.layerDef.tsize1 / self.layerDef.TILE_SIZE
- ) # should be attribute, not method call..
- viewport_mpp = extent.width() / painter.viewport().width()
- lg = math.log(float(tile_mpp1) / float(viewport_mpp), 2)
- zoom = (
- int(math.modf(lg)[1])
- + 1 * (math.modf(lg)[0] > self.CHANGE_SCALE_VALUE)
- + 1
- )
- zoom = max(0, min(zoom, self.layerDef.zmax))
- # zoom = max(self.layerDef.zmin, zoom)
- else:
- # for print composer output image, use last zoom level of map item on print composer (or map canvas)
- zoom = self.canvasLastZoom
-
- # zoom limit
- if zoom < self.layerDef.zmin:
- msg = self.tr(
- "Current zoom level ({0}) is smaller than zmin ({1}): {2}"
- ).format(zoom, self.layerDef.zmin, self.layerDef.title)
- self.emitShowBarMessage(msg, QGisMessageBarLevel.Info, 2)
- return True
-
- while True:
- # calculate tile range (yOrigin is top)
- size = self.layerDef.tsize1 / 2 ** (zoom - 1)
- if (
- self.layerDef.tile_ranges is None
- ): # should add xOffset & yOffset in first part of conditional
- matrixSize = 2**zoom
- ulx = max(
- 0, int((extent.xMinimum() + self.layerDef.tsize1) / size)
- )
- uly = max(
- 0, int((self.layerDef.tsize1 - extent.yMaximum()) / size)
- )
- lrx = min(
- int((extent.xMaximum() + self.layerDef.tsize1) / size),
- matrixSize - 1,
- )
- lry = min(
- int((self.layerDef.tsize1 - extent.yMinimum()) / size),
- matrixSize - 1,
- )
- else: # for tile_ranges
- xmin, xmax, ymin, ymax = self.layerDef.tile_ranges[zoom]
-
- ulx = max(
- int((extent.xMinimum() - self.layerDef.originX) / size),
- xmin,
- )
- uly = max(
- int((self.layerDef.originY - extent.yMaximum()) / size),
- ymin,
- )
- lrx = min(
- int((extent.xMaximum() - self.layerDef.originX) / size),
- xmax,
- )
- lry = min(
- int((self.layerDef.originY - extent.yMinimum()) / size),
- ymax,
- )
-
- # bounding box limit
- if self.layerDef.bbox:
- trange = self.layerDef.bboxDegreesToTileRange(
- zoom, self.layerDef.bbox
- )
- ulx = max(ulx, trange.xmin)
- uly = max(uly, trange.ymin)
- lrx = min(lrx, trange.xmax)
- lry = min(lry, trange.ymax)
- if lrx < ulx or lry < uly:
- # tile range is out of the bounding box
- return True
-
- # tile count limit
- tileCount = (lrx - ulx + 1) * (lry - uly + 1)
- if tileCount > self.MAX_TILE_COUNT:
- # as tile count is over the limit, decrease zoom level
- zoom -= 1
-
- # if the zoom level is less than the minimum, do not draw
- if zoom < self.layerDef.zmin:
- msg = self.tr(
- "Tile count is over limit ({0}, max={1})"
- ).format(tileCount, self.MAX_TILE_COUNT)
- self.emitShowBarMessage(
- msg, QGisMessageBarLevel.Warning, 4
- )
- return True
- continue
-
- # zoom level has been determined
- break
-
- self.logT(
- "TileLayer.draw: {0} {1} {2} {3} {4}".format(
- zoom, ulx, uly, lrx, lry
- )
- )
-
- # save painter state
- painter.save()
-
- # set pen and font
- painter.setPen(Qt.GlobalColor.black)
- font = QFont(painter.font())
- font.setPointSize(10)
- painter.setFont(font)
-
- if self.layerDef.serviceUrl[0] == ":":
- painter.setBrush(QBrush(Qt.BrushStyle.NoBrush))
- self.drawDebugInfo(renderContext, zoom, ulx, uly, lrx, lry)
- else:
- # create Tiles class object and throw url into it
- tiles = Tiles(zoom, ulx, uly, lrx, lry, self.layerDef)
- urls = []
- cacheHits = 0
- for ty in range(uly, lry + 1):
- for tx in range(ulx, lrx + 1):
- data = None
- url = self.layerDef.tileUrl(zoom, tx, ty)
- if (
- self.tiles
- and zoom == self.tiles.zoom
- and url in self.tiles.tiles
- ):
- data = self.tiles.tiles[url].data
- tiles.addTile(url, Tile(zoom, tx, ty, data))
- if data is None:
- urls.append(url)
- elif data: # memory cache exists
- cacheHits += 1
- # else: # tile was not found (Downloader.NOT_FOUND=0)
-
- self.tiles = tiles
- if len(urls) > 0:
- # fetch tile data
- files = self.fetchFiles(urls)
-
- for url in files.keys():
- self.tiles.setImageData(url, files[url])
-
- if self.iface:
- cacheHits += self.downloader.cacheHits
- downloadedCount = (
- self.downloader.fetchSuccesses
- - self.downloader.cacheHits
- )
- msg = self.tr(
- "{0} files downloaded. {1} cache hits."
- ).format(downloadedCount, cacheHits)
- barmsg = None
- if self.downloader.errorStatus != Downloader.NO_ERROR:
- if (
- self.downloader.errorStatus
- == Downloader.TIMEOUT_ERROR
- ):
- barmsg = self.tr("Download Timeout - {}").format(
- self.name()
- )
- else:
- msg += self.tr(" {} files failed.").format(
- self.downloader.fetchErrors
- )
- if self.downloader.fetchSuccesses == 0:
- barmsg = self.tr(
- "Failed to download all {0} files. - {1}"
- ).format(
- self.downloader.fetchErrors, self.name()
- )
- self.showStatusMessage(msg, 5000)
- if barmsg:
- self.emitShowBarMessage(
- barmsg, QGisMessageBarLevel.Warning, 4
- )
-
- # apply layer style
- oldOpacity = painter.opacity()
- painter.setOpacity(0.01 * (100 - self.transparency))
- oldSmoothRenderHint = painter.testRenderHint(
- QPainter.RenderHint.SmoothPixmapTransform
- )
- if self.smoothRender:
- painter.setRenderHint(
- QPainter.RenderHint.SmoothPixmapTransform
- )
-
- # draw tiles
- if not renderContext.coordinateTransform():
- # no need to reproject tiles
- self.drawTiles(renderContext, self.tiles)
- # self.drawTilesDirectly(renderContext, self.tiles)
- else:
- # reproject tiles
- self.drawTilesOnTheFly(renderContext, self.tiles)
-
- # restore layer style
- painter.setOpacity(oldOpacity)
- if self.smoothRender:
- painter.setRenderHint(
- QPainter.RenderHint.SmoothPixmapTransform,
- oldSmoothRenderHint,
- )
-
- # draw credit on the bottom right corner
- if self.creditVisibility and self.layerDef.credit:
- margin, paddingH, paddingV = (3, 4, 3)
- # scale
- scaleX, scaleY = self.getScaleToVisibleExtent(renderContext)
- scale = max(scaleX, scaleY)
- painter.scale(scale, scale)
-
- visibleSWidth = painter.viewport().width() * scaleX / scale
- visibleSHeight = painter.viewport().height() * scaleY / scale
- rect = QRect(
- 0, 0, visibleSWidth - margin, visibleSHeight - margin
- )
- textRect = painter.boundingRect(
- rect,
- Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignRight,
- self.layerDef.credit,
- )
- bgRect = QRect(
- textRect.left() - paddingH,
- textRect.top() - paddingV,
- textRect.width() + 2 * paddingH,
- textRect.height() + 2 * paddingV,
- )
- painter.fillRect(
- bgRect, QColor(240, 240, 240, 150)
- ) # 197, 234, 243, 150))
- painter.drawText(
- rect,
- Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignRight,
- self.layerDef.credit,
- )
-
- # restore painter state
- painter.restore()
-
- if isDpiEqualToCanvas:
- # save zoom level for printing (output with different dpi from map canvas)
- self.canvasLastZoom = zoom
- return True
-
- def drawTiles(self, renderContext, tiles, sdx=1.0, sdy=1.0):
- # create an image that has the same resolution as the tiles
- image = tiles.image()
- if self.grayscaleRender:
- QgsImageOperation.convertToGrayscale(image)
- if (
- self.brigthness != LayerDefaultSettings.BRIGTNESS
- or self.contrast != LayerDefaultSettings.CONTRAST
- ):
- QgsImageOperation.adjustBrightnessContrast(
- image, self.brigthness, self.contrast
- )
-
- # tile extent to pixel
- map2pixel = renderContext.mapToPixel()
- extent = tiles.extent()
- topLeft = map2pixel.transform(extent.xMinimum(), extent.yMaximum())
- bottomRight = map2pixel.transform(extent.xMaximum(), extent.yMinimum())
- rect = QRectF(
- QPointF(topLeft.x() * sdx, topLeft.y() * sdy),
- QPointF(bottomRight.x() * sdx, bottomRight.y() * sdy),
- )
-
- # draw the image on the map canvas
- renderContext.painter().drawImage(rect, image)
-
- self.log("Tiles extent: " + str(extent))
- self.log("Draw into canvas rect: " + str(rect))
-
- def drawTilesOnTheFly(self, renderContext, tiles, sdx=1.0, sdy=1.0):
- if not hasGdal:
- msg = self.tr("Reprojection requires python-gdal")
- self.emitShowBarMessage(msg, QGisMessageBarLevel.Info, 2)
- return
-
- transform = renderContext.coordinateTransform()
- if not transform:
- return
-
- # create an image that has the same resolution as the tiles
- image = tiles.image()
- if self.grayscaleRender:
- QgsImageOperation.convertToGrayscale(image)
- if (
- self.brigthness != LayerDefaultSettings.BRIGTNESS
- or self.contrast != LayerDefaultSettings.CONTRAST
- ):
- QgsImageOperation.adjustBrightnessContrast(
- image, self.brigthness, self.contrast
- )
-
- # tile extent
- extent = tiles.extent()
- geotransform = [
- extent.xMinimum(),
- extent.width() / image.width(),
- 0,
- extent.yMaximum(),
- 0,
- -extent.height() / image.height(),
- ]
-
- driver = gdal.GetDriverByName("MEM")
- tile_ds = driver.Create(
- "", image.width(), image.height(), 1, gdal.GDT_UInt32
- )
- tile_ds.SetProjection(str(transform.sourceCrs().toWkt()))
- tile_ds.SetGeoTransform(geotransform)
-
- # QImage to raster
- ba = image.bits().asstring(image.numBytes())
- tile_ds.GetRasterBand(1).WriteRaster(
- 0, 0, image.width(), image.height(), ba
- )
-
- # canvas extent
- m2p = renderContext.mapToPixel()
- viewport = renderContext.painter().viewport()
- width = viewport.width()
- height = viewport.height()
- extent = QgsRectangle(
- m2p.toMapCoordinatesF(0, 0), m2p.toMapCoordinatesF(width, height)
- )
- geotransform = [
- extent.xMinimum(),
- extent.width() / width,
- 0,
- extent.yMaximum(),
- 0,
- -extent.height() / height,
- ]
-
- canvas_ds = driver.Create("", width, height, 1, gdal.GDT_UInt32)
- canvas_ds.SetProjection(str(transform.destCRS().toWkt()))
- canvas_ds.SetGeoTransform(geotransform)
-
- # reproject image
- gdal.ReprojectImage(tile_ds, canvas_ds)
-
- # raster to QImage
- ba = canvas_ds.GetRasterBand(1).ReadRaster(0, 0, width, height)
- reprojected_image = QImage(
- ba, width, height, QImage.Format_ARGB32_Premultiplied
- )
-
- # draw the image on the map canvas
- rect = QRectF(
- QPointF(0, 0),
- QPointF(viewport.width() * sdx, viewport.height() * sdy),
- )
- renderContext.painter().drawImage(rect, reprojected_image)
-
- def drawTilesDirectly(self, renderContext, tiles, sdx=1.0, sdy=1.0):
- p = renderContext.painter()
- for url, tile in tiles.tiles.items():
- self.log(
- "Draw tile: zoom: %d, x:%d, y:%d, data:%s"
- % (tile.zoom, tile.x, tile.y, str(tile.data))
- )
- rect = self.getTileRect(
- renderContext, tile.zoom, tile.x, tile.y, sdx, sdy
- )
- if tile.data:
- image = QImage()
- image.loadFromData(tile.data)
- p.drawImage(rect, image)
-
- def drawDebugInfo(self, renderContext, zoom, ulx, uly, lrx, lry):
- painter = renderContext.painter()
- scaleX, scaleY = self.getScaleToVisibleExtent(renderContext)
- painter.scale(scaleX, scaleY)
-
- if "frame" in self.layerDef.serviceUrl:
- self.drawFrames(
- renderContext,
- zoom,
- ulx,
- uly,
- lrx,
- lry,
- 1.0 / scaleX,
- 1.0 / scaleY,
- )
- if "number" in self.layerDef.serviceUrl:
- self.drawNumbers(
- renderContext,
- zoom,
- ulx,
- uly,
- lrx,
- lry,
- 1.0 / scaleX,
- 1.0 / scaleY,
- )
- if "info" in self.layerDef.serviceUrl:
- self.drawInfo(renderContext, zoom, ulx, uly, lrx, lry)
-
- def drawFrame(self, renderContext, zoom, x, y, sdx, sdy):
- rect = self.getTileRect(renderContext, zoom, x, y, sdx, sdy)
- p = renderContext.painter()
- # p.drawRect(rect) # A slash appears on the top-right tile without Antialiasing render hint.
- pts = [
- rect.topLeft(),
- rect.topRight(),
- rect.bottomRight(),
- rect.bottomLeft(),
- rect.topLeft(),
- ]
- for i in range(4):
- p.drawLine(pts[i], pts[i + 1])
-
- def drawFrames(
- self, renderContext, zoom, xmin, ymin, xmax, ymax, sdx, sdy
- ):
- for y in range(ymin, ymax + 1):
- for x in range(xmin, xmax + 1):
- self.drawFrame(renderContext, zoom, x, y, sdx, sdy)
-
- def drawNumber(self, renderContext, zoom, x, y, sdx, sdy):
- rect = self.getTileRect(renderContext, zoom, x, y, sdx, sdy)
- p = renderContext.painter()
- if not self.layerDef.yOriginTop:
- y = (2**zoom - 1) - y
- p.drawText(
- rect,
- Qt.AlignmentFlag.AlignCenter,
- "(%d, %d)\nzoom: %d" % (x, y, zoom),
- )
-
- def drawNumbers(
- self, renderContext, zoom, xmin, ymin, xmax, ymax, sdx, sdy
- ):
- for y in range(ymin, ymax + 1):
- for x in range(xmin, xmax + 1):
- self.drawNumber(renderContext, zoom, x, y, sdx, sdy)
-
- def drawInfo(self, renderContext, zoom, xmin, ymin, xmax, ymax):
- # debug information
- mapSettings = self.iface.mapCanvas().mapSettings()
- lines = []
- lines.append("TileLayer")
- lines.append(
- " zoom: %d, tile matrix extent: (%d, %d) - (%d, %d), tile count: %d * %d"
- % (zoom, xmin, ymin, xmax, ymax, xmax - xmin, ymax - ymin)
- )
- extent = renderContext.extent()
- lines.append(" map extent (renderContext): %s" % extent.toString())
- lines.append(
- " map center: %lf, %lf"
- % (extent.center().x(), extent.center().y())
- )
- lines.append(" map size: %f, %f" % (extent.width(), extent.height()))
- lines.append(
- " map extent (map canvas): %s"
- % self.iface.mapCanvas().extent().toString()
- )
- m2p = renderContext.mapToPixel()
- painter = renderContext.painter()
- viewport = painter.viewport()
- mapExtent = QgsRectangle(
- m2p.toMapCoordinatesF(0, 0),
- m2p.toMapCoordinatesF(viewport.width(), viewport.height()),
- )
- lines.append(" map extent (calculated): %s" % mapExtent.toString())
- lines.append(
- " viewport size (pixel): %d, %d"
- % (viewport.width(), viewport.height())
- )
- lines.append(
- " window size (pixel): %d, %d"
- % (painter.window().width(), painter.window().height())
- )
- lines.append(
- " outputSize (pixel): %d, %d"
- % (
- mapSettings.outputSize().width(),
- mapSettings.outputSize().height(),
- )
- )
- device = painter.device()
- lines.append(
- " deviceSize (pixel): %f, %f" % (device.width(), device.height())
- )
- lines.append(
- " logicalDpi: %f, %f"
- % (device.logicalDpiX(), device.logicalDpiY())
- )
- lines.append(" outputDpi: %f" % mapSettings.outputDpi())
- lines.append(" mapToPixel: %s" % m2p.showParameters())
- lines.append(
- " meters per pixel: %f" % (extent.width() / viewport.width())
- )
- lines.append(" scaleFactor: %f" % renderContext.scaleFactor())
- lines.append(" rendererScale: %f" % renderContext.rendererScale())
- scaleX, scaleY = self.getScaleToVisibleExtent(renderContext)
- lines.append(" scale: %f, %f" % (scaleX, scaleY))
-
- # draw information
- textRect = painter.boundingRect(
- QRect(QPoint(0, 0), viewport.size()),
- Qt.AlignmentFlag.AlignLeft,
- "Q",
- )
- for i, line in enumerate(lines):
- painter.drawText(10, (i + 1) * textRect.height(), line)
- self.log(line)
-
- # diagonal
- painter.drawLine(
- QPointF(0, 0),
- QPointF(painter.viewport().width(), painter.viewport().height()),
- )
- painter.drawLine(
- QPointF(painter.viewport().width(), 0),
- QPointF(0, painter.viewport().height()),
- )
-
- # credit label
- margin, paddingH, paddingV = (3, 4, 3)
- credit = "This is credit"
- rect = QRect(
- 0,
- 0,
- painter.viewport().width() - margin,
- painter.viewport().height() - margin,
- )
- textRect = painter.boundingRect(
- rect,
- Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignRight,
- credit,
- )
- bgRect = QRect(
- textRect.left() - paddingH,
- textRect.top() - paddingV,
- textRect.width() + 2 * paddingH,
- textRect.height() + 2 * paddingV,
- )
- painter.drawRect(bgRect)
- painter.drawText(
- rect,
- Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignRight,
- credit,
- )
-
- def getScaleToVisibleExtent(self, renderContext):
- mapSettings = self.iface.mapCanvas().mapSettings()
- painter = renderContext.painter()
- if painter.device().logicalDpiX() == mapSettings.outputDpi():
- return 1.0, 1.0 # scale should be 1.0 in rendering on map canvas
-
- extent = renderContext.extent()
- ct = renderContext.coordinateTransform()
- if ct:
- # FIX ME: want to get original visible extent in project CRS or visible view size in pixels
-
- # extent = ct.transformBoundingBox(extent)
- # xmax, ymin = extent.xMaximum(), extent.yMinimum()
-
- pt1 = ct.transform(extent.xMaximum(), extent.yMaximum())
- pt2 = ct.transform(extent.xMaximum(), extent.yMinimum())
- pt3 = ct.transform(extent.xMinimum(), extent.yMinimum())
- xmax, ymin = min(pt1.x(), pt2.x()), max(pt2.y(), pt3.y())
- else:
- xmax, ymin = extent.xMaximum(), extent.yMinimum()
-
- bottomRight = renderContext.mapToPixel().transform(xmax, ymin)
- viewport = painter.viewport()
- scaleX = bottomRight.x() / viewport.width()
- scaleY = bottomRight.y() / viewport.height()
- return scaleX, scaleY
-
- def getTileRect(
- self, renderContext, zoom, x, y, sdx=1.0, sdy=1.0, toInt=True
- ):
- """get tile pixel rect in the render context"""
- r = self.layerDef.getTileRect(zoom, x, y)
- map2pix = renderContext.mapToPixel()
- topLeft = map2pix.transform(r.xMinimum(), r.yMaximum())
- bottomRight = map2pix.transform(r.xMaximum(), r.yMinimum())
- if toInt:
- return QRect(
- QPoint(round(topLeft.x() * sdx), round(topLeft.y() * sdy)),
- QPoint(
- round(bottomRight.x() * sdx), round(bottomRight.y() * sdy)
- ),
- )
- else:
- return QRectF(
- QPointF(topLeft.x() * sdx, topLeft.y() * sdy),
- QPointF(bottomRight.x() * sdx, bottomRight.y() * sdy),
- )
-
- def isProjectCrsWebMercator(self):
- mapSettings = self.iface.mapCanvas().mapSettings()
- return mapSettings.destinationCrs().postgisSrid() == 3857
-
- def networkReplyFinished(self, url, error, isFromCache):
- if self.iface is None or isFromCache:
- return
- unfinishedCount = self.downloader.unfinishedCount()
- if unfinishedCount == 0:
- # self.emit(SIGNAL("allRepliesFinished()"))
- self.allRepliesFinished.emit()
-
- downloadedCount = (
- self.downloader.fetchSuccesses - self.downloader.cacheHits
- )
- totalCount = self.downloader.finishedCount() + unfinishedCount
- msg = self.tr("{0} of {1} files downloaded.").format(
- downloadedCount, totalCount
- )
- if self.downloader.fetchErrors:
- msg += self.tr(" {} files failed.").format(
- self.downloader.fetchErrors
- )
- self.showStatusMessage(msg)
-
- def readXml(self, node):
- self.readCustomProperties(node)
- self.layerDef.title = self.customProperty("title", "")
- self.layerDef.credit = self.customProperty("credit", "")
- if self.layerDef.credit == "":
- self.layerDef.credit = self.customProperty(
- "providerName", ""
- ) # for compatibility with 0.11
- self.layerDef.serviceUrl = self.customProperty("serviceUrl", "")
- self.layerDef.yOriginTop = int(self.customProperty("yOriginTop", 1))
- self.layerDef.zmin = int(
- self.customProperty("zmin", TileDefaultSettings.ZMIN)
- )
- self.layerDef.zmax = int(
- self.customProperty("zmax", TileDefaultSettings.ZMAX)
- )
- bbox = self.customProperty("bbox", None)
- if bbox:
- self.layerDef.bbox = BoundingBox.fromString(bbox)
- self.setExtent(
- BoundingBox.degreesToMercatorMeters(
- self.layerDef.bbox
- ).toQgsRectangle()
- )
- # layer style
- self.setTransparency(
- int(
- self.customProperty(
- "transparency", LayerDefaultSettings.TRANSPARENCY
- )
- )
- )
- self.setBlendModeByName(
- self.customProperty("blendMode", LayerDefaultSettings.BLEND_MODE)
- )
- self.setSmoothRender(
- int(
- self.customProperty(
- "smoothRender", LayerDefaultSettings.SMOOTH_RENDER
- )
- )
- )
- self.creditVisibility = int(self.customProperty("creditVisibility", 1))
- self.setGrayscaleRender(
- int(
- self.customProperty(
- "grayscaleRender", LayerDefaultSettings.GRAYSCALE_RENDER
- )
- )
- )
- self.setBrigthness(
- int(
- self.customProperty(
- "brigthness", LayerDefaultSettings.BRIGTNESS
- )
- )
- )
- self.setContrast(
- float(
- self.customProperty("contrast", LayerDefaultSettings.CONTRAST)
- )
- )
-
- return True
-
- def writeXml(self, node, doc):
- element = node.toElement()
- element.setAttribute("type", "plugin")
- element.setAttribute("name", TileLayer.LAYER_TYPE)
- return True
-
- def readSymbology(self, node, errorMessage):
- return False
-
- def writeSymbology(self, node, doc, errorMessage):
- return False
-
- def metadata(self):
- lines = []
- fmt = "%s:\t%s"
- lines.append(fmt % (self.tr("Title"), self.layerDef.title))
- lines.append(fmt % (self.tr("Credit"), self.layerDef.credit))
- lines.append(fmt % (self.tr("URL"), self.layerDef.serviceUrl))
- lines.append(
- fmt
- % (
- self.tr("yOrigin"),
- "%s (yOriginTop=%d)"
- % (
- ("Bottom", "Top")[self.layerDef.yOriginTop],
- self.layerDef.yOriginTop,
- ),
- )
- )
- if self.layerDef.bbox:
- extent = self.layerDef.bbox.toString()
- else:
- extent = self.tr("Not set")
- lines.append(
- fmt
- % (
- self.tr("Zoom range"),
- "%d - %d" % (self.layerDef.zmin, self.layerDef.zmax),
- )
- )
- lines.append(fmt % (self.tr("Layer Extent"), extent))
- return "\n".join(lines)
-
- def log(self, msg):
- if debug_mode:
- qDebug(msg)
-
- def logT(self, msg):
- if debug_mode:
- qDebug("%s: %s" % (str(threading.current_thread()), msg))
-
- def dump(self, detail=False, bbox=None):
- pass
-
- # functions for multi-thread rendering
- def fetchFiles(self, urls):
- self.logT("TileLayer.fetchFiles() starts")
- # create a QEventLoop object that belongs to the current thread (if ver. > 2.1, it is render thread)
- eventLoop = QEventLoop()
- self.logT("Create event loop: " + str(eventLoop)) # DEBUG
- # QObject.connect(self, SIGNAL("allRepliesFinished()"), eventLoop.quit)
- self.allRepliesFinished.connect(eventLoop.quit)
-
- # create a timer to watch whether rendering is stopped
- watchTimer = QTimer()
- watchTimer.timeout.connect(eventLoop.quit)
-
- # send a fetch request to the main thread
- # self.emit(SIGNAL("fetchRequest(QStringList)"), urls)
- self.fetchRequest.emit(urls)
-
- # wait for the fetch to finish
- tick = 0
- interval = 500
- timeoutTick = self.downloadTimeout / interval
- watchTimer.start(interval)
- while tick < timeoutTick:
- # run event loop for 0.5 seconds at maximum
- eventLoop.exec()
-
- if debug_mode:
- qDebug("watchTimerTick: %d" % tick)
- qDebug(
- "unfinished downloads: %d"
- % self.downloader.unfinishedCount()
- )
-
- if (
- self.downloader.unfinishedCount() == 0
- or self.renderContext.renderingStopped()
- ):
- break
- tick += 1
- watchTimer.stop()
-
- if tick == timeoutTick and self.downloader.unfinishedCount() > 0:
- self.log("fetchFiles timeout")
- # self.emitShowBarMessage("fetchFiles timeout", duration=5) #DEBUG
- self.downloader.abort()
- self.downloader.errorStatus = Downloader.TIMEOUT_ERROR
- files = self.downloader.fetchedFiles
-
- watchTimer.timeout.disconnect(eventLoop.quit) #
- # QObject.disconnect(self, SIGNAL("allRepliesFinished()"), eventLoop.quit)
- self.allRepliesFinished.disconnect(eventLoop.quit)
-
- self.logT("TileLayer.fetchFiles() ends")
- return files
-
- def fetchRequestSlot(self, urls):
- self.logT("TileLayer.fetchRequestSlot()")
- self.downloader.fetchFilesAsync(urls, self.downloadTimeout)
-
- def showStatusMessage(self, msg, timeout=0):
- # self.emit(SIGNAL("showMessage(QString, int)"), msg, timeout)
- self.showMessage.emit(msg, timeout)
-
- def showStatusMessageSlot(self, msg, timeout):
- self.iface.mainWindow().statusBar().showMessage(msg, timeout)
-
- def emitShowBarMessage(
- self, text, level=QGisMessageBarLevel.Info, duration=0, title=None
- ):
- if PluginSettings.show_messages_in_bar():
- if title is None:
- title = PluginSettings.product_name()
- # self.emit(SIGNAL("showBarMessage(QString, QString, int, int)"), title, text, level, duration)
- self.showBarMessage.emit(title, text, level, duration)
-
- def showBarMessageSlot(self, title, text, level, duration):
- self.iface.messageBar().pushMessage(title, text, level, duration)
-
-
-# def createMapRenderer(self, renderContext):
-# qDebug("createMapRenderer")
-# self.renderer = QgsPluginLayerRenderer(self, renderContext)
-# return self.renderer
-
-
-class TileLayerType(QgsPluginLayerType):
- def __init__(self, plugin):
- QgsPluginLayerType.__init__(self, TileLayer.LAYER_TYPE)
-
- def createLayer(self):
- return TileLayer(TileServiceInfo.createEmptyInfo())
-
- def showLayerProperties(self, layer):
- from .propertiesdialog import PropertiesDialog
-
- dialog = PropertiesDialog(layer)
- # QObject.connect(dialog, SIGNAL("applyClicked()"), self.applyClicked)
- dialog.applyClicked.connect(self.applyClicked)
- dialog.show()
- accepted = dialog.exec()
- if accepted:
- self.applyProperties(dialog)
- return True
-
- def applyClicked(self):
- self.applyProperties(QObject().sender())
-
- def applyProperties(self, dialog):
- layer = dialog.layer
- layer.setTransparency(dialog.ui.spinBox_Transparency.value())
- layer.setBlendModeByName(dialog.ui.comboBox_BlendingMode.currentText())
- layer.setSmoothRender(dialog.ui.checkBox_SmoothRender.isChecked())
- layer.setCreditVisibility(
- dialog.ui.checkBox_CreditVisibility.isChecked()
- )
- layer.setGrayscaleRender(dialog.ui.checkBox_Grayscale.isChecked())
- layer.setBrigthness(dialog.ui.spinBox_Brightness.value())
- layer.setContrast(dialog.ui.doubleSpinBox_Contrast.value())
- # layer.emit(SIGNAL("repaintRequested()"))
- layer.repaintRequested.emit()
diff --git a/src/quick_map_services/py_tiled_layer/tiles.py b/src/quick_map_services/py_tiled_layer/tiles.py
deleted file mode 100644
index e7d4d06..0000000
--- a/src/quick_map_services/py_tiled_layer/tiles.py
+++ /dev/null
@@ -1,271 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-/***************************************************************************
- TileLayer Plugin
- A QGIS plugin
- Plugin layer for Tile Maps
- -------------------
- begin : 2012-12-16
- copyright : (C) 2013 by Minoru Akagi
- email : akaginch@gmail.com
- ***************************************************************************/
-
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
-"""
-
-# Import the PyQt and QGIS libraries
-import math
-
-from qgis.core import QgsRectangle
-from qgis.PyQt.QtCore import QRect, Qt
-from qgis.PyQt.QtGui import QImage, QPainter
-
-R = 6378137
-
-debug_mode = 0
-
-
-class TileDefaultSettings(object):
- ZMIN = 0
- ZMAX = 18
-
-
-def degreesToMercatorMeters(lon, lat):
- # formula: http://en.wikipedia.org/wiki/Mercator_projection#Mathematics_of_the_Mercator_projection
- x = R * lon * math.pi / 180
- y = R * math.log(math.tan((90 + lat) * math.pi / 360))
- return x, y
-
-
-class BoundingBox(object):
- def __init__(self, xmin, ymin, xmax, ymax):
- self.xmin = xmin
- self.ymin = ymin
- self.xmax = xmax
- self.ymax = ymax
-
- def toQgsRectangle(self):
- return QgsRectangle(self.xmin, self.ymin, self.xmax, self.ymax)
-
- def toString(self, digitsAfterPoint=None):
- if digitsAfterPoint is None:
- return "%f,%f,%f,%f" % (self.xmin, self.ymin, self.xmax, self.ymax)
- return "%.{0}f,%.{0}f,%.{0}f,%.{0}f".format(digitsAfterPoint) % (
- self.xmin,
- self.ymin,
- self.xmax,
- self.ymax,
- )
-
- @classmethod
- def degreesToMercatorMeters(cls, bbox):
- xmin, ymin = degreesToMercatorMeters(bbox.xmin, bbox.ymin)
- xmax, ymax = degreesToMercatorMeters(bbox.xmax, bbox.ymax)
- return BoundingBox(xmin, ymin, xmax, ymax)
-
- @classmethod
- def fromString(cls, s):
- a = map(float, s.split(","))
- return BoundingBox(a[0], a[1], a[2], a[3])
-
-
-class Tile(object):
- def __init__(self, zoom, x, y, data=None):
- self.zoom = zoom
- self.x = x
- self.y = y
- self.data = data
-
-
-class Tiles(object):
- def __init__(self, zoom, xmin, ymin, xmax, ymax, serviceInfo):
- self.zoom = zoom
- self.xmin = xmin
- self.ymin = ymin
- self.xmax = xmax
- self.ymax = ymax
- self.TILE_SIZE = serviceInfo.TILE_SIZE
- self.tsize1 = serviceInfo.tsize1
- self.yOriginTop = serviceInfo.yOriginTop
- self.serviceInfo = serviceInfo
- self.tiles = {}
-
- def addTile(self, url, tile):
- self.tiles[url] = tile
-
- def setImageData(self, url, data):
- if url in self.tiles:
- self.tiles[url].data = data
-
- def image(self):
- width = (self.xmax - self.xmin + 1) * self.TILE_SIZE
- height = (self.ymax - self.ymin + 1) * self.TILE_SIZE
-
- image = QImage(width, height, QImage.Format_ARGB32_Premultiplied)
- image.fill(Qt.GlobalColor.transparent)
- p = QPainter(image)
-
- for tile in self.tiles.values():
- if not tile.data:
- continue
-
- x = tile.x - self.xmin
- y = tile.y - self.ymin
- rect = QRect(
- x * self.TILE_SIZE,
- y * self.TILE_SIZE,
- self.TILE_SIZE,
- self.TILE_SIZE,
- )
-
- timg = QImage()
- res = timg.loadFromData(tile.data)
- if res:
- p.drawImage(rect, timg)
-
- if debug_mode:
- p.setPen(Qt.GlobalColor.black)
- p.drawText(
- rect,
- Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignRight,
- # "x: %s, y:%s\nz: %s, data: %s" % (x, y, tile.zoom, tile.data.size())
- "z: %s, data: %s" % (tile.zoom, tile.data.size()),
- )
- if not res:
- p.setPen(Qt.GlobalColor.darkRed)
- p.drawText(rect, Qt.AlignmentFlag.AlignCenter, "Bad tile")
-
- p.setPen(Qt.GlobalColor.black)
- p.drawRect(rect)
-
- return image
-
- def extent(self):
- size = self.tsize1 / 2 ** (self.zoom - 1)
- if self.serviceInfo.tile_ranges is None:
- return QgsRectangle(
- self.xmin * size - self.tsize1,
- self.tsize1 - (self.ymax + 1) * size,
- (self.xmax + 1) * size - self.tsize1,
- self.tsize1 - self.ymin * size,
- )
- else:
- originX = self.serviceInfo.originX
- originY = self.serviceInfo.originY
- return QgsRectangle(
- originX + self.xmin * size,
- originY - (self.ymax + 1) * size,
- originX + (self.xmax + 1) * size,
- originY - self.ymin * size,
- )
-
-
-class TileServiceInfo(object):
- TILE_SIZE = 256
- # TSIZE1 = 20037508.342789244 # (R * math.pi)
-
- def __init__(
- self,
- title,
- credit,
- serviceUrl,
- yOriginTop=1,
- zmin=TileDefaultSettings.ZMIN,
- zmax=TileDefaultSettings.ZMAX,
- bbox=None,
- epsg_crs_id=None,
- postgis_crs_id=None,
- custom_proj=None,
- tile_ranges=None,
- tsize1=R * math.pi,
- originX=-R * math.pi,
- originY=R * math.pi,
- ):
- self.title = title
- self.credit = credit
- self.serviceUrl = serviceUrl
- self.yOriginTop = yOriginTop
- self.zmin = max(zmin, 0)
- self.zmax = zmax
- self.bbox = bbox
- self.epsg_crs_id = epsg_crs_id
- self.postgis_crs_id = postgis_crs_id
- self.custom_proj = custom_proj
- self.tsize1 = tsize1
- self.tile_ranges = tile_ranges
- self.originX = originX
- self.originY = originY
-
- def tileUrl(self, zoom, x, y):
- if not self.yOriginTop:
- y = (2**zoom - 1) - y
- # Added the form to obtain the quadkey and remplace to use.
- # With the following change using the quadkey allowed, take the variable {q} to represent quadkey field.
- # Source and credits of procedure https://github.com/buckheroux/QuadKey/blob/master/quadkey/tile_system.py
- # Adapting code Nelson Ugalde Araya nugaldea@gmail.com
- if "{q}" in self.serviceUrl:
- quadkey = ""
- for i in range(zoom):
- bit = zoom - i
- digit = ord("0")
- mask = 1 << (bit - 1) # if (bit - 1) > 0 else 1 >> (bit - 1)
- if (x & mask) != 0:
- digit += 1
- if (y & mask) != 0:
- digit += 2
- quadkey += chr(digit)
- return self.serviceUrl.replace("{q}", str(quadkey))
-
- return (
- self.serviceUrl.replace("{z}", str(zoom))
- .replace("{x}", str(x))
- .replace("{y}", str(y))
- )
-
- def getTileRect(self, zoom, x, y):
- size = self.tsize1 / 2 ** (zoom - 1)
- return QgsRectangle(
- x * size - self.tsize1,
- self.tsize1 - y * size,
- (x + 1) * size - self.tsize1,
- self.tsize1 - (y + 1) * size,
- )
-
- def degreesToTile(self, zoom, lon, lat):
- x, y = degreesToMercatorMeters(lon, lat)
- size = self.tsize1 / 2 ** (zoom - 1)
- tx = int((x + self.tsize1) / size)
- ty = int((self.tsize1 - y) / size)
- return tx, ty
-
- def bboxDegreesToTileRange(self, zoom, bbox):
- xmin, ymin = self.degreesToTile(zoom, bbox.xmin, bbox.ymax)
- xmax, ymax = self.degreesToTile(zoom, bbox.xmax, bbox.ymin)
- return BoundingBox(xmin, ymin, xmax, ymax)
-
- def __str__(self):
- return "%s (%s)" % (self.title, self.serviceUrl)
-
- def toArrayForTreeView(self):
- extent = ""
- if self.bbox:
- extent = self.bbox.toString(2)
- return [
- self.title,
- self.credit,
- self.serviceUrl,
- "%d-%d" % (self.zmin, self.zmax),
- extent,
- self.yOriginTop,
- ]
-
- @classmethod
- def createEmptyInfo(cls):
- return TileServiceInfo("", "", "")
diff --git a/src/quick_map_services/qgis_map_helpers.py b/src/quick_map_services/qgis_map_helpers.py
index 7122389..06b6fcb 100644
--- a/src/quick_map_services/qgis_map_helpers.py
+++ b/src/quick_map_services/qgis_map_helpers.py
@@ -4,6 +4,7 @@
from qgis.core import (
Qgis,
+ QgsCoordinateReferenceSystem,
QgsMessageLog,
QgsProject,
QgsRasterLayer,
@@ -14,15 +15,7 @@
from qgis.utils import iface
from .compat import QGIS_3_38
-from .compat2qgis import (
- QGisMessageBarLevel,
- QGisMessageLogLevel,
- addMapLayer,
- message_log_levels,
-)
from .plugin_settings import PluginSettings
-from .py_tiled_layer.tilelayer import TileLayer
-from .py_tiled_layer.tiles import TileDefaultSettings, TileServiceInfo
from .qgis_proj_helper import ProjectionHelper
from .qgis_settings import QGISSettings
from .supported_drivers import KNOWN_DRIVERS
@@ -37,9 +30,21 @@ def tr(message):
def add_layer_to_map(ds):
+ """
+ Adds a layer to the current QGIS project based on the datasource config.
+
+ Supports TMS, WMS, WFS, GDAL, and GeoJSON formats. Sets attribution,
+ projection, and correct insertion position in the layer tree.
+ Shows a message if the layer is invalid.
+
+ :param ds: Datasource description with all needed properties
+ :type ds: Datasource
+ """
layers4add = []
+ # === TMS LAYERS ===
if ds.type.lower() == KNOWN_DRIVERS.TMS.lower():
+ # Use alternative TMS URL if available
if ds.alt_tms_urls:
tms_url = ds.alt_tms_urls[
random.randint(0, len(ds.alt_tms_urls) - 1)
@@ -47,58 +52,38 @@ def add_layer_to_map(ds):
else:
tms_url = ds.tms_url
- if PluginSettings.use_native_tms(): # add version check
- service_url = tms_url.replace("=", "%3D").replace("&", "%26")
- if (
- ds.tms_y_origin_top is not None
- and ds.tms_y_origin_top == False
- ):
- service_url = service_url.replace("{y}", "{-y}")
-
- qgis_tms_uri = "type=xyz&zmin={0}&zmax={1}&url={2}".format(
- ds.tms_zmin or TileDefaultSettings.ZMIN,
- ds.tms_zmax or TileDefaultSettings.ZMAX,
- service_url,
- )
+ service_url = tms_url.replace("=", "%3D").replace("&", "%26")
+ if (
+ ds.tms_y_origin_top is not None
+ and ds.tms_y_origin_top == False
+ ):
+ service_url = service_url.replace("{y}", "{-y}")
+
+ # Construct TMS URI for QGIS
+ qgis_tms_uri = "type=xyz&zmin={0}&zmax={1}&url={2}".format(
+ ds.tms_zmin if ds.tms_zmin is not None else 0,
+ ds.tms_zmax if ds.tms_zmax is not None else 18,
+ service_url,
+ )
- layer = QgsRasterLayer(
- qgis_tms_uri, tr(ds.alias), KNOWN_DRIVERS.WMS.lower()
- )
- ProjectionHelper.set_tile_layer_proj(
- layer,
- ds.tms_epsg_crs_id,
- ds.tms_postgis_crs_id,
- ds.tms_custom_proj,
- )
- layers4add.append(layer)
- else:
- service_info = TileServiceInfo(
- tr(ds.alias), ds.copyright_text, tms_url
- )
- service_info.zmin = ds.tms_zmin or service_info.zmin
- service_info.zmax = ds.tms_zmax or service_info.zmax
- if ds.tms_y_origin_top is not None:
- service_info.yOriginTop = ds.tms_y_origin_top
- service_info.epsg_crs_id = ds.tms_epsg_crs_id
- service_info.postgis_crs_id = ds.tms_postgis_crs_id
- service_info.custom_proj = ds.tms_custom_proj
+ # Create and configure TMS raster layer
+ layer = QgsRasterLayer(
+ qgis_tms_uri, tr(ds.alias), KNOWN_DRIVERS.WMS.lower()
+ )
+ ProjectionHelper.set_tile_layer_proj(
+ layer,
+ ds.tms_epsg_crs_id,
+ ds.tms_postgis_crs_id,
+ ds.tms_custom_proj,
+ )
+ layers4add.append(layer)
- if (
- ds.tms_tile_ranges is not None
- ): # needs try block & checks that keys are integers etc..
- service_info.tile_ranges = ast.literal_eval(ds.tms_tile_ranges)
- if ds.tms_tsize1 is not None:
- service_info.tsize1 = ds.tms_tsize1
- if ds.tms_origin_x is not None:
- service_info.originX = ds.tms_origin_x
- if ds.tms_origin_y is not None:
- service_info.originY = ds.tms_origin_y
-
- layer = TileLayer(service_info, False)
- layers4add.append(layer)
+ # === GDAL LAYERS ===
if ds.type.lower() == KNOWN_DRIVERS.GDAL.lower():
layer = QgsRasterLayer(ds.gdal_source_file, tr(ds.alias))
layers4add.append(layer)
+
+ # === WMS LAYERS ===
if ds.type.lower() == KNOWN_DRIVERS.WMS.lower():
qgis_wms_uri = ""
if ds.wms_params:
@@ -124,6 +109,8 @@ def add_layer_to_map(ds):
qgis_wms_uri, tr(ds.alias), KNOWN_DRIVERS.WMS.lower()
)
layers4add.append(layer)
+
+ # === WFS LAYERS ===
if ds.type.lower() == KNOWN_DRIVERS.WFS.lower():
qgis_wfs_uri_base = ds.wfs_url
@@ -161,20 +148,22 @@ def add_layer_to_map(ds):
)
layers4add.append(layer)
+ # === GEOJSON LAYERS ===
if ds.type.lower() == KNOWN_DRIVERS.GEOJSON.lower():
layer = QgsVectorLayer(ds.geojson_url, tr(ds.alias), "ogr")
layers4add.append(layer)
+ # === ADD LAYERS TO PROJECT ===
for layer in layers4add:
if not layer.isValid():
error_message = (
tr("Layer %s can't be added to the map!") % ds.alias
)
iface.messageBar().pushMessage(
- tr("Error"), error_message, level=QGisMessageBarLevel.Critical
+ tr("Error"), error_message, level=Qgis.Critical
)
QgsMessageLog.logMessage(
- error_message, level=message_log_levels["Critical"]
+ error_message, level=Qgis.Critical
)
else:
# Set attribs
@@ -206,7 +195,7 @@ def add_layer_to_map(ds):
else:
position = 0 # insert to top
- addMapLayer(layer, False)
+ QgsProject.instance().addMapLayer(layer, False)
toc_root.insertLayer(position, layer)
@@ -216,15 +205,12 @@ def add_layer_to_map(ds):
if (
PluginSettings.enable_otf_3857()
and ds.type.lower() == KNOWN_DRIVERS.TMS.lower()
- and ds.tms_epsg_crs_id == TileLayer.CRS_ID_3857
+ and ds.tms_epsg_crs_id == 3857
):
- if hasattr(iface.mapCanvas(), "setCrsTransformEnabled"):
- # Need for QGIS2. In QGIS3 CRS transformation is always enabled
- iface.mapCanvas().setCrsTransformEnabled(True)
- iface.mapCanvas().setDestinationCrs(TileLayer.CRS_3857)
+ iface.mapCanvas().setDestinationCrs(QgsCoordinateReferenceSystem.fromEpsgId(3857))
if (
QGISSettings.get_new_project_crs_behavior()
== QGISSettings.NEW_PROJECT_USE_PRESET_CRS
):
- QgsProject.instance().setCrs(TileLayer.CRS_3857)
+ QgsProject.instance().setCrs(QgsCoordinateReferenceSystem.fromEpsgId(3857))
diff --git a/src/quick_map_services/qgis_proj_helper.py b/src/quick_map_services/qgis_proj_helper.py
index 77e6d4a..edcf8c1 100644
--- a/src/quick_map_services/qgis_proj_helper.py
+++ b/src/quick_map_services/qgis_proj_helper.py
@@ -1,7 +1,7 @@
+from qgis.core import Qgis, QgsCoordinateReferenceSystem
from qgis.gui import QgsMessageBar
from qgis.utils import iface
-from .compat2qgis import QGisMessageBarLevel, QgsCoordinateReferenceSystem
from .plugin_settings import PluginSettings
@@ -18,8 +18,8 @@ def set_tile_layer_proj(
try:
crs = None
if epsg_crs_id is not None:
- crs = QgsCoordinateReferenceSystem(
- epsg_crs_id, QgsCoordinateReferenceSystem.EpsgCrsId
+ crs = QgsCoordinateReferenceSystem.fromEpsgId(
+ epsg_crs_id,
)
if postgis_crs_id is not None:
crs = QgsCoordinateReferenceSystem(
@@ -32,7 +32,7 @@ def set_tile_layer_proj(
# try to search in db
searched = custom_crs.findMatchingProj()
if searched:
- crs = QgsCoordinateReferenceSystem(
+ crs = QgsCoordinateReferenceSystem.fromCrsId(
searched, QgsCoordinateReferenceSystem.InternalCrsId
)
else:
@@ -53,11 +53,11 @@ def set_tile_layer_proj(
layer.setCrs(crs)
except:
msg = "Custom crs can't be set for layer {0}!".format(layer.name())
- cls.show_bar_message(msg, QGisMessageBarLevel.Warning, 4)
+ cls.show_bar_message(msg, Qgis.Warning, 4)
@classmethod
def show_bar_message(
- cls, text, level=QGisMessageBarLevel.Info, duration=0, title=None
+ cls, text, level=Qgis.Info, duration=0, title=None
):
if PluginSettings.show_messages_in_bar():
if title is None:
diff --git a/src/quick_map_services/qms_service_toolbox.py b/src/quick_map_services/qms_service_toolbox.py
index 5d476e2..f16aae8 100644
--- a/src/quick_map_services/qms_service_toolbox.py
+++ b/src/quick_map_services/qms_service_toolbox.py
@@ -5,7 +5,14 @@
from pathlib import Path
from urllib.error import URLError
-from qgis.core import QgsGeometry, QgsMessageLog, QgsSettings
+from qgis.core import (
+ Qgis,
+ QgsCoordinateReferenceSystem,
+ QgsCoordinateTransform,
+ QgsGeometry,
+ QgsMessageLog,
+ QgsSettings,
+)
from qgis.PyQt import uic
from qgis.PyQt.QtCore import (
QByteArray,
@@ -33,12 +40,6 @@
QWidget,
)
-from .compat2qgis import (
- QGisMessageLogLevel,
- QgsCoordinateReferenceSystem,
- QgsCoordinateTransform,
- getCanvasDestinationCrs,
-)
from .data_source_serializer import DataSourceSerializer
from .plugin_settings import PluginSettings
from .qgis_map_helpers import add_layer_to_map
@@ -50,7 +51,7 @@
from .singleton import singleton
-def plPrint(msg, level=QGisMessageLogLevel.Info):
+def plPrint(msg, level=Qgis.Info):
QgsMessageLog.logMessage(msg, "QMS", level)
@@ -266,7 +267,7 @@ def start_search(self):
else:
# extent filter
extent = self.iface.mapCanvas().extent()
- map_crs = getCanvasDestinationCrs(self.iface)
+ map_crs = self.iface.mapCanvas().mapSettings().destinationCrs()
if map_crs.postgisSrid() != 4326:
crsDest = QgsCoordinateReferenceSystem.fromEpsgId(
4326
diff --git a/src/quick_map_services/quick_map_services.py b/src/quick_map_services/quick_map_services.py
index 62f270b..c6b511d 100644
--- a/src/quick_map_services/quick_map_services.py
+++ b/src/quick_map_services/quick_map_services.py
@@ -48,14 +48,12 @@
)
from .about_dialog import AboutDialog
-from .compat2qgis import qgisRegistryInstance
from .custom_translator import CustomTranslator, QTranslator
from .data_sources_list import DataSourcesList
from .extra_sources import ExtraSources
from .groups_list import GroupsList
from .plugin_locale import Locale
from .plugin_settings import PluginSettings
-from .py_tiled_layer.tilelayer import TileLayer, TileLayerType
from .qgis_map_helpers import add_layer_to_map
from .qms_service_toolbox import QmsServiceToolbox
from .settings_dialog import SettingsDialog
@@ -125,10 +123,6 @@ def initGui(self):
# import pydevd
# pydevd.settrace('localhost', port=9921, stdoutToServer=True, stderrToServer=True, suspend=False)
- # Register plugin layer type
- self.tileLayerType = TileLayerType(self)
- qgisRegistryInstance.addPluginLayerType(self.tileLayerType)
-
# Create menu
icon_path = self.plugin_dir + "/icons/mActionAddLayer.svg"
self.menu = QMenu(self.tr("QuickMapServices"))
@@ -209,8 +203,6 @@ def unload(self):
self.ds_list = None
self.groups_list = None
self.service_layers = None
- # # Unregister plugin layer type
- qgisRegistryInstance.removePluginLayerType(TileLayer.LAYER_TYPE)
qms_create_service_action = None
set_nearest_scale_act = None
diff --git a/src/quick_map_services/rb_result_renderer.py b/src/quick_map_services/rb_result_renderer.py
index 0cd001c..b7035bd 100644
--- a/src/quick_map_services/rb_result_renderer.py
+++ b/src/quick_map_services/rb_result_renderer.py
@@ -19,17 +19,16 @@
***************************************************************************/
"""
-from qgis.core import QgsRectangle
-from qgis.gui import QgsRubberBand
-from qgis.PyQt.QtGui import QColor
-from qgis.utils import iface
-
-from .compat2qgis import (
- QGisGeometryType,
+from qgis.core import (
QgsCoordinateReferenceSystem,
QgsCoordinateTransform,
- getCanvasDestinationCrs,
+ QgsProject,
+ QgsRectangle,
+ QgsWkbTypes,
)
+from qgis.gui import QgsRubberBand
+from qgis.PyQt.QtGui import QColor
+from qgis.utils import iface
class RubberBandResultRenderer:
@@ -38,15 +37,17 @@ def __init__(self):
self.srs_wgs84 = QgsCoordinateReferenceSystem.fromEpsgId(4326)
self.transform_decorator = QgsCoordinateTransform(
- self.srs_wgs84, self.srs_wgs84
+ self.srs_wgs84,
+ self.srs_wgs84,
+ QgsProject.instance()
)
- self.rb = QgsRubberBand(self.iface.mapCanvas(), QGisGeometryType.Point)
+ self.rb = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry)
self.rb.setColor(QColor("magenta"))
self.rb.setIconSize(12)
self.features_rb = QgsRubberBand(
- self.iface.mapCanvas(), QGisGeometryType.Point
+ self.iface.mapCanvas(), QgsWkbTypes.PointGeometry
)
magenta_transp = QColor("#3388ff")
magenta_transp.setAlpha(120)
@@ -64,16 +65,14 @@ def show_point(self, point, center=False):
self.center_to_point(point)
def clear(self):
- self.rb.reset(QGisGeometryType.Point)
+ self.rb.reset(QgsWkbTypes.PointGeometry)
def need_transform(self):
- return getCanvasDestinationCrs(self.iface).postgisSrid() != 4326
+ return self.iface.mapCanvas().mapSettings().destinationCrs().postgisSrid() != 4326
def transform_point(self, point):
- # dest_srs_id = getCanvasDestinationCrs(self.iface).srsid()
- # self.transformation.setDestCRSID(dest_srs_id)
self.transform_decorator.setDestinationCrs(
- getCanvasDestinationCrs(self.iface)
+ self.iface.mapCanvas().mapSettings().destinationCrs()
)
try:
return self.transform_decorator.transform(point)
@@ -82,10 +81,8 @@ def transform_point(self, point):
return
def transform_bbox(self, bbox):
- # dest_srs_id = getCanvasDestinationCrs(self.iface).srsid()
- # self.transformation.setDestCRSID(dest_srs_id)
self.transform_decorator.setDestinationCrs(
- getCanvasDestinationCrs(self.iface)
+ self.iface.mapCanvas().mapSettings().destinationCrs()
)
try:
return self.transform_decorator.transformBoundingBox(bbox)
@@ -94,10 +91,8 @@ def transform_bbox(self, bbox):
return
def transform_geom(self, geom):
- # dest_srs_id = getCanvasDestinationCrs(self.iface).srsid()
- # self.transformation.setDestCRSID(dest_srs_id)
self.transform_decorator.setDestinationCrs(
- getCanvasDestinationCrs(self.iface)
+ self.iface.mapCanvas().mapSettings().destinationCrs()
)
try:
geom.transform(self.transform_decorator)
@@ -125,4 +120,4 @@ def show_feature(self, geom):
self.features_rb.setToGeometry(geom, None)
def clear_feature(self):
- self.features_rb.reset(QGisGeometryType.Point)
+ self.features_rb.reset(QgsWkbTypes.PointGeometry)
diff --git a/src/quick_map_services/settings_dialog.py b/src/quick_map_services/settings_dialog.py
index 848d05c..d053b7b 100644
--- a/src/quick_map_services/settings_dialog.py
+++ b/src/quick_map_services/settings_dialog.py
@@ -24,17 +24,12 @@
import os
import sys
-from qgis.core import QgsApplication
+from qgis.core import Qgis, QgsApplication
from qgis.PyQt import uic
from qgis.PyQt.QtCore import *
from qgis.PyQt.QtGui import *
from qgis.PyQt.QtWidgets import *
-from .compat2qgis import (
- QGis,
- imageActionHideAllLayers,
- imageActionShowAllLayers,
-)
from .data_sources_model import DSManagerModel
from .extra_sources import ExtraSources
from .plugin_settings import PluginSettings
@@ -69,12 +64,12 @@ def __init__(self, parent=None):
) # !!! need to check
showAllAction = self.toolBarForDSTreeView.addAction(
- QIcon(imageActionShowAllLayers), self.tr("Show all")
+ QIcon(":/images/themes/default/mActionShowAllLayers.svg"), self.tr("Show all")
)
showAllAction.triggered.connect(self.dsManagerViewModel.checkAll)
hideAllAction = self.toolBarForDSTreeView.addAction(
- QIcon(imageActionHideAllLayers), self.tr("Hide all")
+ QIcon(":images/themes/default/mActionHideAllLayers.svg"), self.tr("Hide all")
)
hideAllAction.triggered.connect(self.dsManagerViewModel.uncheckAll)
self.dsManagerViewModel.sort(DSManagerModel.COLUMN_GROUP_DS)
@@ -96,18 +91,12 @@ def fill_pages(self):
self.spnNetworkTimeout.setValue(
QGISSettings.get_default_network_timeout()
)
- if QGis.QGIS_VERSION_INT >= 30000:
- self.useNativeRenderer2188AndHigherLabel.setVisible(False)
- self.chkUseNativeRenderer.setChecked(True)
- self.chkUseNativeRenderer.setEnabled(False)
- self.chkUseNativeRenderer.setVisible(False)
- elif QGis.QGIS_VERSION_INT >= 21808:
- self.chkUseNativeRenderer.setChecked(
- PluginSettings.use_native_tms()
- )
- else:
- self.chkUseNativeRenderer.setChecked(False)
- self.chkUseNativeRenderer.setEnabled(False)
+
+ # Native renderer options (hidden for now)
+ self.useNativeRenderer2188AndHigherLabel.setVisible(False)
+ self.chkUseNativeRenderer.setChecked(True)
+ self.chkUseNativeRenderer.setEnabled(False)
+ self.chkUseNativeRenderer.setVisible(False)
# contrib pack
@@ -125,10 +114,6 @@ def save_settings(self):
QGISSettings.set_default_network_timeout(
self.spnNetworkTimeout.value()
)
- if QGis.QGIS_VERSION_INT >= 21808:
- PluginSettings.set_use_native_tms(
- self.chkUseNativeRenderer.isChecked()
- )
# contrib pack
# ds visibility
diff --git a/src/quick_map_services/singleton.py b/src/quick_map_services/singleton.py
index 6ece72e..a1d7c86 100644
--- a/src/quick_map_services/singleton.py
+++ b/src/quick_map_services/singleton.py
@@ -21,12 +21,7 @@
***************************************************************************/
"""
-from .compat2qgis import QGis
-
-if QGis.QGIS_VERSION_INT >= 30000:
- from qgis.PyQt.QtCore import QObject as QParentClass
-else:
- from qgis.PyQt.QtCore import pyqtWrapperType as QParentClass
+from qgis.PyQt.QtCore import QObject as QParentClass
def singleton(class_):