gdialogs.py 36 KB

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