gdialogs.py 41 KB

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