gselect.py 9.6 KB

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