mcalc_builder.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. """!
  2. @package modules::mcalc_builder
  3. @brief Map calculator, GUI wrapper for r.mapcalc
  4. Classes:
  5. - mcalc_builder::MapCalcFrame
  6. (C) 2008, 2011-2012 by the GRASS Development Team
  7. This program is free software under the GNU General Public License
  8. (>=v2). Read the file COPYING that comes with GRASS for details.
  9. @author Michael Barton, Arizona State University
  10. @author Martin Landa <landa.martin gmail.com>
  11. @author Tim Michelsen (load/save expression)
  12. """
  13. import os
  14. import sys
  15. import wx
  16. import grass.script as grass
  17. if __name__ == "__main__":
  18. sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'wxpython'))
  19. from core import globalvar
  20. from core.gcmd import GError, RunCommand
  21. from gui_core.gselect import Select
  22. from gui_core.forms import GUI
  23. from core.settings import UserSettings
  24. class MapCalcFrame(wx.Frame):
  25. """!Mapcalc Frame class. Calculator-style window to create and run
  26. r(3).mapcalc statements.
  27. """
  28. def __init__(self, parent, cmd, id = wx.ID_ANY,
  29. style = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER, **kwargs):
  30. self.parent = parent
  31. if self.parent:
  32. self.log = self.parent.GetLogWindow()
  33. else:
  34. self.log = None
  35. # grass command
  36. self.cmd = cmd
  37. if self.cmd == 'r.mapcalc':
  38. self.rast3d = False
  39. title = _('GRASS GIS Raster Map Calculator')
  40. if self.cmd == 'r3.mapcalc':
  41. self.rast3d = True
  42. title = _('GRASS GIS 3D Raster Map Calculator')
  43. wx.Frame.__init__(self, parent, id = id, title = title, **kwargs)
  44. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
  45. self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
  46. self.CreateStatusBar()
  47. #
  48. # variables
  49. #
  50. self.heading = _('mapcalc statement')
  51. self.funct_dict = {
  52. 'abs(x)':'abs()',
  53. 'acos(x)':'acos()',
  54. 'asin(x)':'asin()',
  55. 'atan(x)':'atan()',
  56. 'atan(x,y)':'atan( , )',
  57. 'cos(x)':'cos()',
  58. 'double(x)':'double()',
  59. 'eval([x,y,...,]z)':'eval()',
  60. 'exp(x)':'exp()',
  61. 'exp(x,y)':'exp( , )',
  62. 'float(x)':'float()',
  63. 'graph(x,x1,y1[x2,y2..])':'graph( , , )',
  64. 'if(x)':'if()',
  65. 'if(x,a)':'if( , )',
  66. 'if(x,a,b)':'if( , , )',
  67. 'if(x,a,b,c)':'if( , , , )',
  68. 'int(x)':'if()',
  69. 'isnull(x)':'isnull()',
  70. 'log(x)':'log(',
  71. 'log(x,b)':'log( , )',
  72. 'max(x,y[,z...])':'max( , )',
  73. 'median(x,y[,z...])':'median( , )',
  74. 'min(x,y[,z...])':'min( , )',
  75. 'mode(x,y[,z...])':'mode( , )',
  76. 'not(x)':'not()',
  77. 'pow(x,y)':'pow( , )',
  78. 'rand(a,b)':'rand( , )',
  79. 'round(x)':'round()',
  80. 'sin(x)':'sin()',
  81. 'sqrt(x)':'sqrt()',
  82. 'tan(x)':'tan()',
  83. 'xor(x,y)':'xor( , )',
  84. 'row()':'row()',
  85. 'col()':'col()',
  86. 'x()':'x()',
  87. 'y()':'y()',
  88. 'ewres()':'ewres()',
  89. 'nsres()':'nsres()',
  90. 'null()':'null()'
  91. }
  92. if self.rast3d:
  93. self.funct_dict['z()'] = 'z()'
  94. self.funct_dict['tbres()'] = 'tbres()'
  95. element = 'rast3d'
  96. else:
  97. element = 'cell'
  98. # characters which can be in raster map name but the map name must be then quoted
  99. self.charactersToQuote = '+-&!<>%~?^|'
  100. # stores last typed map name in Select widget to distinguish typing from selection
  101. self.lastMapName = ''
  102. self.operatorBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
  103. label=" %s " % _('Operators'))
  104. self.outputBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
  105. label=" %s " % _('Output'))
  106. self.operandBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
  107. label=" %s " % _('Operands'))
  108. self.expressBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
  109. label=" %s " % _('Expression'))
  110. #
  111. # Buttons
  112. #
  113. self.btn_clear = wx.Button(parent = self.panel, id = wx.ID_CLEAR)
  114. self.btn_help = wx.Button(parent = self.panel, id = wx.ID_HELP)
  115. self.btn_run = wx.Button(parent = self.panel, id = wx.ID_ANY, label = _("&Run"))
  116. self.btn_run.SetForegroundColour(wx.Colour(35, 142, 35))
  117. self.btn_run.SetDefault()
  118. self.btn_close = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
  119. self.btn_cmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
  120. label = _("Command dialog"))
  121. self.btn_cmd.SetToolTipString(_('Open %s dialog') % self.cmd)
  122. self.btn_save = wx.Button(parent = self.panel, id = wx.ID_SAVE)
  123. self.btn_save.SetToolTipString(_('Save expression to file'))
  124. self.btn_load = wx.Button(parent = self.panel, id = wx.ID_ANY,
  125. label = _("&Load"))
  126. self.btn_load.SetToolTipString(_('Load expression from file'))
  127. self.btn = dict()
  128. self.btn['pow'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "^")
  129. self.btn['pow'].SetToolTipString(_('exponent'))
  130. self.btn['div'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "/")
  131. self.btn['div'].SetToolTipString(_('divide'))
  132. self.btn['add'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "+")
  133. self.btn['add'].SetToolTipString(_('add'))
  134. self.btn['minus'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "-")
  135. self.btn['minus'].SetToolTipString(_('subtract'))
  136. self.btn['mod'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "%")
  137. self.btn['mod'].SetToolTipString(_('modulus'))
  138. self.btn['mult'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "*")
  139. self.btn['mult'].SetToolTipString(_('multiply'))
  140. self.btn['parenl'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "(")
  141. self.btn['parenr'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ")")
  142. self.btn['lshift'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "<<")
  143. self.btn['lshift'].SetToolTipString(_('left shift'))
  144. self.btn['rshift'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ">>")
  145. self.btn['rshift'].SetToolTipString(_('right shift'))
  146. self.btn['rshiftu'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ">>>")
  147. self.btn['rshiftu'].SetToolTipString(_('right shift (unsigned)'))
  148. self.btn['gt'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ">")
  149. self.btn['gt'].SetToolTipString(_('greater than'))
  150. self.btn['gteq'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ">=")
  151. self.btn['gteq'].SetToolTipString(_('greater than or equal to'))
  152. self.btn['lt'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "<")
  153. self.btn['lt'].SetToolTipString(_('less than'))
  154. self.btn['lteq'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "<=")
  155. self.btn['lteq'].SetToolTipString(_('less than or equal to'))
  156. self.btn['eq'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "==")
  157. self.btn['eq'].SetToolTipString(_('equal to'))
  158. self.btn['noteq'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "!=")
  159. self.btn['noteq'].SetToolTipString(_('not equal to'))
  160. self.btn['compl'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "~")
  161. self.btn['compl'].SetToolTipString(_('one\'s complement'))
  162. self.btn['not'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "!")
  163. self.btn['not'].SetToolTipString(_('NOT'))
  164. self.btn['andbit'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = '&&')
  165. self.btn['andbit'].SetToolTipString(_('bitwise AND'))
  166. self.btn['orbit'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "|")
  167. self.btn['orbit'].SetToolTipString(_('bitwise OR'))
  168. self.btn['and'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "&&&&")
  169. self.btn['and'].SetToolTipString(_('logical AND'))
  170. self.btn['andnull'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "&&&&&&")
  171. self.btn['andnull'].SetToolTipString(_('logical AND (ignores NULLs)'))
  172. self.btn['or'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "||")
  173. self.btn['or'].SetToolTipString(_('logical OR'))
  174. self.btn['ornull'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "|||")
  175. self.btn['ornull'].SetToolTipString(_('logical OR (ignores NULLs)'))
  176. self.btn['cond'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "a ? b : c")
  177. self.btn['cond'].SetToolTipString(_('conditional'))
  178. #
  179. # Text area
  180. #
  181. self.text_mcalc = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY, size = (-1, 75),
  182. style = wx.TE_MULTILINE)
  183. wx.CallAfter(self.text_mcalc.SetFocus)
  184. #
  185. # Map and function insertion text and ComboBoxes
  186. self.newmaplabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY)
  187. if self.rast3d:
  188. self.newmaplabel.SetLabel(_('Name for new 3D raster map to create'))
  189. else:
  190. self.newmaplabel.SetLabel(_('Name for new raster map to create'))
  191. self.newmaptxt = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY, size=(250, -1))
  192. self.mapsellabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY)
  193. if self.rast3d:
  194. self.mapsellabel.SetLabel(_('Insert existing 3D raster map'))
  195. else:
  196. self.mapsellabel.SetLabel(_('Insert existing raster map'))
  197. self.mapselect = Select(parent = self.panel, id = wx.ID_ANY, size = (250, -1),
  198. type = element, multiple = False)
  199. self.functlabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  200. label = _('Insert mapcalc function'))
  201. self.function = wx.ComboBox(parent = self.panel, id = wx.ID_ANY,
  202. size = (250, -1), choices = sorted(self.funct_dict.keys()),
  203. style = wx.CB_DROPDOWN |
  204. wx.CB_READONLY | wx.TE_PROCESS_ENTER)
  205. self.overwrite = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
  206. label=_("Allow output files to overwrite existing files"))
  207. self.overwrite.SetValue(UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'))
  208. self.addbox = wx.CheckBox(parent=self.panel,
  209. label=_('Add created raster map into layer tree'), style = wx.NO_BORDER)
  210. self.addbox.SetValue(UserSettings.Get(group='cmd', key='addNewLayer', subkey='enabled'))
  211. if not self.parent or self.parent.GetName() != 'LayerManager':
  212. self.addbox.Hide()
  213. #
  214. # Bindings
  215. #
  216. for btn in self.btn.keys():
  217. self.btn[btn].Bind(wx.EVT_BUTTON, self.AddMark)
  218. self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
  219. self.btn_clear.Bind(wx.EVT_BUTTON, self.OnClear)
  220. self.btn_run.Bind(wx.EVT_BUTTON, self.OnMCalcRun)
  221. self.btn_help.Bind(wx.EVT_BUTTON, self.OnHelp)
  222. self.btn_cmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
  223. self.btn_save.Bind(wx.EVT_BUTTON, self.OnSaveExpression)
  224. self.btn_load.Bind(wx.EVT_BUTTON, self.OnLoadExpression)
  225. self.mapselect.Bind(wx.EVT_TEXT, self.OnSelectTextEvt)
  226. self.function.Bind(wx.EVT_COMBOBOX, self._return_funct)
  227. self.function.Bind(wx.EVT_TEXT_ENTER, self.OnSelect)
  228. self.newmaptxt.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
  229. self.text_mcalc.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
  230. self._layout()
  231. self.SetMinSize(self.GetBestSize())
  232. def _return_funct(self,event):
  233. i = event.GetString()
  234. self._addSomething(self.funct_dict[i])
  235. def _layout(self):
  236. sizer = wx.BoxSizer(wx.VERTICAL)
  237. controlSizer = wx.BoxSizer(wx.HORIZONTAL)
  238. operatorSizer = wx.StaticBoxSizer(self.operatorBox, wx.HORIZONTAL)
  239. outOpeSizer = wx.BoxSizer(wx.VERTICAL)
  240. buttonSizer1 = wx.GridBagSizer(5, 1)
  241. buttonSizer1.Add(item = self.btn['add'], pos = (0,0))
  242. buttonSizer1.Add(item = self.btn['minus'], pos = (0,1))
  243. buttonSizer1.Add(item = self.btn['mod'], pos = (5,0))
  244. buttonSizer1.Add(item = self.btn['mult'], pos = (1,0))
  245. buttonSizer1.Add(item = self.btn['div'], pos = (1,1))
  246. buttonSizer1.Add(item = self.btn['pow'], pos = (5,1))
  247. buttonSizer1.Add(item = self.btn['gt'], pos = (2,0))
  248. buttonSizer1.Add(item = self.btn['gteq'], pos = (2,1))
  249. buttonSizer1.Add(item = self.btn['eq'], pos = (4,0))
  250. buttonSizer1.Add(item = self.btn['lt'], pos = (3,0))
  251. buttonSizer1.Add(item = self.btn['lteq'], pos = (3,1))
  252. buttonSizer1.Add(item = self.btn['noteq'], pos = (4,1))
  253. buttonSizer2 = wx.GridBagSizer(5, 1)
  254. buttonSizer2.Add(item = self.btn['and'], pos = (0,0))
  255. buttonSizer2.Add(item = self.btn['andbit'], pos = (1,0))
  256. buttonSizer2.Add(item = self.btn['andnull'], pos = (2,0))
  257. buttonSizer2.Add(item = self.btn['or'], pos = (0,1))
  258. buttonSizer2.Add(item = self.btn['orbit'], pos = (1,1))
  259. buttonSizer2.Add(item = self.btn['ornull'], pos = (2,1))
  260. buttonSizer2.Add(item = self.btn['lshift'], pos = (3,0))
  261. buttonSizer2.Add(item = self.btn['rshift'], pos = (3,1))
  262. buttonSizer2.Add(item = self.btn['rshiftu'], pos = (4,0))
  263. buttonSizer2.Add(item = self.btn['cond'], pos = (5,0))
  264. buttonSizer2.Add(item = self.btn['compl'], pos = (5,1))
  265. buttonSizer2.Add(item = self.btn['not'], pos = (4,1))
  266. outputSizer = wx.StaticBoxSizer(self.outputBox, wx.VERTICAL)
  267. outputSizer.Add(item = self.newmaplabel,
  268. flag = wx.ALIGN_CENTER | wx.BOTTOM | wx.TOP, border = 5)
  269. outputSizer.Add(item = self.newmaptxt,
  270. flag = wx.EXPAND)
  271. operandSizer = wx.StaticBoxSizer(self.operandBox, wx.HORIZONTAL)
  272. buttonSizer3 = wx.GridBagSizer(7, 1)
  273. buttonSizer3.Add(item = self.functlabel, pos = (0,0),
  274. span = (1,2), flag = wx.ALIGN_CENTER)
  275. buttonSizer3.Add(item = self.function, pos = (1,0),
  276. span = (1,2))
  277. buttonSizer3.Add(item = self.mapsellabel, pos = (2,0),
  278. span = (1,2), flag = wx.ALIGN_CENTER)
  279. buttonSizer3.Add(item = self.mapselect, pos = (3,0),
  280. span = (1,2))
  281. threebutton = wx.GridBagSizer(1, 2)
  282. threebutton.Add(item = self.btn['parenl'], pos = (0,0),
  283. span = (1,1), flag = wx.ALIGN_LEFT)
  284. threebutton.Add(item = self.btn['parenr'], pos = (0,1),
  285. span = (1,1), flag = wx.ALIGN_CENTER)
  286. threebutton.Add(item = self.btn_clear, pos = (0,2),
  287. span = (1,1), flag = wx.ALIGN_RIGHT)
  288. buttonSizer3.Add(item = threebutton, pos = (4,0),
  289. span = (1,1), flag = wx.ALIGN_CENTER)
  290. buttonSizer4 = wx.BoxSizer(wx.HORIZONTAL)
  291. buttonSizer4.Add(item = self.btn_cmd,
  292. flag = wx.ALL, border = 5)
  293. buttonSizer4.AddSpacer(10)
  294. buttonSizer4.Add(item = self.btn_load,
  295. flag = wx.ALL, border = 5)
  296. buttonSizer4.Add(item = self.btn_save,
  297. flag = wx.ALL, border = 5)
  298. buttonSizer4.AddSpacer(30)
  299. buttonSizer4.Add(item = self.btn_help,
  300. flag = wx.ALL, border = 5)
  301. buttonSizer4.Add(item = self.btn_run,
  302. flag = wx.ALL, border = 5)
  303. buttonSizer4.Add(item = self.btn_close,
  304. flag = wx.ALL, border = 5)
  305. operatorSizer.Add(item = buttonSizer1, proportion = 0,
  306. flag = wx.ALL | wx.EXPAND, border = 5)
  307. operatorSizer.Add(item = buttonSizer2, proportion = 0,
  308. flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND, border = 5)
  309. operandSizer.Add(item = buttonSizer3, proportion = 0,
  310. flag = wx.TOP | wx.BOTTOM | wx.RIGHT, border = 5)
  311. controlSizer.Add(item = operatorSizer, proportion = 1,
  312. flag = wx.RIGHT | wx.EXPAND, border = 5)
  313. outOpeSizer.Add(item = outputSizer, proportion = 0,
  314. flag = wx.EXPAND)
  315. outOpeSizer.Add(item = operandSizer, proportion = 1,
  316. flag = wx.EXPAND | wx.TOP, border = 5)
  317. controlSizer.Add(item = outOpeSizer, proportion = 0,
  318. flag = wx.EXPAND)
  319. expressSizer = wx.StaticBoxSizer(self.expressBox, wx.HORIZONTAL)
  320. expressSizer.Add(item = self.text_mcalc, proportion = 1,
  321. flag = wx.EXPAND)
  322. sizer.Add(item = controlSizer, proportion = 0,
  323. flag = wx.EXPAND | wx.ALL,
  324. border = 5)
  325. sizer.Add(item = expressSizer, proportion = 1,
  326. flag = wx.EXPAND | wx.LEFT | wx.RIGHT,
  327. border = 5)
  328. sizer.Add(item = buttonSizer4, proportion = 0,
  329. flag = wx.ALIGN_RIGHT | wx.ALL, border = 3)
  330. sizer.Add(item = self.overwrite, proportion = 0,
  331. flag = wx.LEFT | wx.RIGHT,
  332. border = 5)
  333. if self.addbox.IsShown():
  334. sizer.Add(item = self.addbox, proportion = 0,
  335. flag = wx.LEFT | wx.RIGHT,
  336. border = 5)
  337. self.panel.SetAutoLayout(True)
  338. self.panel.SetSizer(sizer)
  339. sizer.Fit(self.panel)
  340. self.Layout()
  341. def AddMark(self,event):
  342. """!Sends operators to insertion method
  343. """
  344. if event.GetId() == self.btn['compl'].GetId(): mark = "~"
  345. elif event.GetId() == self.btn['not'].GetId(): mark = "!"
  346. elif event.GetId() == self.btn['pow'].GetId(): mark = "^"
  347. elif event.GetId() == self.btn['div'].GetId(): mark = "/"
  348. elif event.GetId() == self.btn['add'].GetId(): mark = "+"
  349. elif event.GetId() == self.btn['minus'].GetId(): mark = "-"
  350. elif event.GetId() == self.btn['mod'].GetId(): mark = "%"
  351. elif event.GetId() == self.btn['mult'].GetId(): mark = "*"
  352. elif event.GetId() == self.btn['lshift'].GetId(): mark = "<<"
  353. elif event.GetId() == self.btn['rshift'].GetId(): mark = ">>"
  354. elif event.GetId() == self.btn['rshiftu'].GetId(): mark = ">>>"
  355. elif event.GetId() == self.btn['gt'].GetId(): mark = ">"
  356. elif event.GetId() == self.btn['gteq'].GetId(): mark = ">="
  357. elif event.GetId() == self.btn['lt'].GetId(): mark = "<"
  358. elif event.GetId() == self.btn['lteq'].GetId(): mark = "<="
  359. elif event.GetId() == self.btn['eq'].GetId(): mark = "=="
  360. elif event.GetId() == self.btn['noteq'].GetId(): mark = "!="
  361. elif event.GetId() == self.btn['andbit'].GetId(): mark = "&"
  362. elif event.GetId() == self.btn['orbit'].GetId(): mark = "|"
  363. elif event.GetId() == self.btn['or'].GetId(): mark = "||"
  364. elif event.GetId() == self.btn['ornull'].GetId(): mark = "|||"
  365. elif event.GetId() == self.btn['and'].GetId(): mark = "&&"
  366. elif event.GetId() == self.btn['andnull'].GetId(): mark = "&&&"
  367. elif event.GetId() == self.btn['cond'].GetId(): mark = " ? : "
  368. elif event.GetId() == self.btn['parenl'].GetId(): mark = "("
  369. elif event.GetId() == self.btn['parenr'].GetId(): mark = ")"
  370. self._addSomething(mark)
  371. def OnSelectTextEvt(self, event):
  372. """!Checks if user is typing or the event was emited by map selection.
  373. Prevents from changing focus.
  374. """
  375. item = event.GetString()
  376. if not (abs(len(item) - len(self.lastMapName)) == 1 and \
  377. self.lastMapName in item or item in self.lastMapName):
  378. self.OnSelect(event)
  379. self.lastMapName = item
  380. def OnSelect(self, event):
  381. """!Gets raster map or function selection and send it to
  382. insertion method.
  383. Checks for characters which can be in raster map name but
  384. the raster map name must be then quoted.
  385. """
  386. item = event.GetString().strip()
  387. if any((char in item) for char in self.charactersToQuote):
  388. item = '"' + item + '"'
  389. self._addSomething(item)
  390. def OnUpdateStatusBar(self, event):
  391. """!Update statusbar text"""
  392. expr = self.text_mcalc.GetValue().strip().replace("\n", " ")
  393. self.SetStatusText("r.mapcalc '%s = %s'" % (self.newmaptxt.GetValue(),
  394. expr))
  395. event.Skip()
  396. def _addSomething(self, what):
  397. """!Inserts operators, map names, and functions into text area
  398. """
  399. self.text_mcalc.SetFocus()
  400. mcalcstr = self.text_mcalc.GetValue()
  401. position = self.text_mcalc.GetInsertionPoint()
  402. newmcalcstr = mcalcstr[:position]
  403. position_offset = 0
  404. try:
  405. if newmcalcstr[-1] != ' ':
  406. newmcalcstr += ' '
  407. position_offset += 1
  408. except:
  409. pass
  410. newmcalcstr += what + ' ' + mcalcstr[position:]
  411. position_offset += len(what)
  412. self.text_mcalc.SetValue(newmcalcstr)
  413. if len(what) > 1 and what[-2:] == '()':
  414. position_offset -= 1
  415. self.text_mcalc.SetInsertionPoint(position + position_offset)
  416. self.text_mcalc.Update()
  417. def OnMCalcRun(self,event):
  418. """!Builds and runs r.mapcalc statement
  419. """
  420. name = self.newmaptxt.GetValue().strip()
  421. if not name:
  422. GError(parent = self,
  423. message = _("You must enter the name of "
  424. "a new raster map to create."))
  425. return
  426. if not (name[0] == '"' and name[-1] == '"') and any((char in name) for char in self.charactersToQuote):
  427. name = '"' + name + '"'
  428. expr = self.text_mcalc.GetValue().strip().replace("\n", " ")
  429. if not expr:
  430. GError(parent = self,
  431. message = _("You must enter an expression "
  432. "to create a new raster map."))
  433. return
  434. if self.log:
  435. cmd = [self.cmd, str('expression=%s = %s' % (name, expr))]
  436. if self.overwrite.IsChecked():
  437. cmd.append('--overwrite')
  438. self.log.RunCmd(cmd, onDone = self.OnDone)
  439. self.parent.Raise()
  440. else:
  441. if self.overwrite.IsChecked():
  442. overwrite = True
  443. else:
  444. overwrite = False
  445. RunCommand(self.cmd,
  446. expression = "%s=%s" % (name, expr),
  447. overwrite = overwrite)
  448. def OnDone(self, cmd, returncode):
  449. """!Add create map to the layer tree"""
  450. if not self.addbox.IsChecked():
  451. return
  452. name = self.newmaptxt.GetValue().strip(' "') + '@' + grass.gisenv()['MAPSET']
  453. mapTree = self.parent.GetLayerTree()
  454. if not mapTree.GetMap().GetListOfLayers(l_name = name):
  455. mapTree.AddLayer(ltype = 'raster',
  456. lname = name,
  457. lcmd = ['d.rast', 'map=%s' % name],
  458. multiple = False)
  459. display = self.parent.GetLayerTree().GetMapDisplay()
  460. if display and display.IsAutoRendered():
  461. display.GetWindow().UpdateMap(render = True)
  462. def OnSaveExpression(self, event):
  463. """!Saves expression to file
  464. """
  465. mctxt = self.newmaptxt.GetValue() + ' = ' + self.text_mcalc.GetValue() + os.linesep
  466. #dialog
  467. dlg = wx.FileDialog(parent = self,
  468. message = _("Choose a file name to save the expression"),
  469. wildcard = _("Expression file (*)|*"),
  470. style = wx.SAVE | wx.FD_OVERWRITE_PROMPT)
  471. if dlg.ShowModal() == wx.ID_OK:
  472. path = dlg.GetPath()
  473. if not path:
  474. dlg.Destroy()
  475. return
  476. try:
  477. fobj = open(path, 'w')
  478. fobj.write(mctxt)
  479. finally:
  480. fobj.close()
  481. dlg.Destroy()
  482. def OnLoadExpression(self, event):
  483. """!Load expression from file
  484. """
  485. dlg = wx.FileDialog(parent = self,
  486. message = _("Choose a file name to load the expression"),
  487. wildcard = _("Expression file (*)|*"),
  488. style = wx.OPEN)
  489. if dlg.ShowModal() == wx.ID_OK:
  490. path = dlg.GetPath()
  491. if not path:
  492. dlg.Destroy()
  493. return
  494. try:
  495. fobj = open(path,'r')
  496. mctxt = fobj.read()
  497. finally:
  498. fobj.close()
  499. try:
  500. result, exp = mctxt.split('=', 1)
  501. except ValueError:
  502. result = ''
  503. exp = mctxt
  504. self.newmaptxt.SetValue(result.strip())
  505. self.text_mcalc.SetValue(exp.strip())
  506. self.text_mcalc.SetFocus()
  507. self.text_mcalc.SetInsertionPointEnd()
  508. dlg.Destroy()
  509. def OnClear(self, event):
  510. """!Clears text area
  511. """
  512. self.text_mcalc.SetValue('')
  513. def OnHelp(self, event):
  514. """!Launches r.mapcalc help
  515. """
  516. RunCommand('g.manual', parent = self, entry = self.cmd)
  517. def OnClose(self,event):
  518. """!Close window"""
  519. self.Destroy()
  520. def OnCmdDialog(self, event):
  521. """!Shows command dialog"""
  522. name = self.newmaptxt.GetValue().strip()
  523. mctxt = self.text_mcalc.GetValue().strip().replace("\n"," ")
  524. mctxt = mctxt.replace(" " , "")
  525. expr = name
  526. if expr:
  527. expr += '='
  528. expr += mctxt
  529. GUI(parent = self).ParseCommand(cmd = [self.cmd, 'expression=' + expr])
  530. if __name__ == "__main__":
  531. import gettext
  532. gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
  533. app = wx.App(0)
  534. frame = MapCalcFrame(parent = None, cmd = 'r.mapcalc')
  535. frame.Show()
  536. app.MainLoop()