gdialogs.py 36 KB

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