├── .gitignore ├── .gitmodules ├── .travis.yml ├── CONTRIBUTING.rst ├── LICENSE.txt ├── README.rst ├── docker-compose.yml ├── docs ├── Makefile ├── make.bat └── source │ ├── actions.rst │ ├── caveats │ └── sld.rst │ ├── conf.py │ ├── img │ ├── actions │ │ ├── add_catalog.png │ │ ├── add_style.png │ │ ├── catalog_added.png │ │ ├── confirm_delete.png │ │ ├── create_catalog.png │ │ ├── create_workspace.png │ │ ├── define_group.png │ │ ├── define_gwc.png │ │ ├── dragdrop.png │ │ ├── dragdrop_external.png │ │ ├── editsld.png │ │ ├── extent_drag.png │ │ ├── new_style.png │ │ ├── order_in_group.png │ │ ├── plugin_menu.png │ │ ├── plugin_repo.png │ │ ├── plugin_repo_added.png │ │ ├── publish_layer.png │ │ ├── publish_layers.png │ │ ├── publish_project.png │ │ ├── publish_style.png │ │ ├── seed.png │ │ └── seed_status.png │ └── intro │ │ ├── about.png │ │ ├── add_catalog.png │ │ ├── config.png │ │ ├── description_panel.png │ │ ├── description_table.png │ │ ├── duplicated_layer.png │ │ ├── explorer.png │ │ ├── gray_catalog.png │ │ ├── tracking.png │ │ ├── undocked.png │ │ └── version_warning.png │ ├── index.rst │ ├── installation.rst │ ├── intro.rst │ └── settingsconf.rst ├── geoserverexplorer ├── __init__.py ├── extlibs │ ├── geoserver │ │ ├── __init__.py │ │ ├── catalog.py │ │ ├── layer.py │ │ ├── layergroup.py │ │ ├── namespace.py │ │ ├── resource.py │ │ ├── store.py │ │ ├── style.py │ │ ├── support.py │ │ ├── util.py │ │ └── workspace.py │ └── site.py ├── geoserver │ ├── __init__.py │ ├── auth.py │ ├── basecatalog.py │ ├── gwc.py │ ├── settings.py │ └── util.py ├── gui │ ├── __init__.py │ ├── confirm.py │ ├── contextualhelp.py │ ├── dialogs │ │ ├── __init__.py │ │ ├── catalogdialog.py │ │ ├── groupdialog.py │ │ ├── gsnamedialog.py │ │ ├── gwclayer.py │ │ ├── layerdialog.py │ │ ├── projectdialog.py │ │ ├── resources.qrc │ │ ├── resources_rc.py │ │ ├── sldeditor.py │ │ ├── styledialog.py │ │ └── workspacedialog.py │ ├── explorer.py │ ├── exploreritems.py │ ├── explorertree.py │ ├── extentpanel.py │ ├── gsexploreritems.py │ ├── gsnameutils.py │ ├── gsoperations.py │ ├── gwcexploreritems.py │ ├── parametereditor.py │ └── rectangletool.py ├── images │ ├── add-page-blue.png │ ├── add-style-to-layer.png │ ├── add.png │ ├── bottom.png │ ├── browser.gif │ ├── browser.png │ ├── clean.png │ ├── config.png │ ├── create-store-from-layer.png │ ├── default-style.png │ ├── default-workspace.png │ ├── delete.gif │ ├── desktop.svg │ ├── down.png │ ├── edit.png │ ├── edit_sld.png │ ├── geonode.png │ ├── geoserver.png │ ├── geoserver_gray.png │ ├── grid.jpg │ ├── group.gif │ ├── gwc.png │ ├── help.png │ ├── import_into_qgis.png │ ├── layer.png │ ├── layer_line.png │ ├── layer_point.png │ ├── layer_polygon.png │ ├── layer_unknown.png │ ├── new_table.png │ ├── pencil.png │ ├── process.png │ ├── publish-to-geoserver.png │ ├── refresh.png │ ├── rename.png │ ├── seed.png │ ├── sql_window.png │ ├── style.png │ ├── table.png │ ├── top.png │ ├── tree.gif │ ├── up.png │ ├── warning.png │ ├── warning32.png │ ├── workspace.png │ └── wrong.gif ├── metadata.txt ├── plugin.py ├── qgis │ ├── __init__.py │ ├── catalog.py │ ├── exporter.py │ ├── layers.py │ ├── layerwatcher.py │ ├── sldadapter.py │ ├── uri.py │ └── utils.py ├── resources │ ├── grayscale.sld │ └── rgb.sld ├── settings.json └── test │ ├── __init__.py │ ├── catalogtests.py │ ├── coveragerc │ ├── data │ ├── geo.dbf │ ├── geo.prj │ ├── geo.qpj │ ├── geo.shp │ ├── geo.shx │ ├── land.dbf │ ├── land.prj │ ├── land.qpj │ ├── land.shp │ ├── land.shx │ ├── qgis_plugin_test_dem.tif │ ├── qgis_plugin_test_dem.tif.aux.xml │ ├── qgis_plugin_test_dem_exact.tif │ ├── qgis_plugin_test_dem_rbg.tif │ ├── qgis_plugin_test_demascii.asc │ ├── qgis_plugin_test_pt1.dbf │ ├── qgis_plugin_test_pt1.prj │ ├── qgis_plugin_test_pt1.qpj │ ├── qgis_plugin_test_pt1.shp │ ├── qgis_plugin_test_pt1.shx │ ├── qgis_plugin_test_pt1json.geojson │ ├── qgis_plugin_test_pt2.dbf │ ├── qgis_plugin_test_pt2.prj │ ├── qgis_plugin_test_pt2.qpj │ ├── qgis_plugin_test_pt2.shp │ ├── qgis_plugin_test_pt2.shx │ ├── qgis_plugin_test_pt3.dbf │ ├── qgis_plugin_test_pt3.prj │ ├── qgis_plugin_test_pt3.qpj │ ├── qgis_plugin_test_pt3.shp │ ├── qgis_plugin_test_pt3.shx │ ├── qgis_plugin_test_pt4.dbf │ ├── qgis_plugin_test_pt4.prj │ ├── qgis_plugin_test_pt4.qpj │ ├── qgis_plugin_test_pt4.shp │ ├── qgis_plugin_test_pt4.shx │ ├── symbology │ │ ├── graticule.dbf │ │ ├── graticule.prj │ │ ├── graticule.qpj │ │ ├── graticule.shp │ │ ├── graticule.shx │ │ ├── irregular_lines.cpg │ │ ├── irregular_lines.dbf │ │ ├── irregular_lines.prj │ │ ├── irregular_lines.qpj │ │ ├── irregular_lines.shp │ │ ├── irregular_lines.shx │ │ ├── irregular_polygons.cpg │ │ ├── irregular_polygons.dbf │ │ ├── irregular_polygons.prj │ │ ├── irregular_polygons.qpj │ │ ├── irregular_polygons.shp │ │ ├── irregular_polygons.shx │ │ ├── labels_lines_01_parallel.qgs │ │ ├── labels_lines_02_curved.qgs │ │ ├── labels_lines_03_curved_on_line.qgs │ │ ├── labels_lines_04_curved_below_line.qgs │ │ ├── labels_lines_05_horizontal.qgs │ │ ├── labels_points_01_simple.qgs │ │ ├── labels_points_02_rotated_points.qgs │ │ ├── labels_points_03_halo_and_displace.qgs │ │ ├── labels_points_04_quadrant.qgs │ │ ├── labels_points_05_cartographic.qgs │ │ ├── labels_points_06_cartographic_from_symbol.qgs │ │ ├── labels_polygons_01_offset_centroid.qgs │ │ ├── labels_polygons_02_around_centroid.qgs │ │ ├── labels_polygons_03_using_perimeter.qgs │ │ ├── labels_polygons_04_horizontal.qgs │ │ ├── labels_polygons_05_free.qgs │ │ ├── labels_polygons_06_curved_perimeter.qgs │ │ ├── lines.dbf │ │ ├── lines.prj │ │ ├── lines.qgs │ │ ├── lines.qpj │ │ ├── lines.shp │ │ ├── lines.shx │ │ ├── points.dbf │ │ ├── points.prj │ │ ├── points.qgs │ │ ├── points.qpj │ │ ├── points.shp │ │ ├── points.shx │ │ ├── polygons.qgs │ │ ├── qgis.jpeg │ │ ├── raster_grayscale.qgs │ │ ├── raster_grayscale_inverted.qgs │ │ ├── raster_hillshade.qgs │ │ ├── raster_palleted.qgs │ │ ├── raster_pseudocolor.qgs │ │ ├── raster_pseudocolor_discrete.qgs │ │ ├── raster_pseudocolor_exact.qgs │ │ ├── raster_rendered_rgb.qgs │ │ └── symbology_test.qgs │ ├── test.qgs │ └── test_font.qgs │ ├── deletetests.py │ ├── dragdroptests.py │ ├── functional.txt │ ├── guitests.py │ ├── integrationtest.py │ ├── resources │ ├── font.sld │ ├── raster.sld │ ├── vector.2.16.sld │ ├── vector.sld │ └── vector_hook.py │ ├── symbologytests.py │ ├── testplugin.py │ └── utils.py ├── pavement.py ├── pylintrc ├── requirements-dev.txt ├── requirements.txt ├── rundockertests.sh └── travis_secrets.tar.gz.enc /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | geoserverexplorer/docs/ 25 | geoserverexplorer/extlibs/ 26 | 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | #ext-libs 59 | #ext-src 60 | geoserverexplorer.zip 61 | ssh_config 62 | 63 | #QGIS Backup files 64 | *.qgs~ 65 | *.qgz~ 66 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "docs/themes"] 2 | path = docs/themes 3 | url = https://github.com/boundlessgeo/sphinx-theme 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | addons: 3 | hosts: 4 | - suite410.boundless.test 5 | services: 6 | - docker 7 | env: 8 | global: 9 | - PLUGIN_NAME=geoserverexplorer 10 | - secure: "oy82iDfs5KWE2nmMgwqX/uNZs9frXzb212VpPy8wpz5q3pERQiFLuttXinIZbi9KJq92R2hpmEPCLrpnH4de5s1c8N0pJtBc17Sx28DqJcZIcogpO/zXnQfj/w3s6Gw5p+N0KW4LMruGe+wlu3zJadg0i+Bck2haSkO9C2fO62lnas9Hp86wjKAqxbvYIf3XnFHLyB1ICQEQjbXNyrwdP1dXTeoUbFn8UaKhinxRV6OtutDgRDua3ZkFuPGBDqKX3//9xoGze6r2Xo/Y99C7hJkjRHOz0RkJu0khXsw3TlZlKVo1OfkWh1NsdcuZsm7gKpNqAp77BRLWorSxRxCSjyVhqDlqguwSN7MrT/5xQjn0mj/XDnuzhNzTntxOPpeWmXSNskpxKhwcpRd2jni6Wd5W1/UpoBC2Ueo8YBpE/0wVNMUd1q5XVZjBvBc715OnrvI3Z6i002yWUaj6uQHBWG9IP6lGBTfl/271648KCpVdtj4mCQTsv9aTVgFZbc4cQQfSw6kH1IxdRi+7+ulK/O2eoZcnaihzlyfdoHv1pbuKNQCqkqeUYAQG+RXwez0ckch8cRuOcPxF0Y/5DyVmExjgK7O1DPPDWDFvsmThML+wY3lY/ZAH46Sebhch34TLyopjUoTaumhwcm84T3goxUUJTPbg+iEJkOF0EkdCRTQ=" 11 | - secure: "g1apYRlEgftoThS0apF09OuPICw9pIp6OQKsED/ObyuqA+htP+AX6pprqG517BakJW2WMbTCaG0a3S4d+EnyQ3E/NIRtEivdR6/aVNiLHaOJXlSBKw4gWHX0F3ZyiVRMqRSJ2xVSHlNWqmSmUaUkSUJr9FUNYr/zGHVAg3DjUC7Z8wVVQIwBHrNtcfwsDM3cQOpB4tUAQkxOxF5Nb+jVx/7Cw6QGhsEy66XRWhK8d4R56XaC5uf5pmYZcGZaS69Y3O89dnMmY7A63HliXQpTtYjhZ4FF7WAGzuNFENNYVYo30gRUi1cv7CoWd+RE/3qGMGpcxs/lAU3lD5OLu5O7P/apmfFwKKJ0cS+fXKuI+gYMzpWIM/gBulTnNMzVHzWisy+1dVzsAZxzX4XRCb0rD/W89c770k85F/WNYGpUdSE8J7XDSFHV95FfmKIeAjSo1NSt8xijarz6YmxoktDjIWiogtpiLkOp6vhijbo6GiER+6kQ3JjUXWPbl+EOmsqFHUKMq0osclNqS+NWoqFZ7onQvK3L/uvza72eqM2OSqIXy2ilau4nlVNUl4P6IQmmZWlJmAqtmBO/O1f6NV6FO8czliEW6vQJbu2kojvqrFglYnUXNcJzKf/oH9g1ZY4Cw7qsf8s/NkYTN1wBFr9mTJ4B3ZfUgeQohNNZE1Xo8Ws=" 12 | matrix: 13 | - QGIS_VERSION_TAG=master PYTHON_EXECUTABLE=python3 PIP_EXECUTABLE=pip3 14 | before_install: 15 | - echo "$DOCKER_PWD" | docker login -u "$DOCKER_USER" --password-stdin 16 | - docker-compose up -d 17 | - docker-compose ps 18 | - sleep 10 19 | - docker-compose exec qgis-testing-environment sh -c "qgis_setup.sh ${PLUGIN_NAME}" 20 | - docker-compose exec qgis-testing-environment sh -c "pip3 install paver" 21 | script: 22 | - docker-compose exec qgis-testing-environment sh -c "cd /tests_directory && paver setup && paver package --tests" 23 | - docker version 24 | - docker-compose version 25 | - docker-compose exec qgis-testing-environment sh -c "GSPORT=8082 GSHOSTNAME=suite410.boundless.test qgis_testrunner.sh geoserverexplorer.test.catalogtests" 26 | - docker-compose exec qgis-testing-environment sh -c "GSPORT=8082 GSHOSTNAME=suite410.boundless.test qgis_testrunner.sh geoserverexplorer.test.deletetests" 27 | - docker-compose exec qgis-testing-environment sh -c "GSPORT=8082 GSHOSTNAME=suite410.boundless.test qgis_testrunner.sh geoserverexplorer.test.dragdroptests" 28 | - docker-compose exec qgis-testing-environment sh -c "GSPORT=8082 GSHOSTNAME=suite410.boundless.test qgis_testrunner.sh geoserverexplorer.test.guitests" 29 | notifications: 30 | slack: 31 | secure: "BGVhes7seUF5U0T7PNGUxEu0MFmFVSeuF6FL+nOgtDfibX2IqWb+L7lWddJ+ZePvVYBzORTZs2vYJNQkIBPK2zDoX95rT56J+7ej6aVdxWE9dpd5BKf6IC9WBKyvSBv2gRm7J/zfSAIyKDHorY2MvemfuufDCfNoFEO0YNEKZxx3gc5A3xc3F1SCs1N8vp2DKQ0AA+Afg6G5QfEDLpW7xEYLZG/WEtS2zQIw4l/SqyszpvQEoCXblpLe1T/o6jlsuUPzZTMdaPpay2w2IyTs/IQaGUAIKThcL869Tu0TDkfFC209tRaCr2H2Fru9HCLutyX3oPgP4rwT7wI4Yg0TX47no8mBUNE3EHsh6hoKNhi8fXAzNnAZe/qDh0pFs/1yX9UTbMiq9UDa6CqHjH8dSnX8LRcs77dJlolNi9Na875y4L4VOuAqa2dScdHfjsX0WApO/t5e+RarduPfFgHZw1AkpuoW++fPmYt6geBDYyP3sX/f0z//LzIGDtrjNiIgvIlyPWnIBd++mMqLyLkjl2zr7l35JqjGDYKjzJuOPZXCHfvkmcIV7GO17HCs7P9VuyA56sycVp8iJSfYI4X26LW1l5BPVPy2muprSHyj+PnTG96vrcGM/mV2Gb1VcFaZ6RxC5jqgqnCXQ33PC7XpiKVCW80L5di0wYqH8drisnA=" 32 | after_success: 33 | - | 34 | if [ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_BRANCH}" = "master" ]; then 35 | mkdir /home/travis/.ssh/ 36 | chmod 700 /home/travis/.ssh/ 37 | openssl aes-256-cbc -K $encrypted_255ebb4dc86b_key -iv $encrypted_255ebb4dc86b_iv -in travis_secrets.tar.gz.enc -out travis_secrets.tar.gz -d 38 | tar xzvf travis_secrets.tar.gz 39 | mv id_rsa.qgisrepoguest /home/travis/.ssh/id_rsa.qgisrepoguest 40 | mv ssh_config /home/travis/.ssh/config 41 | chmod 600 /home/travis/.ssh/id_rsa.qgisrepoguest 42 | chmod 600 /home/travis/.ssh/config 43 | export RELEASE_ZIPNAME=${PLUGIN_NAME}.zip 44 | echo "Uploading ${RELEASE_ZIPNAME} to QGIS Dev..." 45 | scp ${PLUGIN_NAME}.zip qgisrepoguest:${UPLOADS}/${RELEASE_ZIPNAME} 46 | export GIT_REV=$(git rev-parse --short HEAD | tr -d '\n') 47 | ssh qgisrepoguest "${UPDATER} update --dev --role desktop-qgis-plugin-dev --git-hash ${GIT_REV} ${RELEASE_ZIPNAME}" 48 | fi 49 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | Pull Requests 5 | ------------- 6 | 7 | Pull requests are welcome,: 8 | 9 | * For small changes (under a file in size) a committer can apply the fix on your behalf. 10 | 11 | * For changes over one file in size we ask that you add your details (or your employer details) in the file ``__copyright__``). 12 | 13 | We trust you (and your employer) understand the `GPL License `_ used by this plugin and QGIS. This is why we asks you note your copyright details above. 14 | 15 | The complete list of `contributors `_ is available on github. 16 | 17 | Committers 18 | ---------- 19 | 20 | The project committers: 21 | 22 | * `Victor Olaya `_ (Boundless) 23 | * `Larry Shaffer `_ (Boundless) 24 | * `Luigi Pirelli `_ (Boundless) 25 | * `Alexander Bruy `_ (Boundless) 26 | 27 | This is a small project that communicates via pull request. 28 | 29 | To request commit access issue a pull request against this CONTRIBUTING.rst file. Existing committers can review (+1,0,-1) and merge the change accordingly. 30 | 31 | By the same token committers that are inactive can be retired via a pull request. 32 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. image:: https://travis-ci.org/boundlessgeo/qgis-geoserver-plugin.svg?branch=master 2 | :target: https://travis-ci.org/boundlessgeo/qgis-geoserver-plugin 3 | 4 | GeoServer Explorer 5 | ================== 6 | 7 | A plugin to configure and manage GeoServer from QGIS. 8 | 9 | Installation 10 | ------------ 11 | 12 | The plugin is available through QGIS official plugin repository. Nevertheless, to install it using this repository, run the following in a terminal (you will need to have `paver `_ installed): 13 | 14 | :: 15 | 16 | $ paver setup 17 | $ paver install 18 | 19 | The first command will fetch the dependencies required by the plugin. 20 | The second one will install the plugin in your local QGIS plugins folder. In case you have already downloadd the GeoServer Explorer plugin, this second step will silently fail, in order to make it work go to your local plugin directory (e.g., "$HOME/.qgis2/python/plugins" and remove the "geoserverexplorer" folder, then run ``paver install`` again). 21 | Open QGIS and you should already see the GeoServer Explorer plugin available in your QGIS plugin manager. 22 | 23 | Documentation 24 | ------------- 25 | 26 | Thew plugin is documented `here `_. 27 | 28 | Getting Help 29 | ------------ 30 | 31 | If you have questions, please use the project `mailing list `_ 32 | 33 | Use the Github project for any bug reports. Pull requests are welcome. 34 | 35 | Cloning this repository 36 | ----------------------- 37 | 38 | This repository uses external repositories as submodules. Therefore in order to include the external repositories during cloning you should use the *--recursive* option: 39 | 40 | ``git clone --recursive http://github.com/boundlessgeo/qgis-geoserver-plugin.git`` 41 | 42 | Also, to update the submodules whenever there are changes in the remote repositories one should do: 43 | 44 | ``git submodule update --remote`` 45 | 46 | 47 | Run unit tests 48 | ----------------------- 49 | 50 | just execute the script ``rundockertests.sh`` 51 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | 5 | suite410: 6 | image: boundlessgeo/suite-desktop-testing:4.10 7 | environment: 8 | - TOMCAT_SSL_ENABLED_PROTOCOLS=${TOMCAT_SSL_ENABLED_PROTOCOLS} 9 | ports: 10 | - "8082:8080" 11 | - "8444:8443" 12 | networks: 13 | desktop-network: 14 | aliases: 15 | - suite410.boundless.test 16 | 17 | qgis-testing-environment: 18 | image: elpaso/qgis-testing-environment:${QGIS_VERSION_TAG} 19 | volumes: 20 | - /tmp/.X11-unix:/tmp/.X11-unix 21 | - ./:/tests_directory 22 | environment: 23 | DISPLAY: ':99' 24 | QT_X11_NO_MITSHM: '1' 25 | 26 | volumes: 27 | bs_data_100: 28 | bs_data: 29 | 30 | networks: 31 | desktop-network: 32 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # (c) 2016 Boundless, http://boundlessgeo.com 3 | # This code is licensed under the GPL 2.0 license. 4 | # 5 | # Makefile for Sphinx documentation 6 | # 7 | 8 | # You can set these variables from the command line. 9 | SPHINXOPTS = 10 | SPHINXBUILD = sphinx-build 11 | PAPER = 12 | BUILDDIR = build 13 | 14 | # Internal variables. 15 | PAPEROPT_a4 = -D latex_paper_size=a4 16 | PAPEROPT_letter = -D latex_paper_size=letter 17 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 18 | # the i18n builder cannot share the environment and doctrees with the others 19 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 20 | 21 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 22 | 23 | help: 24 | @echo "Please use \`make ' where is one of" 25 | @echo " html to make standalone HTML files" 26 | @echo " dirhtml to make HTML files named index.html in directories" 27 | @echo " singlehtml to make a single large HTML file" 28 | @echo " pickle to make pickle files" 29 | @echo " json to make JSON files" 30 | @echo " htmlhelp to make HTML files and a HTML help project" 31 | @echo " qthelp to make HTML files and a qthelp project" 32 | @echo " devhelp to make HTML files and a Devhelp project" 33 | @echo " epub to make an epub" 34 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 35 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 36 | @echo " text to make text files" 37 | @echo " man to make manual pages" 38 | @echo " texinfo to make Texinfo files" 39 | @echo " info to make Texinfo files and run them through makeinfo" 40 | @echo " gettext to make PO message catalogs" 41 | @echo " changes to make an overview of all changed/added/deprecated items" 42 | @echo " linkcheck to check all external links for integrity" 43 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 44 | 45 | clean: 46 | -rm -rf $(BUILDDIR)/* 47 | 48 | html: 49 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 50 | @echo 51 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 52 | 53 | dirhtml: 54 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 55 | @echo 56 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 57 | 58 | singlehtml: 59 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 60 | @echo 61 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 62 | 63 | pickle: 64 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 65 | @echo 66 | @echo "Build finished; now you can process the pickle files." 67 | 68 | json: 69 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 70 | @echo 71 | @echo "Build finished; now you can process the JSON files." 72 | 73 | htmlhelp: 74 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 75 | @echo 76 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 77 | ".hhp project file in $(BUILDDIR)/htmlhelp." 78 | 79 | qthelp: 80 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 81 | @echo 82 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 83 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 84 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OpenGeoSuiteQGISplugin.qhcp" 85 | @echo "To view the help file:" 86 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OpenGeoSuiteQGISplugin.qhc" 87 | 88 | devhelp: 89 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 90 | @echo 91 | @echo "Build finished." 92 | @echo "To view the help file:" 93 | @echo "# mkdir -p $$HOME/.local/share/devhelp/OpenGeoSuiteQGISplugin" 94 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OpenGeoSuiteQGISplugin" 95 | @echo "# devhelp" 96 | 97 | epub: 98 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 99 | @echo 100 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 101 | 102 | latex: 103 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 104 | @echo 105 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 106 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 107 | "(use \`make latexpdf' here to do that automatically)." 108 | 109 | latexpdf: 110 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 111 | @echo "Running LaTeX files through pdflatex..." 112 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 113 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 114 | 115 | text: 116 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 117 | @echo 118 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 119 | 120 | man: 121 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 122 | @echo 123 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 124 | 125 | texinfo: 126 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 127 | @echo 128 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 129 | @echo "Run \`make' in that directory to run these through makeinfo" \ 130 | "(use \`make info' here to do that automatically)." 131 | 132 | info: 133 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 134 | @echo "Running Texinfo files through makeinfo..." 135 | make -C $(BUILDDIR)/texinfo info 136 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 137 | 138 | gettext: 139 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 140 | @echo 141 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 142 | 143 | changes: 144 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 145 | @echo 146 | @echo "The overview file is in $(BUILDDIR)/changes." 147 | 148 | linkcheck: 149 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 150 | @echo 151 | @echo "Link check complete; look for any errors in the above output " \ 152 | "or in $(BUILDDIR)/linkcheck/output.txt." 153 | 154 | doctest: 155 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 156 | @echo "Testing of doctests in the sources finished, look at the " \ 157 | "results in $(BUILDDIR)/doctest/output.txt." 158 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | REM 3 | REM (c) 2016 Boundless, http://boundlessgeo.com 4 | REM This code is licensed under the GPL 2.0 license. 5 | REM 6 | 7 | REM Command file for Sphinx documentation 8 | 9 | if "%SPHINXBUILD%" == "" ( 10 | set SPHINXBUILD=sphinx-build 11 | ) 12 | set BUILDDIR=build 13 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 14 | set I18NSPHINXOPTS=%SPHINXOPTS% source 15 | if NOT "%PAPER%" == "" ( 16 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 17 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 18 | ) 19 | 20 | if "%1" == "" goto help 21 | 22 | if "%1" == "help" ( 23 | :help 24 | echo.Please use `make ^` where ^ is one of 25 | echo. html to make standalone HTML files 26 | echo. dirhtml to make HTML files named index.html in directories 27 | echo. singlehtml to make a single large HTML file 28 | echo. pickle to make pickle files 29 | echo. json to make JSON files 30 | echo. htmlhelp to make HTML files and a HTML help project 31 | echo. qthelp to make HTML files and a qthelp project 32 | echo. devhelp to make HTML files and a Devhelp project 33 | echo. epub to make an epub 34 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 35 | echo. text to make text files 36 | echo. man to make manual pages 37 | echo. texinfo to make Texinfo files 38 | echo. gettext to make PO message catalogs 39 | echo. changes to make an overview over all changed/added/deprecated items 40 | echo. linkcheck to check all external links for integrity 41 | echo. doctest to run all doctests embedded in the documentation if enabled 42 | goto end 43 | ) 44 | 45 | if "%1" == "clean" ( 46 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 47 | del /q /s %BUILDDIR%\* 48 | goto end 49 | ) 50 | 51 | if "%1" == "html" ( 52 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 53 | if errorlevel 1 exit /b 1 54 | echo. 55 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 56 | goto end 57 | ) 58 | 59 | if "%1" == "dirhtml" ( 60 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 61 | if errorlevel 1 exit /b 1 62 | echo. 63 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 64 | goto end 65 | ) 66 | 67 | if "%1" == "singlehtml" ( 68 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 69 | if errorlevel 1 exit /b 1 70 | echo. 71 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 72 | goto end 73 | ) 74 | 75 | if "%1" == "pickle" ( 76 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 77 | if errorlevel 1 exit /b 1 78 | echo. 79 | echo.Build finished; now you can process the pickle files. 80 | goto end 81 | ) 82 | 83 | if "%1" == "json" ( 84 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 85 | if errorlevel 1 exit /b 1 86 | echo. 87 | echo.Build finished; now you can process the JSON files. 88 | goto end 89 | ) 90 | 91 | if "%1" == "htmlhelp" ( 92 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 93 | if errorlevel 1 exit /b 1 94 | echo. 95 | echo.Build finished; now you can run HTML Help Workshop with the ^ 96 | .hhp project file in %BUILDDIR%/htmlhelp. 97 | goto end 98 | ) 99 | 100 | if "%1" == "qthelp" ( 101 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 102 | if errorlevel 1 exit /b 1 103 | echo. 104 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 105 | .qhcp project file in %BUILDDIR%/qthelp, like this: 106 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OpenGeoSuiteQGISplugin.qhcp 107 | echo.To view the help file: 108 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OpenGeoSuiteQGISplugin.ghc 109 | goto end 110 | ) 111 | 112 | if "%1" == "devhelp" ( 113 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished. 117 | goto end 118 | ) 119 | 120 | if "%1" == "epub" ( 121 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 122 | if errorlevel 1 exit /b 1 123 | echo. 124 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 125 | goto end 126 | ) 127 | 128 | if "%1" == "latex" ( 129 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 130 | if errorlevel 1 exit /b 1 131 | echo. 132 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 133 | goto end 134 | ) 135 | 136 | if "%1" == "text" ( 137 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 138 | if errorlevel 1 exit /b 1 139 | echo. 140 | echo.Build finished. The text files are in %BUILDDIR%/text. 141 | goto end 142 | ) 143 | 144 | if "%1" == "man" ( 145 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 146 | if errorlevel 1 exit /b 1 147 | echo. 148 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 149 | goto end 150 | ) 151 | 152 | if "%1" == "texinfo" ( 153 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 154 | if errorlevel 1 exit /b 1 155 | echo. 156 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 157 | goto end 158 | ) 159 | 160 | if "%1" == "gettext" ( 161 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 162 | if errorlevel 1 exit /b 1 163 | echo. 164 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 165 | goto end 166 | ) 167 | 168 | if "%1" == "changes" ( 169 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.The overview file is in %BUILDDIR%/changes. 173 | goto end 174 | ) 175 | 176 | if "%1" == "linkcheck" ( 177 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Link check complete; look for any errors in the above output ^ 181 | or in %BUILDDIR%/linkcheck/output.txt. 182 | goto end 183 | ) 184 | 185 | if "%1" == "doctest" ( 186 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 187 | if errorlevel 1 exit /b 1 188 | echo. 189 | echo.Testing of doctests in the sources finished, look at the ^ 190 | results in %BUILDDIR%/doctest/output.txt. 191 | goto end 192 | ) 193 | 194 | :end 195 | -------------------------------------------------------------------------------- /docs/source/caveats/sld.rst: -------------------------------------------------------------------------------- 1 | This document describes the symbology elements from QGIS that are supported when publishing a QGIS layer to GeoServer using the OpenGeo Suite plugin. Layers with symbologies using these elements are guaranteed to have the same styling once published to GeoServer. Otherwise, differences must be found. 2 | 3 | General 4 | ======== 5 | 6 | All units have to be in milimeters. 7 | 8 | Data defined properties are not supported for any type of symbology or element. 9 | 10 | Layer transparency is supported, but layer blending is not. 11 | 12 | SVG icons are supported as long as the symbology only uses one version of the icon in terms of color properties. That is, if the symbology uses the SVG plane icon, it is not possible to have a categorized symbology in which one of the categories uses the icon with a red color and another one where it is used with a blue color. This is due to the fact that QGIS support parameters in SVG files, while GeoServer does not. 13 | 14 | Point layers 15 | ============ 16 | 17 | Supported symbology types: Single Symbol, Categorized, Graduated 18 | 19 | Supported symbol layer types: 20 | 21 | # Simple marker: All properties of markers are supported except Angle, Offset and Anchor point. 22 | 23 | All simple marker shapes are supported except pentagon 24 | 25 | # SVG markers. All properties of SVG markers are supported except Angle, Offset and Anchor point. 26 | 27 | Multi-layered symbols can be used, as long as the same SVG icon is not used with different properties in different symbol layers, as described in the General section. 28 | 29 | 30 | 31 | Line layers 32 | ============ 33 | 34 | Supported symbology types: Single Symbol, Categorized, Graduated 35 | 36 | Supported symbol layer types: 37 | 38 | # Simple line: All properties of markers are supported except custom dash pattern 39 | 40 | # Marker line. Supported, but parameters are not used. Only marker definition itself is used. 41 | 42 | Multi-layered symbols can be used, as long as the same SVG icon is not used with different properties in different symbol layers, as described in the General section. 43 | 44 | 45 | Polygon layers 46 | =============== 47 | 48 | Supported symbology types: Single Symbol, Categorized, Graduated 49 | 50 | Supported symbol layer types: 51 | 52 | # Simple fill: All properties are supported 53 | 54 | # Line pattern fill: Only the Distance parameter is supported. The lines that define the pattern must be single-layered and the layer type must be "Simple line" 55 | 56 | # SVGFill: All parameters are supported except Rotation 57 | 58 | Multi-layered symbols can be used, as long as the same SVG icon is not used with different properties in different symbol layers, as described in the General section. 59 | 60 | 61 | Labelling 62 | ============ 63 | 64 | Only parameters in the Text and Placement sections are supported. 65 | 66 | Text section 67 | -------------- 68 | 69 | Supported parameters: Style, Size, Color. Size only supported in points 70 | 71 | Placement section 72 | ------------------ 73 | 74 | Supported parameters: Displacement, Rotation (in "Offset from point" option) 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /docs/source/img/actions/add_catalog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/add_catalog.png -------------------------------------------------------------------------------- /docs/source/img/actions/add_style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/add_style.png -------------------------------------------------------------------------------- /docs/source/img/actions/catalog_added.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/catalog_added.png -------------------------------------------------------------------------------- /docs/source/img/actions/confirm_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/confirm_delete.png -------------------------------------------------------------------------------- /docs/source/img/actions/create_catalog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/create_catalog.png -------------------------------------------------------------------------------- /docs/source/img/actions/create_workspace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/create_workspace.png -------------------------------------------------------------------------------- /docs/source/img/actions/define_group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/define_group.png -------------------------------------------------------------------------------- /docs/source/img/actions/define_gwc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/define_gwc.png -------------------------------------------------------------------------------- /docs/source/img/actions/dragdrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/dragdrop.png -------------------------------------------------------------------------------- /docs/source/img/actions/dragdrop_external.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/dragdrop_external.png -------------------------------------------------------------------------------- /docs/source/img/actions/editsld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/editsld.png -------------------------------------------------------------------------------- /docs/source/img/actions/extent_drag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/extent_drag.png -------------------------------------------------------------------------------- /docs/source/img/actions/new_style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/new_style.png -------------------------------------------------------------------------------- /docs/source/img/actions/order_in_group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/order_in_group.png -------------------------------------------------------------------------------- /docs/source/img/actions/plugin_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/plugin_menu.png -------------------------------------------------------------------------------- /docs/source/img/actions/plugin_repo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/plugin_repo.png -------------------------------------------------------------------------------- /docs/source/img/actions/plugin_repo_added.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/plugin_repo_added.png -------------------------------------------------------------------------------- /docs/source/img/actions/publish_layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/publish_layer.png -------------------------------------------------------------------------------- /docs/source/img/actions/publish_layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/publish_layers.png -------------------------------------------------------------------------------- /docs/source/img/actions/publish_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/publish_project.png -------------------------------------------------------------------------------- /docs/source/img/actions/publish_style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/publish_style.png -------------------------------------------------------------------------------- /docs/source/img/actions/seed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/seed.png -------------------------------------------------------------------------------- /docs/source/img/actions/seed_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/actions/seed_status.png -------------------------------------------------------------------------------- /docs/source/img/intro/about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/intro/about.png -------------------------------------------------------------------------------- /docs/source/img/intro/add_catalog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/intro/add_catalog.png -------------------------------------------------------------------------------- /docs/source/img/intro/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/intro/config.png -------------------------------------------------------------------------------- /docs/source/img/intro/description_panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/intro/description_panel.png -------------------------------------------------------------------------------- /docs/source/img/intro/description_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/intro/description_table.png -------------------------------------------------------------------------------- /docs/source/img/intro/duplicated_layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/intro/duplicated_layer.png -------------------------------------------------------------------------------- /docs/source/img/intro/explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/intro/explorer.png -------------------------------------------------------------------------------- /docs/source/img/intro/gray_catalog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/intro/gray_catalog.png -------------------------------------------------------------------------------- /docs/source/img/intro/tracking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/intro/tracking.png -------------------------------------------------------------------------------- /docs/source/img/intro/undocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/intro/undocked.png -------------------------------------------------------------------------------- /docs/source/img/intro/version_warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/docs/source/img/intro/version_warning.png -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. (c) 2016 Boundless, http://boundlessgeo.com 2 | This code is licensed under the GPL 2.0 license. 3 | 4 | .. _geoserver_explorer_docs: 5 | 6 | GeoServer Explorer Documentation 7 | ================================ 8 | 9 | The GeoServer Explorer plugin is used to configure GeoServer through QGIS. It allows you to easily configure your GeoServer instance, from preparing data and styling to publishing directly to a catalog, all through the QGIS interface. This manual describes how to use the GeoServer Explorer plugin and the operations that it supports . 10 | 11 | .. toctree:: 12 | :glob: 13 | :maxdepth: 2 14 | 15 | installation 16 | intro 17 | actions 18 | settingsconf 19 | -------------------------------------------------------------------------------- /docs/source/installation.rst: -------------------------------------------------------------------------------- 1 | .. (c) 2018 Boundless, http://boundlessgeo.com 2 | This code is licensed under the GPL 2.0 license. 3 | 4 | Installation 5 | ============ 6 | 7 | The **Geoserver Explorer** plugin is available in the QGIS official Plugin Repository. 8 | 9 | To install the plugin: 10 | 11 | #. Open QGIS. 12 | #. Go to :menuselection:`Plugins --> Install and manager plugins`. 13 | #. Select the :guilabel:`All` tab. 14 | #. Type the name of the plugin in the :guilabel:`search` bar to filter list of plugins. 15 | #. Select the plugin from the list. 16 | #. Click :guilabel:`Install plugin`. 17 | 18 | .. For instructions on how to install QGIS plugins, please refer to `QGIS Users manual `_. 19 | -------------------------------------------------------------------------------- /docs/source/settingsconf.rst: -------------------------------------------------------------------------------- 1 | .. _geoserverexplorer_plugin_settings: 2 | 3 | Plugin settings 4 | =============== 5 | 6 | The plugin can be adjusted using the following settings, to be found in its settings dialog (:menuselection:`Web --> GeoServer --> Plugin Settings`). 7 | 8 | General 9 | ------- 10 | 11 | .. list-table:: 12 | :header-rows: 1 13 | :stub-columns: 1 14 | :widths: 20 80 15 | :class: non-responsive 16 | 17 | * - Option 18 | - Description 19 | * - Show description panel 20 | - Show description panel 21 | * - Ask confirmation before deleting 22 | - Ask confirmation before deleting 23 | * - Show toolbar 24 | - Show toolbar 25 | * - Keep a list of previous catalog connections 26 | - Keep a list of previous catalog connections 27 | * - Track layers and publish styles automatically 28 | - Track layers and publish styles automatically when they change 29 | * - Delete style when deleting layer 30 | - Delete style when deleting layer 31 | * - Delete resource when deleting layer 32 | - Delete resource when deleting layer 33 | * - Overwrite layers when uploading group 34 | - Overwrite layers when uploading group 35 | * - AuthCatalog XML cache time in seconds 36 | - AuthCatalog XML cache time in seconds 37 | * - QGIS manage SLD uom correctly 38 | - QGIS manage SLD uom correctly 39 | * - Size scale factor. !Unused if uom is managed! 40 | - Size scale factor. !Unused if uom is managed! 41 | -------------------------------------------------------------------------------- /geoserverexplorer/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | import sys 7 | import os 8 | import site 9 | 10 | site.addsitedir(os.path.abspath(os.path.dirname(__file__) + '/extlibs')) 11 | 12 | # ABP: TORM import gsconfig from here 13 | # sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/ext-src/gsconfig/src')) 14 | #import httplib2 15 | #httplib2.debuglevel = 1 16 | 17 | 18 | from geoserverexplorer.qgis.catalog import * 19 | 20 | def classFactory(iface): 21 | from geoserverexplorer.plugin import GeoServerExplorerPlugin 22 | return GeoServerExplorerPlugin(iface) 23 | -------------------------------------------------------------------------------- /geoserverexplorer/extlibs/geoserver/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/extlibs/geoserver/__init__.py -------------------------------------------------------------------------------- /geoserverexplorer/extlibs/geoserver/layergroup.py: -------------------------------------------------------------------------------- 1 | ''' 2 | gsconfig is a python library for manipulating a GeoServer instance via the GeoServer RESTConfig API. 3 | 4 | The project is distributed under a MIT License . 5 | ''' 6 | 7 | from geoserver.support import ResourceInfo, bbox, write_bbox, write_string, xml_property, build_url 8 | 9 | try: 10 | from past.builtins import basestring 11 | except ImportError: 12 | pass 13 | 14 | 15 | def _maybe_text(n): 16 | if n is None: 17 | return None 18 | else: 19 | return n.text 20 | 21 | 22 | def _layer_list(node, element): 23 | if node is not None: 24 | return [_maybe_text(n.find("name")) for n in node.findall(element)] 25 | 26 | 27 | def _style_list(node): 28 | if node is not None: 29 | return [_maybe_text(n.find("name")) for n in node.findall("style")] 30 | 31 | 32 | def _write_layers(builder, layers, parent, element, attributes): 33 | builder.start(parent, dict()) 34 | for l in layers: 35 | builder.start(element, attributes or dict()) 36 | if l is not None: 37 | builder.start("name", dict()) 38 | builder.data(l) 39 | builder.end("name") 40 | builder.end(element) 41 | builder.end(parent) 42 | 43 | 44 | def _write_styles(builder, styles): 45 | builder.start("styles", dict()) 46 | for s in styles: 47 | builder.start("style", dict()) 48 | if s is not None: 49 | builder.start("name", dict()) 50 | builder.data(s) 51 | builder.end("name") 52 | builder.end("style") 53 | builder.end("styles") 54 | 55 | 56 | class LayerGroup(ResourceInfo): 57 | """ 58 | Represents a layer group in geoserver 59 | """ 60 | 61 | resource_type = "layerGroup" 62 | save_method = "PUT" 63 | 64 | def __init__(self, catalog, name, workspace=None): 65 | super(LayerGroup, self).__init__() 66 | 67 | assert isinstance(name, basestring) 68 | 69 | self.catalog = catalog 70 | self.name = name 71 | self.workspace = workspace 72 | 73 | # the XML format changed in 2.3.x - the element listing all the layers 74 | # and the entries themselves have changed 75 | if self.catalog.gsversion() == "2.2.x": 76 | parent, element, attributes = "layers", "layer", None 77 | else: 78 | parent, element, attributes = "publishables", "published", {'type': 'layer'} 79 | 80 | self._layer_parent = parent 81 | self._layer_element = element 82 | self._layer_attributes = attributes 83 | self.writers = dict( 84 | name = write_string("name"), 85 | styles = _write_styles, 86 | layers = lambda b, l: _write_layers(b, l, parent, element, attributes), 87 | bounds = write_bbox("bounds"), 88 | workspace = write_string("workspace"), 89 | mode = write_string("mode"), 90 | abstractTxt = write_string("abstractTxt"), 91 | title = write_string("title") 92 | ) 93 | 94 | @property 95 | def href(self): 96 | uri = "layergroups/{}.xml".format(self.name) 97 | if self.workspace is not None: 98 | workspace_name = getattr(self.workspace, 'name', self.workspace) 99 | uri = "workspaces/{}/{}".format(workspace_name, uri) 100 | return "{}/{}".format(self.catalog.service_url, uri) 101 | 102 | styles = xml_property("styles", _style_list) 103 | bounds = xml_property("bounds", bbox) 104 | mode = xml_property("mode") 105 | abstract = xml_property("abstractTxt") 106 | title = xml_property("title") 107 | 108 | def _layers_getter(self): 109 | if "layers" in self.dirty: 110 | return self.dirty["layers"] 111 | else: 112 | if self.dom is None: 113 | self.fetch() 114 | node = self.dom.find(self._layer_parent) 115 | return _layer_list(node, self._layer_element) if node is not None else None 116 | 117 | def _layers_setter(self, value): 118 | self.dirty["layers"] = value 119 | 120 | def _layers_delete(self): 121 | self.dirty["layers"] = None 122 | 123 | layers = property(_layers_getter, _layers_setter, _layers_delete) 124 | 125 | def __str__(self): 126 | return "" % self.name 127 | 128 | __repr__ = __str__ 129 | 130 | 131 | class UnsavedLayerGroup(LayerGroup): 132 | save_method = "POST" 133 | 134 | def __init__(self, catalog, name, layers, styles, bounds, mode, abstract, title, workspace = None): 135 | super(UnsavedLayerGroup, self).__init__(catalog, name, workspace=workspace) 136 | bounds = bounds if bounds is not None else ("-180", "180", "-90", "90", "EPSG:4326") 137 | self.dirty.update( 138 | name = name, 139 | layers = layers, 140 | styles = styles, 141 | bounds = bounds, 142 | workspace = workspace, 143 | mode = mode.upper(), 144 | abstractTxt = abstract, 145 | title = title 146 | ) 147 | 148 | @property 149 | def href(self): 150 | query = {'name': self.name} 151 | path_parts = ['layergroups'] 152 | if self.workspace is not None: 153 | workspace_name = getattr(self.workspace, 'name', self.workspace) 154 | path_parts = ["workspaces", workspace_name] + path_parts 155 | return build_url(self.catalog.service_url, path_parts, query) 156 | -------------------------------------------------------------------------------- /geoserverexplorer/extlibs/geoserver/namespace.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/extlibs/geoserver/namespace.py -------------------------------------------------------------------------------- /geoserverexplorer/extlibs/geoserver/style.py: -------------------------------------------------------------------------------- 1 | ''' 2 | gsconfig is a python library for manipulating a GeoServer instance via the GeoServer RESTConfig API. 3 | 4 | The project is distributed under a MIT License . 5 | ''' 6 | 7 | from geoserver.support import ResourceInfo, build_url, xml_property 8 | try: 9 | from past.builtins import basestring 10 | except ImportError: 11 | pass 12 | 13 | 14 | class Style(ResourceInfo): 15 | supported_formats = ["sld10", "sld11", "zip"] 16 | content_types = { 17 | "sld10": "application/vnd.ogc.sld+xml", 18 | "sld11": "application/vnd.ogc.se+xml", 19 | "zip": "application/zip" 20 | } 21 | 22 | def __init__(self, catalog, name, workspace=None, style_format="sld10"): 23 | super(Style, self).__init__() 24 | assert isinstance(name, basestring) 25 | assert style_format in Style.supported_formats 26 | 27 | self.catalog = catalog 28 | self.workspace = workspace 29 | self.name = name 30 | self.style_format = style_format 31 | self._sld_dom = None 32 | 33 | @property 34 | def fqn(self): 35 | return self.name if not self.workspace else '%s:%s' % (self.workspace, self.name) 36 | 37 | @property 38 | def href(self): 39 | return self._build_href('.xml') 40 | 41 | @property 42 | def body_href(self): 43 | return self._build_href('.sld') 44 | 45 | @property 46 | def create_href(self): 47 | return self._build_href('.xml', True) 48 | 49 | @property 50 | def content_type(self): 51 | return Style.content_types[self.style_format] 52 | 53 | def _build_href(self, extension, create=False): 54 | path_parts = ["styles"] 55 | query = {} 56 | if not create: 57 | path_parts.append(self.name + extension) 58 | else: 59 | query['name'] = self.name 60 | if self.workspace is not None: 61 | path_parts = ["workspaces", getattr(self.workspace, 'name', self.workspace)] + path_parts 62 | return build_url(self.catalog.service_url, path_parts, query) 63 | 64 | filename = xml_property("filename") 65 | 66 | def _get_sld_dom(self): 67 | if self._sld_dom is None: 68 | self._sld_dom = self.catalog.get_xml(self.body_href) 69 | return self._sld_dom 70 | 71 | @property 72 | def sld_title(self): 73 | user_style = self._get_sld_dom().find("{http://www.opengis.net/sld}NamedLayer/{http://www.opengis.net/sld}UserStyle") 74 | if not user_style: 75 | user_style = self._get_sld_dom().find("{http://www.opengis.net/sld}UserLayer/{http://www.opengis.net/sld}UserStyle") 76 | 77 | if user_style: 78 | try: 79 | # it is not mandatory 80 | title_node = user_style.find("{http://www.opengis.net/sld}Title") 81 | except: 82 | title_node = None 83 | 84 | return title_node.text if title_node is not None else None 85 | 86 | @property 87 | def sld_name(self): 88 | user_style = self._get_sld_dom().find("{http://www.opengis.net/sld}NamedLayer/{http://www.opengis.net/sld}UserStyle") 89 | if not user_style: 90 | user_style = self._get_sld_dom().find("{http://www.opengis.net/sld}UserLayer/{http://www.opengis.net/sld}UserStyle") 91 | 92 | if user_style: 93 | try: 94 | # it is not mandatory 95 | name_node = user_style.find("{http://www.opengis.net/sld}Name") 96 | except: 97 | name_node = None 98 | 99 | return name_node.text if name_node is not None else None 100 | 101 | @property 102 | def sld_body(self): 103 | resp = self.catalog.http_request(self.body_href) 104 | return resp.content 105 | 106 | def update_body(self, body): 107 | headers = {"Content-Type": self.content_type} 108 | self.catalog.http_request( 109 | self.body_href, body, "PUT", headers) 110 | -------------------------------------------------------------------------------- /geoserverexplorer/extlibs/geoserver/util.py: -------------------------------------------------------------------------------- 1 | ''' 2 | gsconfig is a python library for manipulating a GeoServer instance via the GeoServer RESTConfig API. 3 | 4 | The project is distributed under a MIT License . 5 | ''' 6 | 7 | # shapefile_and_friends = None 8 | # shapefile_plus_sidecars = shapefile_and_friends("test/data/states") 9 | 10 | 11 | def shapefile_and_friends(path): 12 | return dict((ext, path + "." + ext) for ext in ['shx', 'shp', 'dbf', 'prj']) 13 | -------------------------------------------------------------------------------- /geoserverexplorer/extlibs/geoserver/workspace.py: -------------------------------------------------------------------------------- 1 | ''' 2 | gsconfig is a python library for manipulating a GeoServer instance via the GeoServer RESTConfig API. 3 | 4 | The project is distributed under a MIT License . 5 | ''' 6 | 7 | from geoserver.support import xml_property, write_bool, ResourceInfo, build_url 8 | 9 | 10 | def workspace_from_index(catalog, node): 11 | name = node.find("name") 12 | return Workspace(catalog, name.text) 13 | 14 | 15 | class Workspace(ResourceInfo): 16 | 17 | resource_type = "workspace" 18 | 19 | def __init__(self, catalog, name): 20 | super(Workspace, self).__init__() 21 | self.catalog = catalog 22 | self.name = name 23 | 24 | @property 25 | def href(self): 26 | return build_url(self.catalog.service_url, ["workspaces", self.name + ".xml"]) 27 | 28 | @property 29 | def coveragestore_url(self): 30 | return build_url(self.catalog.service_url, ["workspaces", self.name, "coveragestores.xml"]) 31 | 32 | @property 33 | def datastore_url(self): 34 | return build_url(self.catalog.service_url, ["workspaces", self.name, "datastores.xml"]) 35 | 36 | @property 37 | def wmsstore_url(self): 38 | return "%s/workspaces/%s/wmsstores.xml" % (self.catalog.service_url, self.name) 39 | 40 | def __repr__(self): 41 | return "%s @ %s" % (self.name, self.href) 42 | -------------------------------------------------------------------------------- /geoserverexplorer/extlibs/site.py: -------------------------------------------------------------------------------- 1 | def __boot(): 2 | import sys 3 | import os 4 | PYTHONPATH = os.environ.get('PYTHONPATH') 5 | if PYTHONPATH is None or (sys.platform == 'win32' and not PYTHONPATH): 6 | PYTHONPATH = [] 7 | else: 8 | PYTHONPATH = PYTHONPATH.split(os.pathsep) 9 | 10 | pic = getattr(sys, 'path_importer_cache', {}) 11 | stdpath = sys.path[len(PYTHONPATH):] 12 | mydir = os.path.dirname(__file__) 13 | 14 | for item in stdpath: 15 | if item == mydir or not item: 16 | continue # skip if current dir. on Windows, or my own directory 17 | importer = pic.get(item) 18 | if importer is not None: 19 | loader = importer.find_module('site') 20 | if loader is not None: 21 | # This should actually reload the current module 22 | loader.load_module('site') 23 | break 24 | else: 25 | try: 26 | import imp # Avoid import loop in Python 3 27 | stream, path, descr = imp.find_module('site', [item]) 28 | except ImportError: 29 | continue 30 | if stream is None: 31 | continue 32 | try: 33 | # This should actually reload the current module 34 | imp.load_module('site', stream, path, descr) 35 | finally: 36 | stream.close() 37 | break 38 | else: 39 | raise ImportError("Couldn't find the real 'site' module") 40 | 41 | known_paths = dict([(makepath(item)[1], 1) for item in sys.path]) # 2.2 comp 42 | 43 | oldpos = getattr(sys, '__egginsert', 0) # save old insertion position 44 | sys.__egginsert = 0 # and reset the current one 45 | 46 | for item in PYTHONPATH: 47 | addsitedir(item) 48 | 49 | sys.__egginsert += oldpos # restore effective old position 50 | 51 | d, nd = makepath(stdpath[0]) 52 | insert_at = None 53 | new_path = [] 54 | 55 | for item in sys.path: 56 | p, np = makepath(item) 57 | 58 | if np == nd and insert_at is None: 59 | # We've hit the first 'system' path entry, so added entries go here 60 | insert_at = len(new_path) 61 | 62 | if np in known_paths or insert_at is None: 63 | new_path.append(item) 64 | else: 65 | # new path after the insert point, back-insert it 66 | new_path.insert(insert_at, item) 67 | insert_at += 1 68 | 69 | sys.path[:] = new_path 70 | 71 | 72 | if __name__ == 'site': 73 | __boot() 74 | del __boot 75 | -------------------------------------------------------------------------------- /geoserverexplorer/geoserver/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | class GeoserverException(Exception): 7 | def __init__(self, message, details=None): 8 | super().__init__(message) 9 | self.details = details 10 | -------------------------------------------------------------------------------- /geoserverexplorer/geoserver/auth.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | *************************************************************************** 5 | A catalog that uses QgsNetworkAccessManager 6 | --------------------- 7 | Date : August 2016 8 | Copyright : (C) 2016 Boundless, http://boundlessgeo.com 9 | Email : apasotti at boundlessgeo dot com 10 | *************************************************************************** 11 | * * 12 | * This program is free software; you can redistribute it and/or modify * 13 | * it under the terms of the GNU General Public License as published by * 14 | * the Free Software Foundation; either version 2 of the License, or * 15 | * (at your option) any later version. * 16 | * * 17 | *************************************************************************** 18 | """ 19 | 20 | __author__ = 'Alessandro Pasotti' 21 | __date__ = 'August 2016' 22 | 23 | from datetime import timedelta, datetime 24 | from xml.etree.ElementTree import XML 25 | from xml.parsers.expat import ExpatError 26 | from geoserver.catalog import FailedRequestError 27 | from qgiscommons2.network.networkaccessmanager import NetworkAccessManager 28 | from .basecatalog import BaseCatalog 29 | 30 | class AuthCatalog(BaseCatalog): 31 | 32 | def __init__(self, service_url, authid, cache_time): 33 | # Do not call parent constructor, this is a patching class 34 | self.authid = authid 35 | self.cache_time = cache_time 36 | self.service_url = service_url.strip("/") 37 | self._cache = dict() 38 | self._version = None 39 | self.nam = NetworkAccessManager(self.authid, exception_class=FailedRequestError, debug=False) 40 | self.username = '' 41 | self.password = '' 42 | 43 | def http_request(self, url, data=None, method='get', headers = {}): 44 | resp, content = self.nam.request(url, method, data, headers) 45 | return resp 46 | 47 | def setup_connection(self): 48 | pass 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /geoserverexplorer/geoserver/basecatalog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | *************************************************************************** 5 | A GS config catalog with superpowers 6 | --------------------- 7 | Date : August 2016 8 | Copyright : (C) 2016 Boundless, http://boundlessgeo.com 9 | Email : apasotti at boundlessgeo dot com 10 | *************************************************************************** 11 | * * 12 | * This program is free software; you can redistribute it and/or modify * 13 | * it under the terms of the GNU General Public License as published by * 14 | * the Free Software Foundation; either version 2 of the License, or * 15 | * (at your option) any later version. * 16 | * * 17 | *************************************************************************** 18 | """ 19 | from builtins import str 20 | from datetime import datetime, timedelta 21 | 22 | __author__ = 'Alessandro Pasotti' 23 | __date__ = 'August 2016' 24 | 25 | from geoserver.catalog import Catalog, FailedRequestError 26 | from geoserver.support import build_url 27 | from geoserver.layer import Layer 28 | from qgis.gui import * 29 | from qgis.utils import iface 30 | import json 31 | from xml.etree.ElementTree import XML 32 | from xml.parsers.expat import ExpatError 33 | 34 | class BaseLayer(Layer): 35 | """Patched to get correct resources from workspaces""" 36 | 37 | @property 38 | def resource(self): 39 | if self.dom is None: 40 | self.fetch() 41 | name = self.dom.find("resource/name").text 42 | if self.name.find(':') != -1: 43 | return self.catalog.get_resource(name, workspace=self.name.split(':')[0]) 44 | return self.catalog.get_resource(name) 45 | 46 | 47 | class BaseCatalog(Catalog): 48 | 49 | def layersEndpointUrl(self): 50 | return self.service_url[:self.service_url.find("/rest")] 51 | 52 | def _get_res(self, name): 53 | return [r for r in self.get_resources() if r.name == name] 54 | 55 | def get_namespaced_name(self, layer_name): 56 | """ 57 | Prefix the layer name with the workspace by querying all the resources 58 | and finding the workspace from the one that matches the layer name. 59 | If the layer exists in several workspaces, the first match is returned. 60 | Return layer_name if the layer resource does not exists. 61 | """ 62 | if layer_name.find(':') != -1: 63 | return layer_name 64 | res = self._get_res(layer_name) 65 | try: 66 | return "%s:%s" % (res[0].workspace.name, layer_name) 67 | except IndexError: 68 | return layer_name 69 | 70 | 71 | def get_layers(self, resource=None): 72 | """Prefix the layer name with ws name""" 73 | lyrs = super().get_layers(resource) 74 | # Start patch: 75 | layers = {} 76 | result = [] 77 | for l in lyrs: 78 | try: 79 | layers[l.name].append(l) 80 | except KeyError: 81 | layers[l.name] = [l] 82 | # Prefix all names 83 | noAscii = False 84 | for name, ls in list(layers.items()): 85 | try: 86 | if len(ls) == 1: 87 | l = ls[0] 88 | l.name = self.get_namespaced_name(l.name) 89 | result.append(l) 90 | else: 91 | i = 0 92 | res = self._get_res(ls[0].name) 93 | for l in ls: 94 | l.name = "%s:%s" % (res[i].workspace.name, l.name) 95 | i += 1 96 | result.append(l) 97 | except UnicodeDecodeError: 98 | noAscii = True 99 | 100 | if noAscii: 101 | iface.messageBar().pushMessage("Warning", "Some layers contain non-ascii characters and could not be loaded", 102 | level = QgsMessageBar.WARNING, 103 | duration = 10) 104 | return result 105 | 106 | 107 | -------------------------------------------------------------------------------- /geoserverexplorer/geoserver/settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | 7 | from builtins import str 8 | from builtins import object 9 | import httplib2 10 | from xml.etree.ElementTree import XML 11 | import xml.etree.ElementTree as ET 12 | from urllib.parse import urlparse 13 | from geoserver.support import build_url 14 | from geoserverexplorer.geoserver.auth import AuthCatalog 15 | 16 | class Settings(object): 17 | 18 | def __init__(self, catalog): 19 | self.catalog = catalog 20 | 21 | def settings(self): 22 | settings = {} 23 | settings_url = build_url(self.catalog.service_url, ['settings.xml']) 24 | resp = self.catalog.http_request(settings_url, 'GET') 25 | if resp.status_code != 200: 26 | raise Exception('Settings listing failed: ' + resp.text) 27 | dom = XML(resp.text) 28 | sections = ['settings', 'jai','coverageAccess'] 29 | for section in sections: 30 | params = [] 31 | node = dom.find(section) 32 | if node is not None: #it will be none if the catalog does not support this operation 33 | for entry in node: 34 | if len(entry) == 0: 35 | params.append((entry.tag, entry.text)) 36 | else: 37 | for subentry in entry: 38 | params.append((entry.tag + '/' + subentry.tag, subentry.text)) 39 | settings[section] = params 40 | 41 | return settings 42 | 43 | def update(self, settings): 44 | root = ET.Element('global') 45 | for section in settings: 46 | params = settings[section] 47 | element = ET.SubElement(root, section) 48 | for name, value in params: 49 | if '/' in name: 50 | name, subname = name.split('/') 51 | subelement = element.find(name) 52 | if subelement is None: 53 | subelement = ET.SubElement(element, name) 54 | subsubelement = ET.SubElement(subelement, subname) 55 | subsubelement.text = str(value) 56 | else: 57 | subelement = ET.SubElement(element, name) 58 | subelement.text = str(value) 59 | 60 | xml = ET.tostring(root) 61 | settings_url = build_url(self.catalog.service_url, ['settings.xml']) 62 | headers = {'Content-type': 'text/xml'} 63 | resp = self.catalog.http_request(settings_url, xml, 'PUT', headers = headers) 64 | if resp.status_code != 200: 65 | raise Exception('Settings update failed: ' + resp.text) 66 | -------------------------------------------------------------------------------- /geoserverexplorer/geoserver/util.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from zipfile import ZipFile 7 | import tempfile 8 | from os import path 9 | 10 | 11 | def name(named): 12 | """Get the name out of an object. This varies based on the type of the input: 13 | * the "name" of a string is itself 14 | * the "name" of None is itself 15 | * the "name" of an object with a property named name is that property - 16 | as long as it's a string 17 | * otherwise, we raise a ValueError 18 | """ 19 | if isinstance(named, str) or named is None: 20 | return named 21 | elif hasattr(named, 'name'): 22 | if isinstance(named.name, str): 23 | return named.name 24 | elif callable(named.name) and isinstance(named.name(), str): 25 | return named.name() 26 | else: 27 | raise ValueError("Can't interpret %s as a name or a configuration object" % named) 28 | 29 | def getLayerFromStyle(style): 30 | '''Tries to find out which layer is using a given style. 31 | Returns none if cannot find a layer using the style''' 32 | cat = style.catalog 33 | layers = cat.get_layers() 34 | for layer in layers: 35 | if layer.default_style.name == style.name: 36 | return layer 37 | alternateStyles = layer.styles 38 | for alternateStyle in alternateStyles: 39 | if style.name == alternateStyle.name: 40 | return layer 41 | 42 | def groupsWithLayer(catalog, layer): 43 | grps = catalog.get_layergroups() 44 | grpswlyr = [] 45 | for grp in grps: 46 | lyrs = grp.layers 47 | if lyrs is None: 48 | continue 49 | for lyr in lyrs: 50 | if layer.name == lyr: 51 | grpswlyr.append(grp) 52 | break 53 | return grpswlyr 54 | 55 | def removeLayerFromGroups(catalog, layer, groups=None): 56 | grps = groups or catalog.get_layergroups() 57 | for grp in grps: 58 | lyrs = grp.layers 59 | if lyrs is None: 60 | continue 61 | if layer.name not in lyrs: 62 | continue 63 | styles = grp.styles 64 | idx = lyrs.index(layer.name) 65 | del lyrs[idx] 66 | del styles[idx] 67 | grp.dirty.update(layers=lyrs, styles=styles) 68 | catalog.save(grp) 69 | 70 | def addLayerToGroups(catalog, layer, groups, workspace=None): 71 | '''This assumes the layer style with same name as layer already exists, 72 | otherwise None is assigned''' 73 | for grp in groups: 74 | lyrs = grp.layers 75 | styles = grp.styles 76 | lyrs.append(layer.name) 77 | style = catalog.get_styles(layer.name, workspace=workspace)[0] 78 | styles.append(style) 79 | grp.dirty.update(layers=lyrs, styles=styles) 80 | catalog.save(grp) 81 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from qgis.utils import iface 7 | from qgis.core import Qgis, QgsMessageLog 8 | 9 | def setInfo(msg): 10 | iface.messageBar().pushMessage("Info", msg, 11 | level = Qgis.Info, 12 | duration = 10) 13 | 14 | def setWarning(msg): 15 | iface.messageBar().pushMessage("Warning", msg, 16 | level = Qgis.Warning, 17 | duration = 10) 18 | 19 | def setError(msg, trace=None): 20 | iface.messageBar().pushMessage("Geoserver", msg, level=Qgis.Warning, duration=10) 21 | if trace is not None: 22 | QgsMessageLog.logMessage("{}:{}".format(msg, trace), level=Qgis.Critical) 23 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/confirm.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | ''' 7 | Routines to ask for confirmation when performing certain operations 8 | ''' 9 | from builtins import str 10 | from qgis.PyQt.QtGui import * 11 | from qgis.PyQt.QtCore import * 12 | from qgis.PyQt.QtWidgets import * 13 | from geoserverexplorer.gui.dialogs.gsnamedialog import getGSLayerName 14 | from geoserverexplorer.gui.gsnameutils import isNameValid, xmlNameRegex 15 | from qgiscommons2.settings import pluginSetting 16 | 17 | def publishLayer(catalog, layer, workspace=None, overwrite=False): 18 | name = layer.name() 19 | gslayers = [lyr.name for lyr in catalog.catalog.get_layers()] 20 | # TODO: remove when duplicate names on different workspaces are supported 21 | # we shoud check for unique names only on a given workspace 22 | if (name in gslayers and not overwrite) or not isNameValid(name, gslayers, 0, xmlNameRegex()): 23 | name = getGSLayerName(name=name, names=gslayers, unique=False) 24 | catalog.publishLayer(layer, workspace, True, name) 25 | 26 | 27 | def confirmDelete(): 28 | askConfirmation = pluginSetting("ConfirmDelete") 29 | if not askConfirmation: 30 | return True 31 | msg = "You confirm that you want to delete the selected elements?" 32 | reply = QMessageBox.question(None, "Delete confirmation", 33 | msg, QMessageBox.Yes | 34 | QMessageBox.No, QMessageBox.No) 35 | return reply != QMessageBox.No 36 | 37 | # noinspection PyPep8Naming 38 | class DeleteDependentsDialog(QDialog): 39 | 40 | def __init__(self, dependent, parent=None): 41 | super(DeleteDependentsDialog, self).__init__(parent) 42 | self.title = "Confirm Deletion" 43 | self.msg = "The following elements depend on the elements to delete " \ 44 | "and will be deleted as well:" 45 | typeorder = ['LayerGroup', 'Layer', 'GwcLayer', 'Other'] 46 | names = dict() 47 | for dep in dependent: 48 | cls = dep.__class__.__name__ 49 | name = dep.name 50 | title = '' 51 | if hasattr(dep, 'resource'): 52 | if hasattr(dep.resource, 'title'): 53 | if dep.resource.title != name: 54 | title = dep.resource.title 55 | desc = "- {0}:  {1}{2}".format( 56 | cls, 57 | name, 58 | " ({0})".format(title) if title else '' 59 | ) 60 | if cls in names: 61 | names[cls].append(desc) 62 | else: 63 | if cls in typeorder: 64 | names[cls] = [desc] 65 | else: 66 | if 'Other' in names: 67 | names['Other'].append(desc) 68 | else: 69 | names['Other'] = [desc] 70 | 71 | self.deletes = "

".join( 72 | ["

".join(sorted(list(set(names[typ])))) 73 | for typ in typeorder if typ in names]) 74 | self.question = "Do you really want to delete all these elements?" 75 | self.buttonBox = None 76 | self.initGui() 77 | 78 | def initGui(self): 79 | self.setWindowTitle(self.title) 80 | layout = QVBoxLayout() 81 | 82 | msgLabel = QLabel(self.msg) 83 | msgLabel.setWordWrap(True) 84 | layout.addWidget(msgLabel) 85 | 86 | deletesView = QTextEdit() 87 | deletesView.setText(str(self.deletes)) 88 | deletesView.setReadOnly(True) 89 | deletesView.setLineWrapMode(QTextEdit.NoWrap) 90 | layout.addWidget(deletesView) 91 | 92 | questLabel = QLabel(self.question) 93 | questLabel.setWordWrap(True) 94 | questLabel.setAlignment(Qt.AlignHCenter) 95 | layout.addWidget(questLabel) 96 | 97 | self.buttonBox = QDialogButtonBox( 98 | QDialogButtonBox.Ok | QDialogButtonBox.Cancel) 99 | layout.addWidget(self.buttonBox) 100 | 101 | self.setLayout(layout) 102 | # noinspection PyUnresolvedReferences 103 | self.buttonBox.accepted.connect(self.accept) 104 | # noinspection PyUnresolvedReferences 105 | self.buttonBox.rejected.connect(self.reject) 106 | 107 | self.setMinimumWidth(400) 108 | self.setMinimumHeight(400) 109 | self.resize(500, 400) 110 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/contextualhelp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | """ 7 | Contextual help components for use in dialogs, etc. 8 | """ 9 | 10 | import os 11 | from qgis.PyQt.QtGui import * 12 | from qgis.PyQt.QtCore import * 13 | from qgis.PyQt.QtWidgets import * 14 | 15 | # noinspection PyAttributeOutsideInit, PyPep8Naming 16 | class InfoIcon(QLabel): 17 | def __init__(self, tip, parent=None): 18 | QLabel.__init__(self, parent) 19 | self.tiptxt = tip 20 | self.setSizePolicy(QSizePolicy.Fixed, 21 | QSizePolicy.Fixed) 22 | self.setMaximumSize(QSize(16, 16)) 23 | self.setMinimumSize(QSize(16, 16)) 24 | infopx = QPixmap( 25 | os.path.dirname(os.path.dirname(__file__)) + "/images/help.png") 26 | self.setPixmap(infopx) 27 | 28 | self.setMouseTracking(True) 29 | 30 | def mouseMoveEvent(self, event): 31 | # QToolTip.showText(self.mapToGlobal(event.pos()), 32 | # self.tiptxt, self, self.rect()) 33 | QToolTip.showText(self.mapToGlobal(event.pos()), 34 | self.tiptxt, self) 35 | event.ignore() 36 | 37 | 38 | # noinspection PyPep8Naming 39 | def infoIcon(tip, parent=None): 40 | return InfoIcon(tip, parent) 41 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/dialogs/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/dialogs/gsnamedialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | """ 7 | Dialog to create a user-defined name for a GeoServer component, with optional 8 | validation. 9 | """ 10 | 11 | from qgis.PyQt.QtGui import * 12 | from qgis.PyQt.QtCore import * 13 | from qgis.PyQt.QtWidgets import * 14 | 15 | APP = None 16 | if __name__ == '__main__': 17 | import sys 18 | # instantiate QApplication before importing QtGui subclasses 19 | APP = QApplication(sys.argv) 20 | 21 | from geoserverexplorer.gui.gsnameutils import GSNameWidget 22 | from geoserverexplorer.qgis.utils import UserCanceledOperation 23 | from geoserverexplorer.gui.gsnameutils import GSNameWidget, \ 24 | xmlNameFixUp, xmlNameRegex, xmlNameRegexMsg 25 | 26 | 27 | # noinspection PyAttributeOutsideInit, PyPep8Naming 28 | class GSNameDialog(QDialog): 29 | 30 | def __init__(self, boxtitle='', boxmsg='', name='', namemsg='', 31 | nameregex='', nameregexmsg='', names=None, 32 | unique=False, maxlength=0, parent=None): 33 | super(GSNameDialog, self).__init__(parent) 34 | self.boxtitle = boxtitle 35 | self.boxmsg = boxmsg 36 | self.nameBox = GSNameWidget( 37 | name=name, 38 | namemsg=namemsg, 39 | nameregex=nameregex, 40 | nameregexmsg=nameregexmsg, 41 | names=names, 42 | unique=unique, 43 | maxlength=maxlength 44 | ) 45 | self.initGui() 46 | 47 | def initGui(self): 48 | self.setWindowTitle('Define name') 49 | vertlayout = QVBoxLayout() 50 | 51 | self.groupBox = QGroupBox() 52 | self.groupBox.setTitle(self.boxtitle) 53 | self.groupBox.setLayout(vertlayout) 54 | 55 | if self.boxmsg: 56 | self.groupBoxMsg = QLabel(self.boxmsg) 57 | self.groupBoxMsg.setWordWrap(True) 58 | self.groupBox.layout().addWidget(self.groupBoxMsg) 59 | 60 | self.groupBox.layout().addWidget(self.nameBox) 61 | 62 | layout = QVBoxLayout() 63 | layout.addWidget(self.groupBox) 64 | self.buttonBox = QDialogButtonBox( 65 | QDialogButtonBox.Ok | QDialogButtonBox.Cancel) 66 | self.okButton = self.buttonBox.button(QDialogButtonBox.Ok) 67 | self.cancelButton = self.buttonBox.button(QDialogButtonBox.Cancel) 68 | layout.addWidget(self.buttonBox) 69 | 70 | self.setLayout(layout) 71 | 72 | self.nameBox.nameValidityChanged.connect(self.okButton.setEnabled) 73 | self.nameBox.overwritingChanged.connect(self.updateButtons) 74 | 75 | # noinspection PyUnresolvedReferences 76 | self.buttonBox.accepted.connect(self.accept) 77 | # noinspection PyUnresolvedReferences 78 | self.buttonBox.rejected.connect(self.reject) 79 | 80 | self.setMinimumWidth(240) 81 | 82 | # respond to intial validation 83 | self.okButton.setEnabled(self.nameBox.isValid()) 84 | self.updateButtons(self.nameBox.overwritingName()) 85 | 86 | def definedName(self): 87 | return self.nameBox.definedName() 88 | 89 | def overwritingName(self): 90 | return self.nameBox.overwritingName() 91 | 92 | @pyqtSlot(bool) 93 | def updateButtons(self, overwriting): 94 | txt = "Overwrite" if overwriting else "OK" 95 | self.okButton.setText(txt) 96 | self.okButton.setDefault(not overwriting) 97 | self.cancelButton.setDefault(overwriting) 98 | 99 | 100 | class GSXmlNameDialog(GSNameDialog): 101 | 102 | def __init__(self, kind, **kwargs): 103 | unique = kwargs.get('unique', False) 104 | super(GSXmlNameDialog, self).__init__( 105 | boxtitle='GeoServer {0} name'.format(kind), 106 | boxmsg='Define unique {0}'.format(kind) + 107 | ' or overwrite existing' if not unique else '', 108 | name=xmlNameFixUp(kwargs.get('name', '')), 109 | namemsg=kwargs.get('namemsg', ''), 110 | nameregex=kwargs.get('nameregex', xmlNameRegex()), 111 | nameregexmsg=kwargs.get('nameregexmsg', xmlNameRegexMsg()), 112 | names=kwargs.get('names', None), 113 | unique=unique, 114 | maxlength=kwargs.get('maxlength', 0), 115 | parent=kwargs.get('parent', None)) 116 | 117 | 118 | def getGSXmlName(kind, **kwargs): 119 | dlg = GSXmlNameDialog(kind=kind, **kwargs) 120 | QApplication.setOverrideCursor(QCursor(Qt.ArrowCursor)) 121 | res = dlg.exec_() 122 | QApplication.restoreOverrideCursor() 123 | if res: 124 | return dlg.definedName() 125 | else: 126 | raise UserCanceledOperation() 127 | 128 | 129 | def getGSLayerName(**kwargs): 130 | return getGSXmlName('layer', **kwargs) 131 | 132 | 133 | def getGSStoreName(**kwargs): 134 | return getGSXmlName('data store', **kwargs) 135 | 136 | 137 | if __name__ == '__main__': 138 | from geoserverexplorer.gui.gsnameutils import \ 139 | xmlNameFixUp, xmlNameRegex, xmlNameRegexMsg 140 | gdlg = GSNameDialog( 141 | boxtitle='GeoServer data store name', 142 | boxmsg='My groupbox message', 143 | namemsg='Sample is generated from PostgreSQL connection name.', 144 | # name=xmlNameFixUp('My PG connection'), 145 | name='name_one', 146 | nameregex=xmlNameRegex(), 147 | nameregexmsg=xmlNameRegexMsg(), 148 | names=['name_one', 'name_two'], 149 | unique=False, 150 | maxlength=10) 151 | gdlg.exec_() 152 | # fix_print_with_import 153 | print(gdlg.definedName()) 154 | # fix_print_with_import 155 | print(gdlg.overwritingName()) 156 | # and with no kwargs 157 | gdlg = GSNameDialog() 158 | gdlg.exec_() 159 | # fix_print_with_import 160 | print(gdlg.definedName()) 161 | # fix_print_with_import 162 | print(gdlg.overwritingName()) 163 | # gdlg.show() 164 | # gdlg.raise_() 165 | # gdlg.activateWindow() 166 | # sys.exit(APP.exec_()) 167 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/dialogs/projectdialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from qgis.PyQt.QtGui import * 7 | from qgis.PyQt.QtWidgets import * 8 | 9 | class PublishProjectDialog(QDialog): 10 | 11 | def __init__(self, catalog, parent = None): 12 | super(PublishProjectDialog, self).__init__(parent) 13 | self.catalog = catalog 14 | self.workspace = None 15 | self.ok = False 16 | self.initGui() 17 | 18 | 19 | def initGui(self): 20 | 21 | layout = QVBoxLayout() 22 | self.setWindowTitle('Publish project') 23 | 24 | verticalLayout = QVBoxLayout() 25 | horizontalLayout = QHBoxLayout() 26 | horizontalLayout.setSpacing(30) 27 | horizontalLayout.setMargin(0) 28 | workspaceLabel = QLabel('Workspace') 29 | self.workspaceBox = QComboBox() 30 | self.workspaces = self.catalog.get_workspaces() 31 | try: 32 | defaultWorkspace = self.catalog.get_default_workspace() 33 | defaultWorkspace.fetch() 34 | defaultName = defaultWorkspace.dom.find('name').text 35 | except: 36 | defaultName = None 37 | workspaceNames = [w.name for w in self.workspaces] 38 | self.workspaceBox.addItems(workspaceNames) 39 | if defaultName is not None: 40 | self.workspaceBox.setCurrentIndex(workspaceNames.index(defaultName)) 41 | horizontalLayout.addWidget(workspaceLabel) 42 | horizontalLayout.addWidget(self.workspaceBox) 43 | verticalLayout.addLayout(horizontalLayout) 44 | 45 | self.destGroupBox = QGroupBox() 46 | self.destGroupBox.setLayout(verticalLayout) 47 | 48 | verticalLayout = QVBoxLayout() 49 | 50 | horizontalLayout = QHBoxLayout() 51 | horizontalLayout.setSpacing(30) 52 | horizontalLayout.setMargin(0) 53 | groupLabel = QLabel('Global group name') 54 | self.groupNameBox = QLineEdit() 55 | self.groupNameBox.setPlaceholderText("[leave empty if no global group should be created]") 56 | horizontalLayout.addWidget(groupLabel) 57 | horizontalLayout.addWidget(self.groupNameBox) 58 | verticalLayout.addLayout(horizontalLayout) 59 | 60 | self.groupGroupBox = QGroupBox() 61 | self.groupGroupBox.setLayout(verticalLayout) 62 | 63 | layout.addWidget(self.destGroupBox) 64 | layout.addWidget(self.groupGroupBox) 65 | 66 | self.overwriteBox = QCheckBox() 67 | self.overwriteBox.setChecked(False) 68 | self.overwriteBox.setText("Overwrite without asking") 69 | layout.addWidget(self.overwriteBox) 70 | 71 | self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Close) 72 | layout.addWidget(self.buttonBox) 73 | 74 | self.setLayout(layout) 75 | 76 | self.buttonBox.accepted.connect(self.okPressed) 77 | self.buttonBox.rejected.connect(self.cancelPressed) 78 | 79 | self.resize(400,200) 80 | 81 | 82 | def okPressed(self): 83 | self.workspace = self.workspaces[self.workspaceBox.currentIndex()] 84 | self.overwrite = self.overwriteBox.isChecked() 85 | self.groupName = self.groupNameBox.text() 86 | if self.groupName.strip() == "": 87 | self.groupName = None 88 | self.ok = True 89 | self.close() 90 | 91 | def cancelPressed(self): 92 | self.ok = False 93 | self.workspace = None 94 | self.close() 95 | 96 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/dialogs/resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | ../../images/minus.png 4 | ../../images/plus.png 5 | 6 | 7 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/dialogs/sldeditor.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from qgis.PyQt.Qsci import QsciScintilla 7 | from qgis.PyQt.QtGui import * 8 | from qgis.PyQt.QtCore import * 9 | from qgis.PyQt.QtWidgets import * 10 | import xml.dom.minidom 11 | 12 | 13 | class SldEditorDialog(QDialog): 14 | 15 | def __init__(self, style, explorer, parent = None): 16 | super(SldEditorDialog, self).__init__(parent) 17 | 18 | self.style = style 19 | self.explorer = explorer 20 | self.initGui() 21 | 22 | def initGui(self): 23 | self.resize(600, 350) 24 | self.setWindowFlags(self.windowFlags() | Qt.WindowSystemMenuHint | 25 | Qt.WindowMinMaxButtonsHint) 26 | self.setWindowTitle('Edit SLD style') 27 | 28 | layout = QVBoxLayout() 29 | buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) 30 | sld = "\n".join([line for line in 31 | xml.dom.minidom.parseString(self.style.sld_body).toprettyxml().splitlines() if line.strip()]) 32 | self.editor = SldEditorWidget(sld) 33 | layout.addWidget(self.editor) 34 | layout.addWidget(buttonBox) 35 | self.setLayout(layout) 36 | 37 | buttonBox.accepted.connect(self.okPressed) 38 | buttonBox.rejected.connect(self.cancelPressed) 39 | 40 | def okPressed(self): 41 | self.explorer.run(self.style.update_body, "Update SLD body", [], self.editor.text()) 42 | self.close() 43 | 44 | def cancelPressed(self): 45 | self.close() 46 | 47 | 48 | 49 | class SldEditorWidget(QsciScintilla): 50 | ARROW_MARKER_NUM = 8 51 | 52 | def __init__(self, text, parent=None): 53 | super(SldEditorWidget, self).__init__(parent) 54 | 55 | font = QFont() 56 | font.setFamily('Courier') 57 | font.setFixedPitch(True) 58 | font.setPointSize(10) 59 | self.setFont(font) 60 | self.setMarginsFont(font) 61 | 62 | fontmetrics = QFontMetrics(font) 63 | self.setMarginsFont(font) 64 | self.setMarginWidth(0, fontmetrics.width("00000") + 6) 65 | self.setMarginLineNumbers(0, True) 66 | self.setMarginsBackgroundColor(QColor("#cccccc")) 67 | 68 | self.setBraceMatching(QsciScintilla.SloppyBraceMatch) 69 | 70 | self.setCaretLineVisible(True) 71 | self.setCaretLineBackgroundColor(QColor("#ffe4e4")) 72 | 73 | #lexer = QsciLexerXML() 74 | #lexer.setDefaultFont(font) 75 | #self.setLexer(lexer) 76 | self.SendScintilla(QsciScintilla.SCI_STYLESETFONT, 1, 'Courier'.encode()) 77 | 78 | self.setText(text) 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/dialogs/workspacedialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from builtins import str 7 | from qgis.PyQt.QtGui import * 8 | from qgis.PyQt.QtWidgets import * 9 | 10 | APP = None 11 | if __name__ == '__main__': 12 | import sys 13 | # instantiate QApplication before importing QtGui subclasses 14 | APP = QApplication(sys.argv) 15 | 16 | from geoserverexplorer.gui.gsnameutils import GSNameWidget, xmlNameRegexMsg, xmlNameRegex 17 | 18 | 19 | class DefineWorkspaceDialog(QDialog): 20 | 21 | def __init__(self, workspaces=None, parent=None): 22 | super(DefineWorkspaceDialog, self).__init__(parent) 23 | self.workspaces = workspaces if workspaces is not None else [] 24 | self.uri = None 25 | self.name = None 26 | self.initGui() 27 | 28 | 29 | def initGui(self): 30 | self.setWindowTitle('New workspace') 31 | verticalLayout = QVBoxLayout() 32 | 33 | horizontalLayout = QHBoxLayout() 34 | horizontalLayout.setSpacing(30) 35 | horizontalLayout.setMargin(0) 36 | nameLabel = QLabel('Workspace name') 37 | nameLabel.setMinimumWidth(150) 38 | self.nameBox = GSNameWidget( 39 | namemsg='', 40 | name='workspace', 41 | nameregex=xmlNameRegex(), 42 | nameregexmsg=xmlNameRegexMsg(), 43 | names=self.workspaces, 44 | unique=True, 45 | maxlength=10) 46 | self.nameBox.setMinimumWidth(250) 47 | horizontalLayout.addWidget(nameLabel) 48 | horizontalLayout.addWidget(self.nameBox) 49 | verticalLayout.addLayout(horizontalLayout) 50 | 51 | horizontalLayout = QHBoxLayout() 52 | horizontalLayout.setSpacing(30) 53 | horizontalLayout.setMargin(0) 54 | uriLabel = QLabel('URI') 55 | uriLabel.setMinimumWidth(150) 56 | self.uriBox = QLineEdit() 57 | self.uriBox.setText('') 58 | self.uriBox.setPlaceholderText('Required') 59 | self.uriBox.setMinimumWidth(250) 60 | horizontalLayout.addWidget(uriLabel) 61 | horizontalLayout.addWidget(self.uriBox) 62 | verticalLayout.addLayout(horizontalLayout) 63 | 64 | self.groupBox = QGroupBox() 65 | self.groupBox.setLayout(verticalLayout) 66 | 67 | layout = QVBoxLayout() 68 | layout.addWidget(self.groupBox) 69 | self.spacer = QSpacerItem(20,20, QSizePolicy.Minimum, QSizePolicy.Expanding) 70 | layout.addItem(self.spacer) 71 | 72 | self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) 73 | self.okButton = self.buttonBox.button(QDialogButtonBox.Ok) 74 | layout.addWidget(self.buttonBox) 75 | self.setLayout(layout) 76 | 77 | self.buttonBox.accepted.connect(self.okPressed) 78 | self.buttonBox.rejected.connect(self.cancelPressed) 79 | 80 | self.nameBox.nameValidityChanged.connect(self.updateOkButton) 81 | self.uriBox.textChanged.connect(self.updateOkButton) 82 | self.updateOkButton() 83 | 84 | def getWorkspace(self): 85 | return self.workspace 86 | 87 | def updateOkButton(self): 88 | ok = self.nameBox.isValid() and self.uriBox.text() != '' 89 | self.okButton.setEnabled(ok) 90 | 91 | def okPressed(self): 92 | self.uri = str(self.uriBox.text()) 93 | self.name = str(self.nameBox.definedName()) 94 | self.close() 95 | 96 | def cancelPressed(self): 97 | self.uri = None 98 | self.name = None 99 | self.close() 100 | 101 | if __name__ == '__main__': 102 | wsdlg = DefineWorkspaceDialog(workspaces=['ws_one', 'ws_two']) 103 | wsdlg.exec_() 104 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/explorer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from builtins import str 7 | import os 8 | from qgis.PyQt.QtGui import * 9 | from qgis.PyQt.QtCore import * 10 | from qgis.PyQt.QtWidgets import * 11 | import sip 12 | from qgis.core import * 13 | from qgis.gui import * 14 | from qgis.utils import iface 15 | from geoserverexplorer.geoserver import GeoserverException 16 | from geoserverexplorer.gui.exploreritems import * 17 | import traceback 18 | from geoserverexplorer.gui.explorertree import ExplorerTreeWidget 19 | from geoserverexplorer.qgis.utils import UserCanceledOperation 20 | from qgiscommons2.settings import pluginSetting 21 | from geoserver.catalog import FailedRequestError 22 | from geoserverexplorer.gui import setInfo, setWarning, setError 23 | 24 | class GeoServerExplorer(QDockWidget): 25 | 26 | def __init__(self, parent = None): 27 | super(GeoServerExplorer, self).__init__(parent) 28 | self.setObjectName('GeoServerExplorer') 29 | self.initGui() 30 | 31 | def initGui(self): 32 | self.progressMaximum = 0 33 | self.isProgressVisible = False 34 | self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) 35 | self.dockWidgetContents = QWidget() 36 | self.setWindowTitle('GeoServer Explorer') 37 | self.splitter = QSplitter() 38 | self.splitter.setOrientation(Qt.Vertical) 39 | self.subwidget = QWidget() 40 | self.explorerTree = self.tree = ExplorerTreeWidget(self) 41 | showToolbar = pluginSetting("ShowToolbar") 42 | self.toolbar = QToolBar() 43 | self.toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly) 44 | self.toolbar.setVisible(showToolbar) 45 | self.setToolbarActions([]) 46 | self.splitter.addWidget(self.explorerTree) 47 | self.log = QTextEdit() 48 | self.description = QWidget() 49 | self.descriptionLayout = QVBoxLayout() 50 | self.descriptionLayout.setSpacing(2) 51 | self.descriptionLayout.setMargin(0) 52 | self.description.setLayout(self.descriptionLayout) 53 | self.splitter.addWidget(self.description) 54 | self.setDescriptionWidget() 55 | showDescription = pluginSetting("ShowDescription") 56 | self.description.setVisible(showDescription) 57 | self.progress = None 58 | self.layout = QVBoxLayout() 59 | self.layout.setSpacing(2) 60 | self.layout.setMargin(0) 61 | self.layout.addWidget(self.toolbar) 62 | self.layout.addWidget(self.splitter) 63 | self.dockWidgetContents.setLayout(self.layout) 64 | self.setWidget(self.dockWidgetContents) 65 | 66 | self.topLevelChanged.connect(self.dockStateChanged) 67 | 68 | def dockStateChanged(self, floating): 69 | if floating: 70 | self.resize(800, 450) 71 | self.splitter.setOrientation(Qt.Horizontal) 72 | else: 73 | self.splitter.setOrientation(Qt.Vertical) 74 | 75 | def setToolbarActions(self, actions): 76 | self.toolbar.clear() 77 | for action in actions: 78 | if action.icon().isNull(): 79 | icon = QIcon(os.path.dirname(__file__) + "/../images/process.png") 80 | action.setIcon(icon) 81 | 82 | for action in actions: 83 | button = QPushButton() 84 | button.setIcon(action.icon()) 85 | button.setToolTip(action.text()) 86 | button.setEnabled(action.isEnabled()) 87 | button.clicked.connect(action.trigger) 88 | self.toolbar.addWidget(button) 89 | 90 | self.toolbar.update() 91 | 92 | def refreshContent(self): 93 | showDescription = pluginSetting("ShowDescription") 94 | self.description.setVisible(showDescription) 95 | showToolbar = pluginSetting("ShowToolbar") 96 | self.toolbar.setVisible(showToolbar) 97 | self.refreshDescription() 98 | 99 | def catalogs(self): 100 | if self.explorerTree is None: 101 | return {} 102 | return self.explorerTree.gsItem._catalogs 103 | 104 | def run(self, command, msg, refresh, *params): 105 | noerror = True 106 | QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) 107 | try: 108 | command(*params) 109 | for item in refresh: 110 | if item is not None: 111 | item.refreshContent(self) 112 | if None in refresh: 113 | self.refreshContent() 114 | if msg is not None and not self.isProgressVisible: 115 | setInfo("Operation " + msg + " correctly executed") 116 | except UserCanceledOperation: 117 | pass 118 | except Exception as e: 119 | if isinstance(e, FailedRequestError): 120 | setError("Error connecting to server (See log for more details)", traceback.format_exc()) 121 | elif isinstance(e, GeoserverException): 122 | setError(str(e), e.details) 123 | else: 124 | setError(str(e) + " (See log for more details)", traceback.format_exc()) 125 | noerror = False 126 | finally: 127 | QApplication.restoreOverrideCursor() 128 | self.refreshDescription() 129 | 130 | return noerror 131 | 132 | def resetActivity(self): 133 | if self.progress is not None: 134 | iface.messageBar().clearWidgets() 135 | self.isProgressVisible = False 136 | self.progress = None 137 | self.progressMaximum = 0 138 | 139 | def setProgress(self, value): 140 | if self.progress is not None and not sip.isdeleted(self.progress): 141 | self.progress.setValue(value) 142 | 143 | def setProgressMaximum(self, value, msg = ""): 144 | self.progressMaximum = value 145 | self.isProgressVisible = True 146 | self.progressMessageBar = iface.messageBar().createMessage(msg) 147 | self.progress = QProgressBar() 148 | self.progress.setMaximum(self.progressMaximum) 149 | self.progress.setAlignment(Qt.AlignLeft|Qt.AlignVCenter) 150 | self.progressMessageBar.layout().addWidget(self.progress) 151 | iface.messageBar().pushWidget(self.progressMessageBar, Qgis.Info) 152 | 153 | def setDescriptionWidget(self, widget = None): 154 | item = self.descriptionLayout.itemAt(0) 155 | if item: 156 | self.descriptionLayout.removeItem(item) 157 | item.widget().close() 158 | if widget is None: 159 | widget = QTextBrowser() 160 | widget.setHtml(u'

Select an item above for contextual description

    ') 161 | 162 | self.descriptionLayout.addWidget(widget) 163 | 164 | def refreshDescription(self): 165 | item = self.explorerTree.lastClickedItem() 166 | if item is not None: 167 | try: 168 | self.explorerTree.treeItemClicked(item, 0) 169 | except: 170 | self.setDescriptionWidget(None) 171 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/exploreritems.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from geoserverexplorer.geoserver import util 7 | from qgis.PyQt import QtGui, QtCore, QtWidgets 8 | 9 | class TreeItem(QtWidgets.QTreeWidgetItem): 10 | def __init__(self, element, icon = None, text = None): 11 | QtWidgets.QTreeWidgetItem.__init__(self) 12 | self.element = element 13 | self.setData(0, QtCore.Qt.UserRole, element) 14 | self._text = text 15 | text = text if text is not None else util.name(element) 16 | self.setText(0, text) 17 | if icon is not None: 18 | self.setIcon(0, icon) 19 | self.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) 20 | 21 | def refresh(self): 22 | text = self._text if self._text is not None else util.name(self.element) 23 | self.setText(0, text) 24 | 25 | def refreshContent(self, explorer): 26 | self.takeChildren() 27 | self.refresh() 28 | if hasattr(self, 'populate'): 29 | explorer.run(self.populate, None, []) 30 | 31 | def descriptionWidget(self, tree, explorer): 32 | text = self.getDescriptionHtml(tree, explorer) 33 | class MyBrowser(QtWidgets.QTextBrowser): 34 | def loadResource(self, type, name): 35 | return None 36 | self.description = MyBrowser() 37 | self.description.setOpenLinks(False) 38 | def linkClicked(url): 39 | self.linkClicked(tree, explorer, url) 40 | self.description.anchorClicked.connect(linkClicked) 41 | self.description.setHtml(text) 42 | return self.description 43 | 44 | def getDescriptionHtml(self, tree, explorer): 45 | typesok, html = self._checkAllSelectionTypes(self, tree) 46 | if typesok: 47 | html += self._getDescriptionHtml(tree, explorer) 48 | txt = self.text(0) 49 | items = tree.selectedItems() 50 | if len(items) > 1: 51 | txt = "Multiple Selection" 52 | img = "" 53 | if hasattr(self, "iconPath"): 54 | img = '' 55 | header = u'

      ' + img + " " + txt + '

    ' 56 | html = u""" 57 | 58 | 59 | 60 | 73 | 74 | 75 | %s %s
    76 | 77 | 78 | """ % (header, html) 79 | return html 80 | 81 | def _getDescriptionHtml(self, tree, explorer): 82 | html = "" 83 | typesok, typesmsg = self._checkAllSelectionTypes(self, tree) 84 | if not typesok: 85 | return typesmsg 86 | else: 87 | html += typesmsg 88 | actions = self.contextMenuActions(tree, explorer) 89 | items = tree.selectedItems() 90 | if len(items) > 1: 91 | actions = self.multipleSelectionContextMenuActions( 92 | tree, explorer, items) 93 | actsenabled = [act for act in actions if act.isEnabled()] 94 | if actsenabled: 95 | html += "

    Available actions

    ' 99 | return html 100 | 101 | def linkClicked(self, tree, explorer, url): 102 | actionName = url.toString() 103 | actions = self.contextMenuActions(tree, explorer) 104 | items = tree.selectedItems() 105 | if len(items) > 1: 106 | actions = self.multipleSelectionContextMenuActions( 107 | tree, explorer, items) 108 | for action in actions: 109 | if action.text() == actionName: 110 | action.trigger() 111 | return 112 | 113 | def _checkAllSelectionTypes(self, item, tree): 114 | allTypes, allParentTypes = tree.getSelectionTypes() 115 | if (allTypes and len(allTypes) != 1) or (allParentTypes and len(allParentTypes) != 1): 116 | return False, "Incompatible item types" 117 | items = tree.selectedItems() 118 | if len(items) > 1 and tree.currentItem() in items: 119 | return True, "

    Current item: {0}

    ".format(item.text(0)) 120 | return True, "" 121 | 122 | def contextMenuActions(self, tree, explorer): 123 | return [] 124 | 125 | def multipleSelectionContextMenuActions(self, tree, explorer, selected): 126 | return [] 127 | 128 | def acceptDroppedItem(self, tree, explorer, item): 129 | return [] 130 | 131 | def acceptDroppedItems(self, tree, explorer, items): 132 | if len(items) > 1: 133 | explorer.setProgressMaximum(len(items)) 134 | toUpdate = [] 135 | try: 136 | for i, item in enumerate(items): 137 | toUpdate.extend(self.acceptDroppedItem(tree, explorer, item)) 138 | explorer.setProgress(i + 1) 139 | finally: 140 | explorer.resetActivity() 141 | return toUpdate 142 | 143 | def acceptDroppedUris(self, tree, explorer, uris): 144 | return [] 145 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/extentpanel.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from builtins import str 7 | from geoserverexplorer.gui.rectangletool import RectangleMapTool 8 | from qgis.core import * 9 | from qgis.utils import iface 10 | from qgis.PyQt.QtGui import * 11 | from qgis.PyQt.QtWidgets import * 12 | 13 | class ExtentSelectionPanel(QWidget): 14 | 15 | def __init__(self, dialog): 16 | super(ExtentSelectionPanel, self).__init__(None) 17 | self.dialog = dialog 18 | self.horizontalLayout = QHBoxLayout(self) 19 | self.horizontalLayout.setSpacing(2) 20 | self.horizontalLayout.setMargin(0) 21 | self.text = QLineEdit() 22 | if hasattr(self.text, 'setPlaceholderText'): 23 | self.text.setPlaceholderText("[xmin,xmax,ymin,ymax] Leave blank to use full extent") 24 | self.horizontalLayout.addWidget(self.text) 25 | self.pushButton = QPushButton() 26 | self.pushButton.setText("Define in canvas") 27 | self.pushButton.clicked.connect(self.selectOnCanvas) 28 | self.horizontalLayout.addWidget(self.pushButton) 29 | self.setLayout(self.horizontalLayout) 30 | canvas = iface.mapCanvas() 31 | self.prevMapTool = canvas.mapTool() 32 | self.tool = RectangleMapTool(canvas) 33 | self.tool.rectangleCreated.connect(self.fillCoords) 34 | 35 | def selectOnCanvas(self): 36 | canvas = iface.mapCanvas() 37 | canvas.setMapTool(self.tool) 38 | self.dialog.showMinimized() 39 | 40 | def fillCoords(self): 41 | r = self.tool.rectangle() 42 | self.setValueFromRect(r) 43 | 44 | def setValueFromRect(self,r): 45 | s = str(r.xMinimum()) + "," + str(r.xMaximum()) + "," + str(r.yMinimum()) + "," + str(r.yMaximum()) 46 | self.text.setText(s) 47 | self.tool.reset() 48 | canvas = iface.mapCanvas() 49 | canvas.setMapTool(self.prevMapTool) 50 | self.dialog.showNormal() 51 | self.dialog.raise_() 52 | self.dialog.activateWindow() 53 | 54 | def getValue(self): 55 | text = self.text.text().strip() 56 | if text == "": 57 | return None 58 | else: 59 | return text.split(",") 60 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/parametereditor.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from builtins import range 7 | from qgis.PyQt import QtCore, QtGui, QtWidgets 8 | 9 | class ParameterEditor(QtWidgets.QWidget): 10 | def __init__(self, settings, explorer): 11 | self.explorer = explorer 12 | self.settings = settings 13 | self.parameters = settings.settings() 14 | QtWidgets.QWidget.__init__(self) 15 | self.setupUi() 16 | 17 | def setupUi(self): 18 | layout = QtWidgets.QVBoxLayout() 19 | layout.setSpacing(2) 20 | layout.setMargin(0) 21 | self.tree = QtWidgets.QTreeWidget() 22 | self.tree.setAlternatingRowColors(True) 23 | self.tree.headerItem().setText(0, "Setting") 24 | self.tree.headerItem().setText(1, "Value") 25 | self.tree.setColumnWidth(0, 150) 26 | layout.addWidget(self.tree) 27 | for section in self.parameters: 28 | params = self.parameters[section] 29 | paramsItem = QtWidgets.QTreeWidgetItem() 30 | paramsItem.setText(0, section) 31 | for name, value in params: 32 | item = QtWidgets.QTreeWidgetItem() 33 | item.setText(0, name) 34 | item.setText(1, value) 35 | item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable) 36 | paramsItem.addChild(item) 37 | self.tree.addTopLevelItem(paramsItem) 38 | button = QtWidgets.QPushButton() 39 | button.setText("Save") 40 | button.clicked.connect(self.saveSettings) 41 | buttonBox = QtWidgets.QDialogButtonBox() 42 | buttonBox.setOrientation(QtCore.Qt.Horizontal) 43 | buttonBox.addButton(button, QtWidgets.QDialogButtonBox.ActionRole) 44 | layout.addWidget(buttonBox) 45 | self.setLayout(layout) 46 | 47 | 48 | def saveSettings(self): 49 | parameters = {} 50 | for i in range(self.tree.invisibleRootItem().childCount()): 51 | sectionItem = self.tree.invisibleRootItem().child(i) 52 | sectionParameters = [] 53 | for j in range(sectionItem.childCount()): 54 | parameterItem = sectionItem.child(j) 55 | sectionParameters.append((parameterItem.text(0), parameterItem.text(1))) 56 | parameters[sectionItem.text(0)] = sectionParameters 57 | self.explorer.run(self.settings.update, "Update settings", [], parameters) 58 | 59 | 60 | -------------------------------------------------------------------------------- /geoserverexplorer/gui/rectangletool.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from qgis.core import * 7 | from qgis.gui import * 8 | from qgis.PyQt import QtCore 9 | 10 | class RectangleMapTool(QgsMapToolEmitPoint): 11 | 12 | rectangleCreated = QtCore.pyqtSignal() 13 | 14 | def __init__(self, canvas): 15 | self.canvas = canvas 16 | QgsMapToolEmitPoint.__init__(self, self.canvas) 17 | 18 | self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) 19 | self.rubberBand.setColor(QtCore.Qt.red ) 20 | self.rubberBand.setWidth( 1 ) 21 | 22 | self.reset() 23 | 24 | def reset(self): 25 | self.startPoint = self.endPoint = None 26 | self.isEmittingPoint = False 27 | self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) 28 | 29 | def canvasPressEvent(self, e): 30 | self.startPoint = self.toMapCoordinates( e.pos() ) 31 | self.endPoint = self.startPoint 32 | self.isEmittingPoint = True 33 | 34 | self.showRect(self.startPoint, self.endPoint) 35 | 36 | def canvasReleaseEvent(self, e): 37 | self.isEmittingPoint = False 38 | if self.rectangle() != None: 39 | self.rectangleCreated.emit() 40 | 41 | def canvasMoveEvent(self, e): 42 | if not self.isEmittingPoint: 43 | return 44 | 45 | self.endPoint = self.toMapCoordinates( e.pos() ) 46 | self.showRect(self.startPoint, self.endPoint) 47 | 48 | def showRect(self, startPoint, endPoint): 49 | self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) 50 | if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y(): 51 | return 52 | 53 | point1 = QgsPointXY(startPoint.x(), startPoint.y()) 54 | point2 = QgsPointXY(startPoint.x(), endPoint.y()) 55 | point3 = QgsPointXY(endPoint.x(), endPoint.y()) 56 | point4 = QgsPointXY(endPoint.x(), startPoint.y()) 57 | 58 | self.rubberBand.addPoint( point1, False ) 59 | self.rubberBand.addPoint( point2, False ) 60 | self.rubberBand.addPoint( point3, False ) 61 | self.rubberBand.addPoint( point4, True ) # true to update canvas 62 | self.rubberBand.show() 63 | 64 | def rectangle(self): 65 | if self.startPoint == None or self.endPoint == None: 66 | return None 67 | elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y() == self.endPoint.y(): 68 | return None 69 | 70 | return QgsRectangle(self.startPoint, self.endPoint) 71 | 72 | def setRectangle(self, rect): 73 | if rect == self.rectangle(): 74 | return False 75 | 76 | if rect == None: 77 | self.reset() 78 | else: 79 | self.startPoint = QgsPointXY(rect.xMaximum(), rect.yMaximum()) 80 | self.endPoint = QgsPointXY(rect.xMinimum(), rect.yMinimum()) 81 | self.showRect(self.startPoint, self.endPoint) 82 | return True 83 | 84 | def deactivate(self): 85 | QgsMapTool.deactivate(self) 86 | self.deactivated.emit() 87 | -------------------------------------------------------------------------------- /geoserverexplorer/images/add-page-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/add-page-blue.png -------------------------------------------------------------------------------- /geoserverexplorer/images/add-style-to-layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/add-style-to-layer.png -------------------------------------------------------------------------------- /geoserverexplorer/images/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/add.png -------------------------------------------------------------------------------- /geoserverexplorer/images/bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/bottom.png -------------------------------------------------------------------------------- /geoserverexplorer/images/browser.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/browser.gif -------------------------------------------------------------------------------- /geoserverexplorer/images/browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/browser.png -------------------------------------------------------------------------------- /geoserverexplorer/images/clean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/clean.png -------------------------------------------------------------------------------- /geoserverexplorer/images/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/config.png -------------------------------------------------------------------------------- /geoserverexplorer/images/create-store-from-layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/create-store-from-layer.png -------------------------------------------------------------------------------- /geoserverexplorer/images/default-style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/default-style.png -------------------------------------------------------------------------------- /geoserverexplorer/images/default-workspace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/default-workspace.png -------------------------------------------------------------------------------- /geoserverexplorer/images/delete.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/delete.gif -------------------------------------------------------------------------------- /geoserverexplorer/images/desktop.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /geoserverexplorer/images/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/down.png -------------------------------------------------------------------------------- /geoserverexplorer/images/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/edit.png -------------------------------------------------------------------------------- /geoserverexplorer/images/edit_sld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/edit_sld.png -------------------------------------------------------------------------------- /geoserverexplorer/images/geonode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/geonode.png -------------------------------------------------------------------------------- /geoserverexplorer/images/geoserver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/geoserver.png -------------------------------------------------------------------------------- /geoserverexplorer/images/geoserver_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/geoserver_gray.png -------------------------------------------------------------------------------- /geoserverexplorer/images/grid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/grid.jpg -------------------------------------------------------------------------------- /geoserverexplorer/images/group.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/group.gif -------------------------------------------------------------------------------- /geoserverexplorer/images/gwc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/gwc.png -------------------------------------------------------------------------------- /geoserverexplorer/images/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/help.png -------------------------------------------------------------------------------- /geoserverexplorer/images/import_into_qgis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/import_into_qgis.png -------------------------------------------------------------------------------- /geoserverexplorer/images/layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/layer.png -------------------------------------------------------------------------------- /geoserverexplorer/images/layer_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/layer_line.png -------------------------------------------------------------------------------- /geoserverexplorer/images/layer_point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/layer_point.png -------------------------------------------------------------------------------- /geoserverexplorer/images/layer_polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/layer_polygon.png -------------------------------------------------------------------------------- /geoserverexplorer/images/layer_unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/layer_unknown.png -------------------------------------------------------------------------------- /geoserverexplorer/images/new_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/new_table.png -------------------------------------------------------------------------------- /geoserverexplorer/images/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/pencil.png -------------------------------------------------------------------------------- /geoserverexplorer/images/process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/process.png -------------------------------------------------------------------------------- /geoserverexplorer/images/publish-to-geoserver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/publish-to-geoserver.png -------------------------------------------------------------------------------- /geoserverexplorer/images/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/refresh.png -------------------------------------------------------------------------------- /geoserverexplorer/images/rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/rename.png -------------------------------------------------------------------------------- /geoserverexplorer/images/seed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/seed.png -------------------------------------------------------------------------------- /geoserverexplorer/images/sql_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/sql_window.png -------------------------------------------------------------------------------- /geoserverexplorer/images/style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/style.png -------------------------------------------------------------------------------- /geoserverexplorer/images/table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/table.png -------------------------------------------------------------------------------- /geoserverexplorer/images/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/top.png -------------------------------------------------------------------------------- /geoserverexplorer/images/tree.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/tree.gif -------------------------------------------------------------------------------- /geoserverexplorer/images/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/up.png -------------------------------------------------------------------------------- /geoserverexplorer/images/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/warning.png -------------------------------------------------------------------------------- /geoserverexplorer/images/warning32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/warning32.png -------------------------------------------------------------------------------- /geoserverexplorer/images/workspace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/workspace.png -------------------------------------------------------------------------------- /geoserverexplorer/images/wrong.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/images/wrong.gif -------------------------------------------------------------------------------- /geoserverexplorer/metadata.txt: -------------------------------------------------------------------------------- 1 | [general] 2 | name=GeoServer Explorer 3 | description=Configure and manage GeoServer from QGIS 4 | about=Easily configure GeoServer through QGIS. Prepare data and styling or publish directly to a catalog directly from the QGIS interface, or add a service from GeoServer into your QGIS project. 5 | category=Web 6 | qgisMinimumVersion=3.0 7 | version=1.0 8 | 9 | author=Boundless (Victor Olaya) 10 | email=info@boundlessgeo.com 11 | 12 | icon=images/desktop.svg 13 | tags=boundless,geoserver 14 | 15 | homepage=https://github.com/boundlessgeo/qgis-geoserver-plugin 16 | tracker=https://github.com/boundlessgeo/qgis-geoserver-plugin/issues 17 | repository=https://github.com/boundlessgeo/qgis-geoserver-plugin 18 | 19 | experimental=False 20 | deprecated=False 21 | 22 | -------------------------------------------------------------------------------- /geoserverexplorer/plugin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | 7 | from builtins import object 8 | import os 9 | from geoserverexplorer.gui.explorer import GeoServerExplorer 10 | from qgis.PyQt.QtGui import * 11 | from qgis.PyQt.QtCore import * 12 | from qgis.PyQt.QtWidgets import * 13 | from qgis import utils 14 | from qgis.core import QgsMessageLog 15 | from geoserverexplorer.qgis import layerwatcher 16 | from qgiscommons2.settings import pluginSetting, setPluginSetting, readSettings 17 | from qgiscommons2.gui import addHelpMenu, removeHelpMenu, addAboutMenu, removeAboutMenu 18 | from qgiscommons2.gui.settings import addSettingsMenu, removeSettingsMenu 19 | 20 | class GeoServerExplorerPlugin(object): 21 | 22 | def __init__(self, iface): 23 | self.iface = iface 24 | readSettings() 25 | try: 26 | from qgistester.tests import addTestModule 27 | from geoserverexplorer.test import testplugin 28 | addTestModule(testplugin, "GeoServer") 29 | except Exception as ex: 30 | pass 31 | 32 | def unload(self): 33 | self.explorer.deleteLater() 34 | removeSettingsMenu("GeoServer", self.iface.removePluginWebMenu) 35 | removeHelpMenu("GeoServer", self.iface.removePluginWebMenu) 36 | removeAboutMenu("GeoServer", self.iface.removePluginWebMenu) 37 | self.iface.removePluginWebMenu(u"GeoServer", self.explorerAction) 38 | layerwatcher.disconnectLayerWasAdded() 39 | try: 40 | from qgistester.tests import removeTestModule 41 | from geoserverexplorer.test import testplugin 42 | removeTestModule(testplugin, "GeoServer") 43 | except Exception as ex: 44 | pass 45 | 46 | def initGui(self): 47 | icon = QIcon(os.path.dirname(__file__) + "/images/geoserver.png") 48 | self.explorerAction = QAction(icon, "GeoServer Explorer", self.iface.mainWindow()) 49 | self.explorerAction.triggered.connect(self.openExplorer) 50 | self.iface.addPluginToWebMenu(u"GeoServer", self.explorerAction) 51 | 52 | self.explorer = GeoServerExplorer() 53 | self.iface.addDockWidget(Qt.RightDockWidgetArea, self.explorer) 54 | if not pluginSetting("ExplorerVisible"): 55 | self.explorer.hide() 56 | self.explorer.visibilityChanged.connect(self._explorerVisibilityChanged) 57 | 58 | addSettingsMenu("GeoServer", self.iface.addPluginToWebMenu) 59 | addHelpMenu("GeoServer", self.iface.addPluginToWebMenu) 60 | addAboutMenu("GeoServer", self.iface.addPluginToWebMenu) 61 | 62 | layerwatcher.connectLayerWasAdded(self.explorer) 63 | 64 | def _explorerVisibilityChanged(self, visible): 65 | setPluginSetting("ExplorerVisible", visible) 66 | 67 | def openExplorer(self): 68 | self.explorer.show() 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /geoserverexplorer/qgis/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | -------------------------------------------------------------------------------- /geoserverexplorer/qgis/exporter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | ''' 7 | This module provides methods to export layers so they can be used as valid data 8 | for uploading to GeoServer. 9 | ''' 10 | 11 | from builtins import str 12 | from qgis.core import * 13 | from geoserverexplorer.qgis import utils 14 | import os 15 | from qgis.PyQt import QtCore 16 | from qgis.utils import iface 17 | from qgis.gui import QgsMessageBar 18 | from qgiscommons2.files import tempFilenameInTempFolder 19 | 20 | def exportVectorLayer(layer): 21 | '''accepts a QgsVectorLayer or a string with a filepath''' 22 | settings = QtCore.QSettings() 23 | systemEncoding = settings.value( "/UI/encoding", "System" ) 24 | if isinstance(layer, QgsMapLayer): 25 | filename = str(layer.source()) 26 | destFilename = str(layer.name()) 27 | else: 28 | filename = str(layer) 29 | destFilename = str(os.path.splitext(os.path.basename(filename))[0]) 30 | if (not filename.lower().endswith("shp")): 31 | if not isinstance(layer, QgsMapLayer): 32 | layer = QgsVectorLayer(filename, "layer", "ogr") 33 | if not layer.isValid() or layer.type() != QgsMapLayer.VectorLayer: 34 | raise Exception ("Error reading file {} or it is not a valid vector layer file".format(filename)) 35 | output = tempFilenameInTempFolder(destFilename + ".shp") 36 | QgsVectorFileWriter.writeAsVectorFormat(layer, output, systemEncoding, layer.crs(), "ESRI Shapefile") 37 | QgsMessageLog.logMessage("Layer '%s' had to be exported to shapefile for importing. Data might be lost." % layer.name(), 38 | level = Qgis.Warning) 39 | return output 40 | else: 41 | return filename 42 | 43 | 44 | 45 | def exportRasterLayer(layer): 46 | if (not str(layer.source()).lower().endswith("tif") ): 47 | filename = str(layer.name()) 48 | output = tempFilenameInTempFolder(filename + ".tif") 49 | writer = QgsRasterFileWriter(output) 50 | writer.setOutputFormat("GTiff"); 51 | writer.writeRaster(layer.pipe(), layer.width(), layer.height(), layer.extent(), layer.crs()) 52 | del writer 53 | return output 54 | else: 55 | return str(layer.source()) 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /geoserverexplorer/qgis/layers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from qgis.core import * 7 | 8 | ALL_TYPES = -1 9 | 10 | class WrongLayerNameException(BaseException) : 11 | pass 12 | 13 | def resolveLayer(name): 14 | layers = getAllLayers() 15 | for layer in layers: 16 | if layer.name() == name: 17 | return layer 18 | raise WrongLayerNameException() 19 | 20 | def getPublishableLayers(): 21 | layers = getAllLayers() 22 | return [layer for layer in layers if layer.dataProvider().name() != "wms"] 23 | 24 | def getAllLayers(): 25 | return list(QgsProject.instance().mapLayers().values()) 26 | 27 | def getAllLayersAsDict(): 28 | return {layer.source(): layer for layer in getAllLayers()} 29 | 30 | def getPublishableLayersAsDict(): 31 | return {layer.source(): layer for layer in getPublishableLayers()} 32 | 33 | def getGroups(): 34 | groups = {} 35 | root = QgsProject.instance().layerTreeRoot() 36 | for child in root.children(): 37 | if isinstance(child, QgsLayerTreeGroup): 38 | layers = [] 39 | for subchild in child.children(): 40 | if isinstance(subchild, QgsLayerTreeLayer): 41 | layers.append(subchild.layer()) 42 | groups[child.name()] = layers 43 | 44 | return groups 45 | 46 | def layerFromUri(uri): 47 | allLayers = getAllLayers() 48 | source = uri.uri.split("|")[0] 49 | for layer in getAllLayers(): 50 | if layer.source() == source and layer.name() == uri.name: 51 | return layer 52 | 53 | -------------------------------------------------------------------------------- /geoserverexplorer/qgis/layerwatcher.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from geoserverexplorer.qgis.utils import isTrackedLayer 7 | from geoserverexplorer.qgis import uri as uri_utils 8 | from geoserverexplorer.qgis.sldadapter import adaptGsToQgs 9 | from qgis.core import * 10 | from qgis.gui import * 11 | from qgis.utils import iface 12 | from geoserverexplorer.qgis.utils import readTrackedLayers 13 | from functools import partial 14 | from qgis.PyQt import QtCore, QtGui, QtWidgets 15 | from geoserverexplorer.qgis.utils import getTrackingInfo, removeTrackedLayer 16 | from geoserver.catalog import Catalog 17 | from geoserverexplorer.qgis.catalog import CatalogWrapper 18 | from qgiscommons2.settings import pluginSetting 19 | from qgiscommons2.files import tempFilename 20 | from geoserverexplorer.gui import setInfo, setWarning, setError 21 | 22 | _explorer = None 23 | 24 | def layerAdded(qgislayer): 25 | try: 26 | if qgislayer.providerType().lower() != "wfs": 27 | return 28 | except: 29 | pass #Not all layers have a providerType method 30 | catalogs = list(_explorer.explorerTree.gsItem._catalogs.values()) 31 | for cat in catalogs: 32 | if cat.layersEndpointUrl() in qgislayer.source(): 33 | for layer in cat.get_layers(): 34 | uri = uri_utils.layerUri(layer) 35 | if uri == qgislayer.source(): 36 | try: 37 | sld = layer.default_style.sld_body.decode() 38 | sld = adaptGsToQgs(sld) 39 | sldfile = tempFilename("sld") 40 | with open(sldfile, 'w') as f: 41 | f.write(sld) 42 | msg, ok = qgislayer.loadSldStyle(sldfile) 43 | if not ok: 44 | raise Exception("Could not load style for layer %s" % qgislayer.name()) 45 | qgislayer.styleChanged.connect(partial(updatePublishedStyle, qgislayer)) 46 | except Exception as e: 47 | setWarning("Could not set style for layer %s" % qgislayer.name()) 48 | return 49 | 50 | 51 | _currentMessageBarLayer = None 52 | 53 | def _resetCurrentMessageBarLayer(): 54 | global _currentMessageBarLayer 55 | _currentMessageBarLayer = None 56 | 57 | def updatePublishedStyle(layer): 58 | global _currentMessageBarLayer 59 | track = pluginSetting("TrackLayers") 60 | if track and isTrackedLayer(layer): 61 | if iface.messageBar().currentItem() is None: 62 | _resetCurrentMessageBarLayer() 63 | if _currentMessageBarLayer != layer: 64 | _currentMessageBarLayer = layer 65 | widget = iface.messageBar().createMessage("", 66 | "This layer was uploaded to a geoserver catalog. Do you want to update the published style?") 67 | updateButton = QtWidgets.QPushButton(widget) 68 | updateButton.setText("Update") 69 | def updateStyle(): 70 | url = getTrackingInfo(layer) 71 | catalog = Catalog(url) 72 | wrapper = CatalogWrapper(catalog) 73 | wrapper.publishStyle(layer) 74 | iface.messageBar().popWidget() 75 | _resetCurrentMessageBarLayer() 76 | updateButton.pressed.connect(updateStyle) 77 | widget.layout().addWidget(updateButton) 78 | stopTrackingButton = QtWidgets.QPushButton(widget) 79 | stopTrackingButton.setText("Stop tracking this layer") 80 | def stopTracking(): 81 | removeTrackedLayer(layer) 82 | iface.messageBar().popWidget() 83 | _resetCurrentMessageBarLayer() 84 | stopTrackingButton.pressed.connect(stopTracking) 85 | widget.layout().addWidget(stopTrackingButton) 86 | iface.messageBar().pushWidget(widget, Qgis.Info) 87 | iface.messageBar().currentItem().geoserverLayer = layer 88 | #iface.messageBar().widgetRemoved.connect(_resetCurrentMessageBarLayer) 89 | 90 | 91 | def connectLayerWasAdded(explorer): 92 | global _explorer 93 | _explorer = explorer 94 | QgsProject.instance().layerWasAdded.connect(layerAdded) 95 | readTrackedLayers() 96 | 97 | def disconnectLayerWasAdded(): 98 | QgsProject.instance().layerWasAdded.disconnect(layerAdded) 99 | -------------------------------------------------------------------------------- /geoserverexplorer/qgis/uri.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | 7 | import urllib.request, urllib.parse, urllib.error 8 | from qgis.core import * 9 | from geoserver.layer import Layer 10 | from geoserver.layergroup import LayerGroup 11 | from geoserverexplorer.geoserver.auth import AuthCatalog 12 | 13 | 14 | def addAuth(_params, catalog): 15 | if isinstance(catalog, AuthCatalog): 16 | _params['authcfg'] = catalog.authid 17 | else: 18 | _params['PASSWORD'] = catalog.password 19 | _params['USERNAME'] = catalog.username 20 | 21 | def layerUri(layer): 22 | 23 | def _get_namespaced_name(ws_name, layer_name): 24 | """Prefix ws name in case it is not already there""" 25 | if layer_name.find(':') != -1: 26 | return layer_name 27 | return ws_name + ":" + layer_name 28 | 29 | resource = layer.resource 30 | catalog = layer.catalog 31 | if resource.resource_type == 'featureType': 32 | params = { 33 | 'SERVICE': 'WFS', 34 | 'VERSION': '1.0.0', 35 | 'REQUEST': 'GetFeature', 36 | 'TYPENAME': _get_namespaced_name(resource.workspace.name, layer.name), 37 | 'SRSNAME': resource.projection, 38 | } 39 | addAuth(params, catalog) 40 | uri = layer.catalog.layersEndpointUrl() + '/wfs?' + urllib.parse.unquote(urllib.parse.urlencode(params)) 41 | elif resource.resource_type == 'coverage': 42 | params = { 43 | 'identifier': _get_namespaced_name(resource.workspace.name, resource.name), 44 | 'format': 'GeoTIFF', 45 | 'url': layer.catalog.layersEndpointUrl() + '/wcs', 46 | 'cache': 'PreferNetwork' 47 | } 48 | addAuth(params, catalog) 49 | uri = urllib.parse.unquote(urllib.parse.urlencode(params)) 50 | else: 51 | params = { 52 | 'layers': _get_namespaced_name(resource.workspace.name, resource.name), 53 | 'format': 'image/png', 54 | 'url': layer.catalog.layersEndpointUrl() + '/wms', 55 | 'styles': '', 56 | 'crs': resource.projection 57 | } 58 | addAuth(params, catalog) 59 | uri = urllib.parse.unquote(urllib.parse.urlencode(params)) 60 | 61 | return uri 62 | 63 | def groupUri(group): 64 | params = { 65 | 'layers': group.name, 66 | 'format': 'image/png', 67 | 'url': group.catalog.layersEndpointUrl() + '/wms', 68 | 'styles': '', 69 | } 70 | addAuth(params, group.catalog) 71 | uri = urllib.parse.unquote(urllib.parse.urlencode(params)) 72 | return uri 73 | 74 | def layerMimeUri(element): 75 | if isinstance(element, Layer): 76 | layer = element 77 | uri = layerUri(layer) 78 | resource = layer.resource 79 | if resource.resource_type == 'featureType': 80 | layertype = 'vector' 81 | provider = 'WFS' 82 | elif resource.resource_type == 'coverage': 83 | layertype = 'raster' 84 | provider = 'wcs' 85 | else: 86 | layertype = 'raster' 87 | provider = 'wms' 88 | escapedName = resource.title.replace( ":", "\\:" ); 89 | escapedUri = uri.replace( ":", "\\:" ); 90 | mimeUri = ':'.join([layertype, provider, escapedName, escapedUri]) 91 | return mimeUri 92 | elif isinstance(element, LayerGroup): 93 | uri = groupUri(element) 94 | escapedName = resource.title.replace( ":", "\\:" ); 95 | escapedUri = uri.replace( ":", "\\:" ); 96 | mimeUri = ':'.join(["raster", "wms", escapedName, escapedUri]) 97 | return mimeUri 98 | -------------------------------------------------------------------------------- /geoserverexplorer/qgis/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | import os 7 | import uuid 8 | import time 9 | from qgis.core import * 10 | from qgis.utils import * 11 | from qgis.PyQt.QtGui import * 12 | from qgis.PyQt.QtCore import * 13 | from qgis.PyQt.QtWidgets import * 14 | 15 | from geoserverexplorer.qgis import layers as qgislayers 16 | from geoserverexplorer.qgis import uri as uri_utils 17 | import json 18 | 19 | class UserCanceledOperation(Warning): 20 | pass 21 | 22 | def checkLayers(): 23 | layers = qgislayers.getAllLayers() 24 | if len(layers) == 0: 25 | QMessageBox.warning(iface.mainWindow(), 'QGIS layers needed', 26 | "No suitable layers can be found in your current QGIS project.\n" 27 | "You must open the layers in QGIS to be able to work with them.", 28 | QMessageBox.Ok) 29 | return False 30 | return True 31 | 32 | 33 | def userFolder(): 34 | folder = os.path.join(QgsApplication.qgisSettingsDirPath(), 'geoserver') 35 | try: 36 | os.mkdir(folder) 37 | except OSError: 38 | pass 39 | return folder 40 | 41 | 42 | def isWindows(): 43 | return os.name == 'nt' 44 | 45 | tracked = [] 46 | 47 | def formatSource(source): 48 | if isinstance(source, QgsRasterLayer): 49 | return None 50 | if isinstance(source, QgsVectorLayer): 51 | source = source.source() 52 | source = os.path.normcase(source) 53 | 54 | def addTrackedLayer(layer, catalogUrl): 55 | global tracked 56 | source = formatSource(layer.source()) 57 | if getTrackingInfo(layer) is None: 58 | tracked.append([source, catalogUrl]) 59 | saveTrackedLayers() 60 | 61 | def removeTrackedLayer(layer): 62 | global tracked 63 | source = formatSource(layer.source()) 64 | for i, s in enumerate(tracked): 65 | if s[0] == source: 66 | del tracked[i] 67 | saveTrackedLayers() 68 | return 69 | 70 | def saveTrackedLayers(): 71 | filename = os.path.join(userFolder(), "trackedlayers") 72 | with open(filename, "w") as f: 73 | f.write(json.dumps(tracked)) 74 | 75 | def readTrackedLayers(): 76 | try: 77 | global tracked 78 | filename = os.path.join(userFolder(), "trackedlayers") 79 | if os.path.exists(filename): 80 | with open(filename) as f: 81 | tracked = json.load(f) 82 | except: 83 | pass 84 | 85 | def isTrackedLayer(layer): 86 | return (formatSource(layer.source()) in [t[0] for t in tracked]) 87 | 88 | def getTrackingInfo(layer): 89 | source = formatSource(layer.source()) 90 | for obj in tracked: 91 | if obj[0] == source: 92 | return obj[1] 93 | -------------------------------------------------------------------------------- /geoserverexplorer/resources/grayscale.sld: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | grayscale_raster 5 | 6 | Grayscale raster 7 | 8 | 9 | name 10 | 11 | Single symbol 12 | 13 | 1.0 14 | 15 | 16 | 1 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /geoserverexplorer/resources/rgb.sld: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | rgb_raster 5 | 6 | RGB raster 7 | 8 | 9 | name 10 | 11 | Single symbol 12 | 13 | 1.0 14 | 15 | 16 | 1 17 | 18 | 19 | 2 20 | 21 | 22 | 3 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /geoserverexplorer/settings.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"name":"ShowDescription", 3 | "label": "Show description panel", 4 | "description": "Show description panel", 5 | "type": "bool", 6 | "default": true, 7 | "group": "General" 8 | }, 9 | {"name":"ConfirmDelete", 10 | "label": "Ask confirmation before deleting", 11 | "description": "Ask confirmation before deleting", 12 | "type": "bool", 13 | "default": true, 14 | "group": "General" 15 | }, 16 | {"name":"ShowToolbar", 17 | "label": "Show toolbar", 18 | "description": "Show toolbar", 19 | "type": "bool", 20 | "default": false, 21 | "group": "General" 22 | }, 23 | {"name":"SaveCatalogs", 24 | "label": "Keep a list of previous catalog connections", 25 | "description": "Keep a list of previous catalog connections", 26 | "type": "bool", 27 | "default": true, 28 | "group": "General" 29 | }, 30 | {"name":"TrackLayers", 31 | "label": "Track layers and publish styles automatically", 32 | "description": "Track layers and publish styles automatically when they change", 33 | "type": "bool", 34 | "default": true, 35 | "group": "General" 36 | }, 37 | {"name":"DeleteStyle", 38 | "label": "Delete style when deleting layer", 39 | "description": "Delete style when deleting layer", 40 | "type": "bool", 41 | "default": true, 42 | "group": "General" 43 | }, 44 | {"name":"Recurse", 45 | "label": "Delete resource when deleting layer", 46 | "description": "Delete resource when deleting layer", 47 | "type": "bool", 48 | "default": true, 49 | "group": "General" 50 | }, 51 | {"name":"OverwriteGroupLayers", 52 | "label": "Overwrite layers when uploading group", 53 | "description": "Overwrite layers when uploading group", 54 | "type": "bool", 55 | "default": true, 56 | "group": "General" 57 | }, 58 | {"name":"AuthCatalogXMLCacheTime", 59 | "label": "AuthCatalog XML cache time in seconds", 60 | "description": "AuthCatalog XML cache time in seconds", 61 | "type": "number", 62 | "default": 180, 63 | "group": "General" 64 | }, 65 | {"name":"SldUomManaging", 66 | "label": "QGIS manage SLD uom correctly", 67 | "description": "QGIS manage SLD uom correctly", 68 | "type": "bool", 69 | "default": true, 70 | "group": "General" 71 | }, 72 | {"name":"SldScaleFactor", 73 | "label": "Size scale factor. !Unused if uom is managed!", 74 | "description": "Size scale factor. !Unused if uom is managed!", 75 | "type": "number", 76 | "default": 4, 77 | "group": "General" 78 | } 79 | ] 80 | -------------------------------------------------------------------------------- /geoserverexplorer/test/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | -------------------------------------------------------------------------------- /geoserverexplorer/test/coveragerc: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | # .coveragerc to control coverage.py 7 | [report] 8 | exclude_lines = 9 | pragma: no cover 10 | if __name__ == '__main__': 11 | if __name__ == "__main__": 12 | ignore_errors = True 13 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/geo.dbf: -------------------------------------------------------------------------------- 1 | _)AGEOFORMC Plain_311 Plain_411 Hill_211 Hill_112 Hill_411 Hill_311 Hill_312 Hill_411 Hill_312 Hill_111 Hill_211 Hill_112 Hill_212 Hill_112 Hill_111 Hill_411 Hill_311 Hill_212 Hill_111 Hill_112 Hill_312 Hill_312 Hill_211 Hill_312 Hill_411 Hill_212 Hill_112 Hill_112 Hill_112 Hill_111 Hill_311 Hill_111 Hill_312 Hill_312 Hill_112 ? Hill_111 Hill_411 Hill_111 Hill_311 Hill_411 -------------------------------------------------------------------------------- /geoserverexplorer/test/data/geo.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /geoserverexplorer/test/data/geo.qpj: -------------------------------------------------------------------------------- 1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] 2 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/geo.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/geo.shp -------------------------------------------------------------------------------- /geoserverexplorer/test/data/geo.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/geo.shx -------------------------------------------------------------------------------- /geoserverexplorer/test/data/land.dbf: -------------------------------------------------------------------------------- 1 | _ALANDCOVERC urban_areas agricultural_areas agricultural_areas fishponds fishponds grasslands_pastures natural_forest agricultural_areas natural_forest agricultural_areas agricultural_areas grasslands_pastures natural_forest agricultural_areas grasslands_pastures natural_forest grasslands_pastures grasslands_pastures natural_forest natural_forest grasslands_pastures urban_areas grasslands_pastures natural_forest -------------------------------------------------------------------------------- /geoserverexplorer/test/data/land.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /geoserverexplorer/test/data/land.qpj: -------------------------------------------------------------------------------- 1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] 2 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/land.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/land.shp -------------------------------------------------------------------------------- /geoserverexplorer/test/data/land.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/land.shx -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_dem.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_dem.tif -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_dem.tif.aux.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 1212.428 6 | 2357.572 7 | 1000 8 | 0 9 | 0 10 | 1|0|0|1|0|0|0|1|0|0|0|2|2|0|0|1|0|2|2|0|1|1|3|0|3|3|0|1|2|1|0|2|3|1|2|3|2|2|5|5|3|1|3|1|0|5|1|1|2|5|3|6|5|3|3|3|0|2|3|7|2|4|4|5|7|6|3|3|4|3|5|9|9|3|3|11|0|10|1|12|3|5|2|4|5|4|18|6|8|4|7|6|4|20|4|2|3|4|4|4|14|7|6|7|2|7|5|8|4|5|3|9|7|6|14|4|5|5|2|5|10|8|7|5|12|2|7|12|8|6|8|6|4|7|8|7|5|5|9|4|11|13|7|7|8|5|7|10|12|12|16|6|10|8|10|16|10|13|12|5|6|9|24|6|10|13|8|9|10|14|13|12|4|16|10|9|30|5|11|8|14|9|9|19|10|13|11|9|9|25|18|8|8|14|11|14|18|11|9|8|11|16|10|22|7|14|17|12|14|8|23|7|13|14|9|11|13|31|6|14|13|13|15|12|30|13|10|11|13|13|12|32|19|16|11|17|14|12|36|12|8|15|21|15|14|34|18|21|11|19|11|29|13|20|19|18|23|15|32|19|13|15|16|17|19|36|26|16|17|13|14|12|33|13|22|12|22|16|11|36|20|12|17|14|19|14|39|17|14|19|17|18|14|38|11|16|15|14|20|18|38|18|17|24|16|15|14|38|18|30|20|18|22|29|18|15|19|19|22|23|47|23|21|15|22|26|21|43|27|27|23|23|17|26|47|28|22|22|17|29|17|37|24|28|18|31|22|20|46|17|12|24|22|28|18|51|27|23|21|20|20|26|42|25|22|20|29|19|24|42|21|25|26|23|23|47|27|22|19|30|22|23|44|31|30|23|23|27|29|40|21|20|29|29|20|30|54|24|23|25|25|25|24|60|23|23|21|25|25|36|48|31|27|20|31|34|31|47|26|31|23|29|27|32|52|27|26|34|33|38|20|64|26|36|29|38|24|63|35|31|31|32|25|32|59|25|27|32|24|37|24|64|21|36|31|26|31|31|46|22|29|30|35|30|44|73|29|29|37|41|27|26|78|26|33|28|27|26|46|70|28|28|24|41|35|25|56|28|25|28|21|31|32|71|18|29|32|38|32|66|36|27|28|28|36|30|69|30|35|35|40|31|29|61|26|26|22|31|29|26|71|34|22|30|24|39|25|51|25|33|29|28|30|30|49|20|25|28|29|36|29|58|20|31|20|29|31|23|61|18|23|40|27|25|27|55|29|27|32|42|27|26|53|25|35|30|31|35|69|28|35|25|23|46|20|47|31|19|31|30|27|28|50|57|37|49|42|36|21|59|34|28|30|21|36|23|51|26|21|26|14|30|31|45|23|14|21|20|19|16|46|24|17|28|22|20|12|34|35|25|14|18|16|16|48|24|17|24|18|14|34|18|21|18|17|27|19|48|19|11|19|24|11|21|45|19|21|20|19|19|21|33|18|13|17|24|14|15|32|25|17|14|21|18|14|33|17|17|17|17|22|24|37|20|16|24|26|19|22|35|19|23|19|20|25|22|46|20|18|11|13|20|48|13|17|27|15|20|17|36|21|13|18|20|23|11|39|10|15|19|26|14|20|24|13|9|23|18|17|16|32|18|19|18|18|18|14|28|30|16|29|10|20|17|33|14|18|16|13|18|20|47|26|14|25|18|14|22|47|24|15|21|20|16|36|21|29|26|19|32|25|51|21|39|31|26|27|36|51|28|28|21|26|22|27|55|22|40|71|16|18|24|34|23|19|21|18|18|22|30|21|22|15|21|19|18|41|19|15|25|18|18|19|39|16|18|23|25|15|17|59|30|29|29|24|37|49|25|24|22|30|28|31|53|33|22|19|34|30|31|55|19|17|18|26|31|28|46|23|11|25|16|25|25|52|26|16|25|34|24|18|59|19|27|25|27|20|22|37|26|19|15|23|25|21|41|7|15|15|13|11|15|20|9|11|9|10|9|22|16|8|9|12|16|6|24|16|9|8|7|10|12|19|13|9|6|13|7|7|16|7|12|9|5|7|7|16|7|7|6|9|7|8|15|5|5|6|5|9|9|10|9|8|2|7|7|2|21|2|5|5|4|7|5|10|4|6|6|3|6|9|2|5|2|3|9|3|5|4|4|4|6|4|3|7|2|5|1|3|0|10|6|2|3|1|2|1|0|9|4|3|6|3|1|2|2|4|2|0|3|3|2|3|1|0|1|0|2|2|2|0|1|2|0|1|1|1|0|1|1 11 | 12 | 13 | 14 | 2357 15 | 1821.8091628944 16 | 1213 17 | 244.4154810232 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_dem_exact.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_dem_exact.tif -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_dem_rbg.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_dem_rbg.tif -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_demascii.asc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_demascii.asc -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt1.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt1.qpj: -------------------------------------------------------------------------------- 1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] 2 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt1.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_pt1.shp -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt1.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_pt1.shx -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt2.dbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_pt2.dbf -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt2.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt2.qpj: -------------------------------------------------------------------------------- 1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] 2 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt2.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_pt2.shp -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt2.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_pt2.shx -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt3.dbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_pt3.dbf -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt3.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt3.qpj: -------------------------------------------------------------------------------- 1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] 2 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt3.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_pt3.shp -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt3.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_pt3.shx -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt4.dbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_pt4.dbf -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt4.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt4.qpj: -------------------------------------------------------------------------------- 1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] 2 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt4.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_pt4.shp -------------------------------------------------------------------------------- /geoserverexplorer/test/data/qgis_plugin_test_pt4.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/qgis_plugin_test_pt4.shx -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/graticule.dbf: -------------------------------------------------------------------------------- 1 | _dA nN 2 | 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/graticule.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["WGS 84", 2 | DATUM["World Geodetic System 1984", 3 | SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]], 4 | AUTHORITY["EPSG","6326"]], 5 | PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]], 6 | UNIT["degree", 0.017453292519943295], 7 | AXIS["Geodetic longitude", EAST], 8 | AXIS["Geodetic latitude", NORTH], 9 | AUTHORITY["EPSG","4326"]] -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/graticule.qpj: -------------------------------------------------------------------------------- 1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] 2 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/graticule.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/symbology/graticule.shp -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/graticule.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/symbology/graticule.shx -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/irregular_lines.cpg: -------------------------------------------------------------------------------- 1 | UTF-8 -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/irregular_lines.dbf: -------------------------------------------------------------------------------- 1 | v a[idN 2 | labelCP **********Lorem ipsum dolor sit amet 2Lorem ipsum dolor sit amet 1Lorem ipsum dolor sit amet **********Lorem ipsum dolor sit amet  -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/irregular_lines.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/irregular_lines.qpj: -------------------------------------------------------------------------------- 1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] 2 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/irregular_lines.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/symbology/irregular_lines.shp -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/irregular_lines.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/symbology/irregular_lines.shx -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/irregular_polygons.cpg: -------------------------------------------------------------------------------- 1 | UTF-8 -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/irregular_polygons.dbf: -------------------------------------------------------------------------------- 1 | v a[idN 2 | labelsCP 1Lorem ipsum dolor 2Lorem ipsum dolor 3  -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/irregular_polygons.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/irregular_polygons.qpj: -------------------------------------------------------------------------------- 1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] 2 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/irregular_polygons.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/symbology/irregular_polygons.shp -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/irregular_polygons.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/symbology/irregular_polygons.shx -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/lines.dbf: -------------------------------------------------------------------------------- 1 | v dA nN 2 | 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/lines.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/lines.qpj: -------------------------------------------------------------------------------- 1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] 2 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/lines.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/symbology/lines.shp -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/lines.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/symbology/lines.shx -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/points.dbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/symbology/points.dbf -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/points.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/points.qpj: -------------------------------------------------------------------------------- 1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] 2 | -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/points.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/symbology/points.shp -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/points.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/symbology/points.shx -------------------------------------------------------------------------------- /geoserverexplorer/test/data/symbology/qgis.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/geoserverexplorer/test/data/symbology/qgis.jpeg -------------------------------------------------------------------------------- /geoserverexplorer/test/deletetests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from builtins import map 7 | import unittest 8 | import os 9 | import sys 10 | from qgis.PyQt.QtCore import * 11 | from qgis.core import * 12 | from qgis.utils import iface 13 | from geoserverexplorer.test.utils import PT1, safeName, PT2, WORKSPACE, WORKSPACEB, shapefile_and_friends 14 | from geoserverexplorer.test.integrationtest import ExplorerIntegrationTest 15 | from geoserverexplorer.qgis import layers 16 | from qgiscommons2.settings import pluginSetting, setPluginSetting 17 | 18 | class DeleteTests(ExplorerIntegrationTest): 19 | 20 | @classmethod 21 | def setUpClass(cls): 22 | # do workspace popuplation 23 | super(DeleteTests, cls).setUpClass() 24 | 25 | cls.ws = cls.cat.get_workspaces(WORKSPACE)[0] 26 | 27 | # load project 28 | projectFile = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data", "test.qgs") 29 | if os.path.normcase(projectFile) != os.path.normcase(QgsProject.instance().fileName()): 30 | iface.addProject(projectFile) 31 | # set flags to instruct GUI interaction 32 | cls.confirmDelete = pluginSetting("ConfirmDelete") 33 | setPluginSetting("ConfirmDelete", False) 34 | 35 | @classmethod 36 | def tearDownClass(cls): 37 | super(DeleteTests, cls).tearDownClass() 38 | setPluginSetting("ConfirmDelete", cls.confirmDelete) 39 | 40 | def testDeleteLayerAndStyle(self): 41 | # step 1: publish a layer. publish load layer and style 42 | self.catWrapper.publishLayer(PT1, self.ws, name=PT1) 43 | layer = self.cat.get_layer(PT1) 44 | self.assertIsNotNone(layer) 45 | style = self.cat.get_styles(PT1)[0] 46 | self.assertIsNotNone(style) 47 | self.getLayersItem().refreshContent(self.explorer) 48 | self.getStylesItem().refreshContent(self.explorer) 49 | # step 2: set flag to remove also style 50 | deleteStyle = pluginSetting("DeleteStyle") 51 | setPluginSetting("DeleteStyle", True) 52 | # step 3: then remove layer and style 53 | layerItem = self.getLayerItem(PT1) 54 | self.assertIsNotNone(layerItem) 55 | layerItem.deleteLayer(self.tree, self.explorer) 56 | layerItem = self.getLayerItem(PT1) 57 | self.assertIsNone(layerItem) 58 | styleItem = self.getStyleItem(PT1) 59 | self.assertIsNone(styleItem) 60 | # step 4: republish PT1 and it's style 61 | self.catWrapper.publishLayer(PT1) 62 | layer = self.cat.get_layer(PT1) 63 | self.assertIsNotNone(layer) 64 | style = self.cat.get_styles(PT1)[0] 65 | self.assertIsNotNone(style) 66 | self.getLayersItem().refreshContent(self.explorer) 67 | self.getStylesItem().refreshContent(self.explorer) 68 | # step 5: set flag to remove layer BUT not style 69 | setPluginSetting("DeleteStyle", False) 70 | # step 6: remove layer and check style is not erased 71 | layerItem = self.getLayerItem(PT1) 72 | layerItem.deleteLayer(self.tree, self.explorer) 73 | layerItem = self.getLayerItem(PT1) 74 | self.assertIsNone(layerItem) 75 | styleItem = self.getStyleItem(PT1) 76 | self.assertIsNotNone(styleItem) 77 | # step 7: then remove style 78 | styleItem.deleteStyle(self.tree, self.explorer) 79 | styleItem = self.getStyleItem(PT1) 80 | self.assertIsNone(styleItem) 81 | # step 8: set flag in original mode 82 | setPluginSetting("DeleteStyle", deleteStyle) 83 | 84 | def testDeleteLayersWithSameName(self): 85 | """ 86 | Test that when there are more than one layer with 87 | the same name they can be deleted 88 | """ 89 | wsb = self.catWrapper.catalog.get_workspaces(WORKSPACEB)[0] 90 | 91 | # Need to use prefixed names when retrieving 92 | pt1 = self.ws.name + ':' + PT1 93 | pt1b = wsb.name + ':' + PT1 94 | self.catWrapper.publishLayer(PT1, self.ws, name=PT1) 95 | self.assertIsNotNone(self.catWrapper.catalog.get_layer(pt1)) 96 | 97 | # Add second layer with the same name 98 | self.catWrapper.publishLayer(PT1, wsb, name=PT1) 99 | self.assertIsNotNone(self.catWrapper.catalog.get_layer(pt1b)) 100 | 101 | self.getLayersItem().refreshContent(self.explorer) 102 | 103 | # step 3: then remove layers 104 | layerItem = self.getLayerItem(pt1) 105 | self.assertIsNotNone(layerItem) 106 | layerItem.deleteLayer(self.tree, self.explorer) 107 | layerItem = self.getLayerItem(pt1) 108 | self.assertIsNone(layerItem) 109 | 110 | layerItem = self.getLayerItem(pt1b) 111 | self.assertIsNotNone(layerItem) 112 | layerItem.deleteLayer(self.tree, self.explorer) 113 | layerItem = self.getLayerItem(pt1b) 114 | self.assertIsNone(layerItem) 115 | 116 | 117 | def testDeleteWorkspace(self): 118 | wsname = safeName("another_workspace") 119 | self.cat.create_workspace(wsname, "http://anothertesturl.com") 120 | self.getWorkspacesItem().refreshContent(self.explorer) 121 | wsItem = self.getWorkspaceItem(wsname) 122 | wsItem.deleteWorkspace(self.tree, self.explorer) 123 | self.getWorkspacesItem().refreshContent(self.explorer) 124 | wsItem = self.getWorkspaceItem(wsname) 125 | self.assertIsNone(wsItem) 126 | ws = self.cat.get_workspaces(wsname) 127 | self.assertTrue(len(ws) == 0 ) 128 | 129 | 130 | def testDeleteGWCLayer(self): 131 | name = WORKSPACE + ":" + PT2 132 | item = self.getGWCLayerItem(name) 133 | item.deleteLayer(self.explorer) 134 | item = self.getGWCLayerItem(name) 135 | self.assertIsNone(item) 136 | 137 | 138 | ################################################################################################## 139 | 140 | def suite(): 141 | suite = unittest.makeSuite(DeleteTests, 'test') 142 | return suite 143 | 144 | # run all tests using unittest skipping nose or testplugin 145 | def run_all(): 146 | # demo_test = unittest.TestLoader().loadTestsFromTestCase(DeleteTests) 147 | unittest.TextTestRunner(verbosity=3, stream=sys.stdout).run(suite()) 148 | 149 | # run a subset of tests using unittest skipping nose or testplugin 150 | def run_subset(): 151 | unittest.TextTestRunner(verbosity=3, stream=sys.stdout).run(suiteSubset()) 152 | -------------------------------------------------------------------------------- /geoserverexplorer/test/dragdroptests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from builtins import map 7 | import unittest 8 | import os 9 | import sys 10 | from geoserverexplorer.test.utils import PT1, WORKSPACE, WORKSPACEB, STYLE, PT2, PT3,\ 11 | GROUP, GEOLOGY_GROUP, LANDUSE, GEOFORMS 12 | from geoserverexplorer.test.integrationtest import ExplorerIntegrationTest 13 | from geoserverexplorer.qgis import layers 14 | 15 | class DragDropTests(ExplorerIntegrationTest): 16 | 17 | #=========================================================================== 18 | # Drag & drop URIs (i.e. from QGIS browser) to a Explorer tree item 19 | #=========================================================================== 20 | 21 | def testDropVectorLayerUriInCatalogItem(self): 22 | uri = os.path.join(os.path.dirname(__file__), "data", PT1 + ".shp") 23 | self.catalogItem.acceptDroppedUris(self.tree, self.explorer, [uri]) 24 | layer = self.cat.get_layer(PT1) 25 | self.assertIsNotNone(layer) 26 | self.cat.get_stores(PT1, WORKSPACE)[0] 27 | self.cat.delete(self.cat.get_layer(PT1), recurse = True) 28 | self.cat.delete(self.cat.get_styles(PT1)[0], purge = True) 29 | 30 | def testDropVectorLayerUriInWorkspaceItem(self): 31 | uri = os.path.join(os.path.dirname(__file__), "data", PT1 + ".shp") 32 | item = self.getWorkspaceItem(WORKSPACEB) 33 | self.assertIsNotNone(item) 34 | item.acceptDroppedUris(self.tree, self.explorer, [uri]) 35 | layer = self.cat.get_layer(PT1) 36 | self.assertIsNotNone(layer) 37 | self.cat.get_stores(PT1, WORKSPACEB)[0] 38 | self.cat.delete(self.cat.get_layer(PT1), recurse = True) 39 | self.cat.delete(self.cat.get_styles(PT1)[0], purge = True) 40 | 41 | def testDropVectorLayerUriInLayersItem(self): 42 | uri = os.path.join(os.path.dirname(__file__), "data", PT1 + ".shp") 43 | item = self.getLayersItem() 44 | item.acceptDroppedUris(self.tree, self.explorer, [uri]) 45 | layer = self.cat.get_layer(PT1) 46 | self.assertIsNotNone(layer) 47 | self.cat.get_stores(PT1, WORKSPACE)[0] 48 | self.cat.delete(self.cat.get_layer(PT1), recurse = True) 49 | self.cat.delete(self.cat.get_styles(PT1)[0], purge = True) 50 | 51 | #=========================================================================== 52 | # Drag & drop explorer tree element(s) into another explorer tree element 53 | #=========================================================================== 54 | 55 | 56 | def testDropGsStyleInGsLayerItem(self): 57 | styleItem = self.getStyleItem(STYLE) 58 | self.assertIsNotNone(styleItem) 59 | layerItem = self.getLayerItem(PT2) 60 | self.assertIsNotNone(layerItem) 61 | layerItem.acceptDroppedItems(self.tree, self.explorer, [styleItem]) 62 | self.assertIsNotNone(self._getItemUnder(layerItem, STYLE)) 63 | 64 | def testDropGsLayerInGsGroupItem(self): 65 | groupItem = self.getGroupItem(GROUP) 66 | childCount = groupItem.childCount() 67 | layerItem = self.getLayerItem(PT3) 68 | groupItem.acceptDroppedItems(self.tree, self.explorer, [layerItem]) 69 | self.assertEquals(childCount + 1, groupItem.childCount()) 70 | 71 | 72 | ################################################################################################## 73 | 74 | def suiteSubset(): 75 | # set tests you want to execute adding in the following list 76 | tests = ['testDropVectorLayerUriInCatalogItem'] 77 | suite = unittest.TestSuite(list(map(DragDropTests, tests))) 78 | return suite 79 | 80 | def suite(): 81 | suite = unittest.TestSuite() 82 | suite.addTests(unittest.makeSuite(DragDropTests, 'test')) 83 | return suite 84 | 85 | # run all tests using unittest skipping nose or testplugin 86 | def run_all(): 87 | unittest.TextTestRunner(verbosity=3, stream=sys.stdout).run(suite()) 88 | 89 | # run a subset of tests using unittest skipping nose or testplugin 90 | def run_subset(): 91 | unittest.TextTestRunner(verbosity=3, stream=sys.stdout).run(suiteSubset()) 92 | -------------------------------------------------------------------------------- /geoserverexplorer/test/functional.txt: -------------------------------------------------------------------------------- 1 | GEOSERVER 2 | 3 | CATALOG 4 | -Connect to catalog 5 | -Connect to catalog with wrong url or credentials: should show "could not connect to catalog" message in message bar 6 | -Check connections are persisted if corresponding option is enabled 7 | -Connect to previous workspace that is not enabled (icon is grayed-out) 8 | Check that clicking on the catalog item displays catalog info in the description panel 9 | -Remove catalog: 10 | -Check it removes it from the tree 11 | -Check that, when reopening the explorer, it is not in the list of previous catalogs 12 | -Check that, once deleted, the description panel is not available and the buttons corresponding to the dialog are not present in the toolbar 13 | -Dragging a layer from the QGIS browser into a catalog item should add the resource to the workspace and create a layer that publishes it 14 | 15 | WORKSPACE 16 | -Create new workspace 17 | -Create new worskpace with existing name: should show error message in message bar 18 | -Create new worskpace with wrong/missing uri: should show error message in message bar 19 | -Set workspace as default. 20 | -Check that "set as default workspace" is disabled for the current default workspace 21 | -Delete non-empty workspace: 22 | - Delete empty with all its datastores not used by any layer. It should be deleted without warning 23 | - Delete empty with at least a datastore used by a layer. It should show warning and clicking on ok should delete the workspace and the dependent layers 24 | -Delete empty workspace 25 | -Delete datastore that is used in a layer. 26 | -It should show a confirmation dialog saying that the layer will also be deleted. 27 | -Accept and check that both elements are deleted 28 | -Clean (remove unused stores) workspace: 29 | -Import a layer. It will create a store and a layer 30 | -Delete the layer, making sure that the option to delete the underlying resource is not enabled. That will leave an unused resource 31 | -Run the "Clean (remove unused elements)" option. That should delete the resource 32 | -Dragging a layer from the QGIS browser into a workspace item should add the resource to the workspace and create a layer that publishes it 33 | 34 | LAYER 35 | -Add style to layer 36 | -Add style to layer indicating that it should be considered as the default style 37 | -Make style default 38 | -Add style to layer dragging style item 39 | -Remove style from layer 40 | -Check that default style cannot be removed from layer (option should be disabled) 41 | -Delete layer 42 | -with "delete style" option enabled, check that the style is deleted if and only if no other layer uses that layer 43 | -with "delete resource" layer, check that it also deletes the resource 44 | -Modify layer info using the description panel 45 | -modify abstract 46 | -modify title 47 | -modify SRS 48 | -Add layer to QGIS project 49 | - Both for raster and vector layers 50 | - Both using the context menu action and dragging and dropping on the QGIS canvas 51 | -Dragging a layer from the QGIS browser into a layer item should add the resource to the default workspace and create a layer that publishes it 52 | -Dragging into the "GeoServer Layers" item should do the same. 53 | 54 | GROUPS 55 | -Create group by selecting several layers, right-clicking and using "create group" 56 | -check that it shows error on message bar if name is empty 57 | -Create group by using the "new group" option in the groups item 58 | -check that it shows error on message bar if name is empty 59 | -check that it shows error on message bar if no layer is selected (empty group) 60 | -check that no group is created if clicked on "cancel" 61 | -check that "(de)select option works fine" 62 | -check that when the dialog is opened layers have their default style selected 63 | -Delete group. 64 | -Delete layer that is used in a group. 65 | -It should show a confirmation dialog saying that the group will also be deleted. 66 | -Accept and check that both elements are deleted 67 | -Edit group: 68 | -check that previous layers are in the group definition 69 | -check that group layers have the corresponding style and that style is saved when closing 70 | -check that non-group layers have their default style selected 71 | -check that group is modified when closing 72 | -check that group is not modified if clicking "cancel" 73 | -Remove layer from group 74 | -Check that layer cannot be removed from group when only the group only contains one layer (cannot create empty group) 75 | -Change rendering order (up/down/to top/to bottom) 76 | -Edit group by dragging a layer item on group item 77 | -Edit group by dragging a layer item on a layer item under a group item (should add it to the parent group of the layer item) 78 | 79 | 80 | STYLES 81 | -Import style from style 82 | -check that no style is imported if clicking cancel on dialog 83 | -check that it uses QGIS layer name when name box is left empty 84 | -check that it uses entered name when name box is not empty 85 | -Import style by dragging a QGIS style item 86 | -Clean (remove unused styles): 87 | -Import a layer. It will create a style and a layer 88 | -Delete the layer, making sure that the option to delete the layer style is not enabled. That will leave an unused style 89 | -Run the "Clean (remove unused styles)" option. That should delete the style 90 | -Consolidate styles 91 | -Import several layers with the same style 92 | -Run "consolidate styles". It should leave only the first of those styles, delete the other ones, and use that first one in the layers that used the remaining ones 93 | -Edit style: Set the "prompt for CRS" option in the Options.../CRS group. When editing a stlye, it should not ask for the CRS but go directly to the styling dialog 94 | -Edit SLD 95 | -Delete style. 96 | -If style is used by layer, it should ask for confirmation and warn that the layer will also be deleted. Check that all layers using the style are deleted 97 | 98 | -------------------------------------------------------------------------------- /geoserverexplorer/test/integrationtest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from builtins import range 7 | import unittest 8 | from qgis.PyQt.QtCore import QSettings 9 | from geoserverexplorer.gui.explorer import GeoServerExplorer 10 | from geoserverexplorer.test import utils 11 | from geoserverexplorer.gui.gsexploreritems import GsCatalogItem 12 | import os 13 | from qgis.utils import iface 14 | from qgis.core import * 15 | from qgiscommons2.settings import pluginSetting, setPluginSetting 16 | 17 | class ExplorerIntegrationTest(unittest.TestCase): 18 | 19 | @classmethod 20 | def setUpClass(cls): 21 | cls.explorer = GeoServerExplorer() 22 | # Disable cache 23 | cls.cache_time = pluginSetting("AuthCatalogXMLCacheTime") 24 | setPluginSetting("AuthCatalogXMLCacheTime", 1) 25 | cls.catWrapper = utils.getGeoServerCatalog() 26 | cls.cat = cls.catWrapper.catalog 27 | utils.populateCatalog(cls.cat) 28 | cls.catalogItem = GsCatalogItem(cls.cat, "catalog") 29 | cls.explorer.explorerTree.gsItem.addChild(cls.catalogItem) 30 | cls.catalogItem.populate() 31 | cls.tree = cls.explorer.tree 32 | projectFile = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data", "test.qgs") 33 | iface.addProject(projectFile) 34 | 35 | @classmethod 36 | def tearDownClass(cls): 37 | utils.cleanCatalog(cls.cat) 38 | setPluginSetting("AuthCatalogXMLCacheTime", cls.cache_time) 39 | 40 | def _getItemUnder(self, parent, name): 41 | 42 | def _get_item(name, parent): 43 | for idx in range(parent.childCount()): 44 | item = parent.child(idx) 45 | try: 46 | if item.element.name == name: 47 | return item 48 | except: 49 | if item.text(0) == name: 50 | return item 51 | return None 52 | 53 | result = _get_item(name, parent) 54 | if result is None and name.find(':') != -1: 55 | result = _get_item(name.split(':')[1], parent) 56 | return result 57 | 58 | def getStoreItem(self, ws, name): 59 | return self._getItemUnder(self.getWorkspaceItem(ws), name) 60 | 61 | def getWorkspaceItem(self, name): 62 | return self._getItemUnder(self.getWorkspacesItem(), name) 63 | 64 | def getLayerItem(self, name): 65 | name = self.cat.get_namespaced_name(name) 66 | return self._getItemUnder(self.getLayersItem(), name) 67 | 68 | def getGroupItem(self, name): 69 | return self._getItemUnder(self.getGroupsItem(), name) 70 | 71 | def getStyleItem(self, name): 72 | return self._getItemUnder(self.getStylesItem(), name) 73 | 74 | def getWorkspacesItem(self): 75 | return self.catalogItem.child(0) 76 | 77 | def getLayersItem(self): 78 | return self.catalogItem.child(1) 79 | 80 | def getGroupsItem(self): 81 | return self.catalogItem.child(2) 82 | 83 | def getStylesItem(self): 84 | return self.catalogItem.child(3) 85 | 86 | def getGWCLayersItem(self): 87 | return self.catalogItem.child(4) 88 | 89 | def getGWCLayerItem(self, name): 90 | return self._getItemUnder(self.getGWCLayersItem(), name) 91 | -------------------------------------------------------------------------------- /geoserverexplorer/test/resources/font.sld: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | qgis_plugin_test_pt1 5 | qgis_plugin_test_pt1 6 | 7 | 8 | Single symbol 9 | 10 | 11 | 12 | ttf://DejaVu Sans#0x46 13 | 14 | #570cd7 15 | 16 | 17 | 7 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /geoserverexplorer/test/resources/raster.sld: -------------------------------------------------------------------------------- 1 | qgis_plugin_test_demqgis_plugin_test_demname -------------------------------------------------------------------------------- /geoserverexplorer/test/resources/vector.2.16.sld: -------------------------------------------------------------------------------- 1 | 2 | 3 | qgis_plugin_test_pt1 4 | 5 | qgis_plugin_test_pt1 6 | 7 | name 8 | 9 | 85.0000 - 116.8400 10 | 11 | 12 | 13 | VALUE 14 | 85 15 | 16 | 17 | VALUE 18 | 116.84 19 | 20 | 21 | 22 | 23 | 24 | 25 | circle 26 | 27 | #f1eef6 28 | 29 | 30 | 31 | 28.000000 32 | 33 | 34 | 35 | 36 | 116.8400 - 148.6800 37 | 38 | 39 | 40 | VALUE 41 | 116.84 42 | 43 | 44 | VALUE 45 | 148.68 46 | 47 | 48 | 49 | 50 | 51 | 52 | circle 53 | 54 | #bdc9e1 55 | 56 | 57 | 58 | 28.000000 59 | 60 | 61 | 62 | 63 | 148.6800 - 180.5200 64 | 65 | 66 | 67 | VALUE 68 | 148.68 69 | 70 | 71 | VALUE 72 | 180.52 73 | 74 | 75 | 76 | 77 | 78 | 79 | circle 80 | 81 | #74a9cf 82 | 83 | 84 | 85 | 28.000000 86 | 87 | 88 | 89 | 90 | 180.5200 - 212.3600 91 | 92 | 93 | 94 | VALUE 95 | 180.52 96 | 97 | 98 | VALUE 99 | 212.36 100 | 101 | 102 | 103 | 104 | 105 | 106 | circle 107 | 108 | #2b8cbe 109 | 110 | 111 | 112 | 28.000000 113 | 114 | 115 | 116 | 117 | 212.3600 - 244.2000 118 | 119 | 120 | 121 | VALUE 122 | 212.36 123 | 124 | 125 | VALUE 126 | 244.2 127 | 128 | 129 | 130 | 131 | 132 | 133 | circle 134 | 135 | #045a8d 136 | 137 | 138 | 139 | 28.000000 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /geoserverexplorer/test/resources/vector.sld: -------------------------------------------------------------------------------- 1 | 2 | 3 | qgis_plugin_test_pt1 4 | 5 | qgis_plugin_test_pt1 6 | 7 | name 8 | 9 | 85.0000 - 116.8400 10 | 11 | 12 | 13 | VALUE 14 | 85 15 | 16 | 17 | VALUE 18 | 116.84 19 | 20 | 21 | 22 | 23 | 24 | 25 | circle 26 | 27 | #f1eef6 28 | 29 | 30 | 31 | 8.000000 32 | 33 | 34 | 35 | 36 | 116.8400 - 148.6800 37 | 38 | 39 | 40 | VALUE 41 | 116.84 42 | 43 | 44 | VALUE 45 | 148.68 46 | 47 | 48 | 49 | 50 | 51 | 52 | circle 53 | 54 | #bdc9e1 55 | 56 | 57 | 58 | 8.000000 59 | 60 | 61 | 62 | 63 | 148.6800 - 180.5200 64 | 65 | 66 | 67 | VALUE 68 | 148.68 69 | 70 | 71 | VALUE 72 | 180.52 73 | 74 | 75 | 76 | 77 | 78 | 79 | circle 80 | 81 | #74a9cf 82 | 83 | 84 | 85 | 8.000000 86 | 87 | 88 | 89 | 90 | 180.5200 - 212.3600 91 | 92 | 93 | 94 | VALUE 95 | 180.52 96 | 97 | 98 | VALUE 99 | 212.36 100 | 101 | 102 | 103 | 104 | 105 | 106 | circle 107 | 108 | #2b8cbe 109 | 110 | 111 | 112 | 8.000000 113 | 114 | 115 | 116 | 117 | 212.3600 - 244.2000 118 | 119 | 120 | 121 | VALUE 122 | 212.36 123 | 124 | 125 | VALUE 126 | 244.2 127 | 128 | 129 | 130 | 131 | 132 | 133 | circle 134 | 135 | #045a8d 136 | 137 | 138 | 139 | 8.000000 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /geoserverexplorer/test/resources/vector_hook.py: -------------------------------------------------------------------------------- 1 | ##[Example scripts]=group 2 | ##input=vector 3 | ##output=output vector 4 | 5 | from qgis.core import * 6 | from processing.tools.vector import VectorWriter 7 | 8 | vectorLayer = processing.getObject(input) 9 | 10 | provider = vectorLayer.dataProvider() 11 | 12 | writer = VectorWriter(output, None, provider.fields(), 13 | provider.geometryType(), vectorLayer.crs()) 14 | 15 | features = processing.features(vectorLayer) 16 | 17 | writer.addFeature(next(features.iter)) 18 | 19 | del writer 20 | -------------------------------------------------------------------------------- /geoserverexplorer/test/symbologytests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | from builtins import map 7 | import unittest 8 | import os 9 | import sys 10 | from geoserverexplorer.qgis import layers, catalog 11 | from geoserverexplorer.qgis.sldadapter import adaptGsToQgs,\ 12 | getGsCompatibleSld 13 | from qgis.core import * 14 | from qgis.utils import iface 15 | from qgis.PyQt.QtCore import * 16 | from geoserverexplorer.test import utils 17 | from geoserverexplorer.test.utils import PT1, DEM, DEM2, PT1JSON, DEMASCII,\ 18 | GEOLOGY_GROUP, GEOFORMS, LANDUSE, HOOK, WORKSPACE, WORKSPACEB 19 | import re 20 | 21 | class SymbologyTests(unittest.TestCase): 22 | ''' 23 | Tests for the CatalogWrapper class that provides additional capabilities to a gsconfig catalog 24 | Requires a Geoserver catalog running on localhost:8080 with default credentials 25 | ''' 26 | 27 | @classmethod 28 | def setUpClass(cls): 29 | ''' 'test' workspace cannot exist in the test catalog''' 30 | cls.cat = utils.getGeoServerCatalog() 31 | utils.cleanCatalog(cls.cat.catalog) 32 | cls.cat.catalog.create_workspace(WORKSPACE, "http://geoserver.com") 33 | cls.ws = cls.cat.catalog.get_workspaces(WORKSPACE)[0] 34 | projectFile = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data", "test_font.qgs") 35 | iface.addProject(projectFile) 36 | 37 | @classmethod 38 | def tearDownClass(cls): 39 | utils.cleanCatalog(cls.cat.catalog) 40 | 41 | def testVectorFontStylingUpload(self): 42 | layer = layers.resolveLayer(PT1) 43 | sld, icons = getGsCompatibleSld(layer) 44 | self.assertTrue("ttf://DejaVu Sans#0x46" in sld) 45 | 46 | ################################################################################################## 47 | 48 | 49 | def suite(): 50 | suite = unittest.makeSuite(SymbologyTests, 'test') 51 | return suite 52 | 53 | # run all tests using unittest skipping nose or testplugin 54 | def run_all(): 55 | # demo_test = unittest.TestLoader().loadTestsFromTestCase(CatalogTests) 56 | unittest.TextTestRunner(verbosity=3, stream=sys.stdout).run(suite()) 57 | 58 | # run a subset of tests using unittest skipping nose or testplugin 59 | def run_subset(): 60 | unittest.TextTestRunner(verbosity=3, stream=sys.stdout).run(suiteSubset()) 61 | -------------------------------------------------------------------------------- /geoserverexplorer/test/testplugin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # (c) 2016 Boundless, http://boundlessgeo.com 4 | # This code is licensed under the GPL 2.0 license. 5 | # 6 | import unittest 7 | import os 8 | import sys 9 | from functools import partial 10 | from geoserverexplorer.test import utils 11 | from geoserverexplorer.test.catalogtests import suiteAuth as catalogSuiteAuth 12 | from geoserverexplorer.test.catalogtests import suiteNoAuth as catalogSuiteNoAuth 13 | from geoserverexplorer.test.deletetests import suite as deleteSuite 14 | from geoserverexplorer.test.dragdroptests import suite as dragdropSuite 15 | from geoserverexplorer.test.guitests import suite as guiSuite 16 | from geoserverexplorer.test.symbologytests import suite as symbologySuite 17 | 18 | # Tests for the QGIS Tester plugin. To know more see 19 | # https://github.com/boundlessgeo/qgis-tester-plugin 20 | 21 | # Tests assume a Geoserver 2.8 instance at localhost:8080 or GSHOSTNAME:GSPORT 22 | # and default admin/geoserver credentials 23 | 24 | def functionalTests(): 25 | try: 26 | from qgistester.test import Test 27 | except: 28 | return [] 29 | 30 | allTests = [] 31 | dragdropTest = Test("Verify dragging browser element into workspace") 32 | dragdropTest.addStep("Setting up catalog and explorer", utils.setUpCatalogAndExplorer) 33 | dragdropTest.addStep("Setting up test data project", utils.loadTestData) 34 | dragdropTest.addStep("Drag layer from browser 'Project home->qgis_plugin_test_pt1.shp' into\ntest_catalog->Workspaces->test_workspace") 35 | dragdropTest.addStep("Checking new layer", utils.checkNewLayer) 36 | dragdropTest.setCleanup(utils.clean) 37 | 38 | allTests.append(dragdropTest) 39 | 40 | for testProject in utils.testProjects(): 41 | renderingTest = Test("Verify rendering of uploaded style (%s)" % os.path.basename(testProject)) 42 | renderingTest.addStep("Preparing data", partial(utils.openAndUpload, testProject)) 43 | renderingTest.addStep("Check that WMS layer is correctly rendered") 44 | renderingTest.setCleanup(utils.clean) 45 | allTests.append(renderingTest) 46 | 47 | return allTests 48 | 49 | def unitTests(): 50 | _tests = [] 51 | _tests.extend(catalogSuiteNoAuth()) 52 | _tests.extend(catalogSuiteAuth()) 53 | _tests.extend(deleteSuite()) 54 | _tests.extend(dragdropSuite()) 55 | _tests.extend(guiSuite()) 56 | _tests.extend(symbologySuite()) 57 | return _tests 58 | 59 | def settings(): 60 | return {"GSHOSTNAME": utils.GSHOSTNAME, 61 | "GSPORT": utils.GSPORT, 62 | "GSUSER":utils.GSUSER, 63 | "GSPASSWORD":utils.GSPASSWORD} 64 | 65 | def runAllUnitTests(): 66 | ''' run all unittests - No funcgtional test managed only by Tester Plugin ''' 67 | suite = unittest.TestSuite() 68 | suite.addTest(catalogSuite()) 69 | suite.addTest(deleteSuite()) 70 | suite.addTest(dragdropSuite()) 71 | suite.addTest(guiSuite()) 72 | suite.addTest(symbologySuite()) 73 | unittest.TextTestRunner(verbosity=3, stream=sys.stdout).run(suite) 74 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | pylint 2 | pep8 3 | autopep8 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # (c) 2016 Boundless, http://boundlessgeo.com 3 | # This code is licensed under the GPL 2.0 license. 4 | # 5 | python-dateutil 6 | requests==2.5.0 7 | qgiscommons 8 | httplib2 9 | 10 | # test requirements 11 | 12 | 13 | -------------------------------------------------------------------------------- /rundockertests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Run docker tests on your local machine 3 | 4 | xhost + 5 | 6 | PLUGIN_NAME="geoserverexplorer" 7 | export QGIS_VERSION_TAG="master_2" 8 | 9 | docker-compose down -v 10 | docker-compose up -d 11 | sleep 10 12 | 13 | DOCKER_RUN_COMMAND="docker-compose exec qgis-testing-environment sh -c" 14 | 15 | # Setup 16 | $DOCKER_RUN_COMMAND "qgis_setup.sh $PLUGIN_NAME" 17 | $DOCKER_RUN_COMMAND "pip install paver" 18 | $DOCKER_RUN_COMMAND "cd /tests_directory && paver setup" 19 | 20 | # Run the tests 21 | $DOCKER_RUN_COMMAND "DISPLAY=:0 qgis_testrunner.sh geoserverexplorer.test.catalogtests" 22 | $DOCKER_RUN_COMMAND "qgis_testrunner.sh geoserverexplorer.test.deletetests" 23 | $DOCKER_RUN_COMMAND "qgis_testrunner.sh geoserverexplorer.test.guitests" 24 | $DOCKER_RUN_COMMAND "qgis_testrunner.sh geoserverexplorer.test.dragdroptests" 25 | $DOCKER_RUN_COMMAND "qgis_testrunner.sh geoserverexplorer.test.pkicatalogtests" 26 | $DOCKER_RUN_COMMAND "qgis_testrunner.sh geoserverexplorer.test.pkideletetests" 27 | $DOCKER_RUN_COMMAND "qgis_testrunner.sh geoserverexplorer.test.pkiguitests" 28 | $DOCKER_RUN_COMMAND "qgis_testrunner.sh geoserverexplorer.test.pkidragdroptests" 29 | $DOCKER_RUN_COMMAND "qgis_testrunner.sh geoserverexplorer.test.pkiowstests" 30 | -------------------------------------------------------------------------------- /travis_secrets.tar.gz.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/planetfederal/qgis-geoserver-plugin/95e3fd13dbcbefce40d36a037bc3529678659450/travis_secrets.tar.gz.enc --------------------------------------------------------------------------------