import_export.py 28 KB

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