-
Notifications
You must be signed in to change notification settings - Fork 0
/
functions_style.py
157 lines (126 loc) · 6.72 KB
/
functions_style.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# -*- coding: utf-8 -*-
# network api functions to be added to the call path registry
#
# the functions should take two arguments: the first is the 'iface' variable
# which gives access to QGIS components, the second a NetworkAPIRequest object.
#
# the functions should return an instance of NetworkAPIResult
from .functions import qgis_layer_by_id
from .registry import networkapi, NetworkAPIResult, toGeoJSON
from PyQt4.QtXml import QDomDocument
# GET/POST overloading for reading/writing style XML
@networkapi('/qgis/mapLayer/style')
def mapLayer_style(iface, request):
"""
Retrieve or set the style for the layer with the given id.
If the request is a HTTP POST request, attempts to set the XML style description of the given layer to the value of the request body. In all cases, the response will contain the XML style definition for the layer after applying the change (which might be the same as the request body if applying the new style was unsuccessful).
HTTP query arguments:
id (string): ID of layer whose stylesheet to retrieve or set
Returns:
The XML style definition for the layer with the given ID.
"""
layer = qgis_layer_by_id(request.args['id'])
if request.command == 'POST':
doc = QDomDocument('xml')
# FIXME it appears that layer.readStyle() ALWAYS return True (at least
# for VectorLayers) -- error messages are written into the second
# (string pointer) argument of the method, which I'm not sure how to
# access from Python...
# Another workaround would be to re-retrieve the XML style after
# setting it and flagging up if there is a difference between the two
# (i.e. if the change was not applied)
if not doc.setContent(request.headers.get_payload()) or not layer.readStyle(doc, None):
return NetworkAPIResult(status=NetworkAPIResult.INVALID_ARGUMENTS)
doc = QDomDocument('xml')
root = doc.createElement('pipe')
doc.appendChild(root)
# TODO check return value (although this really shouldn't fail..)
layer.writeStyle(root, doc, '')
# QDomDocument is automatically processed by server
return NetworkAPIResult(doc)
@networkapi('/qgis/mapLayer/styleURI')
def mapLayer_styleURI(iface, request):
"""Retrieve the style URI for a layer."""
location = qgis_layer_by_id(request.args['id']).styleURI()
# TODO check if file exists, if so transfer content
return NetworkAPIResult(location)
@networkapi('/qgis/mapLayer/loadDefaultStyle')
def mapLayer_loadDefaultStyle(iface, request):
"""Retrieve the default style for this layer if one exists.
Retrieve the default style for this layer if one exists, either as a .qml file on disk or as a record in the users style table in their personal qgis.db.
HTTP query arguments:
id (string): ID of the layer whose default style to load
Returns:
A string with any status messages
"""
return NetworkAPIResult(qgis_layer_by_id(request.args['id']).loadDefaultStyle(None))
@networkapi('/qgis/mapLayer/loadNamedStyle')
def mapLayer_loadNamedStyle(iface, request):
"""Retrieve a named style for this layer.
Retrieve a named style for this layer if one exists (either as a .qml file on disk or as a record in the users style table in their personal qgis.db)
HTTP query arguments:
id (string): ID of the layer whose style to load
uri (string): the file name or other URI for the style file. First an attempt will be made to see if this is a file and load that, if that fails the qgis.db styles table will be consulted to see if there is a style who's key matches the URI.
Returns:
A string with any status messages
"""
layer = qgis_layer_by_id(request.args['id'])
return NetworkAPIResult(layer.loadNamedStyle(request.args['uri'], None))
@networkapi('/qgis/mapLayer/saveNamedStyle')
def mapLayer_saveNamedStyle(iface, request):
"""Save the properties of this layer as a named style (either as a .qml file on disk or as a record in the users style table in their personal qgis.db)
HTTP query arguments:
id (string): ID of the layer whose style to save
uri (string): the file name or other URI for the style file. First an attempt will be made to see if this is a file and save to that, if that fails the qgis.db styles table will be used to create a style entry who's key matches the URI.
Returns:
A string with any status messages
"""
layer = qgis_layer_by_id(request.args['id'])
return NetworkAPIResult(layer.saveNamedStyle(request.args['uri'], None))
from qgis.core import QgsRasterLayer, QgsVectorLayer, QgsFeatureRendererV2
# for dynamic loading of raster renderer classes
from importlib import import_module
qgiscore = import_module('qgis.core')
@networkapi('/qgis/mapLayer/renderer')
def mapLayer_renderer(iface, request):
"""
Retrieve or set the given layer's renderer specification.
HTTP query arguments:
id (string): ID of the desired layer.
Returns:
The QGIS XML representation of the given layer's renderer.
"""
layer = qgis_layer_by_id(request.args['id'])
if request.command == 'POST':
# update renderer based on content XML
doc = QDomDocument('xml')
if not doc.setContent(request.headers.get_payload()):
# must be malformed xml?
return NetworkAPIResult(status=NetworkAPIResult.INVALID_ARGUMENTS)
if isinstance(layer, QgsVectorLayer):
# *vector* feature renderers can be instantiated/loaded by a
# central factory method that instantiates the right renderer class
renderer = QgsFeatureRendererV2.load(doc.documentElement())
# TODO additional error checking necessary?
layer.setRendererV2(renderer)
else:
# the same doesn't seem to be available for raster renderers: get
# root element and find the right class based on the tag name
root = doc.documentElement()
class_ = getattr(qgiscore, root.tagName())
# then instantiate the class based on the renderer spec from the
# child element (while retaining the same raster input)
renderer = class_.create(root.firstChildElement('rasterrenderer'), layer.renderer().input())
layer.setRenderer(renderer)
layer.triggerRepaint()
# read and return currently set renderer spec
doc = QDomDocument('xml')
if isinstance(layer, QgsVectorLayer):
ele = layer.rendererV2().save(doc)
doc.appendChild(ele)
else:
# store raster renderer class in root element name
ele = doc.createElement(type(layer.renderer()).__name__)
doc.appendChild(ele)
layer.renderer().writeXML(doc, ele)
return NetworkAPIResult(doc)