gselect.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. """
  2. MODULE: gselect
  3. CLASSES:
  4. * Select
  5. * TreeCrtlComboPopup
  6. PURPOSE: Custon control that selects GRASS GIS elements
  7. AUTHORS: The GRASS Development Team. Michael Barton & Martin Landa
  8. COPYRIGHT: (C) 2007 by the GRASS Development Team
  9. This program is free software under the GNU General Public
  10. License (>=v2). Read the file COPYING that comes with GRASS
  11. for details.
  12. """
  13. import os
  14. import sys
  15. import wx
  16. import wx.combo
  17. import globalvar
  18. import gcmd
  19. import utils
  20. from preferences import globalSettings as UserSettings
  21. class Select(wx.combo.ComboCtrl):
  22. def __init__(self, parent, id, size,
  23. type, multiple=False, mapsets=None, exceptOf=[]):
  24. """
  25. Custom control to create a ComboBox with a tree control
  26. to display and select GIS elements within acessible mapsets.
  27. Elements can be selected with mouse. Can allow multiple selections, when
  28. argument multiple=True. Multiple selections are separated by commas.
  29. """
  30. wx.combo.ComboCtrl.__init__(self, parent=parent, id=id, size=size)
  31. self.tcp = TreeCtrlComboPopup()
  32. self.SetPopupControl(self.tcp)
  33. self.SetPopupExtents(0,100)
  34. self.tcp.GetElementList(type, mapsets, exceptOf)
  35. self.tcp.SetData(type, mapsets, exceptOf, multiple)
  36. def SetElementList(self, type):
  37. self.tcp.seltree.DeleteAllItems()
  38. self.tcp.GetElementList(type)
  39. class TreeCtrlComboPopup(wx.combo.ComboPopup):
  40. """
  41. Create a tree ComboBox for selecting maps and other GIS elements
  42. in accessible mapsets within the current location
  43. """
  44. # overridden ComboPopup methods
  45. def Init(self):
  46. self.value = [] # for multiple is False -> len(self.value) in [0,1]
  47. self.curitem = None
  48. self.multiple = False
  49. self.type = None
  50. self.mapsets = []
  51. self.exceptOf = []
  52. def Create(self, parent):
  53. self.seltree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT
  54. |wx.TR_HAS_BUTTONS
  55. |wx.TR_SINGLE
  56. |wx.TR_LINES_AT_ROOT
  57. |wx.SIMPLE_BORDER
  58. |wx.TR_FULL_ROW_HIGHLIGHT)
  59. self.seltree.Bind(wx.EVT_MOTION, self.OnMotion)
  60. self.seltree.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
  61. self.seltree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.mapsetExpanded)
  62. self.seltree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.mapsetCollapsed)
  63. self.seltree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.mapsetActivated)
  64. self.seltree.Bind(wx.EVT_TREE_SEL_CHANGED, self.mapsetSelected)
  65. self.seltree.Bind(wx.EVT_TREE_DELETE_ITEM, lambda x: None)
  66. # the following dummy handler are needed to keep tree events from propagating up to
  67. # the parent GIS Manager layer tree
  68. def mapsetExpanded(self, event):
  69. pass
  70. def mapsetCollapsed(self, event):
  71. pass
  72. def mapsetActivated(self, event):
  73. pass
  74. def mapsetSelected(self, event):
  75. pass
  76. # end of dummy events
  77. def GetControl(self):
  78. return self.seltree
  79. def GetStringValue(self):
  80. str = ""
  81. for value in self.value:
  82. str += self.seltree.GetItemText(value) + ","
  83. str = str.rstrip(',')
  84. return str
  85. def OnPopup(self):
  86. """Limited only for first selected"""
  87. # update list
  88. self.seltree.DeleteAllItems()
  89. self.GetElementList(self.type, self.mapsets, self.exceptOf)
  90. if len(self.value) > 0:
  91. self.seltree.EnsureVisible(self.value[0])
  92. self.seltree.SelectItem(self.value[0])
  93. def SetStringValue(self, value):
  94. # this assumes that item strings are unique...
  95. root = self.seltree.GetRootItem()
  96. if not root:
  97. return
  98. found = self.FindItem(root, value)
  99. if found:
  100. self.value.append(found)
  101. self.seltree.SelectItem(found)
  102. def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
  103. return wx.Size(minWidth, min(200, maxHeight))
  104. def GetElementList(self, element, mapsets=None, exceptOf=[]):
  105. """
  106. Get list of GIS elements in accessible mapsets and display as tree
  107. with all relevant elements displayed beneath each mapset branch
  108. """
  109. # get current mapset
  110. cmdlist = ['g.gisenv', 'get=MAPSET']
  111. curr_mapset = gcmd.Command(cmdlist).ReadStdOutput()[0]
  112. # list of mapsets in current location
  113. if mapsets is None:
  114. mapsets = utils.ListOfMapsets()
  115. # map element types to g.mlist types
  116. elementdict = {'cell':'rast',
  117. 'raster':'rast',
  118. 'rast':'rast',
  119. 'raster files':'rast',
  120. 'grid3':'rast3d',
  121. 'rast3d':'rast3d',
  122. 'raster3D':'rast3d',
  123. 'raster3D files':'rast3d',
  124. 'vector':'vect',
  125. 'vect':'vect',
  126. 'binary vector files':'vect',
  127. 'dig':'oldvect',
  128. 'oldvect':'oldvect',
  129. 'old vector':'oldvect',
  130. 'dig_ascii':'asciivect',
  131. 'asciivect':'asciivect',
  132. 'asciivector':'asciivect',
  133. 'ascii vector files':'asciivect',
  134. 'icons':'icon',
  135. 'icon':'icon',
  136. 'paint icon files':'icon',
  137. 'paint/labels':'labels',
  138. 'labels':'labels',
  139. 'label':'labels',
  140. 'paint label files':'labels',
  141. 'site_lists':'sites',
  142. 'sites':'sites',
  143. 'site list':'sites',
  144. 'site list files':'sites',
  145. 'windows':'region',
  146. 'region':'region',
  147. 'region definition':'region',
  148. 'region definition files':'region',
  149. 'windows3d':'region3d',
  150. 'region3d':'region3d',
  151. 'region3D definition':'region3d',
  152. 'region3D definition files':'region3d',
  153. 'group':'group',
  154. 'imagery group':'group',
  155. 'imagery group files':'group',
  156. '3d.view':'3dview',
  157. '3dview':'3dview',
  158. '3D viewing parameters':'3dview',
  159. '3D view parameters':'3dview'}
  160. if element not in elementdict:
  161. self.AddItem(_('Not selectable element'))
  162. return
  163. # get directory tree nodes
  164. # reorder mapsets based on search path (TODO)
  165. for i in range(len(mapsets)):
  166. if i > 0 and mapsets[i] == curr_mapset:
  167. mapsets[i] = mapsets[0]
  168. mapsets[0] = curr_mapset
  169. for dir in mapsets:
  170. dir_node = self.AddItem('Mapset: '+dir)
  171. self.seltree.SetItemTextColour(dir_node,wx.Colour(50,50,200))
  172. try:
  173. cmdlist = ['g.mlist', 'type=%s' % elementdict[element], 'mapset=%s' % dir]
  174. elem_list = gcmd.Command(cmdlist).ReadStdOutput()
  175. elem_list.sort()
  176. for elem in elem_list:
  177. if elem != '':
  178. fullqElem = elem + '@' + dir
  179. if len(exceptOf) > 0 and fullqElem in exceptOf:
  180. continue
  181. self.AddItem(fullqElem, parent=dir_node)
  182. except:
  183. continue
  184. if self.seltree.ItemHasChildren(dir_node):
  185. sel = UserSettings.Get(group='general', key='elementListExpand',
  186. subkey='selection')
  187. collapse = True
  188. if sel == 0: # collapse all expect PERMANENT and current
  189. if dir in ('PERMANENT', curr_mapset):
  190. collapse = False
  191. elif sel == 1: # collapse all expect PERMANENT
  192. if dir == 'PERMANENT':
  193. collapse = False
  194. elif sel == 2: # collapse all
  195. pass
  196. elif sel == 3: # expand all
  197. collapse = False
  198. if collapse:
  199. self.seltree.Collapse(dir_node)
  200. else:
  201. self.seltree.Expand(dir_node)
  202. # helpers
  203. def FindItem(self, parentItem, text):
  204. item, cookie = self.seltree.GetFirstChild(parentItem)
  205. while item:
  206. if self.seltree.GetItemText(item) == text:
  207. return item
  208. if self.seltree.ItemHasChildren(item):
  209. item = self.FindItem(item, text)
  210. item, cookie = self.seltree.GetNextChild(parentItem, cookie)
  211. return wx.TreeItemId();
  212. def AddItem(self, value, parent=None):
  213. if not parent:
  214. root = self.seltree.GetRootItem()
  215. if not root:
  216. root = self.seltree.AddRoot("<hidden root>")
  217. parent = root
  218. item = self.seltree.AppendItem(parent, text=value)
  219. return item
  220. def OnMotion(self, evt):
  221. # have the selection follow the mouse, like in a real combobox
  222. item, flags = self.seltree.HitTest(evt.GetPosition())
  223. if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
  224. self.seltree.SelectItem(item)
  225. self.curitem = item
  226. evt.Skip()
  227. def OnLeftDown(self, evt):
  228. # do the combobox selection
  229. item, flags = self.seltree.HitTest(evt.GetPosition())
  230. if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
  231. self.curitem = item
  232. if self.seltree.GetRootItem() == self.seltree.GetItemParent(item):
  233. self.value = [] # cannot select mapset item
  234. else:
  235. if self.multiple is True:
  236. self.value.append(item)
  237. else:
  238. self.value = [item, ]
  239. self.Dismiss()
  240. evt.Skip()
  241. def SetData(self, type, mapsets, exceptOf, multiple):
  242. """Select multiple items?"""
  243. self.type = type
  244. self.mapsets = mapsets
  245. self.exceptOf = exceptOf
  246. self.multiple = multiple