import_export.py 29 KB

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