import_export.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. """
  2. @package modules.import_export
  3. @brief Import/export dialogs used in wxGUI.
  4. List of classes:
  5. - :class:`ImportDialog`
  6. - :class:`GdalImportDialog`
  7. - :class:`GdalOutputDialog`
  8. - :class:`DxfImportDialog`
  9. (C) 2008-2015 by the GRASS Development Team
  10. This program is free software under the GNU General Public License
  11. (>=v2). Read the file COPYING that comes with GRASS for details.
  12. @author Martin Landa <landa.martin gmail.com>
  13. @author Anna Kratochvilova <kratochanna gmail.com> (GroupDialog, SymbolDialog)
  14. """
  15. import os
  16. import wx
  17. import wx.lib.filebrowsebutton as filebrowse
  18. from grass.script import core as grass
  19. from grass.script import task as gtask
  20. from core import globalvar
  21. from core.gcmd import RunCommand, GMessage, GWarning
  22. from gui_core.gselect import OgrTypeSelect, GdalSelect, SubGroupSelect
  23. from gui_core.widgets import LayersList
  24. from core.utils import GetValidLayerName, _
  25. from core.settings import UserSettings, GetDisplayVectSettings
  26. class ImportDialog(wx.Dialog):
  27. """Dialog for bulk import of various data (base class)"""
  28. def __init__(self, parent, giface, itype,
  29. id = wx.ID_ANY, title = _("Multiple import"),
  30. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
  31. self.parent = parent # GMFrame
  32. self._giface = giface # used to add layers
  33. self.importType = itype
  34. self.options = dict() # list of options
  35. self.options_par = dict()
  36. self.commandId = -1 # id of running command
  37. wx.Dialog.__init__(self, parent, id, title, style = style,
  38. name = "MultiImportDialog")
  39. self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
  40. self.layerBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY)
  41. if self.importType == 'gdal':
  42. label = _("List of raster layers")
  43. elif self.importType == 'ogr':
  44. label = _("List of vector layers")
  45. else:
  46. label = _("List of %s layers") % self.importType.upper()
  47. self.layerBox.SetLabel(" %s - %s " % (label, _("right click to (un)select all")))
  48. # list of layers
  49. columns = [_('Layer id'),
  50. _('Layer name'),
  51. _('Name for output GRASS map (editable)')]
  52. if itype == 'ogr':
  53. columns.insert(2, _('Feature type'))
  54. columns.insert(3, _('Projection match'))
  55. self.list = LayersList(parent = self.panel, columns = columns)
  56. self.list.LoadData()
  57. self.optionBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
  58. label = "%s" % _("Options"))
  59. cmd = self._getCommand()
  60. task = gtask.parse_interface(cmd)
  61. for f in task.get_options()['flags']:
  62. name = f.get('name', '')
  63. desc = f.get('label', '')
  64. if not desc:
  65. desc = f.get('description', '')
  66. if not name and not desc:
  67. continue
  68. if cmd == 'r.in.gdal' and name not in ('o', 'e', 'l', 'k'):
  69. continue
  70. elif cmd == 'r.external' and name not in ('o', 'e', 'r', 'h', 'v'):
  71. continue
  72. elif cmd == 'v.in.ogr' and name not in ('c', 'z', 't', 'o', 'r', 'e', 'w'):
  73. continue
  74. elif cmd == 'v.external' and name not in ('b'):
  75. continue
  76. elif cmd == 'v.in.dxf' and name not in ('e', 't', 'b', 'f', 'i'):
  77. continue
  78. self.options[name] = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
  79. label = desc)
  80. for p in task.get_options()['params']:
  81. name = p.get('name', '')
  82. desc = p.get('label', '')
  83. if not desc:
  84. desc = p.get('description', '')
  85. if not name and not desc:
  86. continue
  87. if cmd == 'v.in.ogr' and name == 'encoding':
  88. self.options_par[name] = (_('Encoding'),
  89. wx.TextCtrl(parent = self.panel, id = wx.ID_ANY))
  90. self.overwrite = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
  91. label = _("Allow output files to overwrite existing files"))
  92. self.overwrite.SetValue(UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'))
  93. self.add = wx.CheckBox(parent = self.panel, id = wx.ID_ANY)
  94. self.closeOnFinish = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
  95. label = _("Close dialog on finish"))
  96. self.closeOnFinish.SetValue(UserSettings.Get(group = 'cmd', key = 'closeDlg', subkey = 'enabled'))
  97. #
  98. # buttons
  99. #
  100. # cancel
  101. self.btn_close = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
  102. self.btn_close.SetToolTipString(_("Close dialog"))
  103. self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
  104. # run
  105. self.btn_run = wx.Button(parent = self.panel, id = wx.ID_OK, label = _("&Import"))
  106. self.btn_run.SetToolTipString(_("Import selected layers"))
  107. self.btn_run.SetDefault()
  108. self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun)
  109. self.Bind(wx.EVT_CLOSE, lambda evt: self.Destroy())
  110. def doLayout(self):
  111. """Do layout"""
  112. dialogSizer = wx.BoxSizer(wx.VERTICAL)
  113. # dsn input
  114. dialogSizer.Add(item = self.dsnInput, proportion = 0,
  115. flag = wx.EXPAND)
  116. #
  117. # list of DXF layers
  118. #
  119. layerSizer = wx.StaticBoxSizer(self.layerBox, wx.HORIZONTAL)
  120. layerSizer.Add(item = self.list, proportion = 1,
  121. flag = wx.ALL | wx.EXPAND, border = 5)
  122. dialogSizer.Add(item = layerSizer, proportion = 1,
  123. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
  124. # options
  125. optionSizer = wx.StaticBoxSizer(self.optionBox, wx.VERTICAL)
  126. for key in self.options.keys():
  127. optionSizer.Add(item = self.options[key], proportion = 0)
  128. if self.options_par:
  129. gridBox = wx.GridBagSizer(vgap = 5, hgap = 5)
  130. row = 0
  131. for label, win in self.options_par.itervalues():
  132. gridBox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  133. label = label + ':'),
  134. pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
  135. gridBox.Add(item = win, pos = (row, 1), flag = wx.EXPAND)
  136. row += 1
  137. gridBox.AddGrowableCol(1)
  138. optionSizer.Add(item = gridBox, proportion = 0,
  139. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
  140. dialogSizer.Add(item = optionSizer, proportion = 0,
  141. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
  142. dialogSizer.Add(item = self.overwrite, proportion = 0,
  143. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  144. dialogSizer.Add(item = self.add, proportion = 0,
  145. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  146. dialogSizer.Add(item = self.closeOnFinish, proportion = 0,
  147. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  148. #
  149. # buttons
  150. #
  151. btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
  152. btnsizer.Add(item = self.btn_close, proportion = 0,
  153. flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
  154. border = 10)
  155. btnsizer.Add(item = self.btn_run, proportion = 0,
  156. flag = wx.RIGHT | wx.ALIGN_CENTER,
  157. border = 10)
  158. dialogSizer.Add(item = btnsizer, proportion = 0,
  159. flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.ALIGN_RIGHT,
  160. border = 10)
  161. # dialogSizer.SetSizeHints(self.panel)
  162. self.panel.SetAutoLayout(True)
  163. self.panel.SetSizer(dialogSizer)
  164. dialogSizer.Fit(self.panel)
  165. # auto-layout seems not work here - FIXME
  166. size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 225, 550)
  167. self.SetMinSize(size)
  168. self.SetSize((size.width, size.height + 100))
  169. # width = self.GetSize()[0]
  170. # self.list.SetColumnWidth(col = 1, width = width / 2 - 50)
  171. self.Layout()
  172. def _getCommand(self):
  173. """Get command"""
  174. return ''
  175. def OnClose(self, event = None):
  176. """Close dialog"""
  177. self.Close()
  178. def OnRun(self, event):
  179. """Import/Link data (each layes as separate vector map)"""
  180. pass
  181. def AddLayers(self, returncode, cmd = None, userData = None):
  182. """Add imported/linked layers into layer tree"""
  183. if not self.add.IsChecked() or returncode != 0:
  184. return
  185. # TODO: if importing map creates more map the folowing does not work
  186. # * do nothing if map does not exist or
  187. # * try to determine names using regexp or
  188. # * persuade import tools to report map names
  189. self.commandId += 1
  190. layer, output = self.list.GetLayers()[self.commandId]
  191. if '@' not in output:
  192. name = output + '@' + grass.gisenv()['MAPSET']
  193. else:
  194. name = output
  195. # add imported layers into layer tree
  196. # an alternative would be emit signal (mapCreated) and (optionally)
  197. # connect to this signal
  198. llist = self._giface.GetLayerList()
  199. if self.importType == 'gdal':
  200. if userData:
  201. nBands = int(userData.get('nbands', 1))
  202. else:
  203. nBands = 1
  204. if UserSettings.Get(group = 'rasterLayer', key = 'opaque', subkey = 'enabled'):
  205. nFlag = True
  206. else:
  207. nFlag = False
  208. for i in range(1, nBands+1):
  209. nameOrig = name
  210. if nBands > 1:
  211. mapName, mapsetName = name.split('@')
  212. mapName += '.%d' % i
  213. name = mapName + '@' + mapsetName
  214. cmd = ['d.rast',
  215. 'map=%s' % name]
  216. if nFlag:
  217. cmd.append('-n')
  218. llist.AddLayer(ltype='raster',
  219. name=name, checked=True,
  220. cmd=cmd)
  221. name = nameOrig
  222. else:
  223. llist.AddLayer(ltype='vector',
  224. name=name, checked=True,
  225. cmd=['d.vect',
  226. 'map=%s' % name] + GetDisplayVectSettings())
  227. self._giface.GetMapWindow().ZoomToMap()
  228. def OnAbort(self, event):
  229. """Abort running import
  230. .. todo::
  231. not yet implemented
  232. """
  233. pass
  234. def OnCmdDone(self, event):
  235. """Do what has to be done after importing"""
  236. pass
  237. class GdalImportDialog(ImportDialog):
  238. def __init__(self, parent, giface, ogr = False, link = False):
  239. """Dialog for bulk import of various raster/vector data
  240. .. todo::
  241. Split into GdalImportDialog and OgrImportDialog
  242. :param parent: parent window
  243. :param ogr: True for OGR (vector) otherwise GDAL (raster)
  244. :param link: True for linking data otherwise importing data
  245. """
  246. self._giface = giface
  247. self.link = link
  248. self.ogr = ogr
  249. if ogr:
  250. ImportDialog.__init__(self, parent, giface=giface, itype='ogr')
  251. if link:
  252. self.SetTitle(_("Link external vector data"))
  253. else:
  254. self.SetTitle(_("Import vector data"))
  255. else:
  256. ImportDialog.__init__(self, parent, giface=giface, itype='gdal')
  257. if link:
  258. self.SetTitle(_("Link external raster data"))
  259. else:
  260. self.SetTitle(_("Import raster data"))
  261. self.dsnInput = GdalSelect(parent = self, panel = self.panel,
  262. ogr = ogr, link = link)
  263. self.dsnInput.AttachSettings()
  264. self.dsnInput.reloadDataRequired.connect(lambda data: self.list.LoadData(data))
  265. if link:
  266. self.add.SetLabel(_("Add linked layers into layer tree"))
  267. else:
  268. self.add.SetLabel(_("Add imported layers into layer tree"))
  269. self.add.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
  270. if link:
  271. self.btn_run.SetLabel(_("&Link"))
  272. self.btn_run.SetToolTipString(_("Link selected layers"))
  273. else:
  274. self.btn_run.SetLabel(_("&Import"))
  275. self.btn_run.SetToolTipString(_("Import selected layers"))
  276. self.doLayout()
  277. def OnRun(self, event):
  278. """Import/Link data (each layes as separate vector map)"""
  279. self.commandId = -1
  280. data = self.list.GetLayers()
  281. if not data:
  282. GMessage(_("No layers selected. Operation canceled."),
  283. parent = self)
  284. return
  285. dsn = self.dsnInput.GetDsn()
  286. ext = self.dsnInput.GetFormatExt()
  287. # determine data driver for PostGIS links
  288. self.popOGR = False
  289. if self.importType == 'ogr' and \
  290. self.dsnInput.GetType() == 'db' and \
  291. self.dsnInput.GetFormat() == 'PostgreSQL' and \
  292. 'GRASS_VECTOR_OGR' not in os.environ:
  293. self.popOGR = True
  294. os.environ['GRASS_VECTOR_OGR'] = '1'
  295. for layer, output in data:
  296. userData = {}
  297. if self.importType == 'ogr':
  298. if ext and layer.rfind(ext) > -1:
  299. layer = layer.replace('.' + ext, '')
  300. if '|' in layer:
  301. layer, geometry = layer.split('|', 1)
  302. else:
  303. geometry = None
  304. if self.link:
  305. cmd = ['v.external',
  306. 'input=%s' % dsn,
  307. 'output=%s' % output,
  308. 'layer=%s' % layer]
  309. else:
  310. cmd = ['v.in.ogr',
  311. 'input=%s' % dsn,
  312. 'layer=%s' % layer,
  313. 'output=%s' % output]
  314. if geometry:
  315. cmd.append('geometry=%s' % geometry)
  316. else: # gdal
  317. if self.dsnInput.GetType() == 'dir':
  318. idsn = os.path.join(dsn, layer)
  319. else:
  320. idsn = dsn
  321. # check number of bands
  322. nBandsStr = RunCommand('r.in.gdal',
  323. flags = 'p',
  324. input = idsn, read = True)
  325. nBands = -1
  326. if nBandsStr:
  327. try:
  328. nBands = int(nBandsStr.rstrip('\n'))
  329. except:
  330. pass
  331. if nBands < 0:
  332. GWarning(_("Unable to determine number of raster bands"),
  333. parent = self)
  334. nBands = 1
  335. userData['nbands'] = nBands
  336. if self.link:
  337. cmd = ['r.external',
  338. 'input=%s' % idsn,
  339. 'output=%s' % output]
  340. else:
  341. cmd = ['r.in.gdal',
  342. 'input=%s' % idsn,
  343. 'output=%s' % output]
  344. if nBands > 1:
  345. cmd.append('-k')
  346. if self.overwrite.IsChecked():
  347. cmd.append('--overwrite')
  348. for key in self.options.keys():
  349. if self.options[key].IsChecked():
  350. cmd.append('-%s' % key)
  351. for key in self.options_par.keys():
  352. value = self.options_par[key][1].GetValue()
  353. if value:
  354. cmd.append('%s=%s' % (key, value))
  355. if UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled') and \
  356. '--overwrite' not in cmd:
  357. cmd.append('--overwrite')
  358. # run in Layer Manager
  359. self._giface.RunCmd(cmd, onDone = self.OnCmdDone, userData = userData)
  360. def OnCmdDone(self, event):
  361. """Load layers and close if required"""
  362. if not hasattr(self, 'AddLayers'):
  363. return
  364. self.AddLayers(event.returncode, event.cmd, event.userData)
  365. if self.popOGR:
  366. os.environ.pop('GRASS_VECTOR_OGR')
  367. if event.returncode == 0 and self.closeOnFinish.IsChecked():
  368. self.Close()
  369. def _getCommand(self):
  370. """Get command"""
  371. if self.link:
  372. if self.ogr:
  373. return 'v.external'
  374. else:
  375. return 'r.external'
  376. else:
  377. if self.ogr:
  378. return 'v.in.ogr'
  379. else:
  380. return 'r.in.gdal'
  381. return ''
  382. class GdalOutputDialog(wx.Dialog):
  383. def __init__(self, parent, id = wx.ID_ANY, ogr = False,
  384. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, *kwargs):
  385. """Dialog for setting output format for rasters/vectors
  386. .. todo::
  387. Split into GdalOutputDialog and OgrOutputDialog
  388. :param parent: parent window
  389. :param id: window id
  390. :param ogr: True for OGR (vector) otherwise GDAL (raster)
  391. :param style: window style
  392. :param *kwargs: other wx.Dialog's arguments
  393. """
  394. self.parent = parent # GMFrame
  395. self.ogr = ogr
  396. wx.Dialog.__init__(self, parent, id = id, style = style, *kwargs)
  397. if self.ogr:
  398. self.SetTitle(_("Define output format for vector data"))
  399. else:
  400. self.SetTitle(_("Define output format for raster data"))
  401. self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
  402. # buttons
  403. self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
  404. self.btnCancel.SetToolTipString(_("Close dialog"))
  405. self.btnOk = wx.Button(parent = self.panel, id = wx.ID_OK)
  406. self.btnOk.SetToolTipString(_("Set external format and close dialog"))
  407. self.btnOk.SetDefault()
  408. self.dsnInput = GdalSelect(parent = self, panel = self.panel,
  409. ogr = ogr,
  410. exclude = ['file', 'protocol'], dest = True)
  411. self.dsnInput.AttachSettings()
  412. self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
  413. self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOk)
  414. self._layout()
  415. def _layout(self):
  416. dialogSizer = wx.BoxSizer(wx.VERTICAL)
  417. dialogSizer.Add(item = self.dsnInput, proportion = 1,
  418. flag = wx.EXPAND)
  419. btnSizer = wx.BoxSizer(orient = wx.HORIZONTAL)
  420. btnSizer.Add(item = self.btnCancel, proportion = 0,
  421. flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
  422. border = 10)
  423. btnSizer.Add(item = self.btnOk, proportion = 0,
  424. flag = wx.RIGHT | wx.ALIGN_CENTER,
  425. border = 10)
  426. dialogSizer.Add(item = btnSizer, proportion = 0,
  427. flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.TOP | wx.ALIGN_RIGHT,
  428. border = 10)
  429. self.panel.SetAutoLayout(True)
  430. self.panel.SetSizer(dialogSizer)
  431. dialogSizer.Fit(self.panel)
  432. size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 225, self.GetBestSize()[1] + 35)
  433. self.SetMinSize(size)
  434. self.SetSize((size.width, size.height))
  435. self.Layout()
  436. def OnCancel(self, event):
  437. self.Destroy()
  438. def OnOK(self, event):
  439. if self.dsnInput.GetType() == 'native':
  440. RunCommand('v.external.out',
  441. parent = self,
  442. flags = 'r')
  443. else:
  444. dsn = self.dsnInput.GetDsn()
  445. frmt = self.dsnInput.GetFormat()
  446. options = self.dsnInput.GetOptions()
  447. if not dsn:
  448. GMessage(_("No data source selected."), parent=self)
  449. return
  450. RunCommand('v.external.out',
  451. parent = self,
  452. output = dsn, format = frmt,
  453. options = options)
  454. self.Close()
  455. class DxfImportDialog(ImportDialog):
  456. """Dialog for bulk import of DXF layers"""
  457. def __init__(self, parent, giface):
  458. ImportDialog.__init__(self, parent, giface=giface, itype='dxf',
  459. title = _("Import DXF layers"))
  460. self._giface = giface
  461. self.dsnInput = filebrowse.FileBrowseButton(parent = self.panel, id = wx.ID_ANY,
  462. size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
  463. dialogTitle = _('Choose DXF file to import'),
  464. buttonText = _('Browse'),
  465. startDirectory = os.getcwd(), fileMode = 0,
  466. changeCallback = self.OnSetDsn,
  467. fileMask = "DXF File (*.dxf)|*.dxf")
  468. self.add.SetLabel(_("Add imported layers into layer tree"))
  469. self.add.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
  470. self.doLayout()
  471. def _getCommand(self):
  472. """Get command"""
  473. return 'v.in.dxf'
  474. def OnRun(self, event):
  475. """Import/Link data (each layes as separate vector map)"""
  476. data = self.list.GetLayers()
  477. if not data:
  478. GMessage(_("No layers selected."), parent=self)
  479. return
  480. # hide dialog
  481. self.Hide()
  482. inputDxf = self.dsnInput.GetValue()
  483. for layer, output in data:
  484. cmd = ['v.in.dxf',
  485. 'input=%s' % inputDxf,
  486. 'layers=%s' % layer,
  487. 'output=%s' % output]
  488. for key in self.options.keys():
  489. if self.options[key].IsChecked():
  490. cmd.append('-%s' % key)
  491. if self.overwrite.IsChecked() or \
  492. UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
  493. cmd.append('--overwrite')
  494. # run in Layer Manager
  495. self._giface.RunCmd(cmd, onDone=self.OnCmdDone)
  496. def OnCmdDone(self, event):
  497. """Load layers and close if required"""
  498. if not hasattr(self, 'AddLayers'):
  499. return
  500. self.AddLayers(event.returncode, event.cmd)
  501. if self.closeOnFinish.IsChecked():
  502. self.Close()
  503. def OnSetDsn(self, event):
  504. """Input DXF file defined, update list of layer widget"""
  505. path = event.GetString()
  506. if not path:
  507. return
  508. data = list()
  509. ret = RunCommand('v.in.dxf',
  510. quiet = True,
  511. parent = self,
  512. read = True,
  513. flags = 'l',
  514. input = path)
  515. if not ret:
  516. self.list.LoadData()
  517. return
  518. for line in ret.splitlines():
  519. layerId = line.split(':')[0].split(' ')[1]
  520. layerName = line.split(':')[1].strip()
  521. grassName = GetValidLayerName(layerName)
  522. data.append((layerId, layerName.strip(), grassName.strip()))
  523. self.list.LoadData(data)