GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ogc_services.py
Go to the documentation of this file.
1 """!
2 @package module.ogc_services
3 
4 @brief Dialogs for OGC services
5 
6 Currently only implemeted WMS.
7 
8 List of classes:
9  - ogc_services::WMSDialog
10  - ogc_services::LayersList
11 
12 (C) 2009-2011 by the GRASS Development Team
13 
14 This program is free software under the GNU General Public License
15 (>=v2). Read the file COPYING that comes with GRASS for details.
16 
17 @author Martin Landa <landa.martin gmail.com>
18 """
19 
20 import wx
21 from wx.gizmos import TreeListCtrl
22 import wx.lib.mixins.listctrl as listmix
23 
24 from core.gcmd import GError, RunCommand
25 from core.settings import UserSettings
26 from grass.script.core import find_program
27 
28 class WMSDialog(wx.Dialog):
29  def __init__(self, parent, service = 'wms',
30  id=wx.ID_ANY,
31  style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
32  """!Dialog to import data from WMS server"""
33  self.parent = parent # GMFrame
34  self.service = service # currently only WMS is implemented
35 
36  wx.Dialog.__init__(self, parent, id, style=style)
37  if self.service == 'wms':
38  self.SetTitle(_("Import data from WMS server"))
39 
40  self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
41 
42  self.__createWidgets()
43 
44  self.__doLayout()
45 
46  self.SetMinSize((550, 400))
47 
48  def __createWidgets(self):
49  """!Create dialog widgets"""
50  #
51  # settings
52  #
53  self.settingsBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
54  label = _(" Server settings "))
55 
56  self.serverText = wx.StaticText(parent = self.panel, id = wx.ID_ANY, label = _("Server:"))
57  self.server = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY)
58 
59  #
60  # list of layers
61  #
62  self.layersBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
63  label=_(" List of layers "))
64 
65  self.list = LayersList(self.panel)
66  self.list.LoadData()
67 
68  self.add = wx.CheckBox(parent=self.panel, id=wx.ID_ANY,
69  label=_("Add imported layers into layer tree"))
70  self.add.SetValue(UserSettings.Get(group='cmd', key='addNewLayer', subkey='enabled'))
71 
72  #
73  # buttons
74  #
75  # cancel
76  self.btn_cancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
77  self.btn_cancel.SetToolTipString(_("Close dialog"))
78  # connect
79  self.btn_connect = wx.Button(parent = self.panel, id = wx.ID_ANY, label = _("&Connect"))
80  self.btn_connect.SetToolTipString(_("Connect to the server"))
81  self.btn_connect.SetDefault()
82  if not self.server.GetValue():
83  self.btn_connect.Enable(False)
84  # import
85  self.btn_import = wx.Button(parent = self.panel, id = wx.ID_OK, label = _("&Import"))
86  self.btn_import.SetToolTipString(_("Import selected layers"))
87  self.btn_import.Enable(False)
88 
89  #
90  # bindings
91  #
92  self.btn_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)
93  self.btn_connect.Bind(wx.EVT_BUTTON, self.OnConnect)
94  self.server.Bind(wx.EVT_TEXT, self.OnServer)
95 
96  def __doLayout(self):
97  """!Do dialog layout"""
98  dialogSizer = wx.BoxSizer(wx.VERTICAL)
99 
100  #
101  # settings
102  #
103  settingsSizer = wx.StaticBoxSizer(self.settingsBox, wx.HORIZONTAL)
104 
105  gridSizer = wx.FlexGridSizer(cols=2, vgap=5, hgap=5)
106 
107  gridSizer.Add(item=self.serverText,
108  flag=wx.ALIGN_CENTER_VERTICAL)
109  gridSizer.AddGrowableCol(1)
110  gridSizer.Add(item=self.server,
111  flag=wx.EXPAND | wx.ALL)
112 
113  settingsSizer.Add(item=gridSizer, proportion=1,
114  flag=wx.EXPAND | wx.ALL)
115 
116  dialogSizer.Add(item=settingsSizer, proportion=0,
117  flag=wx.ALL | wx.EXPAND, border=5)
118 
119  #
120  # list of layers
121  #
122  layersSizer = wx.StaticBoxSizer(self.layersBox, wx.HORIZONTAL)
123 
124  layersSizer.Add(item=self.list, proportion=1,
125  flag=wx.ALL | wx.EXPAND, border=5)
126 
127  dialogSizer.Add(item=layersSizer, proportion=1,
128  flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
129 
130  dialogSizer.Add(item=self.add, proportion=0,
131  flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
132 
133  #
134  # buttons
135  #
136  btnsizer = wx.BoxSizer(orient=wx.HORIZONTAL)
137 
138  btnsizer.Add(item=self.btn_cancel, proportion=0,
139  flag=wx.ALL | wx.ALIGN_CENTER,
140  border=10)
141 
142  btnsizer.Add(item=self.btn_connect, proportion=0,
143  flag=wx.ALL | wx.ALIGN_CENTER,
144  border=10)
145 
146  btnsizer.Add(item=self.btn_import, proportion=0,
147  flag=wx.ALL | wx.ALIGN_CENTER,
148  border=10)
149 
150  dialogSizer.Add(item=btnsizer, proportion=0,
151  flag=wx.ALIGN_CENTER)
152 
153  self.panel.SetAutoLayout(True)
154  self.panel.SetSizer(dialogSizer)
155  dialogSizer.Fit(self.panel)
156  self.Layout()
157 
158  def OnCancel(self, event):
159  """!Button 'Cancel' pressed -> close the dialog"""
160  self.Close()
161 
162  def OnConnect(self, event):
163  """!Button 'Connect' pressed"""
164  # 'r.in.wms -l' output changes depending on the parser used.
165  # the parsing below depends on the cleaner `xml2` version.
166  if not find_program('xml2'):
167  GError(_("The 'xml2' parser is required, please install it "
168  "first. You may also try running r.in.wms directly "
169  "from the command line."))
170  return
171 
172  server = self.server.GetValue()
173  if not server:
174  self.btn_import.Enable(False)
175  return # not reachable
176 
177  layers = {}
178  ret = RunCommand('r.in.wms',
179  quiet = True,
180  parent = self,
181  read = True,
182  flags = 'l',
183  mapserver = server)
184 
185  if not ret:
186  self.list.LoadData()
187  self.btn_import.Enable(False)
188  return # no layers found
189 
190  lastLayer = lastStyle = ''
191  for line in ret.splitlines():
192  try:
193  key, value = line.split(':', 1)
194  except ValueError:
195  continue
196  key = key.strip().lower()
197  value = value.strip()
198 
199  if key == 'layer':
200  layers[value] = {}
201  lastLayer = value
202  elif key == 'title':
203  if lastLayer and 'title' not in layers[lastLayer]:
204  layers[lastLayer][key] = value.decode('utf8')
205  elif key == 'style':
206  if lastLayer:
207  if 'style' not in layers[lastLayer]:
208  layers[lastLayer]['style'] = {}
209  layers[lastLayer]['style'][value] = ''
210  lastStyle = value
211  elif key == 'style title':
212  if lastLayer:
213  layers[lastLayer]['style'][lastStyle] = value
214 
215  # update list of layers
216  self.list.LoadData(layers)
217 
218  if len(layers.keys()) > 0:
219  self.btn_import.Enable(True)
220  else:
221  self.btn_import.Enable(False)
222 
223  def OnServer(self, event):
224  """!Server settings changed"""
225  value = event.GetString()
226  if value:
227  self.btn_connect.Enable(True)
228  else:
229  self.btn_connect.Enable(False)
230 
231  def GetLayers(self):
232  """!Get list of selected layers/styles to be imported"""
233  return self.list.GetSelectedLayers()
234 
235  def GetSettings(self):
236  """!Get connection settings"""
237  return { 'server' : self.server.GetValue() }
238 
239 class LayersList(TreeListCtrl, listmix.ListCtrlAutoWidthMixin):
240  def __init__(self, parent, pos=wx.DefaultPosition):
241  """!List of layers to be imported (dxf, shp...)"""
242  self.parent = parent
243 
244  TreeListCtrl.__init__(self, parent, wx.ID_ANY,
245  style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT |
246  wx.TR_FULL_ROW_HIGHLIGHT | wx.TR_MULTIPLE)
247 
248  # setup mixins
249  listmix.ListCtrlAutoWidthMixin.__init__(self)
250 
251  self.AddColumn(_('Layer / Style'))
252  self.AddColumn(_('Title'))
253  self.SetMainColumn(0) # column with the tree
254  self.SetColumnWidth(0, 175)
255 
256  self.root = None
257 
258  def LoadData(self, data = {}):
259  """!Load data into list"""
260  # detete first all items
261  self.DeleteAllItems()
262  self.root = self.AddRoot(_("Layers"))
263 
264  layers = data.keys()
265  if not layers:
266  return
267 
268  layers.sort()
269 
270  for layer in layers:
271  title = data[layer]['title']
272  lchild = self.AppendItem(self.root, layer)
273  self.SetItemText(lchild, title, 1)
274  if 'style' in data[layer]:
275  styles = data[layer]['style'].keys()
276  if not styles:
277  continue
278  styles.sort()
279  for style in styles:
280  title = data[layer]['style'][style]
281  schild = self.AppendItem(lchild, style)
282  self.SetItemText(schild, title, 1)
283 
284  self.Expand(self.root)
285 
286  def GetItemCount(self):
287  """!Required for listmix.ListCtrlAutoWidthMixin"""
288  return 0
289 
290  def GetCountPerPage(self):
291  """!Required for listmix.ListCtrlAutoWidthMixin"""
292  return 0
293 
294  def GetSelectedLayers(self):
295  """!Get selected layers/styles"""
296  layers = dict()
297 
298  for item in self.GetSelections():
299  parent = self.GetItemParent(item)
300  if parent == self.root: # -> layer
301  layer = self.GetItemText(item, 0)
302  layers[layer] = list()
303  sitem, cookie = self.GetFirstChild(item)
304  while sitem:
305  layers[layer].append(self.GetItemText(sitem, 0))
306  sitem, cookie = self.GetNextChild(item, cookie)
307  else: # -> style
308  layer = self.GetItemText(parent, 0)
309  layers[layer] = list()
310  layers[layer].append(self.GetItemText(item, 0))
311 
312  return layers
def GetSelectedLayers
Get selected layers/styles.
wxGUI command interface
def find_program
Attempt to run a program, with optional arguments.
Definition: core.py:972
def GetLayers
Get list of selected layers/styles to be imported.
def OnServer
Server settings changed.
GRASS Python scripting module (core functions)
def GetCountPerPage
Required for listmix.ListCtrlAutoWidthMixin.
def __createWidgets
Create dialog widgets.
Definition: ogc_services.py:48
def GetSettings
Get connection settings.
def LoadData
Load data into list.
def GetItemCount
Required for listmix.ListCtrlAutoWidthMixin.
def OnCancel
Button &#39;Cancel&#39; pressed -&gt; close the dialog.
def __doLayout
Do dialog layout.
Definition: ogc_services.py:96
def OnConnect
Button &#39;Connect&#39; pressed.
def __init__
Dialog to import data from WMS server.
Definition: ogc_services.py:31
Default GUI settings.
def RunCommand
Run GRASS command.
Definition: gcmd.py:625
def __init__
List of layers to be imported (dxf, shp...)