GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gselect.py
Go to the documentation of this file.
1 """!
2 @package gui_core.gselect
3 
4 @brief Custom control that selects elements
5 
6 Classes:
7  - gselect::Select
8  - gselect::VectorSelect
9  - gselect::TreeCrtlComboPopup
10  - gselect::VectorDBInfo
11  - gselect::LayerSelect
12  - gselect::DriverSelect
13  - gselect::DatabaseSelect
14  - gselect::TableSelect
15  - gselect::ColumnSelect
16  - gselect::DbaseSelect
17  - gselect::LocationSelect
18  - gselect::MapsetSelect
19  - gselect::SubGroupSelect
20  - gselect::FormatSelect
21  - gselect::GdalSelect
22  - gselect::ProjSelect
23  - gselect::ElementSelect
24 
25 (C) 2007-2011 by the GRASS Development Team
26 
27 This program is free software under the GNU General Public License
28 (>=v2). Read the file COPYING that comes with GRASS for details.
29 
30 @author Michael Barton
31 @author Martin Landa <landa.martin gmail.com>
32 @author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
33 """
34 
35 import os
36 import sys
37 import glob
38 
39 import wx
40 import wx.combo
41 import wx.lib.filebrowsebutton as filebrowse
42 from wx.lib.newevent import NewEvent
43 
44 from core import globalvar
45 
46 import grass.script as grass
47 from grass.script import task as gtask
48 
49 from core.gcmd import RunCommand, GError, GMessage
50 from core.utils import GetListOfLocations, GetListOfMapsets, GetFormats
51 from core.utils import GetSettingsPath, GetValidLayerName, ListSortLower, GetAllVectorLayers
52 from core.settings import UserSettings
53 from core.debug import Debug
54 
55 wxGdalSelect, EVT_GDALSELECT = NewEvent()
56 
57 class Select(wx.combo.ComboCtrl):
58  def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
59  type = None, multiple = False, nmaps = 1,
60  mapsets = None, updateOnPopup = True, onPopup = None,
61  fullyQualified = True):
62  """!Custom control to create a ComboBox with a tree control to
63  display and select GIS elements within acessible mapsets.
64  Elements can be selected with mouse. Can allow multiple
65  selections, when argument <em>multiple</em> is True. Multiple
66  selections are separated by commas.
67 
68  @param type type of GIS elements ('raster, 'vector', ...)
69  @param multiple True for multiple input
70  @param nmaps number of maps to be entered
71  @param mapsets force list of mapsets (otherwise search path)
72  @param updateOnPopup True for updating list of elements on popup
73  @param onPopup function to be called on Popup
74  @param fullyQualified True to provide fully qualified names (map@mapset)
75  """
76  wx.combo.ComboCtrl.__init__(self, parent=parent, id=id, size=size)
77  self.GetChildren()[0].SetName("Select")
78  self.GetChildren()[0].type = type
79 
81  self.SetPopupControl(self.tcp)
82  self.SetPopupExtents(0, 100)
83  if type:
84  self.tcp.SetData(type = type, mapsets = mapsets,
85  multiple = multiple, nmaps = nmaps,
86  updateOnPopup = updateOnPopup, onPopup = onPopup,
87  fullyQualified = fullyQualified)
88  self.GetChildren()[0].Bind(wx.EVT_KEY_UP, self.OnKeyUp)
89 
90  def OnKeyUp(self, event):
91  """!Shows popupwindow if down arrow key is released"""
92  if event.GetKeyCode() == wx.WXK_DOWN and not self.IsPopupShown():
93  self.ShowPopup()
94  else:
95  event.Skip()
96 
97  def SetElementList(self, type, mapsets = None):
98  """!Set element list
99 
100  @param type GIS element type
101  @param mapsets list of acceptable mapsets (None for all in search path)
102  """
103  self.tcp.SetData(type = type, mapsets = mapsets)
104 
105  def GetElementList(self):
106  """!Load elements"""
107  self.tcp.GetElementList()
108 
109  def SetType(self, etype, multiple = False, nmaps = 1,
110  mapsets = None, updateOnPopup = True, onPopup = None):
111  """!Param set element type for widget
112 
113  @param etype element type, see gselect.ElementSelect
114  """
115  self.tcp.SetData(type = etype, mapsets = mapsets,
116  multiple = multiple, nmaps = nmaps,
117  updateOnPopup = updateOnPopup, onPopup = onPopup)
118 
120  def __init__(self, parent, ftype, **kwargs):
121  """!Custom to create a ComboBox with a tree control to display and
122  select vector maps. You can filter the vector maps. If you
123  don't need this feature use Select class instead
124 
125  @ftype filter vector maps based on feature type
126  """
127  Select.__init__(self, parent = parent, id = wx.ID_ANY,
128  type = 'vector', **kwargs)
129 
130  self.ftype = ftype
131 
132  # remove vector maps which do not contain given feature type
133  self.tcp.SetFilter(self._isElement)
134 
135  def _isElement(self, vectorName):
136  """!Check if element should be filtered out"""
137  try:
138  if int(grass.vector_info_topo(vectorName)[self.ftype]) < 1:
139  return False
140  except KeyError:
141  return False
142 
143  return True
144 
145 class TreeCtrlComboPopup(wx.combo.ComboPopup):
146  """!Create a tree ComboBox for selecting maps and other GIS elements
147  in accessible mapsets within the current location
148  """
149  # overridden ComboPopup methods
150  def Init(self):
151  self.value = [] # for multiple is False -> len(self.value) in [0,1]
152  self.curitem = None
153  self.multiple = False
154  self.nmaps = 1
155  self.type = None
156  self.mapsets = None
157  self.updateOnPopup = True
158  self.onPopup = None
159  self.fullyQualified = True
160 
161  self.SetFilter(None)
162 
163  def Create(self, parent):
164  self.seltree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT
165  |wx.TR_HAS_BUTTONS
166  |wx.TR_SINGLE
167  |wx.TR_LINES_AT_ROOT
168  |wx.SIMPLE_BORDER
169  |wx.TR_FULL_ROW_HIGHLIGHT)
170  self.seltree.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
171  self.seltree.Bind(wx.EVT_MOTION, self.OnMotion)
172  self.seltree.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
173  # the following dummy handler are needed to keep tree events
174  # from propagating up to the parent GIS Manager layer tree
175  self.seltree.Bind(wx.EVT_TREE_ITEM_EXPANDING, lambda x: None)
176  self.seltree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, lambda x: None)
177  self.seltree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, lambda x: None)
178  self.seltree.Bind(wx.EVT_TREE_SEL_CHANGED, lambda x: None)
179  self.seltree.Bind(wx.EVT_TREE_DELETE_ITEM, lambda x: None)
180  self.seltree.Bind(wx.EVT_TREE_BEGIN_DRAG, lambda x: None)
181  self.seltree.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, lambda x: None)
182 
183  def GetControl(self):
184  return self.seltree
185 
186  def GetStringValue(self):
187  """!Get value as a string separated by commas"""
188  return ','.join(self.value)
189 
190  def SetFilter(self, filter):
191  """!Set filter for GIS elements, see e.g. VectorSelect"""
192  self.filterElements = filter
193 
194  def OnPopup(self, force = False):
195  """!Limited only for first selected"""
196  if not force and not self.updateOnPopup:
197  return
198  if self.onPopup:
199  selected, exclude = self.onPopup(self.type)
200  else:
201  selected = None
202  exclude = False
203 
204  self.GetElementList(selected, exclude)
205 
206  # selects map starting according to written text
207  inputText = self.GetCombo().GetValue().strip()
208  if inputText:
209  root = self.seltree.GetRootItem()
210  match = self.FindItem(root, inputText, startLetters = True)
211  self.seltree.EnsureVisible(match)
212  self.seltree.SelectItem(match)
213 
214 
215  def GetElementList(self, elements = None, exclude = False):
216  """!Get filtered list of GIS elements in accessible mapsets
217  and display as tree with all relevant elements displayed
218  beneath each mapset branch
219  """
220  # update list
221  self.seltree.DeleteAllItems()
222  self._getElementList(self.type, self.mapsets, elements, exclude)
223 
224  if len(self.value) > 0:
225  root = self.seltree.GetRootItem()
226  if not root:
227  return
228  item = self.FindItem(root, self.value[0])
229  try:
230  self.seltree.EnsureVisible(item)
231  self.seltree.SelectItem(item)
232  except:
233  pass
234 
235  def SetStringValue(self, value):
236  # this assumes that item strings are unique...
237  root = self.seltree.GetRootItem()
238  if not root:
239  return
240  found = self.FindItem(root, value)
241  winValue = self.GetCombo().GetValue().strip(',')
242  self.value = []
243  if winValue:
244  self.value = winValue.split(',')
245 
246  if found:
247  self.value.append(found)
248  self.seltree.SelectItem(found)
249 
250  def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
251  """!Reads UserSettings to get height (which was 200 in old implementation).
252  """
253  height = UserSettings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'value')
254  return wx.Size(minWidth, min(height, maxHeight))
255 
256  def _getElementList(self, element, mapsets = None, elements = None, exclude = False):
257  """!Get list of GIS elements in accessible mapsets and display as tree
258  with all relevant elements displayed beneath each mapset branch
259 
260  @param element GIS element
261  @param mapsets list of acceptable mapsets (None for all mapsets in search path)
262  @param elements list of forced GIS elements
263  @param exclude True to exclude, False for forcing the list (elements)
264  """
265  # get current mapset
266  curr_mapset = grass.gisenv()['MAPSET']
267 
268  # map element types to g.mlist types
269  elementdict = {'cell':'rast',
270  'raster':'rast',
271  'rast':'rast',
272  'raster files':'rast',
273  'grid3':'rast3d',
274  'rast3d':'rast3d',
275  '3d-raster':'rast3d',
276  'raster3d':'rast3d',
277  'raster3D files':'rast3d',
278  'vector':'vect',
279  'vect':'vect',
280  'binary vector files':'vect',
281  'dig':'oldvect',
282  'oldvect':'oldvect',
283  'old vector':'oldvect',
284  'dig_ascii':'asciivect',
285  'asciivect':'asciivect',
286  'asciivector':'asciivect',
287  'ascii vector files':'asciivect',
288  'icons':'icon',
289  'icon':'icon',
290  'paint icon files':'icon',
291  'paint/labels':'labels',
292  'labels':'labels',
293  'label':'labels',
294  'paint label files':'labels',
295  'site_lists':'sites',
296  'sites':'sites',
297  'site list':'sites',
298  'site list files':'sites',
299  'windows':'region',
300  'region':'region',
301  'region definition':'region',
302  'region definition files':'region',
303  'windows3d':'region3d',
304  'region3d':'region3d',
305  'region3D definition':'region3d',
306  'region3D definition files':'region3d',
307  'group':'group',
308  'imagery group':'group',
309  'imagery group files':'group',
310  '3d.view':'3dview',
311  '3dview':'3dview',
312  '3D viewing parameters':'3dview',
313  '3D view parameters':'3dview'}
314 
315  if element not in elementdict:
316  self.AddItem(_('Not selectable element'))
317  return
318 
319  if globalvar.have_mlist:
320  filesdict = grass.mlist_grouped(elementdict[element],
321  check_search_path = False)
322  else:
323  filesdict = grass.list_grouped(elementdict[element],
324  check_search_path = False)
325 
326  # list of mapsets in current location
327  if mapsets is None:
328  mapsets = grass.mapsets(search_path = True)
329 
330  # current mapset first
331  if curr_mapset in mapsets and mapsets[0] != curr_mapset:
332  mapsets.remove(curr_mapset)
333  mapsets.insert(0, curr_mapset)
334 
335  first_mapset = None
336  for mapset in mapsets:
337  mapset_node = self.AddItem(_('Mapset') + ': ' + mapset)
338  if not first_mapset:
339  first_mapset = mapset_node
340 
341  self.seltree.SetItemTextColour(mapset_node, wx.Colour(50, 50, 200))
342  if mapset not in filesdict:
343  continue
344  try:
345  elem_list = filesdict[mapset]
346  elem_list.sort()
347  for elem in elem_list:
348  if elem != '':
349  fullqElem = elem + '@' + mapset
350  if elements is not None:
351  if (exclude and fullqElem in elements) or \
352  (not exclude and fullqElem not in elements):
353  continue
354 
355  if self.filterElements:
356  if self.filterElements(fullqElem):
357  self.AddItem(elem, parent = mapset_node)
358  else:
359  self.AddItem(elem, parent = mapset_node)
360  except StandardError, e:
361  sys.stderr.write(_("GSelect: invalid item: %s") % e)
362  continue
363 
364  if self.seltree.ItemHasChildren(mapset_node):
365  sel = UserSettings.Get(group='appearance', key='elementListExpand',
366  subkey='selection')
367  collapse = True
368 
369  if sel == 0: # collapse all except PERMANENT and current
370  if mapset in ('PERMANENT', curr_mapset):
371  collapse = False
372  elif sel == 1: # collapse all except PERMANENT
373  if mapset == 'PERMANENT':
374  collapse = False
375  elif sel == 2: # collapse all except current
376  if mapset == curr_mapset:
377  collapse = False
378  elif sel == 3: # collapse all
379  pass
380  elif sel == 4: # expand all
381  collapse = False
382 
383  if collapse:
384  self.seltree.Collapse(mapset_node)
385  else:
386  self.seltree.Expand(mapset_node)
387 
388  if first_mapset:
389  # select first mapset (MSW hack)
390  self.seltree.SelectItem(first_mapset)
391 
392  # helpers
393  def FindItem(self, parentItem, text, startLetters = False):
394  """!Finds item with given name or starting with given text"""
395  startletters = startLetters
396  item, cookie = self.seltree.GetFirstChild(parentItem)
397  while wx.TreeItemId.IsOk(item):
398  if self.seltree.GetItemText(item) == text:
399  return item
400  if self.seltree.ItemHasChildren(item):
401  item = self.FindItem(item, text, startLetters = startletters)
402  if wx.TreeItemId.IsOk(item):
403  return item
404  elif startletters and self.seltree.GetItemText(item).startswith(text.split('@', 1)[0]):
405  return item
406  item, cookie = self.seltree.GetNextChild(parentItem, cookie)
407  return wx.TreeItemId()
408 
409  def AddItem(self, value, parent=None):
410  if not parent:
411  root = self.seltree.GetRootItem()
412  if not root:
413  root = self.seltree.AddRoot("<hidden root>")
414  parent = root
415 
416  item = self.seltree.AppendItem(parent, text=value)
417  return item
418 
419  # able to recieve only wx.EVT_KEY_UP
420  def OnKeyUp(self, event):
421  """!Enables to select items using keyboard"""
422 
423  item = self.seltree.GetSelection()
424  if event.GetKeyCode() == wx.WXK_DOWN:
425  self.seltree.SelectItem(self.seltree.GetNextVisible(item))
426 
427  # problem with GetPrevVisible
428  elif event.GetKeyCode() == wx.WXK_UP:
429  if self.seltree.ItemHasChildren(item) and self.seltree.IsExpanded(self.seltree.GetPrevSibling(item)):
430  itemPrev = self.seltree.GetLastChild(self.seltree.GetPrevSibling(item))
431  else:
432  itemPrev = self.seltree.GetPrevSibling(item)
433  if not wx.TreeItemId.IsOk(itemPrev):
434  itemPrev = self.seltree.GetItemParent(item)
435  if item == self.seltree.GetFirstChild(self.seltree.GetRootItem())[0]:
436  itemPrev = item
437  self.seltree.SelectItem(itemPrev)
438 
439  # selects first item starting with the written text in next mapset
440  elif event.GetKeyCode() == wx.WXK_TAB:
441  selected = self.seltree.GetSelection()
442  if self.seltree.ItemHasChildren(selected):
443  parent = selected
444  else:
445  parent = self.seltree.GetItemParent(selected)
446  nextSibling = self.seltree.GetNextSibling(parent)
447  if wx.TreeItemId.IsOk(nextSibling):
448  match = self.FindItem(nextSibling, self.GetCombo().GetValue().strip(), True)
449  else:
450  match = self.FindItem(self.seltree.GetFirstChild(self.seltree.GetItemParent(parent))[0],
451  self.GetCombo().GetValue().strip(), True)
452  self.seltree.SelectItem(match)
453 
454  elif event.GetKeyCode() == wx.WXK_RIGHT:
455  if self.seltree.ItemHasChildren(item):
456  self.seltree.Expand(item)
457 
458  elif event.GetKeyCode() == wx.WXK_LEFT:
459  if self.seltree.ItemHasChildren(item):
460  self.seltree.Collapse(item)
461 
462  elif event.GetKeyCode() == wx.WXK_ESCAPE:
463  self.Dismiss()
464 
465  elif event.GetKeyCode() == wx.WXK_RETURN:
466  if self.seltree.GetRootItem() == self.seltree.GetItemParent(item):
467  self.value = []
468  else:
469  mapsetItem = self.seltree.GetItemParent(item)
470  fullName = self.seltree.GetItemText(item)
471  if self.fullyQualified:
472  fullName += '@' + self.seltree.GetItemText(mapsetItem).split(':', -1)[1].strip()
473 
474  if self.multiple:
475  self.value.append(fullName)
476  else:
477  if self.nmaps > 1: # see key_desc
478  if len(self.value) >= self.nmaps:
479  self.value = [fullName]
480  else:
481  self.value.append(fullName)
482  else:
483  self.value = [fullName]
484 
485  self.Dismiss()
486 
487  def OnMotion(self, evt):
488  """!Have the selection follow the mouse, like in a real combobox
489  """
490  item, flags = self.seltree.HitTest(evt.GetPosition())
491  if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
492  self.seltree.SelectItem(item)
493  self.curitem = item
494  evt.Skip()
495 
496  def OnLeftDown(self, evt):
497  """!Do the combobox selection
498  """
499  item, flags = self.seltree.HitTest(evt.GetPosition())
500  if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
501  self.curitem = item
502 
503  if self.seltree.GetRootItem() == self.seltree.GetItemParent(item):
504  evt.Skip()
505  return
506 
507  mapsetItem = self.seltree.GetItemParent(item)
508  fullName = self.seltree.GetItemText(item)
509  if self.fullyQualified:
510  fullName += '@' + self.seltree.GetItemText(mapsetItem).split(':', -1)[1].strip()
511 
512  if self.multiple:
513  self.value.append(fullName)
514  else:
515  if self.nmaps > 1: # see key_desc
516  if len(self.value) >= self.nmaps:
517  self.value = [fullName]
518  else:
519  self.value.append(fullName)
520  else:
521  self.value = [fullName]
522 
523  self.Dismiss()
524 
525  evt.Skip()
526 
527  def SetData(self, **kargs):
528  """!Set object properties"""
529  if 'type' in kargs:
530  self.type = kargs['type']
531  if 'mapsets' in kargs:
532  self.mapsets = kargs['mapsets']
533  if 'multiple' in kargs:
534  self.multiple = kargs['multiple']
535  if 'nmaps' in kargs:
536  self.nmaps = kargs['nmaps']
537  if 'updateOnPopup' in kargs:
538  self.updateOnPopup = kargs['updateOnPopup']
539  if 'onPopup' in kargs:
540  self.onPopup = kargs['onPopup']
541  if 'fullyQualified' in kargs:
542  self.fullyQualified = kargs['fullyQualified']
543 
544  def GetType(self):
545  """!Get element type
546  """
547  return self.type
548 
550  """!Class providing information about attribute tables
551  linked to a vector map"""
552  def __init__(self, map):
553  self.map = map
554 
555  # dictionary of layer number and associated (driver, database, table)
556  self.layers = {}
557  # dictionary of table and associated columns (type, length, values, ids)
558  self.tables = {}
559 
560  if not self._CheckDBConnection(): # -> self.layers
561  return
562 
563  self._DescribeTables() # -> self.tables
564 
565  def _CheckDBConnection(self):
566  """!Check DB connection"""
567  nuldev = file(os.devnull, 'w+')
568  self.layers = grass.vector_db(map=self.map, stderr=nuldev)
569  nuldev.close()
570 
571  if (len(self.layers.keys()) == 0):
572  return False
573 
574  return True
575 
576  def _DescribeTables(self):
577  """!Describe linked tables"""
578  for layer in self.layers.keys():
579  # determine column names and types
580  table = self.layers[layer]["table"]
581  columns = {} # {name: {type, length, [values], [ids]}}
582  i = 0
583  Debug.msg(1, "gselect.VectorDBInfo._DescribeTables(): table=%s driver=%s database=%s" % \
584  (self.layers[layer]["table"], self.layers[layer]["driver"],
585  self.layers[layer]["database"]))
586  for item in grass.db_describe(table = self.layers[layer]["table"],
587  driver = self.layers[layer]["driver"],
588  database = self.layers[layer]["database"])['cols']:
589  name, type, length = item
590  # FIXME: support more datatypes
591  if type.lower() == "integer":
592  ctype = int
593  elif type.lower() == "double precision":
594  ctype = float
595  else:
596  ctype = str
597 
598  columns[name.strip()] = { 'index' : i,
599  'type' : type.lower(),
600  'ctype' : ctype,
601  'length' : int(length),
602  'values' : [],
603  'ids' : []}
604  i += 1
605 
606  # check for key column
607  # v.db.connect -g/p returns always key column name lowercase
608  if self.layers[layer]["key"] not in columns.keys():
609  for col in columns.keys():
610  if col.lower() == self.layers[layer]["key"]:
611  self.layers[layer]["key"] = col.upper()
612  break
613 
614  self.tables[table] = columns
615 
616  return True
617 
618  def Reset(self):
619  """!Reset"""
620  for layer in self.layers:
621  table = self.layers[layer]["table"] # get table desc
622  columns = self.tables[table]
623  for name in self.tables[table].keys():
624  self.tables[table][name]['values'] = []
625  self.tables[table][name]['ids'] = []
626 
627  def GetName(self):
628  """!Get vector name"""
629  return self.map
630 
631  def GetKeyColumn(self, layer):
632  """!Get key column of given layer
633 
634  @param layer vector layer number
635  """
636  return str(self.layers[layer]['key'])
637 
638  def GetTable(self, layer):
639  """!Get table name of given layer
640 
641  @param layer vector layer number
642  """
643  return self.layers[layer]['table']
644 
645  def GetDbSettings(self, layer):
646  """!Get database settins
647 
648  @param layer layer number
649 
650  @return (driver, database)
651  """
652  return self.layers[layer]['driver'], self.layers[layer]['database']
653 
654  def GetTableDesc(self, table):
655  """!Get table columns
656 
657  @param table table name
658  """
659  return self.tables[table]
660 
661 class LayerSelect(wx.ComboBox):
662  """!Creates combo box for selecting data layers defined for vector.
663  """
664  def __init__(self, parent,
665  id = wx.ID_ANY, pos = wx.DefaultPosition,
666  size = globalvar.DIALOG_LAYER_SIZE,
667  vector = None, choices = [], initial = [], default = None):
668 
669  super(LayerSelect, self).__init__(parent, id, pos=pos, size=size,
670  choices=choices)
671 
672  self.parent = parent
673  self.initial = initial
674 
675  self.SetName("LayerSelect")
676 
677  # default value
678  self.default = default
679 
680  self.InsertLayers(vector = vector)
681 
682  def InsertLayers(self, vector):
683  """!Insert layers for a vector into the layer combobox
684 
685  @param vector name of vector map
686  """
687  if vector:
688  layers = GetAllVectorLayers(vector)
689  else:
690  layers = list()
691 
692  for layer in self.initial:
693  if layer in layers:
694  continue
695  layers.append(layer)
696 
697  if self.default:
698  if len(layers) == 0:
699  layers.insert(0, str(self.default))
700  elif self.default not in layers:
701  layers.append(self.default)
702 
703  if len(layers) >= 1:
704  self.SetItems(layers)
705 
706  def Reset(self):
707  """!Reset value"""
708  items = self.GetItems()
709  if items:
710  if '-1' in items:
711  self.SetStringSelection('-1')
712  else:
713  self.SetSelection(0)
714  else:
715  self.SetValue('')
716 
717 class DriverSelect(wx.ComboBox):
718  """!Creates combo box for selecting database driver.
719  """
720  def __init__(self, parent, choices, value,
721  id=wx.ID_ANY, pos=wx.DefaultPosition,
722  size=globalvar.DIALOG_LAYER_SIZE, **kargs):
723 
724  super(DriverSelect, self).__init__(parent, id, value, pos, size,
725  choices, style=wx.CB_READONLY)
726 
727  self.SetName("DriverSelect")
728 
729  self.SetStringSelection(value)
730 
731 class DatabaseSelect(wx.TextCtrl):
732  """!Creates combo box for selecting database driver.
733  """
734  def __init__(self, parent, value='',
735  id=wx.ID_ANY, pos=wx.DefaultPosition,
736  size=globalvar.DIALOG_TEXTCTRL_SIZE, **kargs):
737 
738  super(DatabaseSelect, self).__init__(parent, id, value, pos, size)
739 
740  self.SetName("DatabaseSelect")
741 
742 class TableSelect(wx.ComboBox):
743  """!Creates combo box for selecting attribute tables from the database
744  """
745  def __init__(self, parent,
746  id=wx.ID_ANY, value='', pos=wx.DefaultPosition,
747  size=globalvar.DIALOG_COMBOBOX_SIZE,
748  choices=[]):
749 
750  super(TableSelect, self).__init__(parent, id, value, pos, size, choices,
751  style=wx.CB_READONLY)
752 
753  self.SetName("TableSelect")
754 
755  if not choices:
756  self.InsertTables()
757 
758  def InsertTables(self, driver=None, database=None):
759  """!Insert attribute tables into combobox"""
760  items = []
761 
762  if not driver or not database:
763  connect = grass.db_connection()
764 
765  driver = connect['driver']
766  database = connect['database']
767 
768  ret = RunCommand('db.tables',
769  flags = 'p',
770  read = True,
771  driver = driver,
772  database = database)
773 
774  if ret:
775  for table in ret.splitlines():
776  items.append(table)
777 
778  self.SetItems(items)
779  self.SetValue('')
780 
781 class ColumnSelect(wx.ComboBox):
782  """!Creates combo box for selecting columns in the attribute table
783  for a vector map.
784 
785  @param parent window parent
786  @param id window id
787  @param value default value
788  @param size window size
789  @param vector vector map name
790  @param layer layer number
791  @param param parameters list (see menuform.py)
792  @param **kwags wx.ComboBox parameters
793  """
794  def __init__(self, parent, id = wx.ID_ANY, value = '',
795  size=globalvar.DIALOG_COMBOBOX_SIZE,
796  vector = None, layer = 1, param = None, **kwargs):
797  self.defaultValue = value
798  self.param = param
799 
800  super(ColumnSelect, self).__init__(parent, id, value, size = size, **kwargs)
801  self.SetName("ColumnSelect")
802 
803  if vector:
804  self.InsertColumns(vector, layer)
805 
806  def InsertColumns(self, vector, layer, excludeKey = False, excludeCols = None, type = None, dbInfo = None):
807  """!Insert columns for a vector attribute table into the columns combobox
808 
809  @param vector vector name
810  @param layer vector layer number
811  @param excludeKey exclude key column from the list?
812  @param excludeCols list of columns to be removed from the list
813  @param type only columns of given type (given as list)
814  """
815  if not dbInfo:
816  dbInfo = VectorDBInfo(vector)
817 
818  try:
819  table = dbInfo.GetTable(int(layer))
820  columnchoices = dbInfo.GetTableDesc(table)
821  keyColumn = dbInfo.GetKeyColumn(int(layer))
822  columns = len(columnchoices.keys()) * ['']
823  for key, val in columnchoices.iteritems():
824  columns[val['index']] = key
825  if excludeKey: # exclude key column
826  columns.remove(keyColumn)
827  if excludeCols: # exclude key column
828  for key in columnchoices.iterkeys():
829  if key in excludeCols:
830  columns.remove(key)
831  if type: # only selected column types
832  for key, value in columnchoices.iteritems():
833  if value['type'] not in type:
834  try:
835  columns.remove(key)
836  except ValueError:
837  pass
838  except (KeyError, ValueError):
839  columns = list()
840 
841  self.SetItems(columns)
842  self.SetValue(self.defaultValue)
843 
844  if self.param:
845  value = self.param.get('value', '')
846  if value != '' and value in columns:
847  self.SetValue(value)
848 
849  def InsertTableColumns(self, table, driver=None, database=None):
850  """!Insert table columns
851 
852  @param table table name
853  @param driver driver name
854  @param database database name
855  """
856  columns = list()
857 
858  ret = RunCommand('db.columns',
859  read = True,
860  driver = driver,
861  database = database,
862  table = table)
863 
864  if ret:
865  columns = ret.splitlines()
866 
867  self.SetItems(columns)
868  self.SetValue(self.defaultValue)
869 
870  if self.param:
871  value = self.param.get('value', '')
872  if value != '' and value in columns:
873  self.SetValue(value)
874 
875 class DbaseSelect(wx.lib.filebrowsebutton.DirBrowseButton):
876  """!Widget for selecting GRASS Database"""
877  def __init__(self, parent, **kwargs):
878  super(DbaseSelect, self).__init__(parent, id = wx.ID_ANY,
879  size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
880  dialogTitle = _('Choose GIS Data Directory'),
881  buttonText = _('Browse'),
882  startDirectory = grass.gisenv()['GISDBASE'],
883  **kwargs)
884 
885 class LocationSelect(wx.ComboBox):
886  """!Widget for selecting GRASS location"""
887  def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
888  gisdbase = None, **kwargs):
889  super(LocationSelect, self).__init__(parent, id, size = size,
890  style = wx.CB_READONLY, **kwargs)
891  self.SetName("LocationSelect")
892 
893  if not gisdbase:
894  self.gisdbase = grass.gisenv()['GISDBASE']
895  else:
896  self.gisdbase = gisdbase
897 
898  self.SetItems(GetListOfLocations(self.gisdbase))
899 
900  def UpdateItems(self, dbase):
901  """!Update list of locations
902 
903  @param dbase path to GIS database
904  """
905  self.gisdbase = dbase
906  if dbase:
907  self.SetItems(GetListOfLocations(self.gisdbase))
908  else:
909  self.SetItems([])
910 
911 class MapsetSelect(wx.ComboBox):
912  """!Widget for selecting GRASS mapset"""
913  def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
914  gisdbase = None, location = None, setItems = True,
915  searchPath = False, skipCurrent = False, **kwargs):
916  super(MapsetSelect, self).__init__(parent, id, size = size,
917  style = wx.CB_READONLY, **kwargs)
918  self.searchPath = searchPath
919  self.skipCurrent = skipCurrent
920 
921  self.SetName("MapsetSelect")
922  if not gisdbase:
923  self.gisdbase = grass.gisenv()['GISDBASE']
924  else:
925  self.gisdbase = gisdbase
926 
927  if not location:
928  self.location = grass.gisenv()['LOCATION_NAME']
929  else:
930  self.location = location
931 
932  if setItems:
933  self.SetItems(self._getMapsets())
934 
935  def UpdateItems(self, location, dbase = None):
936  """!Update list of mapsets for given location
937 
938  @param dbase path to GIS database (None to use currently selected)
939  @param location name of location
940  """
941  if dbase:
942  self.gisdbase = dbase
943  self.location = location
944  if location:
945  self.SetItems(self._getMapsets())
946  else:
947  self.SetItems([])
948 
949  def _getMapsets(self):
950  if self.searchPath:
951  mlist = RunCommand('g.mapsets',
952  read = True, flags = 'p',
953  fs = 'newline').splitlines()
954  else:
955  mlist = GetListOfMapsets(self.gisdbase, self.location,
956  selectable = False)
957 
958  gisenv = grass.gisenv()
959  if self.skipCurrent and \
960  gisenv['LOCATION_NAME'] == self.location and \
961  gisenv['MAPSET'] in mlist:
962  mlist.remove(gisenv['MAPSET'])
963 
964  return mlist
965 
966 class SubGroupSelect(wx.ComboBox):
967  """!Widget for selecting subgroups"""
968  def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
969  **kwargs):
970  super(SubGroupSelect, self).__init__(parent, id, size = size,
971  **kwargs)
972  self.SetName("SubGroupSelect")
973 
974  def Insert(self, group):
975  """!Insert subgroups for defined group"""
976  if not group:
977  return
978  gisenv = grass.gisenv()
979  try:
980  name, mapset = group.split('@', 1)
981  except ValueError:
982  name = group
983  mapset = gisenv['MAPSET']
984 
985  path = os.path.join(gisenv['GISDBASE'], gisenv['LOCATION_NAME'], mapset,
986  'group', name, 'subgroup')
987  try:
988  self.SetItems(os.listdir(path))
989  except OSError:
990  self.SetItems([])
991  self.SetValue('')
992 
993 class FormatSelect(wx.Choice):
994  def __init__(self, parent, ogr = False,
995  sourceType = None, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
996  **kwargs):
997  """!Widget for selecting external (GDAL/OGR) format
998 
999  @param parent parent window
1000  @param sourceType source type ('file', 'directory', 'database', 'protocol') or None
1001  @param ogr True for OGR otherwise GDAL
1002  """
1003  super(FormatSelect, self).__init__(parent, id, size = size,
1004  **kwargs)
1005  self.SetName("FormatSelect")
1006 
1007  if ogr:
1008  ftype = 'ogr'
1009  else:
1010  ftype = 'gdal'
1011 
1012  formats = list()
1013  for f in GetFormats()[ftype].values():
1014  formats += f
1015  self.SetItems(formats)
1016 
1017  def GetExtension(self, name):
1018  """!Get file extension by format name"""
1019  formatToExt = {
1020  # raster
1021  'GeoTIFF' : 'tif',
1022  'Erdas Imagine Images (.img)' : 'img',
1023  'Ground-based SAR Applications Testbed File Format (.gff)' : 'gff',
1024  'Arc/Info Binary Grid' : 'adf',
1025  'Portable Network Graphics' : 'png',
1026  'JPEG JFIF' : 'jpg',
1027  'Japanese DEM (.mem)' : 'mem',
1028  'Graphics Interchange Format (.gif)' : 'gif',
1029  'X11 PixMap Format' : 'xpm',
1030  'MS Windows Device Independent Bitmap' : 'bmp',
1031  'SPOT DIMAP' : 'dim',
1032  'RadarSat 2 XML Product' : 'xml',
1033  'EarthWatch .TIL' : 'til',
1034  'ERMapper .ers Labelled' : 'ers',
1035  'ERMapper Compressed Wavelets' : 'ecw',
1036  'GRIdded Binary (.grb)' : 'grb',
1037  'EUMETSAT Archive native (.nat)' : 'nat',
1038  'Idrisi Raster A.1' : 'rst',
1039  'Golden Software ASCII Grid (.grd)' : 'grd',
1040  'Golden Software Binary Grid (.grd)' : 'grd',
1041  'Golden Software 7 Binary Grid (.grd)' : 'grd',
1042  'R Object Data Store' : 'r',
1043  'USGS DOQ (Old Style)' : 'doq',
1044  'USGS DOQ (New Style)' : 'doq',
1045  'ENVI .hdr Labelled' : 'hdr',
1046  'ESRI .hdr Labelled' : 'hdr',
1047  'Generic Binary (.hdr Labelled)' : 'hdr',
1048  'PCI .aux Labelled' : 'aux',
1049  'EOSAT FAST Format' : 'fst',
1050  'VTP .bt (Binary Terrain) 1.3 Format' : 'bt',
1051  'FARSITE v.4 Landscape File (.lcp)' : 'lcp',
1052  'Swedish Grid RIK (.rik)' : 'rik',
1053  'USGS Optional ASCII DEM (and CDED)' : 'dem',
1054  'Northwood Numeric Grid Format .grd/.tab' : '',
1055  'Northwood Classified Grid Format .grc/.tab' : '',
1056  'ARC Digitized Raster Graphics' : 'arc',
1057  'Magellan topo (.blx)' : 'blx',
1058  'SAGA GIS Binary Grid (.sdat)' : 'sdat',
1059  # vector
1060  'ESRI Shapefile' : 'shp',
1061  'UK .NTF' : 'ntf',
1062  'SDTS' : 'ddf',
1063  'DGN' : 'dgn',
1064  'VRT' : 'vrt',
1065  'REC' : 'rec',
1066  'BNA' : 'bna',
1067  'CSV' : 'csv',
1068  'GML' : 'gml',
1069  'GPX' : 'gpx',
1070  'KML' : 'kml',
1071  'GMT' : 'gmt',
1072  'PGeo' : 'mdb',
1073  'XPlane' : 'dat',
1074  'AVCBin' : 'adf',
1075  'AVCE00' : 'e00',
1076  'DXF' : 'dxf',
1077  'Geoconcept' : 'gxt',
1078  'GeoRSS' : 'xml',
1079  'GPSTrackMaker' : 'gtm',
1080  'VFK' : 'vfk'
1081  }
1082 
1083  try:
1084  return formatToExt[name]
1085  except KeyError:
1086  return ''
1087 
1088 class GdalSelect(wx.Panel):
1089  def __init__(self, parent, panel, ogr = False, link = False, dest = False,
1090  default = 'file', exclude = [], envHandler = None):
1091  """!Widget for selecting GDAL/OGR datasource, format
1092 
1093  @param parent parent window
1094  @param ogr use OGR selector instead of GDAL
1095  @param dest True for output (destination)
1096  @param default deafult type (ignored when dest == True)
1097  @param exclude list of types to be excluded
1098  """
1099  self.parent = parent
1100  self.ogr = ogr
1101  self.dest = dest
1102  wx.Panel.__init__(self, parent = panel, id = wx.ID_ANY)
1103 
1104  self.settingsBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
1105  label = " %s " % _("Settings"))
1106 
1107  self.inputBox = wx.StaticBox(parent = self, id = wx.ID_ANY)
1108  if dest:
1109  self.inputBox.SetLabel(" %s " % _("Output settings"))
1110  else:
1111  self.inputBox.SetLabel(" %s " % _("Source settings"))
1112 
1113  # source type
1114  sources = list()
1115  self.sourceMap = { 'file' : -1,
1116  'dir' : -1,
1117  'db' : -1,
1118  'pro' : -1,
1119  'native' : -1 }
1120  idx = 0
1121  if dest:
1122  sources.append(_("Native"))
1123  self.sourceMap['native'] = idx
1124  idx += 1
1125  if 'file' not in exclude:
1126  sources.append(_("File"))
1127  self.sourceMap['file'] = idx
1128  idx += 1
1129  if 'directory' not in exclude:
1130  sources.append(_("Directory"))
1131  self.sourceMap['dir'] = idx
1132  idx += 1
1133  if 'database' not in exclude:
1134  sources.append(_("Database"))
1135  self.sourceMap['db'] = idx
1136  idx += 1
1137  if 'protocol' not in exclude:
1138  sources.append(_("Protocol"))
1139  self.sourceMap['pro'] = idx
1140  idx += 1
1141 
1142  if self.ogr:
1143  self.settingsFile = os.path.join(GetSettingsPath(), 'wxOGR')
1144  else:
1145  self.settingsFile = os.path.join(GetSettingsPath(), 'wxGDAL')
1146 
1147  self.settingsChoice = wx.Choice(parent = self, id = wx.ID_ANY)
1148  self.settingsChoice.Bind(wx.EVT_CHOICE, self.OnSettingsLoad)
1149  self._settings = self._loadSettings() # -> self.settingsChoice.SetItems()
1150  self.btnSettingsSave = wx.Button(parent = self, id = wx.ID_SAVE)
1151  self.btnSettingsSave.Bind(wx.EVT_BUTTON, self.OnSettingsSave)
1152  self.btnSettingsSave.SetToolTipString(_("Save current settings"))
1153  self.btnSettingsDel = wx.Button(parent = self, id = wx.ID_REMOVE)
1154  self.btnSettingsDel.Bind(wx.EVT_BUTTON, self.OnSettingsDelete)
1155  self.btnSettingsSave.SetToolTipString(_("Delete currently selected settings"))
1156 
1157  self.source = wx.RadioBox(parent = self, id = wx.ID_ANY,
1158  style = wx.RA_SPECIFY_COLS,
1159  choices = sources)
1160  if dest:
1161  self.source.SetLabel(" %s " % _('Output type'))
1162  else:
1163  self.source.SetLabel(" %s " % _('Source type'))
1164 
1165  self.source.SetSelection(0)
1166  self.source.Bind(wx.EVT_RADIOBOX, self.OnSetType)
1167 
1168  # dsn widgets
1169  if not ogr:
1170  filemask = 'GeoTIFF (%s)|%s|%s (*.*)|*.*' % \
1171  (self._getExtPattern('tif'), self._getExtPattern('tif'), _('All files'))
1172  else:
1173  filemask = 'ESRI Shapefile (%s)|%s|%s (*.*)|*.*' % \
1174  (self._getExtPattern('shp'), self._getExtPattern('shp'), _('All files'))
1175 
1176  dsnFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
1177  size=globalvar.DIALOG_GSELECT_SIZE, labelText = '',
1178  dialogTitle=_('Choose file to import'),
1179  buttonText=_('Browse'),
1180  startDirectory=os.getcwd(),
1181  changeCallback=self.OnSetDsn,
1182  fileMask=filemask)
1183  dsnFile.Hide()
1184 
1185  dsnDir = filebrowse.DirBrowseButton(parent=self, id=wx.ID_ANY,
1186  size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
1187  dialogTitle=_('Choose input directory'),
1188  buttonText=_('Browse'),
1189  startDirectory=os.getcwd(),
1190  changeCallback=self.OnSetDsn)
1191  dsnDir.SetName('GdalSelect')
1192  dsnDir.Hide()
1193 
1194  dsnDbFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
1195  size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
1196  dialogTitle=_('Choose file'),
1197  buttonText=_('Browse'),
1198  startDirectory=os.getcwd(),
1199  changeCallback=self.OnSetDsn)
1200  dsnDbFile.Hide()
1201  dsnDbFile.SetName('GdalSelect')
1202 
1203  dsnDbText = wx.TextCtrl(parent = self, id = wx.ID_ANY)
1204  dsnDbText.Hide()
1205  dsnDbText.Bind(wx.EVT_TEXT, self.OnSetDsn)
1206  dsnDbText.SetName('GdalSelect')
1207 
1208  dsnDbChoice = wx.Choice(parent = self, id = wx.ID_ANY)
1209  dsnDbChoice.Hide()
1210  dsnDbChoice.Bind(wx.EVT_CHOICE, self.OnSetDsn)
1211  dsnDbChoice.SetName('GdalSelect')
1212 
1213  dsnPro = wx.TextCtrl(parent = self, id = wx.ID_ANY)
1214  dsnPro.Hide()
1215  dsnPro.Bind(wx.EVT_TEXT, self.OnSetDsn)
1216  dsnPro.SetName('GdalSelect')
1217 
1218  # format
1219  self.format = FormatSelect(parent = self,
1220  ogr = ogr)
1221  self.format.Bind(wx.EVT_CHOICE, self.OnSetFormat)
1222  self.extension = wx.TextCtrl(parent = self, id = wx.ID_ANY)
1223  self.extension.Bind(wx.EVT_TEXT, self.OnSetExtension)
1224  self.extension.Hide()
1225 
1226  if ogr:
1227  fType = 'ogr'
1228  else:
1229  fType = 'gdal'
1230  self.input = { 'file' : [_("File:"),
1231  dsnFile,
1232  GetFormats()[fType]['file']],
1233  'dir' : [_("Name:"),
1234  dsnDir,
1235  GetFormats()[fType]['file']],
1236  'db' : [_("Name:"),
1237  dsnDbText,
1238  GetFormats()[fType]['database']],
1239  'pro' : [_("Protocol:"),
1240  dsnPro,
1241  GetFormats()[fType]['protocol']],
1242  'db-win' : { 'file' : dsnDbFile,
1243  'text' : dsnDbText,
1244  'choice' : dsnDbChoice },
1245  'native' : [_("Name:"), dsnDir, ''],
1246  }
1247 
1248  if self.dest:
1249  current = RunCommand('v.external.out',
1250  parent = self,
1251  read = True, parse = grass.parse_key_val,
1252  flags = 'g')
1253  if current['format'] == 'native':
1254  self.dsnType = 'native'
1255  elif current['format'] in GetFormats()['ogr']['database']:
1256  self.dsnType = 'db'
1257  else:
1258  self.dsnType = 'dir'
1259  else:
1260  self.dsnType = default
1261 
1262  self.dsnText = wx.StaticText(parent = self, id = wx.ID_ANY,
1263  label = self.input[self.dsnType][0],
1264  size = (75, -1))
1265  self.extensionText = wx.StaticText(parent = self, id = wx.ID_ANY,
1266  label = _("Extension:"))
1267  self.extensionText.Hide()
1268 
1269  self.creationOpt = wx.TextCtrl(parent = self, id = wx.ID_ANY)
1270  if not self.dest:
1271  self.creationOpt.Hide()
1272 
1273  self._layout()
1274 
1275  self.OnSetType(event = None, sel = self.sourceMap[self.dsnType])
1276  if self.dest:
1277  if current['format'] != 'native':
1278  self.OnSetFormat(event = None, format = current['format'])
1279  self.OnSetDsn(event = None, path = current['dsn'])
1280  self.creationOpt.SetValue(current['options'])
1281  else:
1282  if not ogr:
1283  self.OnSetFormat(event = None, format = 'GeoTIFF')
1284  else:
1285  self.OnSetFormat(event = None, format = 'ESRI Shapefile')
1286 
1287  def _layout(self):
1288  """!Layout"""
1289  mainSizer = wx.BoxSizer(wx.VERTICAL)
1290 
1291  settingsSizer = wx.StaticBoxSizer(self.settingsBox, wx.HORIZONTAL)
1292  settingsSizer.Add(item = wx.StaticText(parent = self,
1293  id = wx.ID_ANY,
1294  label = _("Load settings:")),
1295  flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT,
1296  border = 5)
1297  settingsSizer.Add(item = self.settingsChoice,
1298  proportion = 1,
1299  flag = wx.EXPAND)
1300  settingsSizer.Add(item = self.btnSettingsSave,
1301  flag = wx.LEFT | wx.RIGHT,
1302  border = 5)
1303  settingsSizer.Add(item = self.btnSettingsDel,
1304  flag = wx.RIGHT,
1305  border = 5)
1306 
1307  inputSizer = wx.StaticBoxSizer(self.inputBox, wx.HORIZONTAL)
1308 
1309  self.dsnSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
1310 
1311  row = 0
1312  self.dsnSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
1313  label = _("Format:")),
1314  flag = wx.ALIGN_CENTER_VERTICAL,
1315  pos = (row, 0))
1316  self.dsnSizer.Add(item=self.format,
1317  flag = wx.ALIGN_CENTER_VERTICAL,
1318  pos = (row, 1))
1319  self.dsnSizer.Add(item = self.extensionText,
1320  flag=wx.ALIGN_CENTER_VERTICAL,
1321  pos = (row, 2))
1322  self.dsnSizer.Add(item=self.extension,
1323  flag = wx.ALIGN_CENTER_VERTICAL,
1324  pos = (row, 3))
1325  row += 1
1326  self.dsnSizer.Add(item = self.dsnText,
1327  flag = wx.ALIGN_CENTER_VERTICAL,
1328  pos = (row, 0))
1329  self.dsnSizer.Add(item = self.input[self.dsnType][1],
1330  flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
1331  pos = (row, 1), span = (1, 3))
1332  row += 1
1333  if self.creationOpt.IsShown():
1334  self.dsnSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
1335  label = _("Creation options:")),
1336  flag = wx.ALIGN_CENTER_VERTICAL,
1337  pos = (row, 0))
1338  self.dsnSizer.Add(item = self.creationOpt,
1339  flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
1340  pos = (row, 1), span = (1, 3))
1341  row += 1
1342  self.dsnSizer.AddGrowableCol(3)
1343 
1344  inputSizer.Add(item=self.dsnSizer, proportion = 1,
1345  flag=wx.EXPAND | wx.BOTTOM, border = 10)
1346 
1347  mainSizer.Add(item=settingsSizer, proportion=0,
1348  flag=wx.ALL | wx.EXPAND, border=5)
1349  mainSizer.Add(item=self.source, proportion=0,
1350  flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=5)
1351  mainSizer.Add(item=inputSizer, proportion=0,
1352  flag=wx.ALL | wx.EXPAND, border=5)
1353 
1354  self.SetSizer(mainSizer)
1355  mainSizer.Fit(self)
1356 
1357  def _getExtPatternGlob(self, ext):
1358  """!Get pattern for case-insensitive globing"""
1359  pattern = '*.'
1360  for c in ext:
1361  pattern += '[%s%s]' % (c.lower(), c.upper())
1362  return pattern
1363 
1364  def _getExtPattern(self, ext):
1365  """!Get pattern for case-insensitive file mask"""
1366  return '*.%s;*.%s' % (ext.lower(), ext.upper())
1367 
1368  def OnSettingsLoad(self, event):
1369  """!Load named settings"""
1370  name = event.GetString()
1371  if name not in self._settings:
1372  GError(parent = self,
1373  message = _("Settings <%s> not found") % name)
1374  return
1375  data = self._settings[name]
1376  self.OnSetType(event = None, sel = self.sourceMap[data[0]])
1377  self.OnSetFormat(event = None, format = data[2])
1378  self.OnSetDsn(event = None, path = data[1])
1379  self.creationOpt.SetValue(data[3])
1380 
1381  def OnSettingsSave(self, event):
1382  """!Save settings"""
1383  dlg = wx.TextEntryDialog(parent = self,
1384  message = _("Name:"),
1385  caption = _("Save settings"))
1386  if dlg.ShowModal() != wx.ID_OK:
1387  return
1388 
1389  # check required params
1390  if not dlg.GetValue():
1391  GMessage(parent = self,
1392  message = _("Name not given, settings is not saved."))
1393  return
1394 
1395  if not self.GetDsn():
1396  GMessage(parent = self,
1397  message = _("No data source defined, settings is not saved."))
1398  return
1399 
1400  name = dlg.GetValue()
1401 
1402  # check if settings item already exists
1403  if name in self._settings:
1404  dlgOwt = wx.MessageDialog(self, message = _("Settings <%s> already exists. "
1405  "Do you want to overwrite the settings?") % name,
1406  caption = _("Save settings"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
1407  if dlgOwt.ShowModal() != wx.ID_YES:
1408  dlgOwt.Destroy()
1409  return
1410 
1411  self._settings[name] = (self.dsnType, self.GetDsn(),
1412  self.format.GetStringSelection(),
1413  self.creationOpt.GetValue())
1414 
1415  if self._saveSettings() == 0:
1416  self._settings = self._loadSettings()
1417  self.settingsChoice.SetStringSelection(name)
1418 
1419  dlg.Destroy()
1420 
1421  def OnSettingsDelete(self, event):
1422  """!Save settings"""
1423  name = self.settingsChoice.GetStringSelection()
1424  if not name:
1425  GMessage(parent = self,
1426  message = _("No settings is defined. Operation canceled."))
1427  return
1428 
1429  self._settings.pop(name)
1430  if self._saveSettings() == 0:
1431  self._settings = self._loadSettings()
1432 
1433  def _saveSettings(self):
1434  """!Save settings into the file
1435 
1436  @return 0 on success
1437  @return -1 on failure
1438  """
1439  try:
1440  fd = open(self.settingsFile, 'w')
1441  for key, value in self._settings.iteritems():
1442  fd.write('%s;%s;%s;%s\n' % (key, value[0], value[1], value[2]))
1443  except IOError:
1444  GError(parent = self,
1445  message = _("Unable to save settings"))
1446  return -1
1447  else:
1448  fd.close()
1449 
1450  return 0
1451 
1452  def _loadSettings(self):
1453  """!Load settings from the file
1454 
1455  The file is defined by self.SettingsFile.
1456 
1457  @return parsed dict
1458  @return empty dict on error
1459  """
1460  data = dict()
1461  if not os.path.exists(self.settingsFile):
1462  return data
1463 
1464  try:
1465  fd = open(self.settingsFile, 'r')
1466  for line in fd.readlines():
1467  try:
1468  lineData = line.rstrip('\n').split(';')
1469  if len(lineData) > 4:
1470  # type, dsn, format, options
1471  data[lineData[0]] = (lineData[1], lineData[2], lineData[3], lineData[4])
1472  else:
1473  data[lineData[0]] = (lineData[1], lineData[2], lineData[3], '')
1474  except ValueError:
1475  pass
1476  except IOError:
1477  return data
1478  else:
1479  fd.close()
1480 
1481  self.settingsChoice.SetItems(sorted(data.keys()))
1482 
1483  return data
1484 
1485  def OnSetType(self, event, sel = None):
1486  """!Datasource type changed.
1487 
1488  @todo improve showing/hiding widgets
1489  """
1490  if event:
1491  sel = event.GetSelection()
1492  else:
1493  self.source.SetSelection(sel)
1494  win = self.input[self.dsnType][1]
1495  if win:
1496  self.dsnSizer.Detach(win)
1497  win.Hide()
1498 
1499  if sel == self.sourceMap['file']: # file
1500  self.dsnType = 'file'
1501  try:
1502  format = self.input[self.dsnType][2][0]
1503  except IndexError:
1504  format = ''
1505  try:
1506  ext = self.format.GetExtension(format)
1507  if not ext:
1508  raise KeyError
1509  format += ' (%s)|%s|%s (*.*)|*.*' % \
1510  (self._getExtPattern(ext), self._getExtPattern(ext), _('All files'))
1511  except KeyError:
1512  format += '%s (*.*)|*.*' % _('All files')
1513 
1514  win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
1515  size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
1516  dialogTitle=_('Choose file to import'),
1517  buttonText=_('Browse'),
1518  startDirectory=os.getcwd(),
1519  changeCallback=self.OnSetDsn,
1520  fileMask = format)
1521  self.input[self.dsnType][1] = win
1522 
1523  elif sel == self.sourceMap['dir']: # directory
1524  self.dsnType = 'dir'
1525  elif sel == self.sourceMap['db']: # database
1526  self.dsnType = 'db'
1527  elif sel == self.sourceMap['pro']: # protocol
1528  self.dsnType = 'pro'
1529  elif sel == self.sourceMap['native']:
1530  self.dsnType = 'native'
1531 
1532  if self.dsnType == 'db':
1533  self.input[self.dsnType][1] = self.input['db-win']['text']
1534  win = self.input[self.dsnType][1]
1535 
1536  self.dsnSizer.Add(item = self.input[self.dsnType][1],
1537  flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
1538  pos = (1, 1), span = (1, 3))
1539  win.SetValue('')
1540  win.Show()
1541 
1542  if sel == self.sourceMap['native']: # native
1543  win.Enable(False)
1544  self.format.Enable(False)
1545  self.creationOpt.Enable(False)
1546  self.parent.btnOk.Enable(True)
1547  else:
1548  if not win.IsEnabled():
1549  win.Enable(True)
1550  if not self.format.IsEnabled():
1551  self.format.Enable(True)
1552  self.creationOpt.Enable(True)
1553  self.dsnText.SetLabel(self.input[self.dsnType][0])
1554  self.format.SetItems(self.input[self.dsnType][2])
1555  if self.parent.GetName() == 'MultiImportDialog':
1556  self.parent.list.DeleteAllItems()
1557 
1558  if sel in (self.sourceMap['file'], self.sourceMap['dir']):
1559  if not self.ogr:
1560  self.OnSetFormat(event = None, format = 'GeoTIFF')
1561  else:
1562  self.OnSetFormat(event = None, format = 'ESRI Shapefile')
1563 
1564  if sel == self.sourceMap['dir'] and not self.dest:
1565  if not self.extension.IsShown():
1566  self.extensionText.Show()
1567  self.extension.Show()
1568  else:
1569  if self.extension.IsShown():
1570  self.extensionText.Hide()
1571  self.extension.Hide()
1572 
1573  self.dsnSizer.Layout()
1574 
1575  def GetDsn(self):
1576  """!Get datasource name
1577  """
1578  if self.format.GetStringSelection() == 'PostgreSQL':
1579  dsn = 'PG:dbname=%s' % self.input[self.dsnType][1].GetStringSelection()
1580  else:
1581  dsn = self.input[self.dsnType][1].GetValue()
1582 
1583  return dsn
1584 
1585  def OnSetDsn(self, event, path = None):
1586  """!Input DXF file/OGR dsn defined, update list of layer
1587  widget"""
1588  if event:
1589  path = event.GetString()
1590  else:
1591  if self.format.GetStringSelection() == 'PostgreSQL':
1592  for item in path.split(':', 1)[1].split(','):
1593  key, value = item.split('=', 1)
1594  if key == 'dbname':
1595  if not self.input[self.dsnType][1].SetStringSelection(value):
1596  GMessage(_("Database <%s> not accessible.") % value,
1597  parent = self)
1598  break
1599  else:
1600  self.input[self.dsnType][1].SetValue(path)
1601 
1602  if not path:
1603  if self.dest:
1604  self.parent.btnOk.Enable(False)
1605  return
1606 
1607  if self.dest:
1608  self.parent.btnOk.Enable(True)
1609  else:
1610  self._reloadLayers()
1611 
1612  if event:
1613  event.Skip()
1614 
1615  def _reloadLayers(self):
1616  """!Reload list of layers"""
1617  dsn = self.GetDsn()
1618  if not dsn:
1619  return
1620 
1621  data = list()
1622  layerId = 1
1623 
1624  if self.ogr:
1625  ret = RunCommand('v.in.ogr',
1626  quiet = True,
1627  read = True,
1628  flags = 'l',
1629  dsn = dsn)
1630  if not ret:
1631  self.parent.list.LoadData()
1632  if hasattr(self, "btn_run"):
1633  self.btn_run.Enable(False)
1634  return
1635 
1636  layerId = 1
1637  for line in ret.split(','):
1638  layerName = line.strip()
1639  grassName = GetValidLayerName(layerName)
1640  data.append((layerId, layerName, grassName))
1641  layerId += 1
1642  else:
1643  if self.dsnType == 'file':
1644  baseName = os.path.basename(dsn)
1645  grassName = GetValidLayerName(baseName.split('.', -1)[0])
1646  data.append((layerId, baseName, grassName))
1647  elif self.dsnType == 'dir':
1648  ext = self.extension.GetValue()
1649  for filename in glob.glob(os.path.join(dsn, "%s") % self._getExtPatternGlob(ext)):
1650  baseName = os.path.basename(filename)
1651  grassName = GetValidLayerName(baseName.split('.', -1)[0])
1652  data.append((layerId, baseName, grassName))
1653  layerId += 1
1654  if self.ogr:
1655  dsn += '@OGR'
1656 
1657  evt = wxGdalSelect(dsn = dsn)
1658  evt.SetId(self.input[self.dsnType][1].GetId())
1659  wx.PostEvent(self.parent, evt)
1660 
1661  if self.parent.GetName() == 'MultiImportDialog':
1662  self.parent.list.LoadData(data)
1663  if len(data) > 0:
1664  self.parent.btn_run.Enable(True)
1665  else:
1666  self.parent.btn_run.Enable(False)
1667 
1668  def OnSetExtension(self, event):
1669  """!Extension changed"""
1670  if not self.dest:
1671  # reload layers
1672  self._reloadLayers()
1673 
1674  def OnSetFormat(self, event, format = None):
1675  """!Format changed"""
1676  if self.dsnType not in ['file', 'dir', 'db']:
1677  return
1678 
1679  win = self.input[self.dsnType][1]
1680  self.dsnSizer.Detach(win)
1681 
1682  if self.dsnType == 'file':
1683  win.Destroy()
1684  else: # database
1685  win.Hide()
1686 
1687  if event:
1688  format = event.GetString()
1689  else:
1690  self.format.SetStringSelection(format)
1691 
1692  if self.dsnType == 'file':
1693  try:
1694  ext = self.format.GetExtension(format)
1695  if not ext:
1696  raise KeyError
1697  format += ' (%s)|%s|%s (*.*)|*.*' % \
1698  (self._getExtPattern(ext), self._getExtPattern(ext), _('All files'))
1699  except KeyError:
1700  format += '%s (*.*)|*.*' % _('All files')
1701 
1702  win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
1703  size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
1704  dialogTitle=_('Choose file'),
1705  buttonText=_('Browse'),
1706  startDirectory=os.getcwd(),
1707  changeCallback=self.OnSetDsn,
1708  fileMask = format)
1709 
1710  elif self.dsnType == 'dir':
1711  pass
1712 
1713  else: # database
1714  if format == 'SQLite' or format == 'Rasterlite':
1715  win = self.input['db-win']['file']
1716  elif format == 'PostgreSQL' or format == 'PostGIS WKT Raster driver':
1717  if grass.find_program('psql', ['--help']):
1718  win = self.input['db-win']['choice']
1719  if not win.GetItems():
1720  p = grass.Popen(['psql', '-ltA'], stdout = grass.PIPE)
1721  ret = p.communicate()[0]
1722  if ret:
1723  db = list()
1724  for line in ret.splitlines():
1725  sline = line.split('|')
1726  if len(sline) < 2:
1727  continue
1728  dbname = sline[0]
1729  if dbname:
1730  db.append(dbname)
1731  win.SetItems(db)
1732  if self.dest and win.GetStringSelection():
1733  self.parent.btnOk.Enable(True)
1734  else:
1735  win = self.input['db-win']['text']
1736  else:
1737  win = self.input['db-win']['text']
1738 
1739  self.input[self.dsnType][1] = win
1740  if not win.IsShown():
1741  win.Show()
1742  self.dsnSizer.Add(item = self.input[self.dsnType][1],
1743  flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
1744  pos = (1, 1), span = (1, 3))
1745  self.dsnSizer.Layout()
1746 
1747  # update extension
1748  self.extension.SetValue(self.GetFormatExt())
1749 
1750  if not self.dest:
1751  # reload layers
1752  self._reloadLayers()
1753 
1754  def GetType(self):
1755  """!Get source type"""
1756  return self.dsnType
1757 
1758  def GetDsnWin(self):
1759  """!Get list of DSN windows"""
1760  win = list()
1761  for stype in ('file', 'dir', 'pro'):
1762  win.append(self.input[stype][1])
1763  for stype in ('file', 'text', 'choice'):
1764  win.append(self.input['db-win'][stype])
1765 
1766  return win
1767 
1768  def GetFormat(self):
1769  """!Get format as string"""
1770  return self.format.GetStringSelection().replace(' ', '_')
1771 
1772  def GetFormatExt(self):
1773  """!Get format extension"""
1774  return self.format.GetExtension(self.format.GetStringSelection())
1775 
1776  def GetOptions(self):
1777  """!Get creation options"""
1778  if not self.creationOpt.IsShown():
1779  return ''
1780 
1781  return self.creationOpt.GetValue()
1782 
1783 class ProjSelect(wx.ComboBox):
1784  """!Widget for selecting input raster/vector map used by
1785  r.proj/v.proj modules."""
1786  def __init__(self, parent, isRaster, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
1787  **kwargs):
1788  super(ProjSelect, self).__init__(parent, id, size = size,
1789  style = wx.CB_READONLY, **kwargs)
1790  self.SetName("ProjSelect")
1791  self.isRaster = isRaster
1792 
1793  def UpdateItems(self, dbase, location, mapset):
1794  """!Update list of maps
1795 
1796  """
1797  if not dbase:
1798  dbase = grass.gisenv()['GISDBASE']
1799  if not mapset:
1800  mapset = grass.gisenv()['MAPSET']
1801  if self.isRaster:
1802  ret = RunCommand('r.proj',
1803  quiet = True,
1804  read = True,
1805  flags = 'l',
1806  dbase = dbase,
1807  location = location,
1808  mapset = mapset)
1809  else:
1810  ret = RunCommand('v.proj',
1811  quiet = True,
1812  read = True,
1813  flags = 'l',
1814  dbase = dbase,
1815  location = location,
1816  mapset = mapset)
1817  listMaps = list()
1818  if ret:
1819  for line in ret.splitlines():
1820  listMaps.append(line.strip())
1821  ListSortLower(listMaps)
1822 
1823  self.SetItems(listMaps)
1824  self.SetValue('')
1825 
1826 class ElementSelect(wx.Choice):
1827  def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
1828  **kwargs):
1829  """!Widget for selecting GIS element
1830 
1831  @param parent parent window
1832  """
1833  super(ElementSelect, self).__init__(parent, id, size = size,
1834  **kwargs)
1835  self.SetName("ElementSelect")
1836 
1837  task = gtask.parse_interface('g.list')
1838  p = task.get_param(value = 'type')
1839  self.values = p.get('values', [])
1840 
1841  self.SetItems(self.values)
1842 
1843  def GetValue(self, name):
1844  """!Translate value
1845 
1846  @param name element name
1847  """
1848  return name
def InsertTableColumns
Insert table columns.
Definition: gselect.py:849
def GetListOfLocations
Get list of GRASS locations in given dbase.
Definition: core/utils.py:639
def SetElementList
Set element list.
Definition: gselect.py:97
def GetValue
Definition: widgets.py:118
wxGUI command interface
def __init__
Custom to create a ComboBox with a tree control to display and select vector maps.
Definition: gselect.py:120
def GetFormat
Get format as string.
Definition: gselect.py:1768
def GetDbSettings
Get database settins.
Definition: gselect.py:645
def __init__
Widget for selecting external (GDAL/OGR) format.
Definition: gselect.py:996
def GetSettingsPath
Get full path to the settings directory.
Definition: core/utils.py:807
def OnLeftDown
Do the combobox selection.
Definition: gselect.py:496
def __init__
Custom control to create a ComboBox with a tree control to display and select GIS elements within ace...
Definition: gselect.py:61
#define min(x, y)
Definition: draw2.c:68
def UpdateItems
Update list of locations.
Definition: gselect.py:900
wxGUI debugging
def GetDsnWin
Get list of DSN windows.
Definition: gselect.py:1758
Creates combo box for selecting data layers defined for vector.
Definition: gselect.py:661
def _saveSettings
Save settings into the file.
Definition: gselect.py:1433
def _reloadLayers
Reload list of layers.
Definition: gselect.py:1615
def GetDsn
Get datasource name.
Definition: gselect.py:1575
def GetElementList
Load elements.
Definition: gselect.py:105
def GetListOfMapsets
Get list of mapsets in given GRASS location.
Definition: core/utils.py:662
def OnMotion
Have the selection follow the mouse, like in a real combobox.
Definition: gselect.py:487
def _CheckDBConnection
Check DB connection.
Definition: gselect.py:565
def GetElementList
Get filtered list of GIS elements in accessible mapsets and display as tree with all relevant element...
Definition: gselect.py:215
def GetTableDesc
Get table columns.
Definition: gselect.py:654
def OnSetDsn
Input DXF file/OGR dsn defined, update list of layer widget.
Definition: gselect.py:1585
def __init__
Widget for selecting GDAL/OGR datasource, format.
Definition: gselect.py:1090
def OnSettingsDelete
Save settings.
Definition: gselect.py:1421
def SetType
Param set element type for widget.
Definition: gselect.py:110
def SetValue
Definition: widgets.py:115
def GetType
Get element type.
Definition: gselect.py:544
def OnKeyUp
Enables to select items using keyboard.
Definition: gselect.py:420
def _DescribeTables
Describe linked tables.
Definition: gselect.py:576
def _loadSettings
Load settings from the file.
Definition: gselect.py:1452
def Insert
Insert subgroups for defined group.
Definition: gselect.py:974
def split
Platform spefic shlex.split.
Definition: core/utils.py:37
def GetFormats
Get GDAL/OGR formats.
Definition: core/utils.py:796
def OnSetFormat
Format changed.
Definition: gselect.py:1674
def SetData
Set object properties.
Definition: gselect.py:527
Widget for selecting input raster/vector map used by r.proj/v.proj modules.
Definition: gselect.py:1783
def _layout
Layout.
Definition: gselect.py:1287
def UpdateItems
Update list of mapsets for given location.
Definition: gselect.py:935
Creates combo box for selecting attribute tables from the database.
Definition: gselect.py:742
Widget for selecting GRASS Database.
Definition: gselect.py:875
Creates combo box for selecting database driver.
Definition: gselect.py:717
def OnSetExtension
Extension changed.
Definition: gselect.py:1668
def InsertTables
Insert attribute tables into combobox.
Definition: gselect.py:758
def GetKeyColumn
Get key column of given layer.
Definition: gselect.py:631
def _isElement
Check if element should be filtered out.
Definition: gselect.py:135
def GetTable
Get table name of given layer.
Definition: gselect.py:638
def GetAdjustedSize
Reads UserSettings to get height (which was 200 in old implementation).
Definition: gselect.py:250
def GetValue
Translate value.
Definition: gselect.py:1843
def _getExtPatternGlob
Get pattern for case-insensitive globing.
Definition: gselect.py:1357
Widget for selecting GRASS location.
Definition: gselect.py:885
def ListSortLower
Sort list items (not case-sensitive)
Definition: core/utils.py:287
def GetValidLayerName
Make layer name SQL compliant, based on G_str_to_sql()
Definition: core/utils.py:175
def OnSettingsLoad
Load named settings.
Definition: gselect.py:1368
def _getElementList
Get list of GIS elements in accessible mapsets and display as tree with all relevant elements display...
Definition: gselect.py:256
def OnSetType
Datasource type changed.
Definition: gselect.py:1485
def InsertLayers
Insert layers for a vector into the layer combobox.
Definition: gselect.py:682
def OnSettingsSave
Save settings.
Definition: gselect.py:1381
def OnPopup
Limited only for first selected.
Definition: gselect.py:194
Widget for selecting GRASS mapset.
Definition: gselect.py:911
Widget for selecting subgroups.
Definition: gselect.py:966
def _getExtPattern
Get pattern for case-insensitive file mask.
Definition: gselect.py:1364
def FindItem
Finds item with given name or starting with given text.
Definition: gselect.py:393
Creates combo box for selecting columns in the attribute table for a vector map.
Definition: gselect.py:781
Misc utilities for wxGUI.
Creates combo box for selecting database driver.
Definition: gselect.py:731
def GetAllVectorLayers
Returns list of all vector layers as strings.
Definition: core/utils.py:332
def Reset
Reset.
Definition: gselect.py:618
def GetOptions
Get creation options.
Definition: gselect.py:1776
def Reset
Reset value.
Definition: gselect.py:706
def InsertColumns
Insert columns for a vector attribute table into the columns combobox.
Definition: gselect.py:806
def GetExtension
Get file extension by format name.
Definition: gselect.py:1017
def SetFilter
Set filter for GIS elements, see e.g.
Definition: gselect.py:190
def GetStringValue
Get value as a string separated by commas.
Definition: gselect.py:186
def __init__
Widget for selecting GIS element.
Definition: gselect.py:1828
Default GUI settings.
Class providing information about attribute tables linked to a vector map.
Definition: gselect.py:549
def GetName
Get vector name.
Definition: gselect.py:627
def UpdateItems
Update list of maps.
Definition: gselect.py:1793
def GetFormatExt
Get format extension.
Definition: gselect.py:1772
def OnKeyUp
Shows popupwindow if down arrow key is released.
Definition: gselect.py:90
def GetType
Get source type.
Definition: gselect.py:1754
def RunCommand
Run GRASS command.
Definition: gcmd.py:625
Create a tree ComboBox for selecting maps and other GIS elements in accessible mapsets within the cur...
Definition: gselect.py:145