├── COPYING
├── README.md
├── deploy.sh
├── deploy_resources_to_shared_drive.sh
├── make.sh
├── qgis-custom-0.9-2.tar.bz2
└── qgis-custom
├── apps
├── qgis-custom
│ ├── WMTS_scales.xml
│ ├── bin
│ │ └── qgis-custom-ltr.reg
│ ├── layout_checks.py
│ ├── qgis-ltr-custom.bat.template
│ ├── qgis_constrained_settings.py
│ ├── qgis_constrained_settings.yml
│ ├── qgis_global_settings.ini
│ └── startup_project.qgs
└── qgis-ltr
│ └── python
│ └── plugins
│ ├── SpreadsheetLayers
│ ├── CHANGELOG.md
│ ├── README.rst
│ ├── SpreadsheetLayersPlugin.py
│ ├── __init__.py
│ ├── help
│ │ ├── .gitignore
│ │ ├── locale
│ │ │ └── fr
│ │ │ │ └── LC_MESSAGES
│ │ │ │ └── index.po
│ │ ├── make.bat
│ │ └── source
│ │ │ ├── conf.py
│ │ │ └── index.rst
│ ├── i18n
│ │ ├── .gitignore
│ │ ├── SpreadsheetLayers_fr.ts
│ │ └── SpreadsheetLayers_ru.ts
│ ├── metadata.txt
│ ├── plugin_upload.py
│ ├── pylintrc
│ ├── requirements.txt
│ ├── resources
│ │ ├── icon
│ │ │ └── mActionAddSpreadsheetLayer.svg
│ │ └── resources.qrc
│ ├── ui
│ │ ├── __init__.py
│ │ ├── resources_rc.py
│ │ └── ui_SpreadsheetLayersDialog.ui
│ ├── util
│ │ ├── __init__.py
│ │ └── gdal_util.py
│ └── widgets
│ │ ├── SpreadsheetLayersDialog.py
│ │ └── __init__.py
│ ├── coordinator
│ ├── __init__.py
│ ├── coordinator.py
│ ├── coordinator_dockwidget.py
│ ├── coordinator_dockwidget_base.ui
│ ├── funcs.py
│ ├── help
│ │ ├── help.css
│ │ ├── images
│ │ │ ├── capture.gif
│ │ │ ├── screen_basics.png
│ │ │ ├── screen_capture.png
│ │ │ ├── screen_copy.png
│ │ │ ├── screen_digitize.png
│ │ │ ├── screen_labels.ai
│ │ │ ├── screen_main.png
│ │ │ └── screen_maptools.png
│ │ └── index.html
│ ├── i18n
│ │ ├── coordinator_de.qm
│ │ └── coordinator_fr.qm
│ ├── metadata.txt
│ ├── resources.py
│ ├── resources.qrc
│ └── test
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── data
│ │ ├── europe.geojson
│ │ ├── tenbytenraster.asc
│ │ ├── tenbytenraster.keywords
│ │ ├── tenbytenraster.lic
│ │ ├── tenbytenraster.prj
│ │ └── tenbytenraster.qml
│ │ ├── qgis_interface.py
│ │ ├── test_canvas.py
│ │ ├── test_coordinator_dockwidget.py
│ │ ├── test_init.py
│ │ ├── test_integration.py
│ │ ├── test_qgis_environment.py
│ │ ├── test_resources.py
│ │ ├── test_translations.py
│ │ └── utilities.py
│ ├── french_locator_filter
│ ├── __about__.py
│ ├── __init__.py
│ ├── core
│ │ ├── __init__.py
│ │ └── locator_filter.py
│ ├── gui
│ │ ├── __init__.py
│ │ ├── dlg_settings.py
│ │ └── dlg_settings.ui
│ ├── metadata.txt
│ ├── plugin_main.py
│ ├── resources.qrc
│ ├── resources
│ │ ├── help
│ │ │ └── index.html
│ │ ├── i18n
│ │ │ ├── french_locator_filter_fr.qm
│ │ │ ├── french_locator_filter_fr.ts
│ │ │ └── plugin_translation.pro
│ │ └── images
│ │ │ └── icon.svg
│ ├── resources_rc.py
│ └── toolbelt
│ │ ├── __init__.py
│ │ ├── log_handler.py
│ │ ├── network_manager.py
│ │ ├── preferences.py
│ │ └── translator.py
│ ├── mask
│ ├── Makefile
│ ├── __init__.py
│ ├── aeag_mask.png
│ ├── aeag_mask.py
│ ├── default_mask_style.qml
│ ├── doc
│ │ ├── en
│ │ │ ├── about.html
│ │ │ ├── legend_inmask.png
│ │ │ └── tips.html
│ │ └── fr
│ │ │ ├── about.html
│ │ │ ├── legend_inmask.png
│ │ │ └── tips.html
│ ├── htmldialog.py
│ ├── i18n
│ │ └── fr.qm
│ ├── layerlist.py
│ ├── maindialog.py
│ ├── mask_filter.py
│ ├── mask_parameters.py
│ ├── metadata.txt
│ ├── resources_rc.py
│ ├── resources_rc.qrc
│ ├── style_tools.py
│ ├── ui_layer_list.py
│ ├── ui_layer_list.ui
│ ├── ui_plugin_mask.py
│ └── ui_plugin_mask.ui
│ ├── menu_from_project
│ ├── __about__.py
│ ├── __init__.py
│ ├── doc
│ │ ├── index-en.html
│ │ └── index-fr.html
│ ├── i18n
│ │ ├── fr.qm
│ │ └── fr.ts
│ ├── logic
│ │ ├── __init__.py
│ │ ├── custom_datatypes.py
│ │ ├── qgs_manager.py
│ │ └── tools.py
│ ├── menu_from_project.py
│ ├── metadata.txt
│ ├── plugin_translation.pro
│ ├── resources
│ │ ├── edit.svg
│ │ ├── gear.svg
│ │ ├── globe.svg
│ │ └── menu_from_project.png
│ └── ui
│ │ ├── __init__.py
│ │ ├── conf_dialog.ui
│ │ └── menu_conf_dlg.py
│ ├── qNote
│ ├── README.rst
│ ├── __init__.py
│ ├── metadata.txt
│ ├── qnote.py
│ └── ui_qnote.ui
│ └── redLayer
│ ├── .gitattributes
│ ├── .github
│ ├── dependabot.yml
│ └── workflows
│ │ └── linter.yml
│ ├── .gitignore
│ ├── CHANGELOG.txt
│ ├── README.md
│ ├── __init__.py
│ ├── i18n
│ ├── redLayer.pro
│ ├── redLayer_fr.qm
│ └── redLayer_fr.ts
│ ├── icons
│ ├── canvas.svg
│ ├── colorBlack.png
│ ├── colorBlue.png
│ ├── colorGreen.png
│ ├── colorPalette.png
│ ├── colorRed.png
│ ├── colorYellow.png
│ ├── erase.svg
│ ├── inbox.svg
│ ├── note.svg
│ ├── outbox.svg
│ ├── pen.svg
│ ├── readme_menu.png
│ ├── readme_menu_disabled.png
│ ├── readme_screen.png
│ ├── remove.svg
│ ├── sketch.svg
│ ├── toLayer.svg
│ ├── width16.png
│ ├── width2.png
│ ├── width4.png
│ └── width8.png
│ ├── metadata.txt
│ ├── note_class_dialog.py
│ ├── redLayerModule.py
│ ├── redLayerModule_dialog.py
│ ├── redLayerModule_dialog_base.ui
│ ├── setup.cfg
│ ├── sketchLayerStyle.qml
│ ├── tests
│ ├── dev
│ │ └── dev_qfile_dialog.py
│ └── fixtures
│ │ └── patatoid_around_south_america.sketch
│ └── ui_note_dialog.ui
├── etc
├── postinstall
│ └── qgis-custom.bat
└── preremove
│ └── qgis-custom.bat
└── setup.hint
/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | # auteur : Régis Haubourg - GrenobleAlpesMetropole
5 | # Licence GPLV3
6 | # 26/05/2021
7 |
8 | # this script takes your locally built tar.bz2 package and push it to the local repository hosting your osgeo4W binaries
9 |
10 | echo "** Deploying osgeo4W custom package **
11 | "
12 |
13 | cd qgis-custom
14 |
15 | SETUP_TEXT=$(cat setup.hint)
16 |
17 | PACKAGE_DIR="/x/OSGEO4W_DEPLOY_TEST/PAQUETS/http%3a%2f%2fwww.norbit.de%2fosgeo4w%2f"
18 |
19 | echo "-Target package directory :
20 | $PACKAGE_DIR
21 | "
22 |
23 | echo "-PAckage metadata :
24 | ------------
25 | $SETUP_TEXT
26 | ------------"
27 |
28 |
29 | if [ ! -d "$PACKAGE_DIR" ]
30 | then
31 | echo "Target directory doesn't exists"
32 | # e xit 2
33 | fi
34 |
35 |
36 | VERSION=$(grep -i version setup.hint | awk '{printf $2}')
37 |
38 | echo "package version found: $VERSION"
39 |
40 | mkdir -p "$PACKAGE_DIR/x86_64/release/qgis/qgis-custom/"
41 |
42 | cd -
43 |
44 | cp -p qgis-custom-$VERSION.tar.bz2 $PACKAGE_DIR/x86_64/release/qgis/qgis-custom/
45 |
46 | # md5 and size
47 | MD5=$(md5sum qgis-custom-$VERSION.tar.bz2 | awk -F'[ ]' '{print $1}')
48 | size=$(stat -c "%s" qgis-custom-$VERSION.tar.bz2)
49 |
50 | # adds metadata into setup.ini, from setup.hint template
51 |
52 | echo -e "
53 | - Modification du setup.ini cible"
54 |
55 | # deletes previous entry
56 | sed -i '/@ qgis-custom/,+8d;' $PACKAGE_DIR/x86_64/setup.ini
57 |
58 | # append to the end of the file
59 |
60 | echo "@ qgis-custom
61 | $SETUP_TEXT $size $MD5
62 | " >> $PACKAGE_DIR/x86_64/setup.ini
63 |
64 | echo -e "--------"
65 |
66 | echo -e "** Package deployed **"
67 |
68 | echo -e "--------"
69 |
--------------------------------------------------------------------------------
/deploy_resources_to_shared_drive.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | # auteur : Régis Haubourg
5 | # Licence GPLV3
6 | # 26/05/2021
7 |
8 |
9 | echo "** Deployes some resources to a shared drive **
10 | "
11 | S_DIR="/mnt/s/QGIS/custom"
12 |
13 | # Global settings et contraintes
14 | echo "copies global settings"
15 | cp qgis-custom/apps/qgis-custom/qgis_global_settings.ini $S_DIR/QGIS/
16 |
17 | echo "Copies qgis_constrained_settings.yml"
18 | cp qgis-custom/apps/qgis-custom/qgis_constrained_settings.yml $S_DIR/QGIS/
19 |
20 |
21 | # Startup project
22 | echo "Copies startup project"
23 | cp qgis-custom/apps/qgis-custom/startup_project.qgs $S_DIR/
24 |
25 |
26 | echo -e "--------"
27 |
28 | echo -e "** End **"
29 |
30 | echo -e "--------"
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/make.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | # Building script of the custom package
5 | # gets version from setup.ini and build a osgeo4w tar.bz2 ready to be deployed
6 |
7 | cd qgis-custom
8 | # gets version
9 | VERSION=$(grep -i version setup.hint | awk '{printf $2}')
10 |
11 | # fix tar.bz2 name with real version replacing @@ marker with version
12 |
13 | sed -i "/install: x86_64/s/.*/install: x86_64\/release\/qgis\/qgis-custom\/qgis-custom-$VERSION.tar.bz2/" setup.hint
14 |
15 | # pushes version as a environment variable. Helps to diagnose which package version is installed quickly from QGIS settings
16 | sed -i "s/qgis-custom-VERSION=.*/qgis-custom-VERSION=$VERSION/" apps/qgis-custom/qgis-ltr-custom.bat.template
17 |
18 | # compression
19 | tar cvjSf ../qgis-custom-$VERSION.tar.bz2 .
20 |
21 | # restores @@ marker
22 | sed -i "s/qgis-custom-VERSION=.*/qgis-custom-VERSION=@@/" apps/qgis-custom/qgis-ltr-custom.bat.template
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/qgis-custom-0.9-2.tar.bz2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom-0.9-2.tar.bz2
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-custom/WMTS_scales.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-custom/bin/qgis-custom-ltr.reg:
--------------------------------------------------------------------------------
1 | Windows Registry Editor Version 5.00
2 |
3 | [HKEY_CLASSES_ROOT\QGIS Project]
4 | @="QGIS Project"
5 |
6 | [HKEY_CLASSES_ROOT\QGIS Project\DefaultIcon]
7 | @="@osgeo4w@\\apps\\qgis-ltr\\icons\\qgis-qgs.ico"
8 |
9 | [HKEY_CLASSES_ROOT\QGIS Project\Shell]
10 |
11 | [HKEY_CLASSES_ROOT\QGIS Project\Shell\open]
12 | @=""
13 |
14 | [HKEY_CLASSES_ROOT\QGIS Project\Shell\open\command]
15 | @="\"@osgeo4w@\\bin\\qgis-ltr-custom.bat\" \"%1\""
16 |
17 | [HKEY_CLASSES_ROOT\.qgs]
18 | @="QGIS Project"
19 |
20 | [HKEY_CLASSES_ROOT\.qgz]
21 | @="QGIS Project"
22 |
23 | [HKEY_CLASSES_ROOT\QGIS Composer Template]
24 | @="QGIS Composer Template"
25 |
26 | [HKEY_CLASSES_ROOT\QGIS Composer Template\DefaultIcon]
27 | @="@osgeo4w@\\apps\\qgis-ltr\\icons\\qgis-qpt.ico"
28 |
29 | [HKEY_CLASSES_ROOT\.qpt]
30 | @="QGIS Composer Template"
31 |
32 | [HKEY_CLASSES_ROOT\QGIS Layer Settings]
33 | @="QGIS Layer Settings"
34 |
35 | [HKEY_CLASSES_ROOT\QGIS Layer Settings\DefaultIcon]
36 | @="@osgeo4w@\\apps\\qgis-ltr\\icons\\qgis-qml.ico"
37 |
38 | [HKEY_CLASSES_ROOT\.qml]
39 | @="QGIS Layer Settings"
40 |
41 | [HKEY_CLASSES_ROOT\QGIS Layer Definition]
42 | @="QGIS Layer Definition"
43 |
44 | [HKEY_CLASSES_ROOT\QGIS Layer Definition\DefaultIcon]
45 | @="@osgeo4w@\\apps\\qgis-ltr\\icons\\qgis-qlr.ico"
46 |
47 | [HKEY_CLASSES_ROOT\.qlr]
48 | @="QGIS Layer Definition"
49 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-custom/layout_checks.py:
--------------------------------------------------------------------------------
1 | # Some scripts to provide layout pre-print checks - See https://north-road.com/2019/01/14/on-custom-layout-checks-in-qgis-3-6-and-how-they-can-do-your-work-for-you/
2 |
3 |
4 | from qgis.core import check
5 |
6 |
7 | @check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck)
8 | def layout_map_crs_choice_check(context, feedback):
9 | layout = context.layout
10 | for i in layout.items():
11 | if isinstance(i, QgsLayoutItemMap):
12 | for l in i.layersToRender():
13 | # check if layer source is blacklisted
14 | if "mt1.google.com" in l.source():
15 | res = QgsValidityCheckResult()
16 | res.type = QgsValidityCheckResult.Critical
17 | res.title = "Blacklisted layer source"
18 | res.detailedDescription = 'This layout includes a Google Map layer ("{}"), which is in violation with their Terms of Service'.format(
19 | l.name()
20 | )
21 | return [res]
22 |
23 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-custom/qgis-ltr-custom.bat.template:
--------------------------------------------------------------------------------
1 | @echo off
2 | call "%~dp0\o4w_env.bat"
3 | call qt5_env.bat
4 | call py3_env.bat
5 | @echo off
6 | path %OSGEO4W_ROOT%\apps\qgis-ltr\bin;%PATH%
7 | set QGIS_PREFIX_PATH=%OSGEO4W_ROOT:\=/%/apps/qgis-ltr
8 | set GDAL_FILENAME_IS_UTF8=YES
9 | rem Set VSI cache to be used as buffer, see #6448
10 | set VSI_CACHE=TRUE
11 | set VSI_CACHE_SIZE=1000000
12 | set QT_PLUGIN_PATH=%OSGEO4W_ROOT%\apps\qgis-ltr\qtplugins;%OSGEO4W_ROOT%\apps\qt5\plugins
13 |
14 | rem config custom
15 |
16 | REM this "@@" pattern wil be replaced by make.sh with actual version
17 |
18 | set QGIS-CUSTOM-VERSION=@@
19 |
20 | REM point a location for pg_service.conf
21 | set PGSERVICEFILE=\\some-server\sit$\QGIS\custom\.pg_service.conf
22 |
23 | REM centralized plugins on a server if needed
24 | REM set QGIS_PLUGINPATH=\\some-server\sit$\QGIS\custom\python\plugins
25 |
26 | REM location for default settings (if provided by this package)
27 | set QGIS_GLOBAL_SETTINGS_FILE=%OSGEO4W_ROOT%\apps\qgis-custom\qgis_global_settings.ini
28 |
29 | REM location for default settings (if centralized on a network path)
30 | REM set QGIS_GLOBAL_SETTINGS_FILE=\\some-server\sit$\QGIS\custom\QGIS\qgis_global_settings.ini
31 |
32 | REM starts QGIS with various options (profile name, startup code )
33 |
34 | start "QGIS" /B "%OSGEO4W_ROOT%\bin\qgis-ltr-bin.exe" --profile custom --code %OSGEO4W_ROOT%\apps\qgis-custom\qgis_constrained_settings.py %*
35 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-custom/qgis_constrained_settings.py:
--------------------------------------------------------------------------------
1 | # script that will run qsettings constraints when QGIS starts
2 | # config file : qgis_constrained_settings.yml
3 | # cf https://gitlab.com/Oslandia/qgis/qgis-constrained-settings
4 |
5 | import yaml
6 | import codecs
7 | import pathlib
8 | import collections
9 | import configparser
10 | import PyQt5.QtCore
11 | import qgis.core
12 |
13 |
14 | def main():
15 | application = qgis.core.QgsApplication.instance()
16 | applicationSettings = qgis.core.QgsSettings(
17 | application.organizationName(), application.applicationName()
18 | )
19 | globalSettingsPath = pathlib.Path(applicationSettings.globalSettingsPath())
20 | globalSettingsDirPath = globalSettingsPath.parent
21 | qgisConstrainedSettingsPath = (
22 | globalSettingsDirPath / "qgis_constrained_settings.yml"
23 | )
24 |
25 | if not qgisConstrainedSettingsPath.is_file():
26 | print("No file named {}".format(qgisConstrainedSettingsPath))
27 | return
28 |
29 | print("Load constrained settings from {}".format(qgisConstrainedSettingsPath))
30 | with open(str(qgisConstrainedSettingsPath)) as f:
31 | constrainedSettings = yaml.safe_load(f)
32 |
33 | userSettings = PyQt5.QtCore.QSettings()
34 | print("Process {}".format(userSettings.fileName()))
35 |
36 | propertiesToRemove = constrainedSettings.get("propertiesToRemove", {})
37 | for group, properties in propertiesToRemove.items():
38 | userSettings.beginGroup(group)
39 | if isinstance(properties, str):
40 | if properties == "*":
41 | userSettings.remove("")
42 | else:
43 | for prop in properties:
44 | userSettings.remove(prop)
45 | userSettings.endGroup()
46 |
47 | globalSettings = configparser.ConfigParser()
48 | with open(str(globalSettingsPath)) as f:
49 | globalSettings.read_file(f)
50 |
51 | propertiesToMerge = constrainedSettings.get("propertiesToMerge", {})
52 | for group, properties in propertiesToMerge.items():
53 | if not globalSettings.has_section(group):
54 | continue
55 | userSettings.beginGroup(group)
56 | for prop in properties:
57 | if not globalSettings.has_option(group, prop):
58 | continue
59 | userPropertyValues = userSettings.value(prop)
60 | if not userPropertyValues:
61 | continue
62 | if not isinstance(userPropertyValues, list):
63 | userPropertyValues = [userPropertyValues]
64 | globalPropertyValues = globalSettings.get(group, prop)
65 | globalPropertyValues = globalPropertyValues.split(",")
66 | # codecs.decode(v, "unicode_espace") is used to convert the raw string into a normal
67 | # string. This is required to avoid changing \\ sequences into \\\\ sequences
68 | globalPropertyValues = list(
69 | map(
70 | lambda v: codecs.decode(v.strip('" '), "unicode_escape"),
71 | globalPropertyValues,
72 | )
73 | )
74 | userPropertyValues = globalPropertyValues + userPropertyValues
75 | # remove duplicates
76 | userPropertyValues = list(
77 | collections.OrderedDict.fromkeys(userPropertyValues)
78 | )
79 | userSettings.setValue(prop, userPropertyValues)
80 | userSettings.endGroup()
81 |
82 | propertyValuesToRemove = constrainedSettings.get("propertyValuesToRemove", {})
83 | for group, properties in propertyValuesToRemove.items():
84 | userSettings.beginGroup(group)
85 | for prop in properties:
86 | userPropertyValues = userSettings.value(prop)
87 | if not userPropertyValues:
88 | continue
89 | valuesToRemove = list(map(lambda v: v.rstrip("/\\ "), properties[prop]))
90 | userPropertyValues = [
91 | v for v in userPropertyValues if v.rstrip("/\\ ") not in valuesToRemove
92 | ]
93 | userSettings.setValue(prop, userPropertyValues)
94 | userSettings.endGroup()
95 |
96 |
97 | if __name__ == "__main__":
98 | main()
99 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-custom/qgis_constrained_settings.yml:
--------------------------------------------------------------------------------
1 | propertiesToRemove:
2 | qgis:
3 | - defaultProjectFileFormat
4 | proxy:
5 | - authcfg
6 | - proxyEnabled
7 | - proxyExcludeUrls
8 | - proxyHost
9 | - proxyPassword
10 | - proxyPort
11 | - proxyType
12 | - proxyUser
13 | - noProxyUrls
14 | PostgreSQL:
15 | - connections/selected
16 | - connections/bd_prod/service
17 | - connections/bd_prod/host
18 | - connections/bd_prod/port
19 | - connections/bd_prod/database
20 | - connections/bd_prod/username
21 | - connections/bd_prod/password
22 | - connections/bd_prod/sslmode
23 | - connections/bd_prod/saveUsername
24 | - connections/bd_prod/savePassword
25 | - connections/bd_prod/publicOnly
26 | - connections/bd_prod/dontResolveType
27 | - connections/bd_prod/geometryColumnsOnly
28 | - connections/bd_test/service
29 | - connections/bd_test/host
30 | - connections/bd_test/port
31 | - connections/bd_test/database
32 | - connections/bd_test/username
33 | - connections/bd_test/password
34 | - connections/bd_test/sslmode
35 | - connections/bd_test/saveUsername
36 | - connections/bd_test/savePassword
37 | - connections/bd_test/publicOnly
38 | - connections/bd_test/dontResolveType
39 | - connections/bd_test/geometryColumnsOnly
40 | PythonPlugins:
41 | - GdalTools
42 | - db_manager
43 | - processing
44 | - geometrycheckerplugin
45 | - SpreadsheetLayers
46 | - menu_from_project
47 | - redLayer
48 | - coordinator
49 | - french_locator_filter
50 | - mask
51 | - qNote
52 | menu_from_project:
53 | - is_setup_visible
54 | - optionTooltip
55 | - optionCreateGroup
56 | - optionLoadAll
57 | - projects/size
58 | - projects/1/file
59 | - projects/1/name
60 | - projects/1/location
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-custom/qgis_global_settings.ini:
--------------------------------------------------------------------------------
1 | [qgis]
2 | checkVersion=false
3 | defaultProjectFileFormat=Qgs
4 | dataSourceManagerNonModal=true
5 | parallel_rendering=true
6 | max_threads=3
7 | compileExpressions=true
8 | projOpenAtLaunch=0
9 | projOpenAtLaunchPath=//some-server/sit$/QGIS/custom/startup_project.qgs
10 | projectTemplateDir=//some-server/sit$/QGIS/custom/project_templates
11 | networkAndProxy\networkTimeout=30000
12 | networkAndProxy\userAgent=QGIS
13 | digitizing\default_snap_enabled=true
14 | # Default snapping tolerance (distance)
15 | digitizing\default_snapping_tolerance=12.0
16 | # Default snap to type
17 | # Vertex, VertexAndSegment, Segment
18 | digitizing\default_snap_type=Vertex
19 | # Default snapping unit
20 | # LayerUnits, Pixels, ProjectUnits
21 | digitizing\default_snapping_tolerance_unit=Pixels
22 | digitizing\snap_invisible_feature=false
23 | connections-xyz\OpenStreetMap\authcfg=
24 | connections-xyz\OpenStreetMap\password=
25 | connections-xyz\OpenStreetMap\referer=
26 | connections-xyz\OpenStreetMap\url=https://tile.openstreetmap.org/{z}/{x}/{y}.png
27 | connections-xyz\OpenStreetMap\username=
28 | connections-xyz\OpenStreetMap\zmax=19
29 | connections-xyz\OpenStreetMap\zmin=0
30 | connections-wms\%5BCRAIG%5D%20Mod%E8les%20Num%E9riques%20de%20Terrain%20%27tuil%E9%27%3A%20ombrage%2C%20couleur%2C%20courbes%20de%20niveau\ignoreGetMapURI=false
31 | customEnvVarsUse=false
32 | iconSize=24
33 | connections-wms\CRAIG%20ortho%20membres\invertAxisOrientation=false
34 | connections-wms\%5BCRAIG%5D%20Mod%E8les%20Num%E9riques%20de%20Terrain%20%27tuil%E9%27%3A%20ombrage%2C%20couleur%2C%20courbes%20de%20niveau\ignoreGetFeatureInfoURI=false
35 | customEnvVars=@Invalid()
36 | connections-wms\CRAIG%20ortho%20membres\ignoreReportedLayerExtents=false
37 | connections-wms\%5BCRAIG%5D%20Mod%E8les%20Num%E9riques%20de%20Terrain%20%27tuil%E9%27%3A%20ombrage%2C%20couleur%2C%20courbes%20de%20niveau\ignoreAxisOrientation=false
38 | connections-wms\CRAIG%20ortho%20membres\ignoreGetMapURI=false
39 | connections-wms\%5BCRAIG%5D%20Mod%E8les%20Num%E9riques%20de%20Terrain%20%27tuil%E9%27%3A%20ombrage%2C%20couleur%2C%20courbes%20de%20niveau\invertAxisOrientation=false
40 | connections-wms\CRAIG%20ortho%20membres\smoothPixmapTransform=false
41 | connections-wms\%5BCRAIG%5D%20Mod%E8les%20Num%E9riques%20de%20Terrain%20%27tuil%E9%27%3A%20ombrage%2C%20couleur%2C%20courbes%20de%20niveau\referer=
42 | connections-wms\CRAIG%20ortho%20membres\dpiMode=7
43 | connections-wms\%5BCRAIG%5D%20Mod%E8les%20Num%E9riques%20de%20Terrain%20%27tuil%E9%27%3A%20ombrage%2C%20couleur%2C%20courbes%20de%20niveau\smoothPixmapTransform=false
44 | connections-wms\CRAIG%20ortho%20membres\referer=
45 | connections-wms\%5BCRAIG%5D%20Mod%E8les%20Num%E9riques%20de%20Terrain%20%27tuil%E9%27%3A%20ombrage%2C%20couleur%2C%20courbes%20de%20niveau\dpiMode=7
46 |
47 | [proxy]
48 | proxyEnabled=true
49 | proxyType=DefaultProxy
50 |
51 | [PostgreSQL]
52 | connections\selected=bd_prod
53 |
54 | connections\bd_prod\allowGeometrylessTables=true
55 | connections\bd_prod\authcfg=
56 | connections\bd_prod\dontResolveType=false
57 | connections\bd_prod\estimatedMetadata=true
58 | connections\bd_prod\geometryColumnsOnly=false
59 | connections\bd_prod\projectsInDatabase=true
60 | connections\bd_prod\publicOnly=false
61 | connections\bd_prod\service=bd_prod
62 | connections\bd_prod\sslmode=SslPrefer
63 |
64 | connections\bd_test\allowGeometrylessTables=true
65 | connections\bd_test\authcfg=
66 | connections\bd_test\dontResolveType=false
67 | connections\bd_test\estimatedMetadata=true
68 | connections\bd_test\geometryColumnsOnly=false
69 | connections\bd_test\projectsInDatabase=true
70 | connections\bd_test\publicOnly=false
71 | connections\bd_test\service=bd_test
72 | connections\bd_test\sslmode=SslPrefer
73 |
74 | [PythonPlugins]
75 | GdalTools=true
76 | db_manager=true
77 | processing=true
78 | MetaSearch=false
79 | geometrycheckerplugin=true
80 | topolplugin=true
81 | SpreadsheetLayers=true
82 | menu_from_project=true
83 | redLayer=true
84 | coordinator=true
85 | french_locator_filter=true
86 | mask=true
87 | qNote=true
88 |
89 | [app]
90 | projections\defaultProjectCrs=EPSG:3945
91 | projections\newProjectCrsBehavior=UsePresetCrs
92 | projections\unknownCrsBehavior=PromptUserForCrs
93 |
94 | [Projections]
95 | layerDefaultCrs=EPSG:3945
96 |
97 | [svg]
98 | searchPathsForSVG=//some-server/sit$/QGIS/custom/svg
99 |
100 | [Map]
101 | searchRadiusMM=3
102 |
103 | [core]
104 | Layout\searchPathsForTemplates=//some-server/sit$/QGIS/custom/composer_templates
105 |
106 | [gui]
107 | LayoutDesigner\defaultFont=Calibri
108 | locator_filters\enabled_optionpages=false
109 | locator_filters\enabled_layouts=false
110 | locator_filters\enabled_actions=false
111 | locator_filters\default_edit_features=false
112 | locator_filters\default_optionpages=false
113 | locator_filters\default_layouts=false
114 | locator_filters\default_calculator=true
115 | locator_filters\default_features=true
116 |
117 |
118 | [variables]
119 | organisation=Grenoble Alpes M\xe9tropole
120 |
121 |
122 | [cache]
123 | size=@Variant(\0\0\0\x81\0\0\0\0\0\xea`\0)
124 |
125 |
126 | [menu_from_project]
127 | is_setup_visible=true
128 | optionTooltip=true
129 | optionCreateGroup=false
130 | optionLoadAll=true
131 | projects\size=1
132 | projects\1\file=//some-server/sit$/QGIS/custom/socle_data_central.qgs
133 | projects\1\name=Donn\xe9\x65s de r\xe9\x66\xe9rence
134 | projects\1\location=new
135 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## Changelog
2 |
3 | **Version 1.0.1**
4 |
5 | * Add sheet name in default layer name.
6 | * Handle non ascii characters in sheet names.
7 | * Dynamically load .ui files.
8 | * Handle non ascii characters in file paths.
9 | * Add sheet name in .vrt filename to support multiple worksheets.
10 | * Add russian translation file.
11 |
12 | **Version 1.0**
13 |
14 | * Add changelog file.
15 | * Add checkbox for end of file detection.
16 | * Force encoding to UTF-8 before adding layer to layer tree.
17 | * Fix column format selectors line position.
18 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/README.rst:
--------------------------------------------------------------------------------
1 | .. SpreadsheetLayers documentation master file, created by
2 | sphinx-quickstart on Thu Jan 15 15:15:55 2015.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | QGIS-SpreadSheetLayers
7 | ======================
8 |
9 | QGIS plugin to load layers from spreadsheet files (\*.ods, \*.xls, \*.xlsx)
10 |
11 | Description
12 | -----------
13 |
14 | This plugin adds a *Add spreadsheet layer* entry in *Layer* / *Add new Layer*
15 | menu and a corresponding button in *Layers* toolbar. These two links open the
16 | same dialog to load a layer from a spreadsheet file with some options:
17 |
18 | * select file
19 | * layer name
20 | * sheet selection
21 | * header at first line
22 | * ignore some rows
23 | * load geometry from x and y fields
24 |
25 | When dialog is accepted, it creates a new GDAL VRT file in same folder as the
26 | source data file and layer name, expanded with a *.vrt* suffix, which is
27 | loaded into QGIS.
28 |
29 | When reusing the same file twice, the dialog loads its values from the
30 | existing *.vrt* file.
31 |
32 | Limitations
33 | -----------
34 |
35 | Due to a GDAL/OGR lacks of functionalities:
36 |
37 | - use of header line on a per file basis ;
38 | - ignore lines at the beginning of file ;
39 | - correct end of .xls files detection.
40 |
41 | The plugin use an SQLITE select statement with offset and limit parameters
42 | to extract corresponding data from the source file. When one of this
43 | functionalities is in use, this could have some side effects.
44 |
45 | With GDAL <= 1.11.1, the plugin can't load geometry. With graceful
46 | degradation, geometry checkbox is then locked. To get the GDAL version in use,
47 | run this commands in QGIS python console:
48 |
49 | .. code::
50 |
51 | import osgeo.gdal
52 | print osgeo.gdal.__version__
53 |
54 | When opening a spreadsheet file, GDAL/OGR will try to detect the data type of
55 | columns (Date, Integer, Real, String, ...). This automatic detection occurs
56 | outside of plugin header and ignore lines functionalities, so when using this,
57 | GDAL/OGR should be unable to correctly detect data types.
58 |
59 | Configuration
60 | -------------
61 |
62 | GDAL do not allow to define the presence of header line on a per layer basis,
63 | this choice is made through environment variables for each driver
64 | *OGR_ODS_HEADERS*, *OGR_XLS_HEADERS* and *OGR_XLSX_HEADERS*,
65 | with tree possible values *FORCE*, *DISABLE* and *AUTO*.
66 | For more details, consult the corresponding drivers documentation ie:
67 | http://www.gdal.org/drv_ods.html, http://www.gdal.org/drv_xls.html
68 | and http://www.gdal.org/drv_xlsx.html.
69 |
70 | You can change this values in QGIS settings:
71 |
72 | - open *Settings* / *Options* dialog;
73 | - select *System* tab, and go to *Environment* section;
74 | - check *Use custom variables*.
75 | - add a new line. Example:
76 |
77 | *Overwrite* | *OGR_ODS_HEADERS* | *FORCE*
78 |
79 | - restart QGIS to take this into consideration.
80 |
81 | Development install (linux)
82 | ---------------------------
83 |
84 | .. code::
85 |
86 | git clone git@github.com:camptocamp/QGIS-SpreadSheetLayers.git SpreadsheetLayers
87 | ln -s SpreadsheetLayers ~/.qgis2/python/plugins/
88 | cd SpreadsheetLayers
89 | make
90 |
91 | - run QGIS and activate SpreadsheetLayers plugin.
92 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/SpreadsheetLayersPlugin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | /***************************************************************************
4 | SpreadsheetLayersPlugin
5 | A QGIS plugin
6 | Load layers from MS Excel and OpenOffice spreadsheets
7 | -------------------
8 | begin : 2014-10-30
9 | git sha : $Format:%H$
10 | copyright : (C) 2014 by Camptocamp
11 | email : info@camptocamp.com
12 | ***************************************************************************/
13 |
14 | /***************************************************************************
15 | * *
16 | * This program is free software; you can redistribute it and/or modify *
17 | * it under the terms of the GNU General Public License as published by *
18 | * the Free Software Foundation; either version 2 of the License, or *
19 | * (at your option) any later version. *
20 | * *
21 | ***************************************************************************/
22 | """
23 | from __future__ import print_function
24 | import os.path
25 | from qgis.core import Qgis, QgsVectorLayer, QgsProject
26 | from qgis.PyQt import QtCore, QtGui, QtWidgets
27 | # Initialize Qt resources from file resources.py
28 | from .ui import resources_rc
29 | # Import the code for the dialog
30 | from .widgets.SpreadsheetLayersDialog import SpreadsheetLayersDialog
31 |
32 |
33 | class SpreadsheetLayersPlugin(QtCore.QObject):
34 | """QGIS Plugin Implementation."""
35 |
36 | def __init__(self, iface):
37 | """Constructor.
38 |
39 | :param iface: An interface instance that will be passed to this class
40 | which provides the hook by which you can manipulate the QGIS
41 | application at run time.
42 | :type iface: QgsInterface
43 | """
44 | super(SpreadsheetLayersPlugin, self).__init__()
45 | # Save reference to the QGIS interface
46 | self.iface = iface
47 | # initialize plugin directory
48 | self.plugin_dir = os.path.dirname(__file__)
49 | # initialize locale
50 | locale = QtCore.QSettings().value('locale/userLocale')[0:2]
51 | locale_path = os.path.join(
52 | self.plugin_dir,
53 | 'i18n',
54 | 'SpreadsheetLayers_{}.qm'.format(locale))
55 |
56 | if os.path.exists(locale_path):
57 | self.translator = QtCore.QTranslator()
58 | self.translator.load(locale_path)
59 |
60 | if QtCore.qVersion() > '4.3.3':
61 | QtCore.QCoreApplication.installTranslator(self.translator)
62 |
63 | def initGui(self):
64 | self.action = QtWidgets.QAction(
65 | QtGui.QIcon(':/plugins/SpreadsheetLayers/icon/mActionAddSpreadsheetLayer.svg'),
66 | self.tr("Add spreadsheet layer"),
67 | self)
68 | self.action.triggered.connect(self.showDialog)
69 | if Qgis.QGIS_VERSION_INT > 20400:
70 | self.iface.addLayerMenu().addAction(self.action)
71 | else:
72 | menu = self.iface.layerMenu()
73 | for action in menu.actions():
74 | if action.isSeparator():
75 | break
76 | self.iface.layerMenu().insertAction(action, self.action)
77 | self.iface.layerToolBar().addAction(self.action)
78 |
79 | def unload(self):
80 | if hasattr(self, 'action'):
81 | if Qgis.QGIS_VERSION_INT > 20400:
82 | self.iface.addLayerMenu().removeAction(self.action)
83 | else:
84 | self.iface.layerMenu().removeAction(self.action)
85 | self.iface.layerToolBar().removeAction(self.action)
86 |
87 | def showDialog(self):
88 | dlg = SpreadsheetLayersDialog(self.iface.mainWindow())
89 | dlg.show()
90 | if dlg.exec_():
91 | layer = QgsVectorLayer(dlg.vrtPath(), dlg.layerName(), 'ogr')
92 | layer.setProviderEncoding('UTF-8')
93 | if not layer.isValid():
94 | # fix_print_with_import
95 | print("Layer failed to load")
96 | else:
97 | QgsProject.instance().addMapLayer(layer)
98 | dlg.deleteLater()
99 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | /***************************************************************************
4 | SpreadsheetLayersPlugin
5 | A QGIS plugin
6 | Load layers from MS Excel and OpenOffice spreadsheets
7 | -------------------
8 | begin : 2014-10-30
9 | copyright : (C) 2014 by Camptocamp
10 | email : info@camptocamp.com
11 | git sha : $Format:%H$
12 | ***************************************************************************/
13 |
14 | /***************************************************************************
15 | * *
16 | * This program is free software; you can redistribute it and/or modify *
17 | * it under the terms of the GNU General Public License as published by *
18 | * the Free Software Foundation; either version 2 of the License, or *
19 | * (at your option) any later version. *
20 | * *
21 | ***************************************************************************/
22 | This script initializes the plugin, making it known to QGIS.
23 | """
24 |
25 |
26 | # noinspection PyPep8Naming
27 | def classFactory(iface): # pylint: disable=invalid-name
28 | """Load SpreadsheetLayersPlugin class from file SpreadsheetLayersPlugin.
29 |
30 | :param iface: A QGIS interface instance.
31 | :type iface: QgsInterface
32 | """
33 | #
34 | from .SpreadsheetLayersPlugin import SpreadsheetLayersPlugin
35 | return SpreadsheetLayersPlugin(iface)
36 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/help/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | .doctrees
3 | *.pot
4 | *.mo
5 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/help/source/index.rst:
--------------------------------------------------------------------------------
1 | .. SpreadsheetLayers documentation master file, created by
2 | sphinx-quickstart on Thu Jan 15 15:15:55 2015.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | .. include:: ../../README.rst
7 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/i18n/.gitignore:
--------------------------------------------------------------------------------
1 | *.qm
2 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/metadata.txt:
--------------------------------------------------------------------------------
1 | # This file contains metadata for your plugin. Since
2 | # version 2.0 of QGIS this is the proper way to supply
3 | # information about a plugin. The old method of
4 | # embedding metadata in __init__.py will
5 | # is no longer supported since version 2.0.
6 |
7 | # This file should be included when you package your plugin.
8 |
9 | # Mandatory items:
10 |
11 | [general]
12 | name=Spreadsheet Layers
13 | qgisMinimumVersion=3.0
14 | description=Load layers from spreadsheet files (*.ods, *.xls, *.xlsx)
15 | about=This plugin adds a "Add spreadsheet layer" entry in "Layer" / "Add new Layer" menu and a corresponding button in the "Layers" toolbar.
16 | These two links open the same dialog to load a layer from a spreadsheet file (*.ods, *.xls, *.xlsx) with some options (use header at first line, ignore some rows and optionally load geometry from x and y fields).
17 | When this dialog is accepted, it creates a new GDAL VRT file in same folder as the source data file and layer name, expanded with a .vrt suffix which is loaded into QGIS using OGR VRT driver.
18 | When reusing the same file twice, the dialog loads its values from the existing .vrt file.
19 | No need to install additional dependencies.
20 | version=2.0.1
21 | author=Camptocamp
22 | email=info@camptocamp.com
23 |
24 | # End of mandatory metadata
25 |
26 | # Optional items:
27 |
28 | # Uncomment the following line and add your changelog:
29 | # changelog=
30 |
31 | # Tags are comma separated with spaces allowed
32 | tags=spreadsheet,ods,xls,xlsx,calc,excel
33 |
34 | homepage=https://github.com/camptocamp/QGIS-SpreadSheetLayers
35 | tracker=https://github.com/camptocamp/QGIS-SpreadSheetLayers/issues
36 | repository=https://github.com/camptocamp/QGIS-SpreadSheetLayers
37 | icon=resources/icon/mActionAddSpreadsheetLayer.svg
38 | # experimental flag
39 | experimental=False
40 |
41 | # deprecated flag (applies to the whole plugin, not just a single version)
42 | deprecated=False
43 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/plugin_upload.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """This script uploads a plugin package to the plugin repository.
3 | Authors: A. Pasotti, V. Picavet
4 | git sha : $TemplateVCSFormat
5 | """
6 |
7 | import os
8 | import sys
9 | import getpass
10 | import xmlrpc.client
11 | from optparse import OptionParser
12 |
13 | # Configuration
14 | PROTOCOL = 'https'
15 | SERVER = 'plugins.qgis.org'
16 | PORT = '443'
17 | ENDPOINT = '/plugins/RPC2/'
18 | VERBOSE = False
19 |
20 |
21 | def main(parameters, arguments):
22 | """Main entry point.
23 |
24 | :param parameters: Command line parameters.
25 | :param arguments: Command line arguments.
26 | """
27 | address = "{protocol}://{username}:{password}@{server}:{port}{endpoint}".format(
28 | protocol=PROTOCOL,
29 | username=parameters.username,
30 | password=parameters.password,
31 | server=parameters.server,
32 | port=parameters.port,
33 | endpoint=ENDPOINT)
34 | print("Connecting to: %s" % hide_password(address))
35 |
36 | server = xmlrpc.client.ServerProxy(address, verbose=VERBOSE)
37 |
38 | try:
39 | with open(arguments[0], 'rb') as handle:
40 | plugin_id, version_id = server.plugin.upload(
41 | xmlrpc.client.Binary(handle.read()))
42 | print("Plugin ID: %s" % plugin_id)
43 | print("Version ID: %s" % version_id)
44 | except xmlrpc.client.ProtocolError as err:
45 | print("A protocol error occurred")
46 | print("URL: %s" % hide_password(err.url, 0))
47 | print("HTTP/HTTPS headers: %s" % err.headers)
48 | print("Error code: %d" % err.errcode)
49 | print("Error message: %s" % err.errmsg)
50 | except xmlrpc.client.Fault as err:
51 | print("A fault occurred")
52 | print("Fault code: %d" % err.faultCode)
53 | print("Fault string: %s" % err.faultString)
54 |
55 |
56 | def hide_password(url, start=6):
57 | """Returns the http url with password part replaced with '*'.
58 |
59 | :param url: URL to upload the plugin to.
60 | :type url: str
61 |
62 | :param start: Position of start of password.
63 | :type start: int
64 | """
65 | start_position = url.find(':', start) + 1
66 | end_position = url.find('@')
67 | return "%s%s%s" % (
68 | url[:start_position],
69 | '*' * (end_position - start_position),
70 | url[end_position:])
71 |
72 |
73 | if __name__ == "__main__":
74 | parser = OptionParser(usage="%prog [options] plugin.zip")
75 | parser.add_option(
76 | "-w", "--password", dest="password",
77 | help="Password for plugin site. "
78 | "You can use environment variable 'PLUGIN_UPLOAD_PASSWORD', "
79 | "or the password will be prompted on runtime.", metavar="******")
80 | parser.add_option(
81 | "-u", "--username", dest="username",
82 | help="Username of plugin site. "
83 | "You can use environment variable 'PLUGIN_UPLOAD_USERNAME', "
84 | "or the username will be prompted on runtime.", metavar="user")
85 | parser.add_option(
86 | "-p", "--port", dest="port",
87 | help="Server port to connect to", metavar="80")
88 | parser.add_option(
89 | "-s", "--server", dest="server",
90 | help="Specify server name", metavar="plugins.qgis.org")
91 | options, args = parser.parse_args()
92 | if len(args) != 1:
93 | print("Please specify zip file.\n")
94 | parser.print_help()
95 | sys.exit(1)
96 | if not options.server:
97 | options.server = SERVER
98 | if not options.port:
99 | options.port = PORT
100 | if not options.username:
101 | username = os.environ.get('PLUGIN_UPLOAD_USERNAME')
102 | if username:
103 | # environment variable
104 | options.username = username
105 | else:
106 | # interactive mode
107 | username = getpass.getuser()
108 | print("Please enter user name [%s] :" % username, end=' ')
109 |
110 | res = input()
111 | if res != "":
112 | options.username = res
113 | else:
114 | options.username = username
115 | if not options.password:
116 | password = os.environ.get('PLUGIN_UPLOAD_PASSWORD')
117 | if password:
118 | # environment variable
119 | options.password = password
120 | else:
121 | # interactive mode
122 | options.password = getpass.getpass()
123 | main(options, args)
124 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/requirements.txt:
--------------------------------------------------------------------------------
1 | sphinx
2 | sphinx-intl
3 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/resources/resources.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | icon/mActionAddSpreadsheetLayer.svg
4 |
5 |
6 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/ui/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/util/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/util/gdal_util.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import os
4 | import tempfile
5 | from osgeo import ogr
6 |
7 | def testGdal():
8 | # Inspired from gdal test ogr_vrt_34
9 | # https://github.com/OSGeo/gdal/commit/82074ed5bd67d2efbfbcea50c5416856d9c5826d
10 | path = os.path.join(tempfile.gettempdir(), 'gdal_test.csv')
11 | f = open(path, 'wb')
12 | f.write('x,y\n'.encode('ascii'))
13 | f.write('2,49\n'.encode('ascii'))
14 | f.close()
15 |
16 | vrt_xml = """
17 |
18 |
19 | """+path+"""
20 | SELECT * FROM gdal_test
21 |
22 |
23 |
24 |
25 | """
26 |
27 | ds = ogr.Open( vrt_xml )
28 |
29 | lyr = ds.GetLayer(0)
30 | lyr.SetIgnoredFields(['x', 'y'])
31 | f = lyr.GetNextFeature()
32 | result = True
33 | if f is None:
34 | result = False
35 | elif f.GetGeometryRef().ExportToWkt() != 'POINT (2 49)':
36 | result = False
37 |
38 | f = None
39 | lyr = None
40 | ds = None
41 | os.unlink(path)
42 |
43 | return result
44 |
45 | GDAL_COMPAT = testGdal()
46 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/SpreadsheetLayers/widgets/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | /***************************************************************************
4 | Coordinator
5 | A QGIS plugin
6 | Plugin to handle coordinate tasks better
7 | Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
8 | -------------------
9 | begin : 2019-05-04
10 | copyright : (C) 2019 by Jonas K�pper
11 | email : qgis@ag99.de
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 | from qgis.core import QgsMessageLog
26 |
27 | # noinspection PyPep8Naming
28 | def classFactory(iface): # pylint: disable=invalid-name
29 | """Load Coordinator class from file Coordinator.
30 |
31 | :param iface: A QGIS interface instance.
32 | :type iface: QgsInterface
33 | """
34 | #
35 | from .coordinator import Coordinator
36 | #QgsMessageLog.logMessage("!!", "Coordinator")
37 | return Coordinator(iface)
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/funcs.py:
--------------------------------------------------------------------------------
1 | from math import floor
2 |
3 | from PyQt5.Qt import QLocale, QCoreApplication
4 |
5 | from qgis.core import QgsMessageLog
6 |
7 | def coordinatorDmsStringsToDecimal(deg, minute, sec):
8 | result = 0.0
9 | if(len(deg)>0): result += QLocale().toFloat(deg)[0]
10 | if(len(minute)>0): result += QLocale().toFloat(minute)[0]/60
11 | if(len(sec)>0): result += QLocale().toFloat(sec)[0]/3600
12 | return result
13 |
14 | def coordinatorDecimalToDms(deg):
15 | isNegative = deg < 0
16 | degree = int(floor(abs(deg)))
17 | deg2 = abs(deg)-degree
18 | minute = int(floor(deg2 * 60))
19 | seconds = ( deg2 % (1/60) ) * 3600
20 |
21 | return (isNegative, degree, minute, seconds)
22 |
23 |
24 | def coordinatorLog(message):
25 | QgsMessageLog.logMessage(message, "Coordinator")
26 |
27 | class CoordinatorTranslator:
28 | # noinspection PyMethodMayBeStatic
29 | def tr(message, disambugation = None):
30 | """Get the translation for a string using Qt translation API.
31 |
32 | We implement this ourselves since we do not inherit QObject.
33 |
34 | :param message: String for translation.
35 | :type message: str, QString
36 | :param disambugation: an identifying string, for when the same sourceText is used in different roles within the same context
37 | :type disambugation: str, QString
38 |
39 | :returns: Translated version of message.
40 | :rtype: QString
41 | """
42 | # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
43 | return QCoreApplication.translate('CT', message, disambugation)
44 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/help.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Helvetica, Calibri, Arial, sans-serif
3 | }
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/capture.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/capture.gif
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_basics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_basics.png
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_capture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_capture.png
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_copy.png
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_digitize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_digitize.png
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_labels.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_labels.ai
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_main.png
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_maptools.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/help/images/screen_maptools.png
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/i18n/coordinator_de.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/i18n/coordinator_de.qm
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/i18n/coordinator_fr.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/i18n/coordinator_fr.qm
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/metadata.txt:
--------------------------------------------------------------------------------
1 | # This file should be included when you package your plugin.# Mandatory items:
2 |
3 | [general]
4 | name=Coordinator
5 | qgisMinimumVersion=3.4
6 | description=Capture, transform and use coordinates
7 | version=0.4
8 | author=Jonas Küpper
9 | email=qgis@geograffr.eu
10 |
11 | about=The purpose of this plugin is to make handling of coordinate IO easier and includes a transformation tool and supports creation of simple features.
12 | This plugin overlaps in different ways with the purpose of the plugins Coordinate Capture, Lat Lon Tools and the Advanced Digitize Panel. It however aims to integrate in a clean and simple interface multiple tasks these tools are sometimes used together. And yes...: Its almost as it's just another coordinate tool. :)
13 | The two main functions of this plugin are:
14 | (A) a simple and easy to use coordinate transformation tool with an integrated picker and
15 | (B) a quick to use coordinate digitizer with support for coordinates in an arbitrary CRS independent of project or layer CRS.
16 | Both of these functions are seamlessly integrated and are implemented as a single, unique operation.
17 |
18 | tracker=https://github.com/iona5/coordinator/issues
19 | repository=https://github.com/iona5/coordinator
20 | # End of mandatory metadata
21 |
22 | # Recommended items:
23 |
24 | # Uncomment the following line and add your changelog:
25 | changelog=0.4
26 | - fix capture with wrong coordinate system with Point geometry
27 | - ensure a valid CRS is selected when changing through QgsProjectionSelectionDialog (issue #5)
28 | 0.3.2
29 | - metadata fix
30 | 0.3.1
31 | - "add Feature"-button should be disabled when selecting non editing tool
32 | - pull request 16: use default values when capturing points (thanks @AlexanderFinkbeiner)
33 | 0.3
34 | - issue #2: make sure capture tool is deselected when user selects another tool
35 | - issue #12: negative coordinates in geodetic systems were not properly processed
36 | - digitize helper announced feature addition without actually knowing if it succeeded
37 | - various translation issus (including issues #7, #8)
38 | - internal bugfixes regarding stability and test regime
39 | 0.2
40 | - added french translation by SebastienPeillet
41 | - fix issue #3: switching to edit mode in QGIS compiled with Qt < 5.11 failed
42 | - fix issue #1: locked CRS does not change when CRS of selected layer changes
43 | - enhanced test suite
44 | - build improvements
45 | - help improvements
46 | - general cleanup
47 | 0.1 - Initial release
48 |
49 | # Tags are comma separated with spaces allowed
50 | tags=python,coordinate,coordinates,transformation,digitizing,clipboard,capture
51 |
52 | homepage=https://github.com/iona5/coordinator
53 | category=Plugins
54 | icon=icons/marker.svg
55 | # experimental flag
56 | experimental=True
57 |
58 | # deprecated flag (applies to the whole plugin, not just a single version)
59 | deprecated=False
60 |
61 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/resources.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | icons/help.svg
4 | icons/warning.svg
5 | icons/addToCanvas.svg
6 | icons/capture.svg
7 | icons/clear.svg
8 | icons/copy.svg
9 | icons/locked.svg
10 | icons/marker.svg
11 | icons/panMap.svg
12 | icons/unlocked.svg
13 |
14 |
15 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/test/__init__.py:
--------------------------------------------------------------------------------
1 | # import qgis libs so that ve set the correct sip api version
2 | import os, sys, qgis # pylint: disable=W0611 # NOQA
3 | from PyQt5.Qt import QLocale
4 | from qgis.testing import unittest
5 | from qgis.core import QgsProject, QgsVectorLayer
6 |
7 | def run_all():
8 | loader = unittest.TestLoader()
9 |
10 | start_dir = os.path.dirname(__file__)
11 | suite = loader.discover(start_dir)
12 |
13 | runner = unittest.TextTestRunner(verbosity = 3, stream=sys.stdout)
14 | runner.run(suite)
15 |
16 | class CoordinatorTestCase(unittest.TestCase):
17 |
18 | def __init__(self, testCase):
19 | super(unittest.TestCase, self).__init__(testCase)
20 | self.project = None
21 |
22 | self._addedLayers = []
23 |
24 |
25 | def setUp(self):
26 | self.project = QgsProject.instance()
27 |
28 |
29 | def tearDown(self):
30 | while len(self._addedLayers) > 0:
31 | layerName = self._addedLayers.pop()
32 | layers = self.project.mapLayersByName(layerName)
33 | self.project.removeMapLayers([layer.id() for layer in layers])
34 |
35 |
36 | def addMapLayer(self, mapLayer):
37 | self.project.addMapLayer(mapLayer, True)
38 | self._addedLayers.append(mapLayer.name())
39 |
40 |
41 | def addVectorLayerFile(self, vectorLayerFile, vectorLayerName):
42 | vectorLayer = QgsVectorLayer(vectorLayerFile, vectorLayerName, "ogr")
43 | self.addMapLayer(vectorLayer)
44 | return vectorLayer
45 |
46 |
47 | def addEuropeLayer(self):
48 | return self.addVectorLayerFile(os.path.join(os.path.dirname(__file__), "data/europe.geojson" ), "europe")
49 |
50 |
51 | def assertTextFieldCloseTo(self, expected, textField, tolerance = 1, msg = None):
52 | textFieldValue = QLocale().toFloat(textField.text())[0]
53 |
54 | result = ( (expected - tolerance) <= textFieldValue <= (expected + tolerance) )
55 |
56 | if(not result):
57 | if msg == None:
58 | msg = "value '%f' of QTextField is not close to %f±%f)" % (textFieldValue, expected, tolerance)
59 |
60 | raise AssertionError(msg)
61 |
62 |
63 | def assertTextFieldBetween(self, lower, upper, textField, msg = None):
64 | textFieldValue = QLocale().toFloat(textField.text())[0]
65 |
66 | result = (lower < textFieldValue < upper)
67 |
68 | if msg == None:
69 | msg = "value '%f' of QTextField is not between %f and %f)" % (textFieldValue, lower, upper)
70 |
71 | self.assertTrue(result, msg)
72 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/test/__main__.py:
--------------------------------------------------------------------------------
1 | import unittest, sys, os
2 |
3 | from . import run_all
4 |
5 | if sys.platform == "win32" and 'QT_QPA_PLATFORM_PLUGIN_PATH' not in os.environ:
6 | if 'QT_PLUGIN_PATH' in os.environ:
7 | os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = os.environ['QT_PLUGIN_PATH']
8 | else:
9 | if "OSGEO4W_ROOT" in os.environ:
10 | qtPluginPath = os.path.join(os.path.normpath(os.environ["OSGEO4W_ROOT"].strip()),'apps/qt5/plugins')
11 | os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = qtPluginPath
12 | else:
13 | print("Cannot set QT_QPA_PLATFORM")
14 | sys.exit(1)
15 |
16 | sys.path.append(os.path.join(os.path.dirname(__file__), "../.."))
17 |
18 | run_all()
19 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/test/data/tenbytenraster.asc:
--------------------------------------------------------------------------------
1 | NCOLS 10
2 | NROWS 10
3 | XLLCENTER 1535380.000000
4 | YLLCENTER 5083260.000000
5 | DX 10
6 | DY 10
7 | NODATA_VALUE -9999
8 | 0 1 2 3 4 5 6 7 8 9
9 | 0 1 2 3 4 5 6 7 8 9
10 | 0 1 2 3 4 5 6 7 8 9
11 | 0 1 2 3 4 5 6 7 8 9
12 | 0 1 2 3 4 5 6 7 8 9
13 | 0 1 2 3 4 5 6 7 8 9
14 | 0 1 2 3 4 5 6 7 8 9
15 | 0 1 2 3 4 5 6 7 8 9
16 | 0 1 2 3 4 5 6 7 8 9
17 | 0 1 2 3 4 5 6 7 8 9
18 | CRS
19 | NOTES
20 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/test/data/tenbytenraster.keywords:
--------------------------------------------------------------------------------
1 | title: Tenbytenraster
2 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/test/data/tenbytenraster.lic:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Tim Sutton, Linfiniti Consulting CC
5 |
6 |
7 |
8 | tenbytenraster.asc
9 | 2700044251
10 | Yes
11 | Tim Sutton
12 | Tim Sutton (QGIS Source Tree)
13 | Tim Sutton
14 | This data is publicly available from QGIS Source Tree. The original
15 | file was created and contributed to QGIS by Tim Sutton.
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/test/data/tenbytenraster.prj:
--------------------------------------------------------------------------------
1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/test/data/tenbytenraster.qml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 0
26 |
27 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/test/test_init.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """Tests QGIS plugin init."""
3 |
4 | __author__ = 'Tim Sutton '
5 | __revision__ = '$Format:%H$'
6 | __date__ = '17/10/2010'
7 | __license__ = "GPL"
8 | __copyright__ = 'Copyright 2012, Australia Indonesia Facility for '
9 | __copyright__ += 'Disaster Reduction'
10 |
11 | import os
12 | import unittest
13 | import logging
14 | import configparser
15 |
16 | LOGGER = logging.getLogger('QGIS')
17 |
18 |
19 | class TestInit(unittest.TestCase):
20 | """Test that the plugin init is usable for QGIS.
21 |
22 | Based heavily on the validator class by Alessandro
23 | Passoti available here:
24 |
25 | http://github.com/qgis/qgis-django/blob/master/qgis-app/
26 | plugins/validator.py
27 |
28 | """
29 |
30 | def test_read_init(self):
31 | """Test that the plugin __init__ will validate on plugins.qgis.org."""
32 |
33 | # You should update this list according to the latest in
34 | # https://github.com/qgis/qgis-django/blob/master/qgis-app/
35 | # plugins/validator.py
36 |
37 | required_metadata = [
38 | 'name',
39 | 'description',
40 | 'version',
41 | 'qgisMinimumVersion',
42 | 'email',
43 | 'author']
44 |
45 | file_path = os.path.abspath(os.path.join(
46 | os.path.dirname(__file__), os.pardir,
47 | 'metadata.txt'))
48 | LOGGER.info(file_path)
49 | metadata = []
50 | parser = configparser.ConfigParser()
51 | parser.optionxform = str
52 | parser.read(file_path)
53 | message = 'Cannot find a section named "general" in %s' % file_path
54 | assert parser.has_section('general'), message
55 | metadata.extend(parser.items('general'))
56 |
57 | for expectation in required_metadata:
58 | message = ('Cannot find metadata "%s" in metadata source (%s).' % (
59 | expectation, file_path))
60 |
61 | self.assertIn(expectation, dict(metadata), message)
62 |
63 | if __name__ == '__main__':
64 | unittest.main()
65 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/test/test_qgis_environment.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """Tests for QGIS functionality.
3 |
4 |
5 | .. note:: This program is free software; you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation; either version 2 of the License, or
8 | (at your option) any later version.
9 |
10 | """
11 | __author__ = 'tim@linfiniti.com'
12 | __date__ = '20/01/2011'
13 | __copyright__ = ('Copyright 2012, Australia Indonesia Facility for '
14 | 'Disaster Reduction')
15 |
16 | import os
17 | import unittest
18 | from qgis.core import (
19 | QgsProviderRegistry,
20 | QgsCoordinateReferenceSystem,
21 | QgsRasterLayer)
22 |
23 | from coordinator.test.utilities import get_qgis_app
24 | QGIS_APP, IFACE, CANVAS = get_qgis_app()
25 |
26 | class QGISTest(unittest.TestCase):
27 | """Test the QGIS Environment"""
28 |
29 | def test_qgis_environment(self):
30 | """QGIS environment has the expected providers"""
31 |
32 | r = QgsProviderRegistry.instance()
33 | self.assertIn('gdal', r.providerList())
34 | self.assertIn('ogr', r.providerList())
35 | self.assertIn('postgres', r.providerList())
36 |
37 | def test_projection(self):
38 | """Test that QGIS properly parses a wkt string.
39 | """
40 | crs = QgsCoordinateReferenceSystem()
41 | wkt = (
42 | 'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",'
43 | 'SPHEROID["WGS_1984",6378137.0,298.257223563]],'
44 | 'PRIMEM["Greenwich",0.0],UNIT["Degree",'
45 | '0.0174532925199433]]')
46 |
47 | self.assertTrue(crs.createFromWkt(wkt), "couldn't parse CRS")
48 | auth_id = crs.authid()
49 | expected_auth_id = 'EPSG:4326'
50 | self.assertEqual(auth_id, expected_auth_id)
51 |
52 | # now test for a loaded layer
53 | path = os.path.join(os.path.dirname(__file__), 'data/tenbytenraster.asc')
54 | title = 'TestRaster'
55 | layer = QgsRasterLayer(path, title)
56 | auth_id = layer.crs().authid()
57 | self.assertIn(auth_id, ("EPSG:4326", "OGC:CRS84") )
58 |
59 | if __name__ == '__main__':
60 | unittest.main()
61 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/test/test_resources.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """Resources test.
3 |
4 | .. note:: This program is free software; you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation; either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | """
10 |
11 | __author__ = 'qgis@ag99.de'
12 | __date__ = '2019-05-04'
13 | __copyright__ = 'Copyright 2019, Jonas Küpper'
14 |
15 | import unittest
16 |
17 | from PyQt5.QtGui import QIcon
18 |
19 |
20 |
21 | class CoordinatorResourcesTest(unittest.TestCase):
22 |
23 | def setUp(self):
24 | """Runs before each test."""
25 | pass
26 |
27 | def tearDown(self):
28 | """Runs after each test."""
29 | pass
30 |
31 | def test_icon_png(self):
32 | path = ':/plugins/Coordinator/icon.png'
33 | icon = QIcon(path)
34 | self.assertFalse(icon.isNull())
35 |
36 | if __name__ == "__main__":
37 | suite = unittest.makeSuite(CoordinatorResourcesTest)
38 | runner = unittest.TextTestRunner(verbosity=2)
39 | runner.run(suite)
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/test/test_translations.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """Safe Translations Test.
3 |
4 | .. note:: This program is free software; you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation; either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | """
10 | from coordinator.test.utilities import get_qgis_app
11 |
12 | __author__ = 'ismailsunni@yahoo.co.id'
13 | __date__ = '12/10/2011'
14 | __copyright__ = ('Copyright 2012, Australia Indonesia Facility for '
15 | 'Disaster Reduction')
16 | import unittest
17 | import os
18 |
19 | from PyQt5.QtCore import QCoreApplication, QTranslator
20 |
21 | QGIS_APP, IFACE, CANVAS = get_qgis_app()
22 |
23 |
24 | class SafeTranslationsTest(unittest.TestCase):
25 | """Test translations work."""
26 |
27 | translator = QTranslator()
28 |
29 | @classmethod
30 | def setUpClass(cls):
31 | super(SafeTranslationsTest, cls).setUpClass()
32 | parent_path = os.path.join(os.path.dirname(__file__), os.path.pardir)
33 | dir_path = os.path.abspath(parent_path)
34 | file_path = os.path.join(dir_path, 'i18n', 'coordinator_de.qm')
35 | SafeTranslationsTest.translator.load(file_path)
36 |
37 |
38 | def setUp(self):
39 | """Runs before each test."""
40 | if 'LANG' in iter(os.environ.keys()):
41 | os.environ.__delitem__('LANG')
42 |
43 |
44 | def tearDown(self):
45 | """Runs after each test."""
46 | if 'LANG' in iter(os.environ.keys()):
47 | os.environ.__delitem__('LANG')
48 |
49 |
50 | def test_qgis_translations(self):
51 | """Test that translations work."""
52 | QCoreApplication.installTranslator(SafeTranslationsTest.translator)
53 | real_message = QCoreApplication.translate("CT", 'outside of map extent')
54 | self.assertEqual(real_message, 'außerhalb der Karte')
55 |
56 |
57 | if __name__ == "__main__":
58 | suite = unittest.makeSuite(SafeTranslationsTest)
59 | runner = unittest.TextTestRunner(verbosity=2)
60 | runner.run(suite)
61 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/coordinator/test/utilities.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """Common functionality used by regression tests."""
3 |
4 | import sys
5 | import logging
6 | from PyQt5.QtWidgets import QWidget
7 | from PyQt5.Qt import QMainWindow, QDialog, QWindow, QLocale
8 | from time import sleep
9 | from qgis.core import QgsCoordinateReferenceSystem
10 | from qgis.PyQt import sip
11 |
12 |
13 | LOGGER = logging.getLogger('QGIS')
14 | QGIS_APP = None # Static variable used to hold hand to running QGIS app
15 | CANVAS = None
16 | PARENT = None
17 | IFACE = None
18 |
19 |
20 | def get_qgis_app():
21 | """ Start one QGIS application to test against.
22 |
23 | :returns: Handle to QGIS app, canvas, iface and parent. If there are any
24 | errors the tuple members will be returned as None.
25 | :rtype: (QgsApplication, CANVAS, IFACE, PARENT)
26 |
27 | If QGIS is already running the handle to that app will be returned.
28 | """
29 |
30 | try:
31 | from PyQt5 import QtGui, QtCore
32 | from qgis.core import QgsApplication
33 | from qgis.gui import QgsMapCanvas
34 | import qgis.utils
35 | from .qgis_interface import QgisStubInterface
36 | except ImportError as error:
37 | print("Failed to import QGIS libs %s" % error)
38 | return None, None, None
39 |
40 | global QGIS_APP, IFACE, CANVAS, PARENT
41 |
42 | if CANVAS and sip.isdeleted(CANVAS):
43 | CANVAS = None
44 | IFACE = None
45 |
46 | if not IFACE or not CANVAS:
47 | if qgis.utils.iface:
48 | # we are probably running in the QGIS Applications Python console.
49 | # so we have all we need:
50 | IFACE = qgis.utils.iface
51 | CANVAS = IFACE.mapCanvas()
52 | QGIS_APP = QgsApplication.instance()
53 | PARENT = CANVAS.parentWidget()
54 | else:
55 | try:
56 | sysargsUtf8 = [sysarg.encode("utf-8") for sysarg in sys.argv]
57 | except AttributeError:
58 | sysargsUtf8 = []
59 | QGIS_APP = QgsApplication(sysargsUtf8, True)
60 | QGIS_APP.initQgis()
61 | PARENT = QWidget()
62 | CANVAS = QgsMapCanvas(PARENT)
63 | CANVAS.resize(QtCore.QSize(400, 400))
64 | CANVAS.setDestinationCrs(QgsCoordinateReferenceSystem("EPSG:4326"))
65 | IFACE = QgisStubInterface(CANVAS)
66 |
67 | return QGIS_APP, IFACE, CANVAS
68 |
69 |
70 | DEC_POINT = QLocale().decimalPoint()
71 | GROUP_SEPARATOR = QLocale().groupSeparator()
72 | TRANSLATION = str.maketrans(".,", "%s%s" % (DEC_POINT, GROUP_SEPARATOR) )
73 |
74 | def helperFormatCoordinates(coordinate):
75 | # if the locale does not use grouping, we need to remove the grouping
76 | # separator before translation:
77 | if QLocale.OmitGroupSeparator & QLocale().numberOptions():
78 | coordinate = coordinate.replace(",", "")
79 | return coordinate.translate(TRANSLATION)
80 |
81 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/__about__.py:
--------------------------------------------------------------------------------
1 | #! python3 # noqa: E265
2 |
3 | """
4 | Metadata about the package to easily retrieve informations about it.
5 | See: https://packaging.python.org/guides/single-sourcing-package-version/
6 | """
7 |
8 | # ############################################################################
9 | # ########## Libraries #############
10 | # ##################################
11 |
12 | # standard library
13 | from configparser import ConfigParser
14 | from datetime import date
15 | from pathlib import Path
16 |
17 | # ############################################################################
18 | # ########## Globals ###############
19 | # ##################################
20 |
21 | __all__ = [
22 | "__author__",
23 | "__copyright__",
24 | "__email__",
25 | "__license__",
26 | "__summary__",
27 | "__title__",
28 | "__uri__",
29 | "__version__",
30 | ]
31 |
32 | DIR_PLUGIN_ROOT = Path(__file__).parent
33 | PLG_METADATA_FILE = DIR_PLUGIN_ROOT.resolve() / "metadata.txt"
34 |
35 | # ############################################################################
36 | # ########## Functions #############
37 | # ##################################
38 |
39 |
40 | def plugin_metadata_as_dict() -> dict:
41 | """Read plugin metadata.txt and returns it as a Python dict.
42 |
43 | Raises:
44 | IOError: if metadata.txt is not found
45 |
46 | Returns:
47 | dict: dict of dicts.
48 | """
49 | config = ConfigParser()
50 | if PLG_METADATA_FILE.is_file():
51 | config.read(PLG_METADATA_FILE.resolve(), encoding="UTF-8")
52 | return {s: dict(config.items(s)) for s in config.sections()}
53 | else:
54 | raise IOError("Plugin metadata.txt not found at: %s" % PLG_METADATA_FILE)
55 |
56 |
57 | # ############################################################################
58 | # ########## Variables #############
59 | # ##################################
60 |
61 | # store full metadata.txt as dict into a var
62 | __plugin_md__ = plugin_metadata_as_dict()
63 |
64 | __author__ = __plugin_md__.get("general").get("author")
65 | __copyright__ = "2014 - {0}, {1}".format(date.today().year, __author__)
66 | __email__ = __plugin_md__.get("general").get("email")
67 | __keywords__ = [
68 | t.strip() for t in __plugin_md__.get("general").get("repository").split("tags")
69 | ]
70 | __license__ = "GPL-2.0"
71 | __summary__ = "{}\n{}".format(
72 | __plugin_md__.get("general").get("description"),
73 | __plugin_md__.get("general").get("about"),
74 | )
75 |
76 | __title__ = __plugin_md__.get("general").get("name")
77 | __title_clean__ = "".join(e for e in __title__ if e.isalnum())
78 |
79 | __uri_homepage__ = __plugin_md__.get("general").get("homepage")
80 | __uri_repository__ = __plugin_md__.get("general").get("repository")
81 | __uri_tracker__ = __plugin_md__.get("general").get("tracker")
82 | __uri__ = __uri_repository__
83 |
84 | __version__ = __plugin_md__.get("general").get("version")
85 | __version_info__ = tuple(
86 | [
87 | int(num) if num.isdigit() else num
88 | for num in __version__.replace("-", ".", 1).split(".")
89 | ]
90 | )
91 |
92 | # #############################################################################
93 | # ##### Main #######################
94 | # ##################################
95 | if __name__ == "__main__":
96 | plugin_md = plugin_metadata_as_dict()
97 | assert isinstance(plugin_md, dict)
98 | assert plugin_md.get("general").get("name") == __title__
99 | print("Plugin: " + __title__)
100 | print("Plugin (clean): " + __title_clean__)
101 | print("By: " + __author__)
102 | print("Version: " + __version__)
103 | print("Description: " + __summary__)
104 | print(
105 | "For: %s > QGIS > %s"
106 | % (
107 | plugin_md.get("general").get("qgisminimumversion"),
108 | plugin_md.get("general").get("qgismaximumversion", "3.99"),
109 | )
110 | )
111 | print(__title_clean__)
112 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/__init__.py:
--------------------------------------------------------------------------------
1 | #! python3 # noqa: E265
2 |
3 |
4 | def classFactory(iface): # pylint: disable=invalid-name
5 | """Load NominatimFilterPlugin class from file nominatimfilter.
6 |
7 | :param iface: A QGIS interface instance.
8 | :type iface: QgsInterface
9 | """
10 | from .plugin_main import LocatorFilterPlugin
11 |
12 | return LocatorFilterPlugin(iface)
13 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/core/__init__.py:
--------------------------------------------------------------------------------
1 | #! python3 # noqa: E265
2 | from .locator_filter import FrenchBanGeocoderLocatorFilter # noqa: F401
3 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/gui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/gui/__init__.py
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/gui/dlg_settings.py:
--------------------------------------------------------------------------------
1 | #! python3 # noqa: E265
2 |
3 | """
4 | Plugin settings dialog.
5 | """
6 |
7 | # standard
8 | import logging
9 | from functools import partial
10 | from pathlib import Path
11 |
12 | # PyQGIS
13 | from qgis.gui import QgsOptionsPageWidget, QgsOptionsWidgetFactory
14 | from qgis.PyQt import uic
15 | from qgis.PyQt.Qt import QUrl
16 | from qgis.PyQt.QtCore import pyqtSignal
17 | from qgis.PyQt.QtGui import QDesktopServices, QIcon
18 | from qgis.PyQt.QtWidgets import QHBoxLayout, QWidget
19 | from qgis.utils import showPluginHelp
20 |
21 | # project
22 | from french_locator_filter.__about__ import (
23 | DIR_PLUGIN_ROOT,
24 | __title__,
25 | __uri_tracker__,
26 | __version__,
27 | )
28 | from french_locator_filter.toolbelt import PlgLogger, PlgOptionsManager
29 |
30 | # ############################################################################
31 | # ########## Globals ###############
32 | # ##################################
33 |
34 | logger = logging.getLogger(__name__)
35 | FORM_CLASS, _ = uic.loadUiType(
36 | Path(__file__).parent / "{}.ui".format(Path(__file__).stem)
37 | )
38 |
39 | # ############################################################################
40 | # ########## Classes ###############
41 | # ##################################
42 |
43 |
44 | class DlgSettings(QWidget, FORM_CLASS):
45 |
46 | closingPlugin = pyqtSignal()
47 |
48 | def __init__(self, parent=None):
49 | """Constructor."""
50 | super(DlgSettings, self).__init__(parent)
51 | self.setupUi(self)
52 | self.log = PlgLogger().log
53 |
54 | # header
55 | self.lbl_title.setText(f"{__title__} - Version {__version__}")
56 |
57 | # customization
58 | self.btn_help.setIcon(QIcon(":/images/themes/default/mActionHelpContents.svg"))
59 | self.btn_help.pressed.connect(
60 | partial(showPluginHelp, filename=f"{DIR_PLUGIN_ROOT}/resources/help/index")
61 | )
62 |
63 | self.btn_report.setIcon(
64 | QIcon(":images/themes/default/console/iconSyntaxErrorConsole.svg")
65 | )
66 | self.btn_report.pressed.connect(
67 | partial(QDesktopServices.openUrl, QUrl(__uri_tracker__))
68 | )
69 |
70 | # load previously saved settings
71 | self.plg_settings = PlgOptionsManager()
72 | self.load_settings()
73 |
74 | def closeEvent(self, event):
75 | """Map on plugin close.
76 |
77 | :param event: [description]
78 | :type event: [type]
79 | """
80 | self.closingPlugin.emit()
81 | event.accept()
82 |
83 | def load_settings(self) -> dict:
84 | """Load options from QgsSettings into UI form."""
85 | settings = self.plg_settings.get_plg_settings()
86 |
87 | # features
88 | self.lbl_url_path_value.setText(settings.request_url)
89 | self.lbl_url_query_value.setText(settings.request_url_query)
90 | self.lbl_http_content_type_value.setText(settings.http_content_type)
91 | self.lbl_http_user_agent_value.setText(settings.http_user_agent)
92 | self.sbx_min_search_length.setValue(settings.min_search_length)
93 |
94 | # misc
95 | self.opt_debug.setChecked(settings.debug_mode)
96 | self.lbl_version_saved_value.setText(settings.version)
97 |
98 | def save_settings(self):
99 | """Save options from UI form into QSettings."""
100 | # save user settings
101 | self.plg_settings.set_value_from_key(
102 | "min_search_length", self.sbx_min_search_length.value()
103 | )
104 |
105 | # save miscellaneous
106 | self.plg_settings.set_value_from_key("debug_mode", self.opt_debug.isChecked())
107 | self.plg_settings.set_value_from_key("version", __version__)
108 |
109 | if __debug__:
110 | self.log(
111 | message="DEBUG - Settings successfully saved.",
112 | log_level=4,
113 | )
114 |
115 |
116 | class PlgOptionsFactory(QgsOptionsWidgetFactory):
117 | def __init__(self):
118 | super().__init__()
119 |
120 | def icon(self):
121 | return QIcon(str(DIR_PLUGIN_ROOT / "resources/images/icon.svg"))
122 |
123 | def createWidget(self, parent):
124 | return ConfigOptionsPage(parent)
125 |
126 | def title(self):
127 | return __title__
128 |
129 |
130 | class ConfigOptionsPage(QgsOptionsPageWidget):
131 | def __init__(self, parent):
132 | super().__init__(parent)
133 | self.dlg_settings = DlgSettings(self)
134 | layout = QHBoxLayout()
135 | layout.setContentsMargins(0, 0, 0, 0)
136 | self.dlg_settings.setLayout(layout)
137 | self.setLayout(layout)
138 | self.setObjectName("mOptionsPage{}".format(__title__))
139 |
140 | def apply(self):
141 | """Called to permanently apply the settings shown in the options page (e.g. \
142 | save them to QgsSettings objects). This is usually called when the options \
143 | dialog is accepted."""
144 | self.dlg_settings.save_settings()
145 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/metadata.txt:
--------------------------------------------------------------------------------
1 | [general]
2 | name=French Locator Filter
3 | about=The French geo.api is an open Geocoder service provided by French Government.
4 | A Locator Filter implements the fetching of data from internal or external sources.
5 | This plugin is forked from the work of Richard Duivenvoorde. Kudos Richard
6 | Read more: http://www.qgis.nl/2018/05/16/english-coding-a-qgslocator-plugin
7 | about[fr]=L'API du gouvernement français est un service de geocodage gratuit et ouvert base sur la base adresse nationale. Ce plugin ajoute un filtre de recherche sur ce service dans la barre de recherche universelle.
8 |
9 | category=Filter
10 |
11 | description=This is a plugin which adds a Locator Filter (Geocoder) based on the french API geo.api.gouv.fr/adresse to QGIS
12 | description[fr]=Extension activant la recherche d'adresse dans la barre de recherche universelle, basee sur l'API geo.api.gouv.fr/adresse
13 | Financement par les services de la gendarmerie Nationale.
14 | Ce plugin est basé sur le travail de Richard Duivenvoorde (merci Richard !).
15 | En savoir plus sur ce plugin http://www.qgis.nl/2018/05/16/english-coding-a-qgslocator-plugin
16 |
17 | icon=resources/images/icon.svg
18 |
19 | tags=geocoder, locator, filter, addok, France, french
20 | tags[fr]=geocodeur, recherche, adresse, France, ADDOK, Etalab, BAN, BANO
21 |
22 | # credits and contact
23 | author=Régis Haubourg (Oslandia), Richard Duivenvoorde, Zuidt, Julien Moura (Oslandia)
24 | email=qgis@oslandia.com
25 | homepage=https://oslandia.gitlab.io/qgis/french_locator_filter/
26 | repository=https://gitlab.com/Oslandia/qgis/french_locator_filter/
27 | tracker=https://gitlab.com/Oslandia/qgis/french_locator_filter/-/issues
28 |
29 | # status
30 | deprecated=False
31 | experimental=True
32 | qgisMinimumVersion=3.16
33 | qgisMaximumVersion=3.99
34 |
35 | # versioning
36 | version=1.0.0-beta1
37 | changelog=
38 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/plugin_main.py:
--------------------------------------------------------------------------------
1 | #! python3 # noqa: E265
2 |
3 | """
4 | Main plugin module.
5 | """
6 |
7 | # standard library
8 | from string import Template
9 |
10 | # PyQGIS
11 | from qgis.gui import QgisInterface
12 | from qgis.PyQt.QtCore import QCoreApplication
13 |
14 | # project
15 | from french_locator_filter.__about__ import __title__, __version__
16 | from french_locator_filter.core import FrenchBanGeocoderLocatorFilter
17 | from french_locator_filter.gui.dlg_settings import PlgOptionsFactory
18 | from french_locator_filter.toolbelt import PlgLogger, PlgTranslator
19 |
20 | # ############################################################################
21 | # ########## Classes ###############
22 | # ##################################
23 |
24 |
25 | class LocatorFilterPlugin:
26 | def __init__(self, iface: QgisInterface):
27 | """Constructor.
28 |
29 | :param iface: An interface instance that will be passed to this class which \
30 | provides the hook by which you can manipulate the QGIS application at run time.
31 | :type iface: QgsInterface
32 | """
33 | self.iface = iface
34 | self.log = PlgLogger().log
35 |
36 | # translation
37 | plg_translation_mngr = PlgTranslator(
38 | tpl_filename=Template("french_locator_filter_$locale.qm")
39 | )
40 | translator = plg_translation_mngr.get_translator()
41 | if translator:
42 | QCoreApplication.installTranslator(translator)
43 | self.tr = plg_translation_mngr.tr
44 |
45 | # install locator filter
46 | self.filter = FrenchBanGeocoderLocatorFilter(self.iface)
47 | self.iface.registerLocatorFilter(self.filter)
48 |
49 | if __debug__:
50 | self.log(
51 | message=(
52 | "DEBUG - French (BAN Geocoder) Locator Filter"
53 | f" ({__title__} {__version__}) installed."
54 | ),
55 | log_level=4,
56 | )
57 |
58 | def initGui(self):
59 | """Set up plugin UI elements."""
60 | # settings page within the QGIS preferences menu
61 | self.options_factory = PlgOptionsFactory()
62 | self.iface.registerOptionsWidgetFactory(self.options_factory)
63 |
64 | def unload(self):
65 | """Cleans up when plugin is disabled/uninstalled."""
66 | # -- Clean up preferences panel in QGIS settings
67 | self.iface.unregisterOptionsWidgetFactory(self.options_factory)
68 |
69 | # remove filter from locator
70 | self.iface.deregisterLocatorFilter(self.filter)
71 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/resources.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | resources/images/icon.svg
4 |
5 |
6 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/resources/help/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Redirecting...
7 |
8 |
9 |
10 |
11 |
12 |
Redirection to the online documentation...
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/resources/i18n/french_locator_filter_fr.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/resources/i18n/french_locator_filter_fr.qm
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/resources/i18n/french_locator_filter_fr.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | FrenchBanGeocoderLocatorFilter
6 |
7 |
8 | French Adress geocoder
9 | Géocodeur API BAN
10 |
11 |
12 |
13 | dlg_settings
14 |
15 |
16 | Settings
17 | Paramètres
18 |
19 |
20 |
21 | Features
22 | Fonctionnalités
23 |
24 |
25 |
26 | HTTP user-agent:
27 | HTTP user-agent :
28 |
29 |
30 |
31 | Request URL:
32 | Base de l'URL de requête :
33 |
34 |
35 |
36 | Request parameters:
37 | Paramètres de la requête :
38 |
39 |
40 |
41 | Miscellaneous
42 | Divers
43 |
44 |
45 |
46 | Enable debug mode.
47 | Activer le mode debug.
48 |
49 |
50 |
51 | Debug mode (degraded performances)
52 | Activer le mode debug (performances dégradées)
53 |
54 |
55 |
56 | Version used to save settings:
57 | Paramaètres sauvegardés avec la version :
58 |
59 |
60 |
61 | Report an issue
62 | Signaler une anomalie
63 |
64 |
65 |
66 | Help
67 | Aide en ligne
68 |
69 |
70 |
71 | Minimal search length
72 | Nombre minimal de caractères avant de déclencher la requête à l'API
73 |
74 |
75 |
76 | characters
77 | caractères
78 |
79 |
80 |
81 | Minimal search length:
82 | Longueur minimale de la recherche :
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/resources/i18n/plugin_translation.pro:
--------------------------------------------------------------------------------
1 | FORMS = ../../gui/dlg_settings.ui
2 |
3 | SOURCES= ../../plugin_main.py \
4 | ../../core/locator_filter.py \
5 | ../../toolbelt/log_handler.py \
6 | ../../toolbelt/network_manager.py \
7 | ../../toolbelt/preferences.py
8 |
9 | TRANSLATIONS = french_locator_filter_fr.ts
10 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/toolbelt/__init__.py:
--------------------------------------------------------------------------------
1 | #! python3 # noqa: E265
2 | from .log_handler import PlgLogger # noqa: F401
3 | from .network_manager import NetworkRequestsManager # noqa: F401
4 | from .preferences import PlgOptionsManager # noqa: F401
5 | from .translator import PlgTranslator # noqa: F401
6 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/toolbelt/log_handler.py:
--------------------------------------------------------------------------------
1 | #! python3 # noqa: E265
2 |
3 | # standard library
4 | import logging
5 |
6 | # PyQGIS
7 | from qgis.core import QgsMessageLog
8 | from qgis.utils import iface
9 |
10 | # project package
11 | from french_locator_filter.__about__ import __title__
12 |
13 | # ############################################################################
14 | # ########## Classes ###############
15 | # ##################################
16 |
17 |
18 | class PlgLogger(logging.Handler):
19 | """Python logging handler supercharged with QGIS useful methods."""
20 |
21 | @staticmethod
22 | def log(
23 | message: str,
24 | application: str = __title__,
25 | log_level: int = 0,
26 | push: bool = False,
27 | ):
28 | """Send messages to QGIS messages windows and to the user as a message bar. \
29 | Plugin name is used as title.
30 |
31 | :param message: message to display
32 | :type message: str
33 | :param application: name of the application sending the message. \
34 | Defaults to __about__.__title__
35 | :type application: str, optional
36 | :param log_level: message level. Possible values: 0 (info), 1 (warning), \
37 | 2 (critical), 3 (success), 4 (none - grey). Defaults to 0 (info)
38 | :type log_level: int, optional
39 | :param push: also display the message in the QGIS message bar in addition to \
40 | the log, defaults to False
41 | :type push: bool, optional
42 |
43 | :Example:
44 |
45 | .. code-block:: python
46 |
47 | log(message="Plugin loaded - INFO", log_level=0, push=1)
48 | log(message="Plugin loaded - WARNING", log_level=1, push=1)
49 | log(message="Plugin loaded - ERROR", log_level=2, push=1)
50 | log(message="Plugin loaded - SUCCESS", log_level=3, push=1)
51 | log(message="Plugin loaded - TEST", log_level=4, push=1)
52 | """
53 | # ensure message is a string
54 | if not isinstance(message, str):
55 | try:
56 | message = str(message)
57 | except Exception as err:
58 | err_msg = "Log message must be a string, not: {}. Trace: {}".format(
59 | type(message), err
60 | )
61 | logging.error(err_msg)
62 | message = err_msg
63 |
64 | # send it to QGIS messages panel
65 | QgsMessageLog.logMessage(
66 | message=message, tag=application, notifyUser=push, level=log_level
67 | )
68 |
69 | # optionally, display message on QGIS Message bar (above the map canvas)
70 | if push:
71 | iface.messageBar().pushMessage(
72 | title=application,
73 | text=message,
74 | level=log_level,
75 | duration=(log_level + 1) * 3,
76 | )
77 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/toolbelt/preferences.py:
--------------------------------------------------------------------------------
1 | #! python3 # noqa: E265
2 |
3 | """
4 | Plugin settings.
5 | """
6 |
7 | # standard
8 | import logging
9 | from typing import NamedTuple
10 |
11 | # PyQGIS
12 | from qgis.core import QgsSettings
13 |
14 | # package
15 | from french_locator_filter.__about__ import __title__, __version__
16 |
17 | from .log_handler import PlgLogger
18 |
19 | # ############################################################################
20 | # ########## Globals ###############
21 | # ##################################
22 |
23 | logger = logging.getLogger(__name__)
24 | plg_logger = PlgLogger()
25 |
26 | # ############################################################################
27 | # ########## Classes ###############
28 | # ##################################
29 |
30 |
31 | class PlgSettingsStructure(NamedTuple):
32 | """Plugin settings structure and defaults values."""
33 |
34 | # misc
35 | debug_mode: bool = False
36 | version: str = __version__
37 |
38 | # network
39 | http_content_type: str = "application/json"
40 | http_user_agent: str = f"{__title__}/{__version__}"
41 | min_search_length: int = 2
42 | request_url: str = "https://api-adresse.data.gouv.fr/search/"
43 | request_url_query: str = "limit=10&autocomplete=1"
44 |
45 |
46 | class PlgOptionsManager:
47 | @staticmethod
48 | def get_plg_settings() -> PlgSettingsStructure:
49 | """Load and return plugin settings as a dictionary. \
50 | Useful to get user preferences across plugin logic.
51 |
52 | :return: plugin settings
53 | :rtype: PlgSettingsStructure
54 | """
55 | settings = QgsSettings()
56 | settings.beginGroup(__title__)
57 |
58 | options = PlgSettingsStructure(
59 | # misc
60 | debug_mode=settings.value(key="debug_mode", defaultValue=False, type=bool),
61 | version=settings.value(key="version", defaultValue=__version__, type=str),
62 | # network
63 | http_content_type=settings.value(
64 | key="http_content_type",
65 | defaultValue="application/json",
66 | type=str,
67 | ),
68 | http_user_agent=settings.value(
69 | key="http_user_agent",
70 | defaultValue=f"{__title__}/{__version__}",
71 | type=str,
72 | ),
73 | min_search_length=settings.value(
74 | key="min_search_length",
75 | defaultValue=2,
76 | type=int,
77 | ),
78 | request_url=settings.value(
79 | key="request_url",
80 | defaultValue="https://api-adresse.data.gouv.fr/search/",
81 | type=str,
82 | ),
83 | request_url_query=settings.value(
84 | key="request_url_query",
85 | defaultValue="limit=10&autocomplete=1",
86 | type=str,
87 | ),
88 | )
89 |
90 | settings.endGroup()
91 |
92 | return options
93 |
94 | @staticmethod
95 | def get_value_from_key(key: str, default=None, exp_type=None):
96 | """Load and return plugin settings as a dictionary. \
97 | Useful to get user preferences across plugin logic.
98 |
99 | :return: plugin settings value matching key
100 | """
101 | if not hasattr(PlgSettingsStructure, key):
102 | logger.error(
103 | "Bad settings key. Must be one of: {}".format(
104 | ",".join(PlgSettingsStructure._fields)
105 | )
106 | )
107 | return None
108 |
109 | settings = QgsSettings()
110 | settings.beginGroup(__title__)
111 |
112 | try:
113 | out_value = settings.value(key=key, defaultValue=default, type=exp_type)
114 | except Exception as err:
115 | logger.error(err)
116 | plg_logger.log(err)
117 | out_value = None
118 |
119 | settings.endGroup()
120 |
121 | return out_value
122 |
123 | @staticmethod
124 | def set_value_from_key(key: str, value):
125 | """Load and return plugin settings as a dictionary. \
126 | Useful to get user preferences across plugin logic.
127 |
128 | :return: plugin settings value matching key
129 | """
130 | if not hasattr(PlgSettingsStructure, key):
131 | logger.error(
132 | "Bad settings key. Must be one of: {}".format(
133 | ",".join(PlgSettingsStructure._fields)
134 | )
135 | )
136 | return False
137 |
138 | settings = QgsSettings()
139 | settings.beginGroup(__title__)
140 |
141 | try:
142 | settings.setValue(key, value)
143 | out_value = True
144 | except Exception as err:
145 | logger.error(err)
146 | plg_logger.log(err)
147 | out_value = False
148 |
149 | settings.endGroup()
150 |
151 | return out_value
152 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/french_locator_filter/toolbelt/translator.py:
--------------------------------------------------------------------------------
1 | #! python3 # noqa: E265
2 |
3 | # standard library
4 | import logging
5 | from functools import lru_cache
6 | from inspect import currentframe
7 | from pathlib import Path
8 | from string import Template
9 |
10 | # PyQGIS
11 | from qgis.core import QgsSettings
12 | from qgis.PyQt.QtCore import QLocale, QTranslator
13 | from qgis.PyQt.QtWidgets import QApplication
14 |
15 | # project package
16 | from french_locator_filter.__about__ import DIR_PLUGIN_ROOT, __email__, __title__
17 | from french_locator_filter.toolbelt import PlgLogger
18 |
19 | # ############################################################################
20 | # ########## Globals ###############
21 | # ##################################
22 |
23 | logger = logging.getLogger(__name__)
24 |
25 |
26 | # ############################################################################
27 | # ########## Classes ###############
28 | # ##################################
29 |
30 |
31 | class PlgTranslator:
32 | """Helper module to manage plugin translations.
33 |
34 | :param qm_search_start_path: folder where to search fro QM files. \
35 | Defaults to DIR_PLUGIN_ROOT
36 | :type qm_search_start_path: Path, optional
37 | :param tpl_filename: pattern of translations filenames. \
38 | Defaults to Template(f"{__title__.lower()}_.qm")
39 | :type tpl_filename: str, optional
40 | """
41 |
42 | AVAILABLE_TRANSLATIONS: tuple = None
43 |
44 | def __init__(
45 | self,
46 | qm_search_start_path: Path = DIR_PLUGIN_ROOT,
47 | tpl_filename: str = Template(f"{__title__.lower()}_$locale.qm"),
48 | ):
49 | """Initialize method."""
50 |
51 | self.log = PlgLogger().log
52 |
53 | # list .qm files
54 | qm_files = tuple(qm_search_start_path.glob("**/*.qm"))
55 | self.AVAILABLE_TRANSLATIONS = tuple(q.name for q in qm_files)
56 |
57 | # get locale and identify the compiled translation file (*.qm) to use
58 | locale = QgsSettings().value("locale/userLocale", QLocale().name())[0:2]
59 | locale_filename = tpl_filename.substitute(locale=locale)
60 |
61 | self.qm_filepath = None
62 | for qm in qm_files:
63 | if qm.name == locale_filename:
64 | self.qm_filepath = qm
65 | break
66 |
67 | if not self.qm_filepath:
68 | info_msg = self.tr(
69 | "Your selected locale ({}) is not available. "
70 | "Please consider to contribute with your own translation :). "
71 | "Contact the plugin maintener(s): {}".format(locale, __email__)
72 | )
73 | self.log(message=str(info_msg), log_level=1, push=0)
74 | logger.info(info_msg)
75 |
76 | def get_translator(self) -> QTranslator:
77 | """Load translation file into QTranslator.
78 |
79 | :return: translator instance
80 | :rtype: QTranslator
81 | """
82 | if self.AVAILABLE_TRANSLATIONS is None:
83 | warn_msg = self.tr(
84 | text="No translation found among plugin files and folders.",
85 | context="PlgTranslator",
86 | )
87 | logger.warning(warn_msg)
88 | self.log(message=warn_msg, log_level=1)
89 | return None
90 |
91 | if not self.qm_filepath:
92 | return None
93 |
94 | # load translation
95 | self.translator = QTranslator()
96 | self.translator.load(str(self.qm_filepath.resolve()))
97 | return self.translator
98 |
99 | @lru_cache(maxsize=128)
100 | def tr(self, text: str, context: str = None) -> str:
101 | """Translate a text using the installed translator.
102 |
103 | :param text: text to translate, defaults to None.
104 | :type text: str
105 | :param context: where the text is located. In Python code, it's the class name. \
106 | If None, it tries to automatically retrieve class name. Defaults to None.
107 | :type context: str, optional
108 |
109 | :return: translated text.
110 | :rtype: str
111 | """
112 | if not context:
113 | frame = currentframe().f_back
114 | if "self" in frame.f_locals:
115 | context = type(frame.f_locals["self"]).__name__
116 |
117 | return QApplication.translate(context, text)
118 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/Makefile:
--------------------------------------------------------------------------------
1 | #/***************************************************************************
2 | # -------------------
3 | # begin : 2014-02-20
4 | # copyright : (C) 2014 by Oslandia
5 | # email : hugo.mercier@oslandia.com
6 | # ***************************************************************************/
7 | #
8 | #/***************************************************************************
9 | # * *
10 | # * This program is free software; you can redistribute it and/or modify *
11 | # * it under the terms of the GNU General Public License as published by *
12 | # * the Free Software Foundation; either version 2 of the License, or *
13 | # * (at your option) any later version. *
14 | # * *
15 | # ***************************************************************************/
16 |
17 | QGISDIR=.qgis2
18 |
19 | # Makefile for a PyQGIS plugin
20 |
21 | # global
22 |
23 | PLUGINNAME = mask
24 |
25 | #
26 | SOURCES = aeag_mask.py maindialog.py __init__.py layerlist.py mask_filter.py mask_parameters.py style_tools.py htmldialog.py
27 | TRANSLATIONS = mask_fr.ts
28 |
29 | EXTRAS = aeag_mask.png metadata.txt default_mask_style.qml
30 | UI_FILES = ui_plugin_mask.py ui_layer_list.py
31 |
32 | RESOURCE_FILES = resources_rc.py
33 |
34 | default: compile
35 |
36 | compile: $(UI_FILES) $(RESOURCE_FILES)
37 |
38 | %_rc.py : %.qrc
39 | pyrcc4 -o $*_rc.py $<
40 |
41 | %.py : %.ui
42 | pyuic4 -o $@ $<
43 |
44 | %.qm : %.ts
45 | lrelease-qt4 $<
46 |
47 | # The deploy target only works on unix like operating system where
48 | # the Python plugin directory is located at:
49 | # $HOME/$(QGISDIR)/python/plugins
50 | deploy: compile transcompile
51 | mkdir -p $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
52 | mkdir -p $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)/db
53 | cp -vf $(SOURCES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
54 | cp -vf $(UI_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
55 | cp -vf $(RESOURCE_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
56 | cp -vf $(EXTRAS) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
57 | cp -vf *.ts *.qm $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
58 | cp -vfr doc/ $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
59 |
60 | # The dclean target removes compiled python files from plugin directory
61 | # also delets any .svn entry
62 | dclean:
63 | find $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) -iname "*.pyc" -delete
64 | find $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) -iname ".svn" -prune -exec rm -Rf {} \;
65 |
66 | # The derase deletes deployed plugin
67 | derase:
68 | rm -Rf $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
69 |
70 | # The zip target deploys the plugin and creates a zip file with the deployed
71 | # content. You can then upload the zip file on http://plugins.qgis.org
72 | zip: deploy dclean
73 | rm -f $(PLUGINNAME).zip
74 | cd $(HOME)/$(QGISDIR)/python/plugins; zip -9r $(CURDIR)/$(PLUGINNAME).zip $(PLUGINNAME)
75 |
76 | # Create a zip package of the plugin named $(PLUGINNAME).zip.
77 | # This requires use of git (your plugin development directory must be a
78 | # git repository).
79 | # To use, pass a valid commit or tag as follows:
80 | # make package VERSION=Version_0.3.2
81 | package: compile
82 | rm -f $(PLUGINNAME).zip
83 | git archive --prefix=$(PLUGINNAME)/ -o $(PLUGINNAME).zip $(VERSION)
84 | echo "Created package: $(PLUGINNAME).zip"
85 |
86 | upload: zip
87 | $(PLUGIN_UPLOAD) $(PLUGINNAME).zip
88 |
89 | # transup
90 | # update .ts translation files
91 | transup:
92 | pylupdate4 $(SOURCES) $(UI_FILES:.py=.ui) -ts $(TRANSLATIONS)
93 |
94 | # transcompile
95 | # compile translation files into .qm binary format
96 | transcompile: $(TRANSLATIONS:.ts=.qm)
97 |
98 | # transclean
99 | # deletes all .qm files
100 | transclean:
101 | rm -f *.qm
102 |
103 | clean:
104 | rm $(UI_FILES) $(RESOURCE_FILES)
105 |
106 | # build documentation with sphinx
107 | #doc:
108 | # cd help; make html
109 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | /***************************************************************************
3 | Name : Mask plugin
4 | Description : Help to create mask
5 | Date : 08/Feb/12
6 | copyright : (C) 2011 by AEAG
7 | email : xavier.culos@eau-adour-garonne.fr
8 | ***************************************************************************/
9 |
10 | /***************************************************************************
11 | * *
12 | * This program is free software; you can redistribute it and/or modify *
13 | * it under the terms of the GNU General Public License as published by *
14 | * the Free Software Foundation; either version 2 of the License, or *
15 | * (at your option) any later version. *
16 | * *
17 | ***************************************************************************/
18 | This script initializes the plugin, making it known to QGIS.
19 | """
20 | def classFactory(iface):
21 | # load aeag_mask class from file aeag_mask
22 | from .aeag_mask import aeag_mask
23 | return aeag_mask(iface)
24 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/aeag_mask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/mask/aeag_mask.png
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/default_mask_style.qml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | 0
39 | 0
40 | 2
41 |
42 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/doc/en/about.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | About
4 |
5 |
6 | That tool is designed to help users to quickly generate cartographic masking layer to enlight an area of interest.
7 | Current features are:
8 |
creates or modifies a mask relying on current polygon selection (on active layer)
9 |
creates or modifies a mask via a call of do_mask function so that mask can be called programmatically from other plugins
10 |
opens a dialog to choose mask layer properties:
11 |
style options (default is inverted polygon renderer + border shading)
12 |
buffer around mask
13 |
filter labels of features falling outside area of interest (achieved by a in_mask(SRID) function filter on labeling placement options)
14 |
choose mask layer format (Memory or any OGR datasource)
15 |
16 |
17 |
18 |
Mask plugin was developped by Xavier Culos (AEAG) and contributed by Hugo Mercier (Oslandia) on funding by Agence de l'eau Adour Garonne.
19 | Please notify any issue or enhancement request here
How to filter out legend elements based on the mask ?
7 |
One may want to use the mask to highlight some part of a map. In which case, one may want to hide
8 | elements of the legend (in a composition) that are not displayed inside the polygon of the mask.
9 |
The in_mask function can be used for that purpose. Starting with QGIS 2.14, a new option
10 | has been added to the legend filter tool, allowing to specify an expression. A symbol will be part of
11 | the legend only if at least one of its features make the boolean expression evaluated to true.
12 |
That can especially be used to filter out features that are not visible inside the mask by using
13 | the function in_mask(SRID). The first argument must be the EPSG code of the target CRS of the evaluated features.
14 | For example in_mask(2154) for a French Lambert 93.
15 |
Use in_mask(0) if all layers (mask and labels) are in the same projection.
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/doc/fr/about.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | À propos
5 |
6 |
7 | Cet outil a été développé pour aider les utilisateurs à générer rapidement des couches de masque pour mettre en évidence une zone d'intérêt.
8 | Les fonctionnalités actuelles sont :
9 |
création et modificiation d'un masque à partir d'une sélection polygonale (sur la couche active)
10 |
création et modification d'un masque via un appel à la fonction do_mask, de sorte que la génération de masque peut être pilotée par d'autres plugins
11 |
ouverture d'une boîte de dialogue pour choisir les propriétés du masque :
12 |
options de style (par défaut: polygone inversé avec bords flous)
13 |
tampon autour du masque
14 |
filtre des étiquettes pour les entités qui sont à l'intérieur de la zone d'intérêt (obtenu via la fonction filtre booléenne in_mask(SRID) sur les options de positionnement des étiquettes)
15 |
choix du format de la couche de masque (couche mémoire ou OGR)
16 |
17 |
18 |
19 |
Le plugin Mask a été développé par Xavier Culos (AEAG) avec des contributions de Hugo Mercier (Oslandia) sur financements de l'Agence de l'eau Adour Garonne.
20 | Merci de notifier tout problème ou demande d'évolution ici
Comment éliminer les élements de légende en dehors du masque ?
8 |
On peut vouloir utiliser le masque pour mettre en évidence une zone d'une carte. Auquel cas, on peut vouloir cacher
9 | les éléments de légende qui ne sont pas affichés à l'intérieur du polygon de masque.
10 |
La fonction in_mask peut être utilisée dans ce but. À partir de QGIS 2.14, une nouvelle option
11 | a été ajoutée aux outils de filtre de légende, permettant de spécifier une expression. Un symbole fera partie de
12 | la légende seulement si au moins une de ses entités fait que l'expression booléenne est évaluée à vrai.
13 |
Ceci peut en particulier être utilisé pour éliminer de la légende les entités qui ne sont pas dans le masque en utilisant
14 | la fonction in_mask(SRID). Le premier argument doit être le code EPSG du système de coordonnées de l'entité sur laquelle l'expression est évaluée.
15 | Par exemple in_mask(2154) pour du Lambert 93.
16 |
Utilisez in_mask(0) si l'ensemble de vos données (masque et étiquettes) sont codées dans une même projection.
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/htmldialog.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import (QSettings, QUrl, Qt)
2 | from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QTextBrowser, QDialogButtonBox)
3 |
4 | import os
5 |
6 |
7 | class HtmlDialog(QDialog):
8 |
9 | def __init__(self, parent, url):
10 | QDialog.__init__(self, parent)
11 |
12 | self.resize(800, 600)
13 |
14 | l = QVBoxLayout()
15 |
16 | self.te = QTextBrowser(self)
17 | self.te.sourceChanged.connect(self.onSourceChanged)
18 | self.te.setOpenExternalLinks(True)
19 | if not url.startswith('http'):
20 | pwd = os.path.dirname(__file__)
21 | locale = QSettings().value("locale/userLocale")[0:2]
22 | file = "{}/doc/{}/{}".format(pwd, locale, url)
23 | if not os.path.isfile(file):
24 | file = "{}/doc/en/{}".format(pwd, url)
25 | self.te.setSource(QUrl.fromLocalFile(file))
26 | else:
27 | self.te.setSource(QUrl(url))
28 |
29 | btn = QDialogButtonBox(QDialogButtonBox.Ok, Qt.Horizontal, self)
30 | btn.clicked.connect(self.close)
31 |
32 | l.addWidget(self.te)
33 | l.addWidget(btn)
34 |
35 | self.setLayout(l)
36 |
37 | def onSourceChanged(self, url):
38 | self.setWindowTitle(self.te.documentTitle())
39 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/i18n/fr.qm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haubourg/custom-osgeo4w-qgis/3c26b187b6b94562327338a610ca467697ba21c7/qgis-custom/apps/qgis-ltr/python/plugins/mask/i18n/fr.qm
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/layerlist.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import (Qt)
2 | from PyQt5.QtWidgets import (QWidget, QTableWidgetItem, QDialog, QCheckBox,
3 | QDialogButtonBox, QVBoxLayout)
4 | from qgis.core import (QgsProject, QgsVectorLayer)
5 |
6 | from .ui_layer_list import Ui_LayerListWidget
7 |
8 | from . import mask_filter
9 |
10 |
11 | class LayerListWidget(QWidget):
12 | def __init__(self, parent):
13 | QWidget.__init__(self, parent)
14 |
15 | self.ui = Ui_LayerListWidget()
16 | self.ui.setupUi(self)
17 |
18 | self.ui.selectAllBtn.clicked.connect(self.on_selectall)
19 | self.ui.unselectAllBtn.clicked.connect(self.on_unselectall)
20 |
21 | # list of limited layers (list of layer id)
22 | self.limited = []
23 |
24 | def get_limited_layers(self):
25 | return self.limited
26 |
27 | def on_selectall(self):
28 | "Select all layers for label filtering"
29 | ll = self.ui.layerTable
30 | for i in range(ll.rowCount()):
31 | ll.cellWidget(i, 0).setChecked(True)
32 |
33 | def on_unselectall(self):
34 | "Unselect all layers for label filtering"
35 | ll = self.ui.layerTable
36 | for i in range(ll.rowCount()):
37 | ll.cellWidget(i, 0).setChecked(False)
38 |
39 | def update_from_layers(self, is_new=False):
40 | layers = QgsProject.instance().mapLayers()
41 | n = 0
42 | for name, layer in layers.items():
43 |
44 | if layer.name() == 'Mask':
45 | continue
46 | # skip non vector layers
47 | if not isinstance(layer, QgsVectorLayer):
48 | continue
49 |
50 | # skip layers without labels
51 | if layer.labeling() is None:
52 | continue
53 |
54 | do_limit = False
55 | did_limit = layer.id() in self.limited
56 | do_limit = mask_filter.has_mask_filter(layer)
57 |
58 | if do_limit and not did_limit:
59 | self.limited.append(layer.id())
60 | if not do_limit and did_limit:
61 | self.limited.remove(layer.id())
62 |
63 | self.ui.layerTable.insertRow(n)
64 | name_item = QTableWidgetItem()
65 | name_item.setData(Qt.DisplayRole, layer.name())
66 | self.ui.layerTable.setItem(n, 1, name_item)
67 | w = QCheckBox(self.ui.layerTable)
68 | w.setEnabled(layer.labeling() is not None)
69 | w.setChecked(do_limit or is_new)
70 | self.ui.layerTable.setCellWidget(n, 0, w)
71 | item = QTableWidgetItem()
72 | item.setData(Qt.UserRole, layer)
73 | self.ui.layerTable.setItem(n, 0, item)
74 | n += 1
75 |
76 | self.ui.selectAllBtn.setEnabled(n != 0)
77 | self.ui.unselectAllBtn.setEnabled(n != 0)
78 |
79 | def update_labeling_from_list(self):
80 | ll = self.ui.layerTable
81 |
82 | for i in range(ll.rowCount()):
83 | do_limit = ll.cellWidget(i, 0).isChecked()
84 | layer = ll.item(i, 0).data(Qt.UserRole)
85 | did_limit = layer.id() in self.limited
86 |
87 | if not did_limit and do_limit:
88 | # add spatial filtering
89 | mask_filter.add_mask_filter(layer)
90 | self.limited.append(layer.id())
91 |
92 | if did_limit and not do_limit:
93 | mask_filter.remove_mask_filter(layer)
94 | self.limited.remove(layer.id())
95 |
96 |
97 | class LayerListDialog(QDialog):
98 | def __init__(self, parent):
99 | QDialog.__init__(self, parent)
100 |
101 | # add a button box
102 | self.layout = QVBoxLayout()
103 |
104 | self.layer_list = LayerListWidget(self)
105 | self.button_box = QDialogButtonBox(self)
106 | self.button_box.setOrientation(Qt.Horizontal)
107 | self.button_box.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok)
108 | self.button_box.accepted.connect(self.accept)
109 | self.button_box.rejected.connect(self.reject)
110 |
111 | self.layout.addWidget(self.layer_list)
112 | self.layout.addWidget(self.button_box)
113 |
114 | self.setLayout(self.layout)
115 |
116 | def set_labeling_model(self, model):
117 | self.layer_list.set_model(model)
118 |
119 | def exec_(self):
120 | self.layer_list.update_from_layers()
121 | return QDialog.exec_(self)
122 |
123 | def accept(self):
124 | # update layers
125 | self.layer_list.update_labeling_from_list()
126 | QDialog.accept(self)
127 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/mask_filter.py:
--------------------------------------------------------------------------------
1 | from qgis.core import (QgsVectorLayer, QgsPalLayerSettings, QgsProperty, QgsMessageLog,
2 | QgsVectorLayerSimpleLabeling)
3 |
4 | SPATIAL_FILTER = "in_mask"
5 |
6 |
7 | def has_mask_filter(layer):
8 | if not isinstance(layer, QgsVectorLayer):
9 | return False
10 |
11 | # check if a layer has already a mask filter enabled
12 | if layer.labeling() is None:
13 | return False
14 |
15 | settings = layer.labeling().settings()
16 | show_expr = settings.dataDefinedProperties().property(QgsPalLayerSettings.Show)
17 | if show_expr is None:
18 | return False
19 |
20 | return show_expr.expressionString().startswith(SPATIAL_FILTER)
21 |
22 |
23 | def remove_mask_filter(layer):
24 | if not isinstance(layer, QgsVectorLayer):
25 | return False
26 |
27 | # check if a layer has already a mask filter enabled
28 | if layer.labeling() is None:
29 | return False
30 |
31 | settings = layer.labeling().settings()
32 |
33 | try:
34 | if settings.dataDefinedProperties().hasProperty(QgsPalLayerSettings.Show) and \
35 | settings.dataDefinedProperties().property(QgsPalLayerSettings.Show).expressionString().startswith(SPATIAL_FILTER):
36 | # new settings
37 | settings = QgsPalLayerSettings(layer.labeling().settings())
38 | settings.dataDefinedProperties().setProperty(QgsPalLayerSettings.Show, True)
39 | if isinstance(layer.labeling(), QgsVectorLayerSimpleLabeling):
40 | layer.setLabeling(QgsVectorLayerSimpleLabeling(settings))
41 | except Exception as e:
42 | for m in e.args:
43 | QgsMessageLog.logMessage(m, 'Extensions')
44 |
45 |
46 | def add_mask_filter(layer):
47 | if not isinstance(layer, QgsVectorLayer):
48 | return False
49 |
50 | # check if a layer has already a mask filter enabled
51 | if layer.labeling() is None:
52 | return False
53 |
54 | try:
55 | expr = "%s(%d)" % (SPATIAL_FILTER, layer.crs().postgisSrid())
56 | prop = QgsProperty()
57 | prop.setExpressionString(expr)
58 |
59 | # new settings
60 | settings = QgsPalLayerSettings(layer.labeling().settings())
61 | settings.dataDefinedProperties().setProperty(QgsPalLayerSettings.Show, prop)
62 | if isinstance(layer.labeling(), QgsVectorLayerSimpleLabeling):
63 | layer.setLabeling(QgsVectorLayerSimpleLabeling(settings))
64 |
65 | except Exception as e:
66 | for m in e.args:
67 | QgsMessageLog.logMessage(m, 'Extensions')
68 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/metadata.txt:
--------------------------------------------------------------------------------
1 | # Mandatory items:
2 |
3 | [general]
4 | name=Mask
5 | qgisMinimumVersion=3.4
6 | qgisMaximumVersion=3.98
7 |
8 | description=Help to create mask, filter labels in it
9 | description[fr]=Aide à la création de masque, filtrage d'étiquette
10 | version=1.9.4
11 | # end of mandatory metadata
12 |
13 | # Optional items:
14 | about=This plugin allows user to quickly transform a polygon selection into a map masking layer or a region of interest, following symbology choice. The plugin allows also to spatially filter labeling of other layer, so that labels will only appear in the Region of Interest.
15 | about[fr]=Cette extension permet de générer un masque à partir d'une sélection de polygones. Le plugin permet également de filtrer l'étiquetage uniquement pour les objets à l'intérieur de ce masque.
16 | # Uncomment the following line and add your changelog entries:
17 | changelog=
18 | 1.9.4 : fix #78 : Python error atlas + mask, fix #79 locale.Error
19 | 1.9.3 : fix #77 : The absence of 'locale' probably behind the bug.
20 | 1.9.2 : fix #76 : Updating the existing mask doesn't update extents, and mask little less blue by default
21 | 1.9.1 : fix #75 : Locale symbol for decimal value, https://github.com/aeag/mask/issues/75
22 | 1.9.0 : Minimum fixes allowing a nominal work with the atlas. Fix #68
23 | 1.8.4 : fix #72, issues/21214
24 | 1.8.3 : a partially functional version (Atlas does not work anymore)
25 | 1.8.2 : adaptation to API changes (QgsCoordinateTransform)
26 | 1.8.1 : do not affect Rule based labeling
27 | 1.8 : Some API changes (QgsExpression, QgsPalLayerSettings)
28 | 1.7 : Migration to QGis 3
29 | 1.6 : master developpement version (not released)
30 | 1.5.1 : enables plugin only for qgis <=2.8 . See https://github.com/aeag/mask/issues/51
31 | 1.5 : fixes number of issues with Atlas, UI improvements.
32 | 1.4 : zooms to mask and clears selection on the fly. Some fixes due to mask_plugin renamed to mask
33 | 1.3 : enhance spatial operator for exact labeling filter. Was "contains", now is "contains" or "overlaps"
34 | 1.2 : bugfixe release :
35 | - Crash after removal of the mask layer
36 | - Unfreeze mapcanvas when atlas previewx is ON
37 | - Disable label filtering if mask layer has no object
38 | 1.1 : bugfixe release
39 | 1.0 : Can be used with atlas, 2.4 compatible
40 | 0.9 : Can be used with atlas, 2.4 compatible - test version
41 | 0.5 : QGis 2.0 Compatible
42 | 0.4 : Python console callable
43 | --fr--
44 | 1.4 : Zoom sur le masque et nettoyage de la sélection à la volée. Corrections mineures liées au renommage des répertoire de mask_plugin en mask
45 | 1.3 : Amélioration de l'opérateur spatial exact de filtre des étiquettes. Avant:"contains", après: "contains" OU "overlaps"
46 | 1.2 : correction de bugs :
47 | - Crash après la suppression d'un couche de masque
48 | - Ne gèle plus l'affichage si la prévisualisation d'Atlas est activée
49 | - Désactive le filtrage d'étiquette si la couche de masque est vide
50 | 1.1 : bugfixe release
51 | 1.0 : Ajoute la capacité à masquer les cartes du générateur d'Atlas
52 | 0.9 : Can be used with atlas, 2.4 compatible - test version
53 | 0.5 : Version QGis 2.0
54 | 0.4 : ajoute une classe permettant d'appeler le plugin depuis la console python ou un autre plugin.
55 |
56 | # tags are comma separated with spaces allowed
57 | tags=mask, ROI, filter labels, étiquettes, masque, zone d'intérêt
58 |
59 | homepage=https://github.com/aeag/mask
60 | tracker=https://github.com/aeag/mask/issues
61 | repository=https://github.com/aeag/mask
62 | icon=aeag_mask.png
63 | # experimental flag
64 | experimental=False
65 |
66 | # deprecated flag (applies to the whole plugin, not just a single version
67 | deprecated=False
68 |
69 | # Author contact information
70 | author=Hugo Mercier (Oslandia) - Xavier Culos (Agence de l'eau Adour Garonne) - Régis Haubourg (Oslandia)
71 | email=geocatalogue@eau-adour-garonne.fr
72 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/resources_rc.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | aeag_mask.png
4 |
5 |
6 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/style_tools.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from PyQt5.QtCore import QSettings
4 | from PyQt5.QtXml import QDomDocument, QDomImplementation
5 | from qgis.core import QgsReadWriteContext
6 |
7 | from .mask_parameters import MaskParameters
8 |
9 |
10 | def set_layer_symbology(layer, symbology):
11 | if symbology is not None:
12 | doc = QDomDocument("qgis")
13 | doc.setContent(symbology)
14 | errorMsg = ''
15 | ctx = QgsReadWriteContext()
16 | layer.readSymbology(doc.firstChildElement("qgis"), errorMsg, ctx)
17 |
18 |
19 | def get_layer_symbology(layer):
20 | doc = QDomDocument(QDomImplementation().createDocumentType("qgis",
21 | "http://mrcc.com/qgis.dtd",
22 | "SYSTEM"))
23 | rootNode = doc.createElement("qgis")
24 | doc.appendChild(rootNode)
25 | errorMsg = ''
26 | ctx = QgsReadWriteContext()
27 | layer.writeSymbology(rootNode, doc, errorMsg, ctx)
28 | return doc.toByteArray()
29 |
30 |
31 | def set_default_layer_symbology(layer):
32 | settings = QSettings()
33 |
34 | parameters = MaskParameters()
35 | defaults = settings.value("mask/defaults", None)
36 | if defaults is not None:
37 | parameters.unserialize(defaults)
38 | set_layer_symbology(layer, parameters.style)
39 | else:
40 | default_style = os.path.join(os.path.dirname(__file__), "default_mask_style.qml")
41 | layer.loadNamedStyle(default_style)
42 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/ui_layer_list.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'W:\GitHub\mask\mask\ui_layer_list.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.6
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 | class Ui_LayerListWidget(object):
12 | def setupUi(self, LayerListWidget):
13 | LayerListWidget.setObjectName("LayerListWidget")
14 | LayerListWidget.resize(768, 438)
15 | self.verticalLayout = QtWidgets.QVBoxLayout(LayerListWidget)
16 | self.verticalLayout.setObjectName("verticalLayout")
17 | self.formLayout = QtWidgets.QFormLayout()
18 | self.formLayout.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
19 | self.formLayout.setObjectName("formLayout")
20 | self.label = QtWidgets.QLabel(LayerListWidget)
21 | self.label.setObjectName("label")
22 | self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label)
23 | self.polygonOperatorCombo = QtWidgets.QComboBox(LayerListWidget)
24 | self.polygonOperatorCombo.setObjectName("polygonOperatorCombo")
25 | self.polygonOperatorCombo.addItem("")
26 | self.polygonOperatorCombo.addItem("")
27 | self.polygonOperatorCombo.addItem("")
28 | self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.polygonOperatorCombo)
29 | self.label_2 = QtWidgets.QLabel(LayerListWidget)
30 | self.label_2.setObjectName("label_2")
31 | self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_2)
32 | self.lineOperatorCombo = QtWidgets.QComboBox(LayerListWidget)
33 | self.lineOperatorCombo.setObjectName("lineOperatorCombo")
34 | self.lineOperatorCombo.addItem("")
35 | self.lineOperatorCombo.addItem("")
36 | self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lineOperatorCombo)
37 | self.verticalLayout.addLayout(self.formLayout)
38 | self.layerTable = QtWidgets.QTableWidget(LayerListWidget)
39 | self.layerTable.setObjectName("layerTable")
40 | self.layerTable.setColumnCount(2)
41 | self.layerTable.setRowCount(0)
42 | item = QtWidgets.QTableWidgetItem()
43 | self.layerTable.setHorizontalHeaderItem(0, item)
44 | item = QtWidgets.QTableWidgetItem()
45 | self.layerTable.setHorizontalHeaderItem(1, item)
46 | self.layerTable.horizontalHeader().setStretchLastSection(True)
47 | self.verticalLayout.addWidget(self.layerTable)
48 | self.horizontalLayout = QtWidgets.QHBoxLayout()
49 | self.horizontalLayout.setObjectName("horizontalLayout")
50 | self.selectAllBtn = QtWidgets.QPushButton(LayerListWidget)
51 | self.selectAllBtn.setObjectName("selectAllBtn")
52 | self.horizontalLayout.addWidget(self.selectAllBtn)
53 | self.unselectAllBtn = QtWidgets.QPushButton(LayerListWidget)
54 | self.unselectAllBtn.setObjectName("unselectAllBtn")
55 | self.horizontalLayout.addWidget(self.unselectAllBtn)
56 | self.verticalLayout.addLayout(self.horizontalLayout)
57 |
58 | self.retranslateUi(LayerListWidget)
59 | self.polygonOperatorCombo.setCurrentIndex(0)
60 | self.lineOperatorCombo.setCurrentIndex(0)
61 | QtCore.QMetaObject.connectSlotsByName(LayerListWidget)
62 |
63 | def retranslateUi(self, LayerListWidget):
64 | _translate = QtCore.QCoreApplication.translate
65 | LayerListWidget.setWindowTitle(_translate("LayerListWidget", "Form"))
66 | self.label.setText(_translate("LayerListWidget", "Function used for labeling filtering on polygons"))
67 | self.polygonOperatorCombo.setItemText(0, _translate("LayerListWidget", "Exact (slow and will disable simplification)"))
68 | self.polygonOperatorCombo.setItemText(1, _translate("LayerListWidget", "The mask geometry contains the centroid"))
69 | self.polygonOperatorCombo.setItemText(2, _translate("LayerListWidget", "The mask geometry contains a point on the polygon surface"))
70 | self.label_2.setText(_translate("LayerListWidget", "Function used for labeling filtering on lines"))
71 | self.lineOperatorCombo.setItemText(0, _translate("LayerListWidget", "The mask geometry intersects the line"))
72 | self.lineOperatorCombo.setItemText(1, _translate("LayerListWidget", "The mask geometry contains the line"))
73 | item = self.layerTable.horizontalHeaderItem(0)
74 | item.setText(_translate("LayerListWidget", "Limit"))
75 | item = self.layerTable.horizontalHeaderItem(1)
76 | item.setText(_translate("LayerListWidget", "Layer"))
77 | self.selectAllBtn.setText(_translate("LayerListWidget", "Select all"))
78 | self.unselectAllBtn.setText(_translate("LayerListWidget", "Unselect all"))
79 |
80 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/mask/ui_layer_list.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | LayerListWidget
4 |
5 |
6 |
7 | 0
8 | 0
9 | 768
10 | 438
11 |
12 |
13 |
14 | Form
15 |
16 |
17 |
18 |
19 |
20 | QFormLayout::AllNonFixedFieldsGrow
21 |
22 |
23 |
24 |
25 | Function used for labeling filtering on polygons
26 |
27 |
28 |
29 |
30 |
31 |
32 | 0
33 |
34 |
35 |
36 | Exact (slow and will disable simplification)
37 |
38 |
39 |
40 |
41 | The mask geometry contains the centroid
42 |
43 |
44 |
45 |
46 | The mask geometry contains a point on the polygon surface
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | Function used for labeling filtering on lines
55 |
56 |
57 |
58 |
59 |
60 |
61 | 0
62 |
63 |
64 |
65 | The mask geometry intersects the line
66 |
67 |
68 |
69 |
70 | The mask geometry contains the line
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | true
81 |
82 |
83 |
84 | Limit
85 |
86 |
87 |
88 |
89 | Layer
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | Select all
100 |
101 |
102 |
103 |
104 |
105 |
106 | Unselect all
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/menu_from_project/__about__.py:
--------------------------------------------------------------------------------
1 | #! python3 # noqa: E265
2 |
3 | """
4 | Metadata about the package to easily retrieve informations about it.
5 | See: https://packaging.python.org/guides/single-sourcing-package-version/
6 | """
7 |
8 | from configparser import ConfigParser
9 | from datetime import date
10 | from pathlib import Path
11 |
12 | __all__ = [
13 | "__author__",
14 | "__copyright__",
15 | "__email__",
16 | "__license__",
17 | "__summary__",
18 | "__title__",
19 | "__uri__",
20 | "__version__",
21 | ]
22 |
23 | # -- GLOBALS --------------------------------------------------------------------
24 |
25 | DIR_PLUGIN_ROOT = Path(__file__).parent
26 | PLG_METADATA_FILE = DIR_PLUGIN_ROOT / "metadata.txt"
27 |
28 |
29 | # -- FUNCTIONS --------------------------------------------------------------------
30 |
31 |
32 | def plugin_metadata_as_dict() -> dict:
33 | """Read plugin metadata.txt and returns it as a Python dict.
34 |
35 | Raises:
36 | IOError: if metadata.txt is not found
37 |
38 | Returns:
39 | dict: dict of dicts.
40 | """
41 | config = ConfigParser()
42 | if PLG_METADATA_FILE.is_file():
43 | config.read(PLG_METADATA_FILE, encoding="UTF-8")
44 | return {s: dict(config.items(s)) for s in config.sections()}
45 | else:
46 | raise IOError("Plugin metadata.txt not found at: %s" % PLG_METADATA_FILE)
47 |
48 |
49 | # -- VARIABLES --------------------------------------------------------------------
50 |
51 | # store full metadata.txt as dict into a var
52 | __plugin_md__ = plugin_metadata_as_dict()
53 |
54 | __author__ = __plugin_md__.get("general").get("author")
55 | __copyright__ = "2014 - {0}, {1}".format(date.today().year, __author__)
56 | __email__ = __plugin_md__.get("general").get("email")
57 | __keywords__ = __plugin_md__.get("general").get("repository").split("tags")
58 | __license__ = "GPL-2.0"
59 | __summary__ = "{}\n{}".format(
60 | __plugin_md__.get("general").get("description"),
61 | __plugin_md__.get("general").get("about"),
62 | )
63 |
64 | __title__ = __plugin_md__.get("general").get("name")
65 | __title_clean__ = "".join(e for e in __title__ if e.isalnum())
66 |
67 | __uri_homepage__ = __plugin_md__.get("general").get("homepage")
68 | __uri_repository__ = __plugin_md__.get("general").get("repository")
69 | __uri_tracker__ = __plugin_md__.get("general").get("tracker")
70 | __uri__ = __uri_repository__
71 |
72 | __version__ = __plugin_md__.get("general").get("version")
73 | __version_info__ = tuple(
74 | [
75 | int(num) if num.isdigit() else num
76 | for num in __version__.replace("-", ".", 1).split(".")
77 | ]
78 | )
79 |
80 | # #############################################################################
81 | # ##### Main #######################
82 | # ##################################
83 | if __name__ == "__main__":
84 | plugin_md = plugin_metadata_as_dict()
85 | assert isinstance(plugin_md, dict)
86 | assert plugin_md.get("general").get("name") == __title__
87 | print("Plugin: " + __title__)
88 | print("Plugin (clean): " + __title_clean__)
89 | print("By: " + __author__)
90 | print("Version: " + __version__)
91 | print("Description: " + __summary__)
92 | print(
93 | "For: %s > QGIS > %s"
94 | % (
95 | plugin_md.get("general").get("qgisminimumversion"),
96 | plugin_md.get("general").get("qgismaximumversion"),
97 | )
98 | )
99 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/menu_from_project/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | /***************************************************************************
3 | Name : menu_from_project plugin
4 | Description : Build layers shortcut menu based on QGIS project
5 | Date : 10/11/2011
6 | copyright : (C) 2011 by Agence de l'Eau Adour Garonne
7 | email : xavier.culos@eau-adour-garonne.fr
8 | ***************************************************************************/
9 |
10 | /***************************************************************************
11 | * *
12 | * This program is free software; you can redistribute it and/or modify *
13 | * it under the terms of the GNU General Public License as published by *
14 | * the Free Software Foundation; either version 2 of the License, or *
15 | * (at your option) any later version. *
16 | * *
17 | ***************************************************************************/
18 | This script initializes the plugin, making it known to QGIS.
19 | """
20 |
21 |
22 | def classFactory(iface):
23 | # load menu_from_project class from file menu_from_project
24 | from .menu_from_project import MenuFromProject
25 |
26 | return MenuFromProject(iface)
27 |
--------------------------------------------------------------------------------
/qgis-custom/apps/qgis-ltr/python/plugins/menu_from_project/doc/index-en.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Menu Layer from Project - Redirecting...
7 |
8 |
9 |
10 |
11 |
12 |