import_export.py 30 KB

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