gdialogs.py 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  1. """
  2. @package gdialogs.py
  3. @brief Common dialog used in wxGUI.
  4. List of classes:
  5. - NewVectorDialog
  6. - SavedRegion
  7. - DecorationDialog
  8. - TextLayerDialog
  9. - LoadMapLayersDialog
  10. - ImportDxfDialog
  11. - LayerList (used by ImportDxfMulti)
  12. - SetOpacityDialog
  13. (C) 2008 by the GRASS Development Team
  14. This program is free software under the GNU General Public
  15. License (>=v2). Read the file COPYING that comes with GRASS
  16. for details.
  17. @author Martin Landa <landa.martin gmail.com>
  18. """
  19. import os
  20. import sys
  21. import re
  22. import wx
  23. import wx.lib.filebrowsebutton as filebrowse
  24. import wx.lib.mixins.listctrl as listmix
  25. import gcmd
  26. import grassenv
  27. import globalvar
  28. import gselect
  29. import menuform
  30. import utils
  31. import grass
  32. from preferences import globalSettings as UserSettings
  33. class NewVectorDialog(wx.Dialog):
  34. """Create new vector map layer"""
  35. def __init__(self, parent, id, title,
  36. style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
  37. wx.Dialog.__init__(self, parent, id, title, style=style)
  38. self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
  39. self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
  40. self.btnOK = wx.Button(self.panel, wx.ID_OK)
  41. self.btnOK.SetDefault()
  42. self.btnOK.Enable(False)
  43. self.label = wx.StaticText(parent=self.panel, id=wx.ID_ANY,
  44. label=_("Name for new vector map:"))
  45. self.mapName = gselect.Select(parent=self.panel, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE,
  46. type='vector', mapsets=[grassenv.GetGRASSVariable('MAPSET'),])
  47. self.mapName.Bind(wx.EVT_TEXT, self.OnMapName)
  48. # TODO remove (see Preferences dialog)
  49. self.overwrite = wx.CheckBox(parent=self.panel, id=wx.ID_ANY,
  50. label=_("Allow output files to overwrite existing files"))
  51. self.overwrite.SetValue(UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'))
  52. self.__Layout()
  53. self.SetMinSize(self.GetSize())
  54. def OnMapName(self, event):
  55. """Name for vector map layer given"""
  56. if len(event.GetString()) > 0:
  57. self.btnOK.Enable(True)
  58. else:
  59. self.btnOK.Enable(False)
  60. def __Layout(self):
  61. """Do layout"""
  62. sizer = wx.BoxSizer(wx.VERTICAL)
  63. dataSizer = wx.BoxSizer(wx.VERTICAL)
  64. dataSizer.Add(self.label, proportion=0,
  65. flag=wx.ALL, border=1)
  66. dataSizer.Add(self.mapName, proportion=0,
  67. flag=wx.EXPAND | wx.ALL, border=1)
  68. dataSizer.Add(self.overwrite, proportion=0,
  69. flag=wx.ALL, border=1)
  70. # buttons
  71. btnSizer = wx.StdDialogButtonSizer()
  72. btnSizer.AddButton(self.btnCancel)
  73. btnSizer.AddButton(self.btnOK)
  74. btnSizer.Realize()
  75. sizer.Add(item=dataSizer, proportion=1,
  76. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  77. sizer.Add(item=btnSizer, proportion=0,
  78. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  79. self.panel.SetSizer(sizer)
  80. sizer.Fit(self)
  81. def GetName(self):
  82. """Return (mapName, overwrite)"""
  83. mapName = self.mapName.GetValue().split('@', 1)[0]
  84. return (mapName,
  85. self.overwrite.IsChecked())
  86. def CreateNewVector(parent, title=_('Create new vector map'),
  87. exceptMap=None):
  88. """Create new vector map layer
  89. @return name of create vector map
  90. @return None of failure
  91. """
  92. dlg = NewVectorDialog(parent=parent, id=wx.ID_ANY, title=title)
  93. if dlg.ShowModal() == wx.ID_OK:
  94. outmap, overwrite = dlg.GetName()
  95. if outmap == exceptMap:
  96. wx.MessageBox(parent=parent,
  97. message=_("Unable to create vector map <%s>.") % outmap,
  98. caption=_("Error"),
  99. style=wx.ID_OK | wx.ICON_ERROR | wx.CENTRE)
  100. return False
  101. if outmap == '': # should not happen
  102. return False
  103. cmd = ["v.edit",
  104. "map=%s" % outmap,
  105. "tool=create"]
  106. if overwrite is True:
  107. cmd.append('--overwrite')
  108. try:
  109. p = gcmd.Command(cmd, stderr=None)
  110. except gcmd.CmdError, e:
  111. print >> sys.stderr, e
  112. return None
  113. if p.returncode == 0:
  114. # return fully qualified map name
  115. return outmap + '@' + grassenv.GetGRASSVariable('MAPSET')
  116. return None
  117. class SavedRegion(wx.Dialog):
  118. def __init__(self, parent, id, title="", pos=wx.DefaultPosition, size=wx.DefaultSize,
  119. style=wx.DEFAULT_DIALOG_STYLE,
  120. loadsave='load'):
  121. """
  122. Loading and saving of display extents to saved region file
  123. """
  124. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  125. self.loadsave = loadsave
  126. self.wind = ''
  127. sizer = wx.BoxSizer(wx.VERTICAL)
  128. box = wx.BoxSizer(wx.HORIZONTAL)
  129. if loadsave == 'load':
  130. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Load region:"))
  131. box.Add(item=label, proportion=0, flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
  132. self.selection = gselect.Select(parent=self, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE,
  133. type='windows')
  134. box.Add(item=self.selection, proportion=0, flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
  135. self.selection.Bind(wx.EVT_TEXT, self.OnSelection)
  136. elif loadsave == 'save':
  137. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Save region:"))
  138. box.Add(item=label, proportion=0, flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
  139. self.textentry = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="",
  140. size=globalvar.DIALOG_TEXTCTRL_SIZE)
  141. box.Add(item=self.textentry, proportion=0, flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
  142. self.textentry.Bind(wx.EVT_TEXT, self.OnText)
  143. sizer.Add(item=box, proportion=0, flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL,
  144. border=5)
  145. line = wx.StaticLine(parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL)
  146. sizer.Add(item=line, proportion=0,
  147. flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border=5)
  148. btnsizer = wx.StdDialogButtonSizer()
  149. btn = wx.Button(self, wx.ID_OK)
  150. btn.SetDefault()
  151. btnsizer.AddButton(btn)
  152. btn = wx.Button(self, wx.ID_CANCEL)
  153. btnsizer.AddButton(btn)
  154. btnsizer.Realize()
  155. sizer.Add(item=btnsizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  156. self.SetSizer(sizer)
  157. sizer.Fit(self)
  158. def OnSelection(self, event):
  159. self.wind = event.GetString()
  160. def OnText(self, event):
  161. self.wind = event.GetString()
  162. class DecorationDialog(wx.Dialog):
  163. """
  164. Controls setting options and displaying/hiding map overlay decorations
  165. """
  166. def __init__(self, parent, ovlId, title, cmd, name=None,
  167. pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE,
  168. checktxt='', ctrltxt=''):
  169. wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
  170. self.ovlId = ovlId # PseudoDC id
  171. self.cmd = cmd
  172. self.name = name # overlay name
  173. self.parent = parent # MapFrame
  174. sizer = wx.BoxSizer(wx.VERTICAL)
  175. box = wx.BoxSizer(wx.HORIZONTAL)
  176. self.chkbox = wx.CheckBox(parent=self, id=wx.ID_ANY, label=checktxt)
  177. if self.parent.Map.GetOverlay(self.ovlId) is None:
  178. self.chkbox.SetValue(True)
  179. else:
  180. self.chkbox.SetValue(self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive())
  181. box.Add(item=self.chkbox, proportion=0,
  182. flag=wx.ALIGN_CENTRE|wx.ALL, border=5)
  183. sizer.Add(item=box, proportion=0,
  184. flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5)
  185. box = wx.BoxSizer(wx.HORIZONTAL)
  186. optnbtn = wx.Button(parent=self, id=wx.ID_ANY, label=_("Set options"))
  187. box.Add(item=optnbtn, proportion=0, flag=wx.ALIGN_CENTRE|wx.ALL, border=5)
  188. sizer.Add(item=box, proportion=0,
  189. flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5)
  190. box = wx.BoxSizer(wx.HORIZONTAL)
  191. label = wx.StaticText(parent=self, id=wx.ID_ANY,
  192. label=_("Drag %s with mouse in pointer mode to position.\n"
  193. "Double-click to change options." % ctrltxt))
  194. if self.name == 'legend':
  195. label.SetLabel(label.GetLabel() + _('\nDefine raster map name for legend in '
  196. 'properties dialog.'))
  197. box.Add(item=label, proportion=0,
  198. flag=wx.ALIGN_CENTRE|wx.ALL, border=5)
  199. sizer.Add(item=box, proportion=0,
  200. flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5)
  201. line = wx.StaticLine(parent=self, id=wx.ID_ANY, size=(20,-1), style=wx.LI_HORIZONTAL)
  202. sizer.Add(item=line, proportion=0,
  203. flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5)
  204. # buttons
  205. btnsizer = wx.StdDialogButtonSizer()
  206. self.btnOK = wx.Button(parent=self, id=wx.ID_OK)
  207. self.btnOK.SetDefault()
  208. if self.name == 'legend':
  209. self.btnOK.Enable(False)
  210. btnsizer.AddButton(self.btnOK)
  211. btnCancel = wx.Button(parent=self, id=wx.ID_CANCEL)
  212. btnsizer.AddButton(btnCancel)
  213. btnsizer.Realize()
  214. sizer.Add(item=btnsizer, proportion=0,
  215. flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
  216. #
  217. # bindings
  218. #
  219. self.Bind(wx.EVT_BUTTON, self.OnOptions, optnbtn)
  220. self.Bind(wx.EVT_BUTTON, self.OnCancel, btnCancel)
  221. self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOK)
  222. self.SetSizer(sizer)
  223. sizer.Fit(self)
  224. # create overlay if doesn't exist
  225. self._CreateOverlay()
  226. if len(self.parent.MapWindow.overlays[self.ovlId]['cmd']) > 1:
  227. mapName = utils.GetLayerNameFromCmd(self.parent.MapWindow.overlays[self.ovlId]['cmd'])
  228. if self.parent.MapWindow.overlays[self.ovlId]['propwin'] is None and mapName:
  229. # build properties dialog
  230. menuform.GUI().ParseCommand(cmd=self.cmd,
  231. completed=(self.GetOptData, self.name, ''),
  232. parentframe=self.parent, show=False)
  233. if mapName:
  234. # enable 'OK' button
  235. self.btnOK.Enable()
  236. # set title
  237. self.SetTitle(_('Legend of raster map <%s>') % \
  238. mapName)
  239. def _CreateOverlay(self):
  240. if not self.parent.Map.GetOverlay(self.ovlId):
  241. overlay = self.parent.Map.AddOverlay(id=self.ovlId, type=self.name,
  242. command=self.cmd,
  243. l_active=False, l_render=False, l_hidden=True)
  244. self.parent.MapWindow.overlays[self.ovlId] = {}
  245. self.parent.MapWindow.overlays[self.ovlId] = { 'layer' : overlay,
  246. 'params' : None,
  247. 'propwin' : None,
  248. 'cmd' : self.cmd,
  249. 'coords': (10, 10),
  250. 'pdcType': 'image' }
  251. else:
  252. self.parent.MapWindow.overlays[self.ovlId]['propwin'].get_dcmd = self.GetOptData
  253. def OnOptions(self, event):
  254. """ self.SetSizer(sizer)
  255. sizer.Fit(self)
  256. Sets option for decoration map overlays
  257. """
  258. if self.parent.MapWindow.overlays[self.ovlId]['propwin'] is None:
  259. # build properties dialog
  260. menuform.GUI().ParseCommand(cmd=self.cmd,
  261. completed=(self.GetOptData, self.name, ''),
  262. parentframe=self.parent)
  263. else:
  264. if self.parent.MapWindow.overlays[self.ovlId]['propwin'].IsShown():
  265. self.parent.MapWindow.overlays[self.ovlId]['propwin'].SetFocus()
  266. else:
  267. self.parent.MapWindow.overlays[self.ovlId]['propwin'].Show()
  268. def OnCancel(self, event):
  269. """Cancel dialog"""
  270. self.parent.dialogs['barscale'] = None
  271. self.Destroy()
  272. def OnOK(self, event):
  273. """Button 'OK' pressed"""
  274. # enable or disable overlay
  275. self.parent.Map.GetOverlay(self.ovlId).SetActive(self.chkbox.IsChecked())
  276. # update map
  277. self.parent.MapWindow.UpdateMap()
  278. # close dialog
  279. self.OnCancel(None)
  280. def GetOptData(self, dcmd, layer, params, propwin):
  281. """Process decoration layer data"""
  282. # update layer data
  283. if params:
  284. self.parent.MapWindow.overlays[self.ovlId]['params'] = params
  285. if dcmd:
  286. self.parent.MapWindow.overlays[self.ovlId]['cmd'] = dcmd
  287. self.parent.MapWindow.overlays[self.ovlId]['propwin'] = propwin
  288. # change parameters for item in layers list in render.Map
  289. # "Use mouse..." (-m) flag causes GUI freeze, trac #119
  290. try:
  291. self.parent.MapWindow.overlays[self.ovlId]['cmd'].remove('-m')
  292. except ValueError:
  293. pass
  294. self.parent.Map.ChangeOverlay(id=self.ovlId, type=self.name,
  295. command=self.parent.MapWindow.overlays[self.ovlId]['cmd'],
  296. l_active=self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive(),
  297. l_render=False, l_hidden=True)
  298. if self.name == 'legend' and \
  299. params and \
  300. not self.btnOK.IsEnabled():
  301. self.btnOK.Enable()
  302. self.SetTitle(_('Legend of raster map <%s>') % \
  303. utils.GetLayerNameFromCmd(self.parent.MapWindow.overlays[self.ovlId]['cmd']))
  304. class TextLayerDialog(wx.Dialog):
  305. """
  306. Controls setting options and displaying/hiding map overlay decorations
  307. """
  308. def __init__(self, parent, ovlId, title, name='text',
  309. pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE):
  310. wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
  311. self.ovlId = ovlId
  312. self.parent = parent
  313. if self.ovlId in self.parent.MapWindow.textdict:
  314. self.currText, self.currFont, self.currClr, self.currRot = self.parent.MapWindow.textdict[drawid]
  315. else:
  316. self.currClr = wx.BLACK
  317. self.currText = ''
  318. self.currFont = self.GetFont()
  319. self.currRot = 0.0
  320. sizer = wx.BoxSizer(wx.VERTICAL)
  321. box = wx.GridBagSizer(vgap=5, hgap=5)
  322. # text entry
  323. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Enter text:"))
  324. box.Add(item=label,
  325. flag=wx.ALIGN_CENTER_VERTICAL,
  326. pos=(0, 0))
  327. self.textentry = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(300,-1))
  328. self.textentry.SetFont(self.currFont)
  329. self.textentry.SetForegroundColour(self.currClr)
  330. self.textentry.SetValue(self.currText)
  331. box.Add(item=self.textentry,
  332. pos=(0, 1))
  333. # rotation
  334. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Rotation:"))
  335. box.Add(item=label,
  336. flag=wx.ALIGN_CENTER_VERTICAL,
  337. pos=(1, 0))
  338. self.rotation = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="", pos=(30, 50),
  339. size=(75,-1), style=wx.SP_ARROW_KEYS)
  340. self.rotation.SetRange(-360, 360)
  341. self.rotation.SetValue(int(self.currRot))
  342. box.Add(item=self.rotation,
  343. flag=wx.ALIGN_RIGHT,
  344. pos=(1, 1))
  345. # font
  346. fontbtn = wx.Button(parent=self, id=wx.ID_ANY, label=_("Set font"))
  347. box.Add(item=fontbtn,
  348. flag=wx.ALIGN_RIGHT,
  349. pos=(2, 1))
  350. sizer.Add(item=box, proportion=1,
  351. flag=wx.ALL, border=10)
  352. # note
  353. box = wx.BoxSizer(wx.HORIZONTAL)
  354. label = wx.StaticText(parent=self, id=wx.ID_ANY,
  355. label=_("Drag text with mouse in pointer mode "
  356. "to position.\nDouble-click to change options"))
  357. box.Add(item=label, proportion=0,
  358. flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
  359. sizer.Add(item=box, proportion=0,
  360. flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER | wx.ALL, border=5)
  361. line = wx.StaticLine(parent=self, id=wx.ID_ANY,
  362. size=(20,-1), style=wx.LI_HORIZONTAL)
  363. sizer.Add(item=line, proportion=0,
  364. flag=wx.EXPAND | wx.ALIGN_CENTRE | wx.ALL, border=5)
  365. btnsizer = wx.StdDialogButtonSizer()
  366. btn = wx.Button(parent=self, id=wx.ID_OK)
  367. btn.SetDefault()
  368. btnsizer.AddButton(btn)
  369. btn = wx.Button(parent=self, id=wx.ID_CANCEL)
  370. btnsizer.AddButton(btn)
  371. btnsizer.Realize()
  372. sizer.Add(item=btnsizer, proportion=0,
  373. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  374. self.SetSizer(sizer)
  375. sizer.Fit(self)
  376. # bindings
  377. self.Bind(wx.EVT_BUTTON, self.OnSelectFont, fontbtn)
  378. self.Bind(wx.EVT_TEXT, self.OnText, self.textentry)
  379. self.Bind(wx.EVT_SPINCTRL, self.OnRotation, self.rotation)
  380. def OnText(self, event):
  381. """Change text string"""
  382. self.currText = event.GetString()
  383. def OnRotation(self, event):
  384. """Change rotation"""
  385. self.currRot = event.GetInt()
  386. event.Skip()
  387. def OnSelectFont(self, event):
  388. """Change font"""
  389. data = wx.FontData()
  390. data.EnableEffects(True)
  391. data.SetColour(self.currClr) # set colour
  392. data.SetInitialFont(self.currFont)
  393. dlg = wx.FontDialog(self, data)
  394. if dlg.ShowModal() == wx.ID_OK:
  395. data = dlg.GetFontData()
  396. self.currFont = data.GetChosenFont()
  397. self.currClr = data.GetColour()
  398. self.textentry.SetFont(self.currFont)
  399. self.textentry.SetForegroundColour(self.currClr)
  400. self.Layout()
  401. dlg.Destroy()
  402. def GetValues(self):
  403. """Get text properties"""
  404. return (self.currText, self.currFont,
  405. self.currClr, self.currRot)
  406. class LoadMapLayersDialog(wx.Dialog):
  407. """Load selected map layers (raster, vector) into layer tree"""
  408. def __init__(self, parent, title, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
  409. wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title, style=style)
  410. self.parent = parent # GMFrame
  411. #
  412. # dialog body
  413. #
  414. self.bodySizer = self.__createDialogBody()
  415. # update list of layer to be loaded
  416. self.map_layers = [] # list of map layers (full list type/mapset)
  417. self.LoadMapLayers(self.layerType.GetStringSelection()[:4],
  418. self.mapset.GetStringSelection())
  419. #
  420. # buttons
  421. #
  422. btnCancel = wx.Button(self, wx.ID_CANCEL)
  423. btnOk = wx.Button(self, wx.ID_OK, _("Load") )
  424. btnOk.SetDefault()
  425. #
  426. # bindigs
  427. #
  428. #btnOk.Bind(wx.EVT_BUTTON, self.OnOK)
  429. #btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  430. #
  431. # sizers & do layout
  432. #
  433. btnSizer = wx.StdDialogButtonSizer()
  434. btnSizer.AddButton(btnCancel)
  435. btnSizer.AddButton(btnOk)
  436. btnSizer.Realize()
  437. mainSizer = wx.BoxSizer(wx.VERTICAL)
  438. mainSizer.Add(item=self.bodySizer, proportion=1,
  439. flag=wx.EXPAND | wx.ALL, border=5)
  440. mainSizer.Add(item=btnSizer, proportion=0,
  441. flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  442. self.SetSizer(mainSizer)
  443. mainSizer.Fit(self)
  444. # set dialog min size
  445. self.SetMinSize(self.GetSize())
  446. def __createDialogBody(self):
  447. bodySizer = wx.GridBagSizer(vgap=3, hgap=3)
  448. bodySizer.AddGrowableCol(1)
  449. bodySizer.AddGrowableRow(3)
  450. # layer type
  451. bodySizer.Add(item=wx.StaticText(parent=self, label=_("Map layer type:")),
  452. flag=wx.ALIGN_CENTER_VERTICAL,
  453. pos=(0,0))
  454. self.layerType = wx.Choice(parent=self, id=wx.ID_ANY,
  455. choices=['raster', 'vector'], size=(100,-1))
  456. self.layerType.SetSelection(0)
  457. bodySizer.Add(item=self.layerType,
  458. pos=(0,1))
  459. # mapset filter
  460. bodySizer.Add(item=wx.StaticText(parent=self, label=_("Mapset:")),
  461. flag=wx.ALIGN_CENTER_VERTICAL,
  462. pos=(1,0))
  463. self.mapset = wx.ComboBox(parent=self, id=wx.ID_ANY,
  464. style=wx.CB_SIMPLE | wx.CB_READONLY,
  465. choices=utils.ListOfMapsets(),
  466. size=(250,-1))
  467. self.mapset.SetStringSelection(grassenv.GetGRASSVariable("MAPSET"))
  468. bodySizer.Add(item=self.mapset,
  469. pos=(1,1))
  470. # map name filter
  471. bodySizer.Add(item=wx.StaticText(parent=self, label=_("Filter:")),
  472. flag=wx.ALIGN_CENTER_VERTICAL,
  473. pos=(2,0))
  474. self.filter = wx.TextCtrl(parent=self, id=wx.ID_ANY,
  475. value="",
  476. size=(250,-1))
  477. bodySizer.Add(item=self.filter,
  478. flag=wx.EXPAND,
  479. pos=(2,1))
  480. # layer list
  481. bodySizer.Add(item=wx.StaticText(parent=self, label=_("List of maps:")),
  482. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_TOP,
  483. pos=(3,0))
  484. self.layers = wx.CheckListBox(parent=self, id=wx.ID_ANY,
  485. size=(250, 100),
  486. choices=[])
  487. bodySizer.Add(item=self.layers,
  488. flag=wx.EXPAND,
  489. pos=(3,1))
  490. # bindings
  491. self.layerType.Bind(wx.EVT_CHOICE, self.OnChangeParams)
  492. self.mapset.Bind(wx.EVT_COMBOBOX, self.OnChangeParams)
  493. self.layers.Bind(wx.EVT_RIGHT_DOWN, self.OnMenu)
  494. self.filter.Bind(wx.EVT_TEXT, self.OnFilter)
  495. return bodySizer
  496. def LoadMapLayers(self, type, mapset):
  497. """Load list of map layers
  498. @param type layer type ('raster' or 'vector')
  499. @param mapset mapset name
  500. """
  501. list = gcmd.Command(['g.mlist',
  502. 'type=%s' % type,
  503. 'mapset=%s' % mapset])
  504. self.map_layers = []
  505. for map in list.ReadStdOutput():
  506. self.map_layers.append(map)
  507. self.layers.Set(self.map_layers)
  508. # check all items by default
  509. for item in range(self.layers.GetCount()):
  510. self.layers.Check(item)
  511. def OnChangeParams(self, event):
  512. """Filter parameters changed by user"""
  513. # update list of layer to be loaded
  514. self.LoadMapLayers(self.layerType.GetStringSelection()[:4],
  515. self.mapset.GetStringSelection())
  516. event.Skip()
  517. def OnMenu(self, event):
  518. """Table description area, context menu"""
  519. if not hasattr(self, "popupID1"):
  520. self.popupDataID1 = wx.NewId()
  521. self.popupDataID2 = wx.NewId()
  522. self.Bind(wx.EVT_MENU, self.OnSelectAll, id=self.popupDataID1)
  523. self.Bind(wx.EVT_MENU, self.OnDeselectAll, id=self.popupDataID2)
  524. # generate popup-menu
  525. menu = wx.Menu()
  526. menu.Append(self.popupDataID1, _("Select all"))
  527. menu.Append(self.popupDataID2, _("Deselect all"))
  528. self.PopupMenu(menu)
  529. menu.Destroy()
  530. def OnSelectAll(self, event):
  531. """Select all map layer from list"""
  532. for item in range(self.layers.GetCount()):
  533. self.layers.Check(item, True)
  534. def OnDeselectAll(self, event):
  535. """Select all map layer from list"""
  536. for item in range(self.layers.GetCount()):
  537. self.layers.Check(item, False)
  538. def OnFilter(self, event):
  539. """Apply filter for map names"""
  540. if len(event.GetString()) == 0:
  541. self.layers.Set(self.map_layers)
  542. return
  543. list = []
  544. for layer in self.map_layers:
  545. if re.compile('^' + event.GetString()).search(layer):
  546. list.append(layer)
  547. self.layers.Set(list)
  548. event.Skip()
  549. def GetMapLayers(self):
  550. """Return list of checked map layers"""
  551. layerNames = []
  552. for indx in self.layers.GetSelections():
  553. # layers.append(self.layers.GetStringSelec(indx))
  554. pass
  555. # return fully qualified map names
  556. mapset = self.mapset.GetStringSelection()
  557. for item in range(self.layers.GetCount()):
  558. if not self.layers.IsChecked(item):
  559. continue
  560. layerNames.append(self.layers.GetString(item) + '@' + mapset)
  561. return layerNames
  562. def GetLayerType(self):
  563. """Get selected layer type"""
  564. return self.layerType.GetStringSelection()
  565. class ImportDxfDialog(wx.Dialog):
  566. """Import dxf layers"""
  567. def __init__(self, parent, id=wx.ID_ANY, title=_("Import DXF layers"),
  568. style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
  569. self.parent = parent # GMFrame
  570. wx.Dialog.__init__(self, parent, id, title, style=style)
  571. self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
  572. #
  573. # input
  574. #
  575. self.input = filebrowse.FileBrowseButton(parent=self.panel, id=wx.ID_ANY,
  576. size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
  577. dialogTitle=_('Choose DXF file to import'),
  578. buttonText=_('Browse'),
  579. startDirectory=os.getcwd(), fileMode=0,
  580. changeCallback=self.OnSetInput) # TODO: wildcard
  581. #
  582. # list of layers
  583. #
  584. self.list = LayersList(self.panel)
  585. self.list.LoadData()
  586. self.add = wx.CheckBox(parent=self.panel, id=wx.ID_ANY,
  587. label=_("Add imported layers into layer tree"))
  588. self.add.SetValue(UserSettings.Get(group='cmd', key='addNewLayer', subkey='enabled'))
  589. #
  590. # buttons
  591. #
  592. # cancel
  593. self.btn_cancel = wx.Button(parent=self.panel, id=wx.ID_CANCEL)
  594. self.btn_cancel.SetToolTipString(_("Close dialog"))
  595. self.btn_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  596. # run
  597. self.btn_run = wx.Button(parent=self.panel, id=wx.ID_OK, label= _("&Import"))
  598. self.btn_run.SetToolTipString(_("Import selected layers"))
  599. self.btn_run.SetDefault()
  600. self.btn_run.Enable(False)
  601. self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun)
  602. self.__doLayout()
  603. self.Layout()
  604. def __doLayout(self):
  605. dialogSizer = wx.BoxSizer(wx.VERTICAL)
  606. #
  607. # input
  608. #
  609. inputBox = wx.StaticBox(parent=self.panel, id=wx.ID_ANY,
  610. label=" %s " % _("Input DXF file"))
  611. inputSizer = wx.StaticBoxSizer(inputBox, wx.HORIZONTAL)
  612. inputSizer.Add(item=wx.StaticText(self.panel, id=wx.ID_ANY, label=_("Choose DXF file:")),
  613. proportion=0,
  614. flag=wx.ALIGN_CENTER_VERTICAL)
  615. inputSizer.Add(item=self.input, proportion=1,
  616. flag=wx.EXPAND, border=1)
  617. dialogSizer.Add(item=inputSizer, proportion=0,
  618. flag=wx.ALL | wx.EXPAND, border=5)
  619. #
  620. # list of DXF layers
  621. #
  622. layerBox = wx.StaticBox(parent=self.panel, id=wx.ID_ANY,
  623. label=" %s " % _("List of DXF layers"))
  624. layerSizer = wx.StaticBoxSizer(layerBox, wx.HORIZONTAL)
  625. layerSizer.Add(item=self.list, proportion=1,
  626. flag=wx.ALL | wx.EXPAND, border=5)
  627. dialogSizer.Add(item=layerSizer, proportion=1,
  628. flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
  629. dialogSizer.Add(item=self.add, proportion=0,
  630. flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
  631. #
  632. # buttons
  633. #
  634. btnsizer = wx.BoxSizer(orient=wx.HORIZONTAL)
  635. btnsizer.Add(item=self.btn_cancel, proportion=0,
  636. flag=wx.ALL | wx.ALIGN_CENTER,
  637. border=10)
  638. btnsizer.Add(item=self.btn_run, proportion=0,
  639. flag=wx.ALL | wx.ALIGN_CENTER,
  640. border=10)
  641. dialogSizer.Add(item=btnsizer, proportion=0,
  642. flag=wx.ALIGN_CENTER)
  643. # dialogSizer.SetSizeHints(self.panel)
  644. self.panel.SetAutoLayout(True)
  645. self.panel.SetSizer(dialogSizer)
  646. dialogSizer.Fit(self.panel)
  647. self.Layout()
  648. # auto-layout seems not work here - FIXME
  649. self.SetMinSize((globalvar.DIALOG_GSELECT_SIZE[0] + 125, 300))
  650. width = self.GetSize()[0]
  651. self.list.SetColumnWidth(col=1, width=width/2 - 50)
  652. def OnCancel(self, event=None):
  653. """Close dialog"""
  654. self.Close()
  655. def OnRun(self, event):
  656. """Import data (each layes as separate vector map)"""
  657. data = self.list.GetLayers()
  658. # hide dialog
  659. self.Hide()
  660. for layer, output in data:
  661. cmd = ['v.in.dxf',
  662. 'input=%s' % self.input.GetValue(),
  663. 'layers=%s' % layer,
  664. 'output=%s' % output]
  665. if UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'):
  666. cmd.append('--overwrite')
  667. # run in Layer Manager
  668. self.parent.goutput.RunCmd(cmd)
  669. if self.add.IsChecked():
  670. maptree = self.parent.curr_page.maptree
  671. for layer, output in data:
  672. if '@' not in output:
  673. name = output + '@' + grass.gisenv()['MAPSET']
  674. else:
  675. name = output
  676. # add imported layers into layer tree
  677. maptree.AddLayer(ltype='vector',
  678. lname=name,
  679. lcmd=['d.vect',
  680. 'map=%s' % name])
  681. self.parent.notebook.SetSelection(0)
  682. self.OnCancel()
  683. def OnAbort(self, event):
  684. """Abort running import
  685. @todo not yet implemented
  686. """
  687. pass
  688. def OnSetInput(self, event):
  689. """Input DXF file/OGR dsn defined, update list of layer widget"""
  690. filePath = event.GetString()
  691. try:
  692. cmd = gcmd.Command(['v.in.dxf',
  693. 'input=%s' % filePath,
  694. '-l', '--q'], stderr=None)
  695. except gcmd.CmdError, e:
  696. wx.MessageBox(parent=self, message=_("File <%(file)s>: Unable to get list of DXF layers.\n\n%(details)s") % \
  697. { 'file' : filePath, 'details' : e.message },
  698. caption=_("Error"), style=wx.ID_OK | wx.ICON_ERROR | wx.CENTRE)
  699. self.list.LoadData()
  700. self.btn_run.Enable(False)
  701. return
  702. data = []
  703. for line in cmd.ReadStdOutput():
  704. layerId = line.split(':')[0].split(' ')[1]
  705. layer = line.split(':')[1]
  706. layerName, grassName = layer.split('/')
  707. data.append((layerId, layerName.strip(), grassName.strip()))
  708. self.list.LoadData(data)
  709. self.btn_run.Enable(True)
  710. class LayersList(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin,
  711. listmix.CheckListCtrlMixin, listmix.TextEditMixin):
  712. """List of layers to be imported (dxf, shp...)"""
  713. def __init__(self, parent, pos=wx.DefaultPosition,
  714. log=None):
  715. self.parent = parent
  716. wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
  717. style=wx.LC_REPORT)
  718. listmix.CheckListCtrlMixin.__init__(self)
  719. self.log = log
  720. # setup mixins
  721. listmix.ListCtrlAutoWidthMixin.__init__(self)
  722. listmix.TextEditMixin.__init__(self)
  723. self.InsertColumn(0, _('Layer'))
  724. self.InsertColumn(1, _('Layer name'))
  725. self.InsertColumn(2, _('Output vector map name (editable)'))
  726. self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnPopupMenu) #wxMSW
  727. self.Bind(wx.EVT_RIGHT_UP, self.OnPopupMenu) #wxGTK
  728. def LoadData(self, data=None):
  729. """Load data into list"""
  730. if data is None:
  731. return
  732. for id, name, grassName in data:
  733. index = self.InsertStringItem(sys.maxint, str(id))
  734. self.SetStringItem(index, 1, "%s" % str(name))
  735. self.SetStringItem(index, 2, "%s" % str(grassName))
  736. # check by default
  737. self.CheckItem(index, True)
  738. self.SetColumnWidth(col=0, width=wx.LIST_AUTOSIZE_USEHEADER)
  739. def OnPopupMenu(self, event):
  740. """Show popup menu"""
  741. if self.GetItemCount() < 1:
  742. return
  743. if not hasattr(self, "popupDataID1"):
  744. self.popupDataID1 = wx.NewId()
  745. self.popupDataID2 = wx.NewId()
  746. self.Bind(wx.EVT_MENU, self.OnSelectAll, id=self.popupDataID1)
  747. self.Bind(wx.EVT_MENU, self.OnSelectNone, id=self.popupDataID2)
  748. # generate popup-menu
  749. menu = wx.Menu()
  750. menu.Append(self.popupDataID1, _("Select all"))
  751. menu.Append(self.popupDataID2, _("Deselect all"))
  752. self.PopupMenu(menu)
  753. menu.Destroy()
  754. def OnSelectAll(self, event):
  755. """Select all items"""
  756. item = -1
  757. while True:
  758. item = self.GetNextItem(item)
  759. if item == -1:
  760. break
  761. self.CheckItem(item, True)
  762. event.Skip()
  763. def OnSelectNone(self, event):
  764. """Deselect items"""
  765. item = -1
  766. while True:
  767. item = self.GetNextItem(item, wx.LIST_STATE_SELECTED)
  768. if item == -1:
  769. break
  770. self.CheckItem(item, False)
  771. event.Skip()
  772. def GetLayers(self):
  773. """Get list of layers (layer name, output name)"""
  774. data = []
  775. item = -1
  776. while True:
  777. item = self.GetNextItem(item)
  778. if item == -1:
  779. break
  780. if self.IsChecked(item):
  781. # layer / output name
  782. data.append((self.GetItem(item, 1).GetText(),
  783. self.GetItem(item, 2).GetText()))
  784. return data
  785. class SetOpacityDialog(wx.Dialog):
  786. """Set opacity of map layers"""
  787. def __init__(self, parent, id=wx.ID_ANY, title=_("Set Map Layer Opacity"),
  788. size=wx.DefaultSize, pos=wx.DefaultPosition,
  789. style=wx.DEFAULT_DIALOG_STYLE, opacity=100):
  790. self.parent = parent # GMFrame
  791. self.opacity = opacity # current opacity
  792. super(SetOpacityDialog, self).__init__(parent, id=id, pos=pos,
  793. size=size, style=style, title=title)
  794. panel = wx.Panel(parent=self, id=wx.ID_ANY)
  795. sizer = wx.BoxSizer(wx.VERTICAL)
  796. box = wx.GridBagSizer(vgap=5, hgap=5)
  797. self.value = wx.Slider(panel, id=wx.ID_ANY, value=self.opacity,
  798. style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | \
  799. wx.SL_TOP | wx.SL_LABELS,
  800. minValue=0, maxValue=100,
  801. size=(350, -1))
  802. box.Add(item=self.value,
  803. flag=wx.ALIGN_CENTRE, pos=(0, 0), span=(1, 2))
  804. box.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
  805. label=_("transparent")),
  806. pos=(1, 0))
  807. box.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
  808. label=_("opaque")),
  809. flag=wx.ALIGN_RIGHT,
  810. pos=(1, 1))
  811. sizer.Add(item=box, proportion=0,
  812. flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
  813. line = wx.StaticLine(parent=panel, id=wx.ID_ANY,
  814. style=wx.LI_HORIZONTAL)
  815. sizer.Add(item=line, proportion=0,
  816. flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
  817. # buttons
  818. btnsizer = wx.StdDialogButtonSizer()
  819. btnOK = wx.Button(parent=panel, id=wx.ID_OK)
  820. btnOK.SetDefault()
  821. btnsizer.AddButton(btnOK)
  822. btnCancel = wx.Button(parent=panel, id=wx.ID_CANCEL)
  823. btnsizer.AddButton(btnCancel)
  824. btnsizer.Realize()
  825. sizer.Add(item=btnsizer, proportion=0,
  826. flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
  827. panel.SetSizer(sizer)
  828. sizer.Fit(panel)
  829. self.SetSize(self.GetBestSize())
  830. self.Layout()
  831. def GetOpacity(self):
  832. """Button 'OK' pressed"""
  833. # return opacity value
  834. opacity = float(self.value.GetValue()) / 100
  835. return opacity