gselect.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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 grass
  18. import globalvar
  19. import gcmd
  20. import utils
  21. from preferences import globalSettings as UserSettings
  22. class Select(wx.combo.ComboCtrl):
  23. def __init__(self, parent, id, size,
  24. type, multiple=False, mapsets=None, exceptOf=[]):
  25. """
  26. Custom control to create a ComboBox with a tree control
  27. to display and select GIS elements within acessible mapsets.
  28. Elements can be selected with mouse. Can allow multiple selections, when
  29. argument multiple=True. Multiple selections are separated by commas.
  30. """
  31. wx.combo.ComboCtrl.__init__(self, parent=parent, id=id, size=size)
  32. self.tcp = TreeCtrlComboPopup()
  33. self.SetPopupControl(self.tcp)
  34. self.SetPopupExtents(0,100)
  35. self.tcp.GetElementList(type, mapsets, exceptOf)
  36. self.tcp.SetData(type, mapsets, exceptOf, multiple)
  37. def SetElementList(self, type):
  38. self.tcp.seltree.DeleteAllItems()
  39. self.tcp.GetElementList(type)
  40. class TreeCtrlComboPopup(wx.combo.ComboPopup):
  41. """
  42. Create a tree ComboBox for selecting maps and other GIS elements
  43. in accessible mapsets within the current location
  44. """
  45. # overridden ComboPopup methods
  46. def Init(self):
  47. self.value = [] # for multiple is False -> len(self.value) in [0,1]
  48. self.curitem = None
  49. self.multiple = False
  50. self.type = None
  51. self.mapsets = []
  52. self.exceptOf = []
  53. def Create(self, parent):
  54. self.seltree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT
  55. |wx.TR_HAS_BUTTONS
  56. |wx.TR_SINGLE
  57. |wx.TR_LINES_AT_ROOT
  58. |wx.SIMPLE_BORDER
  59. |wx.TR_FULL_ROW_HIGHLIGHT)
  60. self.seltree.Bind(wx.EVT_MOTION, self.OnMotion)
  61. self.seltree.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
  62. self.seltree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.mapsetExpanded)
  63. self.seltree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.mapsetCollapsed)
  64. self.seltree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.mapsetActivated)
  65. self.seltree.Bind(wx.EVT_TREE_SEL_CHANGED, self.mapsetSelected)
  66. self.seltree.Bind(wx.EVT_TREE_DELETE_ITEM, lambda x: None)
  67. # the following dummy handler are needed to keep tree events from propagating up to
  68. # the parent GIS Manager layer tree
  69. def mapsetExpanded(self, event):
  70. pass
  71. def mapsetCollapsed(self, event):
  72. pass
  73. def mapsetActivated(self, event):
  74. pass
  75. def mapsetSelected(self, event):
  76. pass
  77. # end of dummy events
  78. def GetControl(self):
  79. return self.seltree
  80. def GetStringValue(self):
  81. str = ""
  82. for value in self.value:
  83. str += self.seltree.GetItemText(value) + ","
  84. str = str.rstrip(',')
  85. return str
  86. def OnPopup(self):
  87. """Limited only for first selected"""
  88. # update list
  89. self.seltree.DeleteAllItems()
  90. self.GetElementList(self.type, self.mapsets, self.exceptOf)
  91. if len(self.value) > 0:
  92. self.seltree.EnsureVisible(self.value[0])
  93. self.seltree.SelectItem(self.value[0])
  94. def SetStringValue(self, value):
  95. # this assumes that item strings are unique...
  96. root = self.seltree.GetRootItem()
  97. if not root:
  98. return
  99. found = self.FindItem(root, value)
  100. if found:
  101. self.value.append(found)
  102. self.seltree.SelectItem(found)
  103. def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
  104. return wx.Size(minWidth, min(200, maxHeight))
  105. def GetElementList(self, element, mapsets=None, exceptOf=[]):
  106. """
  107. Get list of GIS elements in accessible mapsets and display as tree
  108. with all relevant elements displayed beneath each mapset branch
  109. """
  110. # get current mapset
  111. curr_mapset = grass.gisenv()['MAPSET']
  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. filesdict = grass.list_grouped(elementdict[element])
  170. for dir in mapsets:
  171. dir_node = self.AddItem('Mapset: '+dir)
  172. self.seltree.SetItemTextColour(dir_node,wx.Colour(50,50,200))
  173. try:
  174. elem_list = filesdict[dir]
  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