import_export.py 31 KB

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