gselect.py 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390
  1. """!
  2. @package gselect
  3. @brief Custom control that selects elements
  4. Classes:
  5. - Select
  6. - VectorSelect
  7. - TreeCrtlComboPopup
  8. - VectorDBInfo
  9. - LayerSelect
  10. - LayerNameSelect
  11. - DriverSelect
  12. - DatabaseSelect
  13. - ColumnSelect
  14. - DbaseSelect
  15. - LocationSelect
  16. - MapsetSelect
  17. - SubGroupSelect
  18. - FormatSelect
  19. - GdalSelect
  20. - ProjSelect
  21. (C) 2007-2010 by the GRASS Development Team This program is free
  22. software under the GNU General Public License (>=v2). Read the file
  23. COPYING that comes with GRASS for details.
  24. @author Michael Barton
  25. @author Martin Landa <landa.martin gmail.com>
  26. """
  27. import os
  28. import sys
  29. import glob
  30. import wx
  31. import wx.combo
  32. import wx.lib.filebrowsebutton as filebrowse
  33. from wx.lib.newevent import NewEvent
  34. import globalvar
  35. sys.path.append(os.path.join(globalvar.ETCDIR, "python"))
  36. import grass.script as grass
  37. import gcmd
  38. import utils
  39. from preferences import globalSettings as UserSettings
  40. from debug import Debug
  41. wxGdalSelect, EVT_GDALSELECT = NewEvent()
  42. class Select(wx.combo.ComboCtrl):
  43. def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
  44. type = None, multiple = False, mapsets = None,
  45. updateOnPopup = True, onPopup = None):
  46. """!Custom control to create a ComboBox with a tree control to
  47. display and select GIS elements within acessible mapsets.
  48. Elements can be selected with mouse. Can allow multiple
  49. selections, when argument multiple=True. Multiple selections
  50. are separated by commas.
  51. @param type type of GIS elements ('raster, 'vector', ...)
  52. @param multiple multiple input allowed?
  53. @param mapsets force list of mapsets (otherwise search path)
  54. @param updateOnPopup True for updating list of elements on popup
  55. @param onPopup function to be called on Popup
  56. """
  57. wx.combo.ComboCtrl.__init__(self, parent=parent, id=id, size=size)
  58. self.GetChildren()[0].SetName("Select")
  59. self.GetChildren()[0].type = type
  60. self.tcp = TreeCtrlComboPopup()
  61. self.SetPopupControl(self.tcp)
  62. self.SetPopupExtents(0,100)
  63. if type:
  64. self.tcp.SetData(type = type, mapsets = mapsets,
  65. multiple = multiple,
  66. updateOnPopup = updateOnPopup, onPopup = onPopup)
  67. def SetElementList(self, type, mapsets = None):
  68. """!Set element list
  69. @param type GIS element type
  70. @param mapsets list of acceptable mapsets (None for all in search path)
  71. """
  72. self.tcp.SetData(type = type, mapsets = mapsets)
  73. def GetElementList(self):
  74. """!Load elements"""
  75. self.tcp.GetElementList()
  76. class VectorSelect(Select):
  77. def __init__(self, parent, ftype, **kwargs):
  78. """!Custom to create a ComboBox with a tree control to display and
  79. select vector maps. Control allows to filter vector maps. If you
  80. don't need this feature use Select class instead
  81. @ftype filter vector maps based on feature type
  82. """
  83. Select.__init__(self, parent = parent, id = wx.ID_ANY,
  84. type = 'vector', **kwargs)
  85. self.ftype = ftype
  86. # remove vector maps which do not contain given feature type
  87. self.tcp.SetFilter(self._isElement)
  88. def _isElement(self, vectorName):
  89. """!Check if element should be filtered out"""
  90. try:
  91. if int(grass.vector_info_topo(vectorName)[self.ftype]) < 1:
  92. return False
  93. except KeyError:
  94. return False
  95. return True
  96. class TreeCtrlComboPopup(wx.combo.ComboPopup):
  97. """!Create a tree ComboBox for selecting maps and other GIS elements
  98. in accessible mapsets within the current location
  99. """
  100. # overridden ComboPopup methods
  101. def Init(self):
  102. self.value = [] # for multiple is False -> len(self.value) in [0,1]
  103. self.curitem = None
  104. self.multiple = False
  105. self.type = None
  106. self.mapsets = None
  107. self.updateOnPopup = True
  108. self.onPopup = None
  109. self.SetFilter(None)
  110. def Create(self, parent):
  111. self.seltree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT
  112. |wx.TR_HAS_BUTTONS
  113. |wx.TR_SINGLE
  114. |wx.TR_LINES_AT_ROOT
  115. |wx.SIMPLE_BORDER
  116. |wx.TR_FULL_ROW_HIGHLIGHT)
  117. self.seltree.Bind(wx.EVT_MOTION, self.OnMotion)
  118. self.seltree.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
  119. self.seltree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.mapsetExpanded)
  120. self.seltree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.mapsetCollapsed)
  121. self.seltree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.mapsetActivated)
  122. self.seltree.Bind(wx.EVT_TREE_SEL_CHANGED, self.mapsetSelected)
  123. self.seltree.Bind(wx.EVT_TREE_DELETE_ITEM, lambda x: None)
  124. # the following dummy handler are needed to keep tree events from propagating up to
  125. # the parent GIS Manager layer tree
  126. def mapsetExpanded(self, event):
  127. pass
  128. def mapsetCollapsed(self, event):
  129. pass
  130. def mapsetActivated(self, event):
  131. pass
  132. def mapsetSelected(self, event):
  133. pass
  134. # end of dummy events
  135. def GetControl(self):
  136. return self.seltree
  137. def GetStringValue(self):
  138. str = ""
  139. for value in self.value:
  140. str += value + ","
  141. str = str.rstrip(',')
  142. return str
  143. def SetFilter(self, filter):
  144. """!Set filter for GIS elements, see e.g. VectorSelect"""
  145. self.filterElements = filter
  146. def OnPopup(self, force = False):
  147. """!Limited only for first selected"""
  148. if not force and not self.updateOnPopup:
  149. return
  150. if self.onPopup:
  151. selected, exclude = self.onPopup(self.type)
  152. else:
  153. selected = None
  154. exclude = False
  155. self.GetElementList(selected, exclude)
  156. def GetElementList(self, elements = None, exclude = False):
  157. """!Get filtered list of GIS elements in accessible mapsets
  158. and display as tree with all relevant elements displayed
  159. beneath each mapset branch
  160. """
  161. # update list
  162. self.seltree.DeleteAllItems()
  163. self._getElementList(self.type, self.mapsets, elements, exclude)
  164. if len(self.value) > 0:
  165. root = self.seltree.GetRootItem()
  166. if not root:
  167. return
  168. item = self.FindItem(root, self.value[0])
  169. try:
  170. self.seltree.EnsureVisible(item)
  171. self.seltree.SelectItem(item)
  172. except:
  173. pass
  174. def SetStringValue(self, value):
  175. # this assumes that item strings are unique...
  176. root = self.seltree.GetRootItem()
  177. if not root:
  178. return
  179. found = self.FindItem(root, value)
  180. if found:
  181. self.value.append(found)
  182. self.seltree.SelectItem(found)
  183. def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
  184. return wx.Size(minWidth, min(200, maxHeight))
  185. def _getElementList(self, element, mapsets = None, elements = None, exclude = False):
  186. """!Get list of GIS elements in accessible mapsets and display as tree
  187. with all relevant elements displayed beneath each mapset branch
  188. @param element GIS element
  189. @param mapsets list of acceptable mapsets (None for all mapsets in search path)
  190. @param elements list of forced GIS elements
  191. @param exclude True to exclude, False for forcing the list (elements)
  192. """
  193. # get current mapset
  194. curr_mapset = grass.gisenv()['MAPSET']
  195. # list of mapsets in current location
  196. if mapsets is None:
  197. mapsets = utils.ListOfMapsets(get = 'accessible')
  198. # map element types to g.mlist types
  199. elementdict = {'cell':'rast',
  200. 'raster':'rast',
  201. 'rast':'rast',
  202. 'raster files':'rast',
  203. 'grid3':'rast3d',
  204. 'rast3d':'rast3d',
  205. 'raster3D':'rast3d',
  206. 'raster3D files':'rast3d',
  207. 'vector':'vect',
  208. 'vect':'vect',
  209. 'binary vector files':'vect',
  210. 'dig':'oldvect',
  211. 'oldvect':'oldvect',
  212. 'old vector':'oldvect',
  213. 'dig_ascii':'asciivect',
  214. 'asciivect':'asciivect',
  215. 'asciivector':'asciivect',
  216. 'ascii vector files':'asciivect',
  217. 'icons':'icon',
  218. 'icon':'icon',
  219. 'paint icon files':'icon',
  220. 'paint/labels':'labels',
  221. 'labels':'labels',
  222. 'label':'labels',
  223. 'paint label files':'labels',
  224. 'site_lists':'sites',
  225. 'sites':'sites',
  226. 'site list':'sites',
  227. 'site list files':'sites',
  228. 'windows':'region',
  229. 'region':'region',
  230. 'region definition':'region',
  231. 'region definition files':'region',
  232. 'windows3d':'region3d',
  233. 'region3d':'region3d',
  234. 'region3D definition':'region3d',
  235. 'region3D definition files':'region3d',
  236. 'group':'group',
  237. 'imagery group':'group',
  238. 'imagery group files':'group',
  239. '3d.view':'3dview',
  240. '3dview':'3dview',
  241. '3D viewing parameters':'3dview',
  242. '3D view parameters':'3dview'}
  243. if element not in elementdict:
  244. self.AddItem(_('Not selectable element'))
  245. return
  246. # get directory tree nodes
  247. # reorder mapsets based on search path (TODO)
  248. for i in range(len(mapsets)):
  249. if i > 0 and mapsets[i] == curr_mapset:
  250. mapsets[i] = mapsets[0]
  251. mapsets[0] = curr_mapset
  252. if globalvar.have_mlist:
  253. filesdict = grass.mlist_grouped(elementdict[element])
  254. else:
  255. filesdict = grass.list_grouped(elementdict[element])
  256. first_dir = None
  257. for dir in mapsets:
  258. dir_node = self.AddItem('Mapset: ' + dir)
  259. if not first_dir:
  260. first_dir = dir_node
  261. self.seltree.SetItemTextColour(dir_node, wx.Colour(50, 50, 200))
  262. try:
  263. elem_list = filesdict[dir]
  264. elem_list.sort(key=str.lower)
  265. for elem in elem_list:
  266. if elem != '':
  267. fullqElem = elem + '@' + dir
  268. if elements:
  269. if (exclude and fullqElem in elements) or \
  270. (not exclude and fullqElem not in elements):
  271. continue
  272. if self.filterElements:
  273. if self.filterElements(fullqElem):
  274. self.AddItem(fullqElem, parent=dir_node)
  275. else:
  276. self.AddItem(fullqElem, parent=dir_node)
  277. except:
  278. continue
  279. if self.seltree.ItemHasChildren(dir_node):
  280. sel = UserSettings.Get(group='general', key='elementListExpand',
  281. subkey='selection')
  282. collapse = True
  283. if sel == 0: # collapse all except PERMANENT and current
  284. if dir in ('PERMANENT', curr_mapset):
  285. collapse = False
  286. elif sel == 1: # collapse all except PERMANENT
  287. if dir == 'PERMANENT':
  288. collapse = False
  289. elif sel == 2: # collapse all except current
  290. if dir == curr_mapset:
  291. collapse = False
  292. elif sel == 3: # collapse all
  293. pass
  294. elif sel == 4: # expand all
  295. collapse = False
  296. if collapse:
  297. self.seltree.Collapse(dir_node)
  298. else:
  299. self.seltree.Expand(dir_node)
  300. if first_dir:
  301. # select first mapset (MSW hack)
  302. self.seltree.SelectItem(first_dir)
  303. # helpers
  304. def FindItem(self, parentItem, text):
  305. item, cookie = self.seltree.GetFirstChild(parentItem)
  306. while item:
  307. if self.seltree.GetItemText(item) == text:
  308. return item
  309. if self.seltree.ItemHasChildren(item):
  310. item = self.FindItem(item, text)
  311. item, cookie = self.seltree.GetNextChild(parentItem, cookie)
  312. return wx.TreeItemId()
  313. def AddItem(self, value, parent=None):
  314. if not parent:
  315. root = self.seltree.GetRootItem()
  316. if not root:
  317. root = self.seltree.AddRoot("<hidden root>")
  318. parent = root
  319. item = self.seltree.AppendItem(parent, text=value)
  320. return item
  321. def OnMotion(self, evt):
  322. # have the selection follow the mouse, like in a real combobox
  323. item, flags = self.seltree.HitTest(evt.GetPosition())
  324. if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
  325. self.seltree.SelectItem(item)
  326. self.curitem = item
  327. evt.Skip()
  328. def OnLeftDown(self, evt):
  329. # do the combobox selection
  330. item, flags = self.seltree.HitTest(evt.GetPosition())
  331. if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
  332. self.curitem = item
  333. if self.seltree.GetRootItem() == self.seltree.GetItemParent(item):
  334. self.value = [] # cannot select mapset item
  335. else:
  336. if self.multiple is True:
  337. # text item should be unique
  338. self.value.append(self.seltree.GetItemText(item))
  339. else:
  340. self.value = [self.seltree.GetItemText(item), ]
  341. self.Dismiss()
  342. evt.Skip()
  343. def SetData(self, **kargs):
  344. """!Set object properties"""
  345. if kargs.has_key('type'):
  346. self.type = kargs['type']
  347. if kargs.has_key('mapsets'):
  348. self.mapsets = kargs['mapsets']
  349. if kargs.has_key('multiple'):
  350. self.multiple = kargs['multiple']
  351. if kargs.has_key('updateOnPopup'):
  352. self.updateOnPopup = kargs['updateOnPopup']
  353. if kargs.has_key('onPopup'):
  354. self.onPopup = kargs['onPopup']
  355. class VectorDBInfo:
  356. """!Class providing information about attribute tables
  357. linked to a vector map"""
  358. def __init__(self, map):
  359. self.map = map
  360. # dictionary of layer number and associated (driver, database, table)
  361. self.layers = {}
  362. # dictionary of table and associated columns (type, length, values, ids)
  363. self.tables = {}
  364. if not self._CheckDBConnection(): # -> self.layers
  365. return
  366. self._DescribeTables() # -> self.tables
  367. def _CheckDBConnection(self):
  368. """!Check DB connection"""
  369. nuldev = file(os.devnull, 'w+')
  370. self.layers = grass.vector_db(map=self.map, stderr=nuldev)
  371. nuldev.close()
  372. if (len(self.layers.keys()) == 0):
  373. return False
  374. return True
  375. def _DescribeTables(self):
  376. """!Describe linked tables"""
  377. for layer in self.layers.keys():
  378. # determine column names and types
  379. table = self.layers[layer]["table"]
  380. columns = {} # {name: {type, length, [values], [ids]}}
  381. i = 0
  382. Debug.msg(1, "gselect.VectorDBInfo._DescribeTables(): table=%s driver=%s database=%s" % \
  383. (self.layers[layer]["table"], self.layers[layer]["driver"],
  384. self.layers[layer]["database"]))
  385. for item in grass.db_describe(table = self.layers[layer]["table"],
  386. driver = self.layers[layer]["driver"],
  387. database = self.layers[layer]["database"])['cols']:
  388. name, type, length = item
  389. # FIXME: support more datatypes
  390. if type.lower() == "integer":
  391. ctype = int
  392. elif type.lower() == "double precision":
  393. ctype = float
  394. else:
  395. ctype = str
  396. columns[name.strip()] = { 'index' : i,
  397. 'type' : type.lower(),
  398. 'ctype' : ctype,
  399. 'length' : int(length),
  400. 'values' : [],
  401. 'ids' : []}
  402. i += 1
  403. # check for key column
  404. # v.db.connect -g/p returns always key column name lowercase
  405. if self.layers[layer]["key"] not in columns.keys():
  406. for col in columns.keys():
  407. if col.lower() == self.layers[layer]["key"]:
  408. self.layers[layer]["key"] = col.upper()
  409. break
  410. self.tables[table] = columns
  411. return True
  412. def Reset(self):
  413. """!Reset"""
  414. for layer in self.layers:
  415. table = self.layers[layer]["table"] # get table desc
  416. columns = self.tables[table]
  417. for name in self.tables[table].keys():
  418. self.tables[table][name]['values'] = []
  419. self.tables[table][name]['ids'] = []
  420. def GetName(self):
  421. """!Get vector name"""
  422. return self.map
  423. def GetKeyColumn(self, layer):
  424. """!Get key column of given layer
  425. @param layer vector layer number
  426. """
  427. return self.layers[layer]['key']
  428. def GetTable(self, layer):
  429. """!Get table name of given layer
  430. @param layer vector layer number
  431. """
  432. return self.layers[layer]['table']
  433. def GetDbSettings(self, layer):
  434. """!Get database settins
  435. @param layer layer number
  436. @return (driver, database)
  437. """
  438. return self.layers[layer]['driver'], self.layers[layer]['database']
  439. def GetTableDesc(self, table):
  440. """!Get table columns
  441. @param table table name
  442. """
  443. return self.tables[table]
  444. class LayerSelect(wx.Choice):
  445. def __init__(self, parent, id = wx.ID_ANY,
  446. size=globalvar.DIALOG_LAYER_SIZE,
  447. vector = None, choices = [], all = False, default = None):
  448. """!Creates widget for selecting vector map layer numbers
  449. @param vector vector map name or None
  450. @param choices list of predefined choices
  451. @param all adds layer '-1' (e.g., for d.vect)
  452. @param default default layer number
  453. """
  454. super(LayerSelect, self).__init__(parent, id, size = size,
  455. choices = choices)
  456. self.all = all
  457. self.SetName("LayerSelect")
  458. # default value
  459. self.default = default
  460. if len(choices) > 1:
  461. return
  462. if vector:
  463. self.InsertLayers(vector)
  464. else:
  465. if all:
  466. self.SetItems(['-1', '1'])
  467. else:
  468. self.SetItems(['1'])
  469. self.SetStringSelection('1')
  470. def InsertLayers(self, vector):
  471. """!Insert layers for a vector into the layer combobox"""
  472. layerchoices = utils.GetVectorNumberOfLayers(vector)
  473. if self.all:
  474. layerchoices.insert(0, '-1')
  475. if len(layerchoices) > 1:
  476. self.SetItems(layerchoices)
  477. self.SetStringSelection('1')
  478. else:
  479. self.SetItems(['1'])
  480. self.SetStringSelection('1')
  481. if self.default:
  482. self.SetStringSelection(str(self.default))
  483. class LayerNameSelect(wx.ComboBox):
  484. def __init__(self, parent, id = wx.ID_ANY,
  485. size = globalvar.DIALOG_COMBOBOX_SIZE,
  486. vector = None, dsn = None):
  487. """!Creates combo box for selecting vector map layer names
  488. @param vector vector map name (native or connected via v.external)
  489. @param dsn OGR data source name
  490. """
  491. super(LayerNameSelect, self).__init__(parent, id, size = size)
  492. self.SetName("LayerNameSelect")
  493. if vector:
  494. # -> native
  495. self.InsertLayers(vector = vector)
  496. elif dsn:
  497. self.InsertLayers(dsn = dsn)
  498. def InsertLayers(self, vector = None, dsn = None):
  499. """!Insert layers for a vector into the layer combobox
  500. @todo Implement native format
  501. @param vector vector map name (native or connected via v.external)
  502. @param dsn OGR data source name
  503. """
  504. layers = list()
  505. if vector:
  506. # TODO
  507. pass
  508. elif dsn:
  509. ret = gcmd.RunCommand('v.in.ogr',
  510. read = True,
  511. quiet = True,
  512. flags = 'l',
  513. dsn = dsn)
  514. if ret:
  515. layers = ret.splitlines()
  516. self.SetItems(layers)
  517. self.SetSelection(0)
  518. class DriverSelect(wx.ComboBox):
  519. """!Creates combo box for selecting database driver.
  520. """
  521. def __init__(self, parent, choices, value,
  522. id=wx.ID_ANY, pos=wx.DefaultPosition,
  523. size=globalvar.DIALOG_LAYER_SIZE, **kargs):
  524. super(DriverSelect, self).__init__(parent, id, value, pos, size,
  525. choices, style=wx.CB_READONLY)
  526. self.SetName("DriverSelect")
  527. self.SetStringSelection(value)
  528. class DatabaseSelect(wx.TextCtrl):
  529. """!Creates combo box for selecting database driver.
  530. """
  531. def __init__(self, parent, value='',
  532. id=wx.ID_ANY, pos=wx.DefaultPosition,
  533. size=globalvar.DIALOG_TEXTCTRL_SIZE, **kargs):
  534. super(DatabaseSelect, self).__init__(parent, id, value, pos, size)
  535. self.SetName("DatabaseSelect")
  536. class TableSelect(wx.ComboBox):
  537. """!Creates combo box for selecting attribute tables from the database
  538. """
  539. def __init__(self, parent,
  540. id=wx.ID_ANY, value='', pos=wx.DefaultPosition,
  541. size=globalvar.DIALOG_COMBOBOX_SIZE,
  542. choices=[]):
  543. super(TableSelect, self).__init__(parent, id, value, pos, size, choices,
  544. style=wx.CB_READONLY)
  545. self.SetName("TableSelect")
  546. if not choices:
  547. self.InsertTables()
  548. def InsertTables(self, driver=None, database=None):
  549. """!Insert attribute tables into combobox"""
  550. items = []
  551. if not driver or not database:
  552. connect = grass.db_connection()
  553. driver = connect['driver']
  554. database = connect['database']
  555. ret = gcmd.RunCommand('db.tables',
  556. flags = 'p',
  557. read = True,
  558. driver = driver,
  559. database = database)
  560. if ret:
  561. for table in ret.splitlines():
  562. items.append(table)
  563. self.SetItems(items)
  564. self.SetValue('')
  565. class ColumnSelect(wx.ComboBox):
  566. """!Creates combo box for selecting columns in the attribute table
  567. for a vector map.
  568. @param parent window parent
  569. @param id window id
  570. @param value default value
  571. @param size window size
  572. @param vector vector map name
  573. @param layer layer number
  574. @param param parameters list (see menuform.py)
  575. @param **kwags wx.ComboBox parameters
  576. """
  577. def __init__(self, parent, id = wx.ID_ANY, value = '',
  578. size=globalvar.DIALOG_COMBOBOX_SIZE,
  579. vector = None, layer = 1, param = None, **kwargs):
  580. self.defaultValue = value
  581. self.param = param
  582. super(ColumnSelect, self).__init__(parent, id, value, size = size, **kwargs)
  583. self.SetName("ColumnSelect")
  584. if vector:
  585. self.InsertColumns(vector, layer)
  586. def InsertColumns(self, vector, layer, excludeKey = False, type = None, dbInfo = None):
  587. """!Insert columns for a vector attribute table into the columns combobox
  588. @param vector vector name
  589. @param layer vector layer number
  590. @param excludeKey exclude key column from the list?
  591. @param type only columns of given type (given as list)
  592. """
  593. if not dbInfo:
  594. dbInfo = VectorDBInfo(vector)
  595. try:
  596. table = dbInfo.GetTable(int(layer))
  597. columnchoices = dbInfo.GetTableDesc(table)
  598. keyColumn = dbInfo.GetKeyColumn(int(layer))
  599. columns = len(columnchoices.keys()) * ['']
  600. for key, val in columnchoices.iteritems():
  601. columns[val['index']] = key
  602. if excludeKey: # exclude key column
  603. columns.remove(keyColumn)
  604. if type: # only selected column types
  605. for key, value in columnchoices.iteritems():
  606. if value['type'] not in type:
  607. columns.remove(key)
  608. except (KeyError, ValueError):
  609. columns = list()
  610. self.SetItems(columns)
  611. self.SetValue(self.defaultValue)
  612. if self.param:
  613. self.param['value'] = ''
  614. def InsertTableColumns(self, table, driver=None, database=None):
  615. """!Insert table columns
  616. @param table table name
  617. @param driver driver name
  618. @param database database name
  619. """
  620. columns = list()
  621. ret = gcmd.RunCommand('db.columns',
  622. read = True,
  623. driver = driver,
  624. database = database,
  625. table = table)
  626. if ret:
  627. columns = ret.splitlines()
  628. self.SetItems(columns)
  629. self.SetValue(self.defaultValue)
  630. if self.param:
  631. self.param['value'] = ''
  632. class DbaseSelect(wx.lib.filebrowsebutton.DirBrowseButton):
  633. """!Widget for selecting GRASS Database"""
  634. def __init__(self, parent, **kwargs):
  635. super(DbaseSelect, self).__init__(parent, id = wx.ID_ANY,
  636. size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
  637. dialogTitle = _('Choose GIS Data Directory'),
  638. buttonText = _('Browse'),
  639. startDirectory = grass.gisenv()['GISDBASE'],
  640. **kwargs)
  641. class LocationSelect(wx.ComboBox):
  642. """!Widget for selecting GRASS location"""
  643. def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
  644. gisdbase = None, **kwargs):
  645. super(LocationSelect, self).__init__(parent, id, size = size,
  646. style = wx.CB_READONLY, **kwargs)
  647. self.SetName("LocationSelect")
  648. if not gisdbase:
  649. self.gisdbase = grass.gisenv()['GISDBASE']
  650. else:
  651. self.gisdbase = gisdbase
  652. self.SetItems(utils.GetListOfLocations(self.gisdbase))
  653. def UpdateItems(self, dbase):
  654. """!Update list of locations
  655. @param dbase path to GIS database
  656. """
  657. self.gisdbase = dbase
  658. if dbase:
  659. self.SetItems(utils.GetListOfLocations(self.gisdbase))
  660. else:
  661. self.SetItems([])
  662. class MapsetSelect(wx.ComboBox):
  663. """!Widget for selecting GRASS mapset"""
  664. def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
  665. gisdbase = None, location = None, setItems = True, **kwargs):
  666. super(MapsetSelect, self).__init__(parent, id, size = size,
  667. style = wx.CB_READONLY, **kwargs)
  668. self.SetName("MapsetSelect")
  669. if not gisdbase:
  670. self.gisdbase = grass.gisenv()['GISDBASE']
  671. else:
  672. self.gisdbase = gisdbase
  673. if not location:
  674. self.location = grass.gisenv()['LOCATION_NAME']
  675. else:
  676. self.location = location
  677. if setItems:
  678. self.SetItems(utils.GetListOfMapsets(self.gisdbase, self.location, selectable = False)) # selectable
  679. def UpdateItems(self, location, dbase = None):
  680. """!Update list of mapsets for given location
  681. @param dbase path to GIS database (None to use currently selected)
  682. @param location name of location
  683. """
  684. if dbase:
  685. self.gisdbase = dbase
  686. self.location = location
  687. if location:
  688. self.SetItems(utils.GetListOfMapsets(self.gisdbase, self.location, selectable = False))
  689. else:
  690. self.SetItems([])
  691. class SubGroupSelect(wx.ComboBox):
  692. """!Widget for selecting subgroups"""
  693. def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
  694. **kwargs):
  695. super(SubGroupSelect, self).__init__(parent, id, size = size,
  696. style = wx.CB_READONLY, **kwargs)
  697. self.SetName("SubGroupSelect")
  698. def Insert(self, group):
  699. """!Insert subgroups for defined group"""
  700. if not group:
  701. return
  702. gisenv = grass.gisenv()
  703. try:
  704. name, mapset = group.split('@', 1)
  705. except ValueError:
  706. name = group
  707. mapset = gisenv['MAPSET']
  708. path = os.path.join(gisenv['GISDBASE'], gisenv['LOCATION_NAME'], mapset,
  709. 'group', name, 'subgroup')
  710. try:
  711. self.SetItems(os.listdir(path))
  712. except OSError:
  713. self.SetItems([])
  714. self.SetValue('')
  715. class FormatSelect(wx.Choice):
  716. def __init__(self, parent, ogr = False,
  717. sourceType = None, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
  718. **kwargs):
  719. """!Widget for selecting external (GDAL/OGR) format
  720. @param parent parent window
  721. @param sourceType source type ('file', 'directory', 'database', 'protocol') or None
  722. @param ogr True for OGR otherwise GDAL
  723. """
  724. super(FormatSelect, self).__init__(parent, id, size = size,
  725. style = wx.CB_READONLY, **kwargs)
  726. self.SetName("FormatSelect")
  727. if ogr:
  728. ftype = 'ogr'
  729. else:
  730. ftype = 'gdal'
  731. formats = list()
  732. for f in utils.GetFormats()[ftype].values():
  733. formats += f
  734. self.SetItems(formats)
  735. def GetExtension(self, name):
  736. """!Get file extension by format name"""
  737. formatToExt = {
  738. # raster
  739. 'GeoTIFF' : 'tif',
  740. 'Erdas Imagine Images (.img)' : 'img',
  741. 'Ground-based SAR Applications Testbed File Format (.gff)' : 'gff',
  742. 'Arc/Info Binary Grid' : 'adf',
  743. 'Portable Network Graphics' : 'png',
  744. 'JPEG JFIF' : 'jpg',
  745. 'Japanese DEM (.mem)' : 'mem',
  746. 'Graphics Interchange Format (.gif)' : 'gif',
  747. 'X11 PixMap Format' : 'xpm',
  748. 'MS Windows Device Independent Bitmap' : 'bmp',
  749. 'SPOT DIMAP' : 'dim',
  750. 'RadarSat 2 XML Product' : 'xml',
  751. 'EarthWatch .TIL' : 'til',
  752. 'ERMapper .ers Labelled' : 'ers',
  753. 'ERMapper Compressed Wavelets' : 'ecw',
  754. 'GRIdded Binary (.grb)' : 'grb',
  755. 'EUMETSAT Archive native (.nat)' : 'nat',
  756. 'Idrisi Raster A.1' : 'rst',
  757. 'Golden Software ASCII Grid (.grd)' : 'grd',
  758. 'Golden Software Binary Grid (.grd)' : 'grd',
  759. 'Golden Software 7 Binary Grid (.grd)' : 'grd',
  760. 'R Object Data Store' : 'r',
  761. 'USGS DOQ (Old Style)' : 'doq',
  762. 'USGS DOQ (New Style)' : 'doq',
  763. 'ENVI .hdr Labelled' : 'hdr',
  764. 'ESRI .hdr Labelled' : 'hdr',
  765. 'Generic Binary (.hdr Labelled)' : 'hdr',
  766. 'PCI .aux Labelled' : 'aux',
  767. 'EOSAT FAST Format' : 'fst',
  768. 'VTP .bt (Binary Terrain) 1.3 Format' : 'bt',
  769. 'FARSITE v.4 Landscape File (.lcp)' : 'lcp',
  770. 'Swedish Grid RIK (.rik)' : 'rik',
  771. 'USGS Optional ASCII DEM (and CDED)' : 'dem',
  772. 'Northwood Numeric Grid Format .grd/.tab' : '',
  773. 'Northwood Classified Grid Format .grc/.tab' : '',
  774. 'ARC Digitized Raster Graphics' : 'arc',
  775. 'Magellan topo (.blx)' : 'blx',
  776. 'SAGA GIS Binary Grid (.sdat)' : 'sdat',
  777. # vector
  778. 'ESRI Shapefile' : 'shp',
  779. 'UK .NTF' : 'ntf',
  780. 'SDTS' : 'ddf',
  781. 'DGN' : 'dgn',
  782. 'VRT' : 'vrt',
  783. 'REC' : 'rec',
  784. 'BNA' : 'bna',
  785. 'CSV' : 'csv',
  786. 'GML' : 'gml',
  787. 'GPX' : 'gpx',
  788. 'KML' : 'kml',
  789. 'GMT' : 'gmt',
  790. 'PGeo' : 'mdb',
  791. 'XPlane' : 'dat',
  792. 'AVCBin' : 'adf',
  793. 'AVCE00' : 'e00',
  794. 'DXF' : 'dxf',
  795. 'Geoconcept' : 'gxt',
  796. 'GeoRSS' : 'xml',
  797. 'GPSTrackMaker' : 'gtm',
  798. 'VFK' : 'vfk'
  799. }
  800. try:
  801. return formatToExt[name]
  802. except KeyError:
  803. return ''
  804. class GdalSelect(wx.Panel):
  805. def __init__(self, parent, panel, ogr = False,
  806. default = 'file',
  807. exclude = [],
  808. envHandler = None):
  809. """!Widget for selecting GDAL/OGR datasource, format
  810. @param parent parent window
  811. @param ogr use OGR selector instead of GDAL
  812. """
  813. self.parent = parent
  814. self.ogr = ogr
  815. wx.Panel.__init__(self, parent = panel, id = wx.ID_ANY)
  816. self.inputBox = wx.StaticBox(parent = self, id=wx.ID_ANY,
  817. label=" %s " % _("Source name"))
  818. # source type
  819. sources = list()
  820. self.sourceMap = { 'file' : -1,
  821. 'dir' : -1,
  822. 'db' : -1,
  823. 'pro' : -1 }
  824. idx = 0
  825. if 'file' not in exclude:
  826. sources.append(_("File"))
  827. self.sourceMap['file'] = idx
  828. idx += 1
  829. if 'directory' not in exclude:
  830. sources.append(_("Directory"))
  831. self.sourceMap['dir'] = idx
  832. idx += 1
  833. if 'database' not in exclude:
  834. sources.append(_("Database"))
  835. self.sourceMap['db'] = idx
  836. idx += 1
  837. if 'protocol' not in exclude:
  838. sources.append(_("Protocol"))
  839. self.sourceMap['pro'] = idx
  840. self.source = wx.RadioBox(parent = self, id = wx.ID_ANY,
  841. label = _('Source type'),
  842. style = wx.RA_SPECIFY_COLS,
  843. choices = sources)
  844. self.source.SetSelection(0)
  845. self.source.Bind(wx.EVT_RADIOBOX, self.OnSetType)
  846. # dsn widgets
  847. if not ogr:
  848. filemask = 'GeoTIFF (*.tif)|*.%s' % self._getExtPattern('tif')
  849. else:
  850. filemask = 'ESRI Shapefile (*.shp)|*.%s' % self._getExtPattern('shp')
  851. dsnFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
  852. size=globalvar.DIALOG_GSELECT_SIZE, labelText = '',
  853. dialogTitle=_('Choose file to import'),
  854. buttonText=_('Browse'),
  855. startDirectory=os.getcwd(),
  856. changeCallback=self.OnSetDsn,
  857. fileMask=filemask)
  858. dsnFile.Hide()
  859. dsnDir = filebrowse.DirBrowseButton(parent=self, id=wx.ID_ANY,
  860. size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
  861. dialogTitle=_('Choose input directory'),
  862. buttonText=_('Browse'),
  863. startDirectory=os.getcwd(),
  864. changeCallback=self.OnSetDsn)
  865. dsnDir.SetName('GdalSelect')
  866. dsnDir.Hide()
  867. dsnDbFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
  868. size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
  869. dialogTitle=_('Choose file'),
  870. buttonText=_('Browse'),
  871. startDirectory=os.getcwd(),
  872. changeCallback=self.OnSetDsn)
  873. dsnDbFile.Hide()
  874. dsnDbFile.SetName('GdalSelect')
  875. dsnDbText = wx.TextCtrl(parent = self, id = wx.ID_ANY)
  876. dsnDbText.Hide()
  877. dsnDbText.Bind(wx.EVT_TEXT, self.OnSetDsn)
  878. dsnDbText.SetName('GdalSelect')
  879. dsnDbChoice = wx.Choice(parent = self, id = wx.ID_ANY)
  880. dsnDbChoice.Hide()
  881. dsnDbChoice.Bind(wx.EVT_CHOICE, self.OnSetDsn)
  882. dsnDbChoice.SetName('GdalSelect')
  883. dsnPro = wx.TextCtrl(parent = self, id = wx.ID_ANY)
  884. dsnPro.Hide()
  885. dsnPro.Bind(wx.EVT_TEXT, self.OnSetDsn)
  886. dsnPro.SetName('GdalSelect')
  887. # format
  888. self.format = FormatSelect(parent = self,
  889. ogr = ogr)
  890. self.format.Bind(wx.EVT_CHOICE, self.OnSetFormat)
  891. if ogr:
  892. fType = 'ogr'
  893. else:
  894. fType = 'gdal'
  895. self.input = { 'file' : [_("File:"),
  896. dsnFile,
  897. utils.GetFormats()[fType]['file']],
  898. 'dir' : [_("Directory:"),
  899. dsnDir,
  900. utils.GetFormats()[fType]['file']],
  901. 'db' : [_("Database:"),
  902. dsnDbFile,
  903. utils.GetFormats()[fType]['database']],
  904. 'pro' : [_("Protocol:"),
  905. dsnPro,
  906. utils.GetFormats()[fType]['protocol']],
  907. 'db-win' : { 'file' : dsnDbFile,
  908. 'text' : dsnDbText,
  909. 'choice' : dsnDbChoice },
  910. }
  911. self.dsnType = default
  912. self.input[self.dsnType][1].Show()
  913. self.format.SetItems(self.input[self.dsnType][2])
  914. if not ogr:
  915. self.format.SetStringSelection('GeoTIFF')
  916. else:
  917. self.format.SetStringSelection('ESRI Shapefile')
  918. self.dsnText = wx.StaticText(parent = self, id = wx.ID_ANY,
  919. label = self.input[self.dsnType][0],
  920. size = (75, -1))
  921. self.formatText = wx.StaticText(parent = self, id = wx.ID_ANY,
  922. label = _("Format:"))
  923. self._layout()
  924. def _layout(self):
  925. """!Layout"""
  926. mainSizer = wx.BoxSizer(wx.VERTICAL)
  927. inputSizer = wx.StaticBoxSizer(self.inputBox, wx.HORIZONTAL)
  928. self.dsnSizer = wx.GridBagSizer(vgap=3, hgap=3)
  929. self.dsnSizer.AddGrowableRow(1)
  930. self.dsnSizer.AddGrowableCol(1)
  931. self.dsnSizer.Add(item=self.dsnText,
  932. flag=wx.ALIGN_CENTER_VERTICAL,
  933. pos = (0, 0))
  934. self.dsnSizer.Add(item=self.input[self.dsnType][1],
  935. flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
  936. pos = (0, 1))
  937. self.dsnSizer.Add(item=self.formatText,
  938. flag=wx.ALIGN_CENTER_VERTICAL,
  939. pos = (1, 0))
  940. self.dsnSizer.Add(item=self.format,
  941. flag = wx.ALIGN_CENTER_VERTICAL,
  942. pos = (1, 1))
  943. inputSizer.Add(item=self.dsnSizer, proportion=1,
  944. flag=wx.EXPAND | wx.ALL)
  945. mainSizer.Add(item=self.source, proportion=0,
  946. flag=wx.ALL | wx.EXPAND, border=5)
  947. mainSizer.Add(item=inputSizer, proportion=0,
  948. flag=wx.ALL | wx.EXPAND, border=5)
  949. self.SetSizer(mainSizer)
  950. mainSizer.Fit(self)
  951. def _getExtPattern(self, ext):
  952. """!Get pattern for case-insensitive mask"""
  953. pattern = ''
  954. for c in ext:
  955. pattern += '[' + c + c.upper() + ']'
  956. return pattern
  957. def OnSetType(self, event):
  958. """!Datasource type changed"""
  959. sel = event.GetSelection()
  960. win = self.input[self.dsnType][1]
  961. self.dsnSizer.Remove(win)
  962. win.Hide()
  963. if sel == self.sourceMap['file']: # file
  964. self.dsnType = 'file'
  965. format = self.input[self.dsnType][2][0]
  966. try:
  967. ext = self.format.GetExtension(format)
  968. if not ext:
  969. raise KeyError
  970. format += ' (*.%s)|*.%s' % (ext, self._getExtPattern(ext))
  971. print format
  972. except KeyError:
  973. format += ' (*.*)|*.*'
  974. win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
  975. size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
  976. dialogTitle=_('Choose file to import'),
  977. buttonText=_('Browse'),
  978. startDirectory=os.getcwd(),
  979. changeCallback=self.OnSetDsn,
  980. fileMask = format)
  981. self.input[self.dsnType][1] = win
  982. elif sel == self.sourceMap['dir']: # directory
  983. self.dsnType = 'dir'
  984. elif sel == self.sourceMap['db']: # database
  985. self.dsnType = 'db'
  986. elif sel == self.sourceMap['pro']: # protocol
  987. self.dsnType = 'pro'
  988. self.dsnText.SetLabel(self.input[self.dsnType][0])
  989. if self.parent.GetName() == 'MultiImportDialog':
  990. self.parent.list.DeleteAllItems()
  991. self.format.SetItems(self.input[self.dsnType][2])
  992. if sel in (self.sourceMap['file'],
  993. self.sourceMap['dir']):
  994. win = self.input[self.dsnType][1]
  995. self.dsnSizer.Add(item=self.input[self.dsnType][1],
  996. flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
  997. pos = (0, 1))
  998. win.SetValue('')
  999. win.Show()
  1000. if not self.ogr:
  1001. self.format.SetStringSelection('GeoTIFF')
  1002. else:
  1003. self.format.SetStringSelection('ESRI Shapefile')
  1004. elif sel == self.sourceMap['pro']:
  1005. win = self.input[self.dsnType][1]
  1006. self.dsnSizer.Add(item=self.input[self.dsnType][1],
  1007. flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
  1008. pos = (0, 1))
  1009. win.SetValue('')
  1010. win.Show()
  1011. self.dsnSizer.Layout()
  1012. def OnSetDsn(self, event):
  1013. """!Input DXF file/OGR dsn defined, update list of layer widget"""
  1014. path = event.GetString()
  1015. if not path:
  1016. return
  1017. data = list()
  1018. layerId = 1
  1019. if self.format.GetStringSelection() == 'PostgreSQL':
  1020. dsn = 'PG:dbname=%s' % self.input[self.dsnType][1].GetValue()
  1021. else:
  1022. dsn = self.input[self.dsnType][1].GetValue()
  1023. if self.dsnType == 'file':
  1024. baseName = os.path.basename(dsn)
  1025. grassName = utils.GetValidLayerName(baseName.split('.', -1)[0])
  1026. data.append((layerId, baseName, grassName))
  1027. elif self.dsnType == 'dir':
  1028. try:
  1029. ext = self.format.GetExtension(self.format.GetStringSelection())
  1030. except KeyError:
  1031. ext = ''
  1032. for file in glob.glob(os.path.join(dsn, "*.%s") % self._getExtPattern(ext)):
  1033. baseName = os.path.basename(file)
  1034. grassName = utils.GetValidLayerName(baseName.split('.', -1)[0])
  1035. data.append((layerId, baseName, grassName))
  1036. layerId += 1
  1037. elif self.dsnType == 'db':
  1038. ret = gcmd.RunCommand('v.in.ogr',
  1039. quiet = True,
  1040. read = True,
  1041. flags = 'l',
  1042. dsn = dsn)
  1043. if not ret:
  1044. self.parent.list.LoadData()
  1045. if hasattr(self, "btn_run"):
  1046. self.btn_run.Enable(False)
  1047. return
  1048. layerId = 1
  1049. for line in ret.splitlines():
  1050. layerName = line.strip()
  1051. grassName = utils.GetValidLayerName(layerName)
  1052. data.append((layerId, layerName.strip(), grassName.strip()))
  1053. layerId += 1
  1054. evt = wxGdalSelect(dsn = dsn + '@OGR')
  1055. evt.SetId(self.input[self.dsnType][1].GetId())
  1056. wx.PostEvent(self.parent, evt)
  1057. if self.parent.GetName() == 'MultiImportDialog':
  1058. self.parent.list.LoadData(data)
  1059. if len(data) > 0:
  1060. self.parent.btn_run.Enable(True)
  1061. else:
  1062. self.parent.btn_run.Enable(False)
  1063. event.Skip()
  1064. def OnSetFormat(self, event):
  1065. """!Format changed"""
  1066. if self.dsnType not in ['file', 'db']:
  1067. return
  1068. win = self.input[self.dsnType][1]
  1069. self.dsnSizer.Remove(win)
  1070. if self.dsnType == 'file':
  1071. win.Destroy()
  1072. else: # database
  1073. win.Hide()
  1074. format = event.GetString()
  1075. if self.dsnType == 'file':
  1076. try:
  1077. ext = self.format.GetExtension(format)
  1078. if not ext:
  1079. raise KeyError
  1080. format += ' (*.%s)|*.%s' % (ext, self._getExtPattern(ext))
  1081. except KeyError:
  1082. format += ' (*.*)|*.*'
  1083. win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
  1084. size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
  1085. dialogTitle=_('Choose file'),
  1086. buttonText=_('Browse'),
  1087. startDirectory=os.getcwd(),
  1088. changeCallback=self.OnSetDsn,
  1089. fileMask = format)
  1090. else: # database
  1091. if format == 'SQLite' or format == 'Rasterlite':
  1092. win = self.input['db-win']['file']
  1093. elif format == 'PostgreSQL' or format == 'PostGIS WKT Raster driver':
  1094. if grass.find_program('psql'):
  1095. win = self.input['db-win']['choice']
  1096. if not win.GetItems():
  1097. p = grass.Popen(['psql', '-ltA'], stdout = grass.PIPE)
  1098. ret = p.communicate()[0]
  1099. if ret:
  1100. db = list()
  1101. for line in ret.splitlines():
  1102. sline = line.split('|')
  1103. if len(sline) < 2:
  1104. continue
  1105. dbname = sline[0]
  1106. if dbname:
  1107. db.append(dbname)
  1108. win.SetItems(db)
  1109. else:
  1110. win = self.input['db-win']['text']
  1111. else:
  1112. win = self.input['db-win']['text']
  1113. self.input[self.dsnType][1] = win
  1114. if not win.IsShown():
  1115. win.Show()
  1116. self.dsnSizer.Add(item=self.input[self.dsnType][1],
  1117. flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
  1118. pos = (0, 1))
  1119. self.dsnSizer.Layout()
  1120. def GetType(self):
  1121. """!Get source type"""
  1122. return self.dsnType
  1123. def GetDsn(self):
  1124. """!Get DSN"""
  1125. if self.format.GetStringSelection() == 'PostgreSQL':
  1126. return 'PG:dbname=%s' % self.input[self.dsnType][1].GetValue()
  1127. return self.input[self.dsnType][1].GetValue()
  1128. def GetDsnWin(self):
  1129. """!Get list of DSN windows"""
  1130. win = list()
  1131. for stype in ('file', 'dir', 'pro'):
  1132. win.append(self.input[stype][1])
  1133. for stype in ('file', 'text', 'choice'):
  1134. win.append(self.input['db-win'][stype])
  1135. return win
  1136. def GetFormatExt(self):
  1137. """!Get format extension"""
  1138. return self.format.GetExtension(self.format.GetStringSelection())
  1139. class ProjSelect(wx.ComboBox):
  1140. """!Widget for selecting input raster/vector map used by
  1141. r.proj/v.proj modules."""
  1142. def __init__(self, parent, isRaster, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
  1143. **kwargs):
  1144. super(ProjSelect, self).__init__(parent, id, size = size,
  1145. style = wx.CB_READONLY, **kwargs)
  1146. self.SetName("ProjSelect")
  1147. self.isRaster = isRaster
  1148. def UpdateItems(self, dbase, location, mapset):
  1149. """!Update list of maps
  1150. """
  1151. if not dbase:
  1152. dbase = grass.gisenv()['GISDBASE']
  1153. if not mapset:
  1154. mapset = grass.gisenv()['MAPSET']
  1155. if self.isRaster:
  1156. ret = gcmd.RunCommand('r.proj',
  1157. quiet = True,
  1158. read = True,
  1159. flags = 'l',
  1160. dbase = dbase,
  1161. location = location,
  1162. mapset = mapset)
  1163. else:
  1164. ret = gcmd.RunCommand('v.proj',
  1165. quiet = True,
  1166. read = True,
  1167. flags = 'l',
  1168. dbase = dbase,
  1169. location = location,
  1170. mapset = mapset)
  1171. listMaps = list()
  1172. if ret:
  1173. for line in ret.splitlines():
  1174. listMaps.append(line.strip())
  1175. utils.ListSortLower(listMaps)
  1176. self.SetItems(listMaps)
  1177. self.SetValue('')