gselect.py 48 KB

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