import_export.py 30 KB

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